diff --git a/libs/Format/Confluence/Api.php b/libs/Format/Confluence/Api.php index 29da007..30e8813 100644 --- a/libs/Format/Confluence/Api.php +++ b/libs/Format/Confluence/Api.php @@ -257,42 +257,20 @@ class Api } } - /** - * @param int $id - * @param array $attachment - * @param callback $write Write output to the console - */ - public function uploadAttachment($id, $attachment, $write) + private function getAttachment($id, $attachment) { // Check if an attachment with // this name is uploaded try { $url = "content/$id/child/attachment?filename=" . urlencode($attachment['filename']); - $result = json_decode($this->getClient()->get($url)->getBody(), true); + return json_decode($this->getClient()->get($url)->getBody(), true); } catch (BadResponseException $e) { throw $this->handleError($e); } + } - $url = "content/$id/child/attachment"; - - // If the attachment is already uploaded, - // the update URL is different - if (count($result['results'])) { - - if (array_key_exists('file', $attachment)) { - $size = filesize($attachment['file']->getPath()); - } else { - $size = function_exists('mb_strlen') ? mb_strlen($attachment['content']) : strlen($attachment['content']); - } - - if ($size == $result['results'][0]['extensions']['fileSize']) { - $write(" ( An attachment of the same size already exists, skipping. )"); - return; - } - - $url .= "/{$result['results'][0]['id']}/data"; - } - + private function putAttachment($url, $id, $attachment) + { $contents = array_key_exists('file', $attachment) ? fopen($attachment['file']->getPath(), 'r') : $attachment['content']; try { @@ -307,4 +285,43 @@ class Api throw $this->handleError($e); } } + + private function getFileSize($attachment) + { + if (array_key_exists('file', $attachment)) { + return filesize($attachment['file']->getPath()); + } + + if (function_exists('mb_strlen')) { + return mb_strlen($attachment['content']); + } + + return strlen($attachment['content']); + } + + /** + * @param int $id + * @param array $attachment + * @param callback $write Write output to the console + */ + public function uploadAttachment($id, $attachment, $write) + { + $result = $this->getAttachment($id, $attachment); + + $url = "content/$id/child/attachment"; + + // If the attachment is already uploaded, + // the update URL is different + if (count($result['results'])) { + + if ($this->getFileSize($attachment) == $result['results'][0]['extensions']['fileSize']) { + $write(" ( An attachment of the same size already exists, skipping. )"); + return; + } + + $url .= "/{$result['results'][0]['id']}/data"; + } + + $this->putAttachment($url, $id, $attachment); + } } diff --git a/libs/Format/Confluence/Publisher.php b/libs/Format/Confluence/Publisher.php index 1901c43..c6bfc2d 100644 --- a/libs/Format/Confluence/Publisher.php +++ b/libs/Format/Confluence/Publisher.php @@ -17,26 +17,16 @@ class Publisher */ protected $confluence; - /** - * @var string - */ - protected $previous_title; - /** * @var int terminal width */ public $width; /** - * @var + * @var \Symfony\Component\Console\Output\Output */ public $output; - /** - * @var array files that can be deleted - */ - protected $deletable; - /** * @param $confluence */ @@ -61,24 +51,8 @@ class Publisher public function publish(array $tree) { - echo "Finding Root Page...\n"; - if (array_key_exists('ancestor_id', $this->confluence)) { - $pages = $this->client->getList($this->confluence['ancestor_id']); - $published = null; - foreach ($pages as $page) { - if ($page['title'] == $tree['title']) { - $published = $page; - break; - } - } - } elseif (array_key_exists('root_id', $this->confluence)) { - $published = $this->client->getPage($this->confluence['root_id']); - $this->confluence['ancestor_id'] = $published['ancestor_id']; - } else { - throw new \RuntimeException('You must at least specify a `root_id` or `ancestor_id` in your confluence configuration.'); - } - - + $this->output->writeLn('Finding Root Page...'); + $published = $this->getRootPage($tree); $this->run( 'Getting already published pages...', @@ -99,21 +73,35 @@ class Publisher $this->output->writeLn('Publishing updates...'); $published = $this->updateRecursive($this->confluence['ancestor_id'], $tree, $published); - $this->handleDeletables($published); + $shouldDelete = array_key_exists('delete', $this->confluence) && $this->confluence['delete']; + $delete = new PublisherDelete($this->output, $shouldDelete, $this->client); + $delete->handle($published); } - protected function niceTitle($title) + protected function getRootPage($tree) { - if ($title == 'index.html') { - return 'Homepage'; + if (array_key_exists('ancestor_id', $this->confluence)) { + $pages = $this->client->getList($this->confluence['ancestor_id']); + $published = null; + foreach ($pages as $page) { + if ($page['title'] == $tree['title']) { + return $page; + } + } } - return rtrim(strtr($title, ['index.html' => '', '.html' => '']), '/'); + if (array_key_exists('root_id', $this->confluence)) { + $published = $this->client->getPage($this->confluence['root_id']); + $this->confluence['ancestor_id'] = $published['ancestor_id']; + return $published; + } + + throw new \RuntimeException('You must at least specify a `root_id` or `ancestor_id` in your confluence configuration.'); } protected function createPage($parent_id, $entry, $published) { - echo '- ' . $this->niceTitle($entry['file']->getUrl()) . "\n"; + echo '- ' . PublisherUtilities::niceTitle($entry['file']->getUrl()) . "\n"; $published['version'] = 1; $published['title'] = $entry['title']; $published['id'] = $this->client->createPage($parent_id, $entry['title'], 'The content will come very soon !'); @@ -191,108 +179,15 @@ class Publisher return $this->recursiveWithCallback($parent_id, $entry, $published, $callback); } - protected function shouldDelete() - { - return array_key_exists('delete', $this->confluence) && $this->confluence['delete']; - } - - protected function listDeletable($published, $prefix = '') - { - foreach ($published['children'] as $child) { - if (array_key_exists('children', $child) && count($child['children'])) { - $this->listDeletable($child, $child['title'] . '/'); - } - - if (!array_key_exists('needed', $child)) { - $this->deletable[$child['id']] = $prefix . $child['title']; - } - } - } - - protected function handleDeletables($published) - { - $this->listDeletable($published); - - if (!count($this->deletable)) { - return; - } - - if ($this->shouldDelete()) { - $this->output->writeLn('Deleting obsolete pages...'); - foreach ($this->deletable as $id => $title) { - $this->run( - '- ' . $title, - function () use ($id) { - $this->client->deletePage($id); - } - ); - } - - } else { - $this->output->writeLn('Listing obsolete pages...'); - $this->output->writeLn("> The following pages will not be deleted, but just listed for information."); - $this->output->writeLn("> If you want to delete these pages, you need to set the --delete flag on the command."); - foreach ($this->deletable as $id => $title) { - $this->output->writeLn("- $title"); - } - } - } - - protected function shouldUpdate($local, $local_content, $published) - { - if (!array_key_exists('content', $published)) { - return true; - } - - $trimmed_local = trim($local_content); - $trimmed_distant = trim($published['content']); - - if ($trimmed_local == $trimmed_distant) { - return false; - } - - // I consider that if the files are 98% identical you - // don't need to update. This will work for false positives. - // But sadly will miss if it's just a typo update - // This is configurable with `update_threshold` - $threshold = 98; - if (array_key_exists('update_threshold', $this->confluence)) { - $threshold = 100 - $this->confluence['update_threshold']; - } - - if ($threshold < 100) { - similar_text($trimmed_local, $trimmed_distant, $percent); - if ($percent > $threshold) { - return false; - } - } - - //DEBUG - if (getenv('DEBUG') && strtolower(getenv('DEBUG')) != 'false') { - $prefix = 'static/export/'; - if (!is_dir($prefix)) { - mkdir($prefix, 0777, true); - } - $url = $local->getFile()->getUrl(); - file_put_contents($prefix . strtr($url, ['/' => '_', '.html' => '_local.html']), $trimmed_local); - file_put_contents($prefix . strtr($url, ['/' => '_', '.html' => '_distant.html']), $trimmed_distant); - } - - return true; - } - protected function updatePage($parent_id, $entry, $published) { - if ($this->previous_title != 'Updating') { - $this->previous_title = 'Updating'; - echo "Updating Pages...\n"; - } + $updateThreshold = array_key_exists('update_threshold', $this->confluence) ? $this->confluence['update_threshold'] : 2; $this->run( - '- ' . $this->niceTitle($entry['file']->getUrl()), - function () use ($entry, $published, $parent_id) { + '- ' . PublisherUtilities::niceTitle($entry['file']->getUrl()), + function () use ($entry, $published, $parent_id, $updateThreshold) { $generated_content = $entry['page']->getContent(); - if ($this->shouldUpdate($entry['page'], $generated_content, $published)) { + if (PublisherUtilities::shouldUpdate($entry['page'], $generated_content, $published, $updateThreshold)) { $this->client->updatePage( $parent_id, $published['id'], diff --git a/libs/Format/Confluence/PublisherDelete.php b/libs/Format/Confluence/PublisherDelete.php new file mode 100644 index 0000000..a41c3e3 --- /dev/null +++ b/libs/Format/Confluence/PublisherDelete.php @@ -0,0 +1,77 @@ +output = $output; + $this->delete = $delete; + $this->client = $client; + } + + protected function listDeletable($published, $prefix = '') + { + foreach ($published['children'] as $child) { + if (array_key_exists('children', $child) && count($child['children'])) { + $this->listDeletable($child, $child['title'] . '/'); + } + + if (!array_key_exists('needed', $child)) { + $this->deletable[$child['id']] = $prefix . $child['title']; + } + } + } + + public function handle($published) + { + $this->listDeletable($published); + + if (!count($this->deletable)) { + return; + } + + if ($this->delete) { + $this->doDelete(); + + } else { + $this->displayDeletable(); + } + } + + protected function doDelete() { + $this->output->writeLn('Deleting obsolete pages...'); + foreach ($this->deletable as $id => $title) { + $this->output->writeLn("- $title"); + $this->client->deletePage($id); + } + } + + protected function displayDeletable() { + $this->output->writeLn('Listing obsolete pages...'); + $this->output->writeLn("> The following pages will not be deleted, but just listed for information."); + $this->output->writeLn("> If you want to delete these pages, you need to set the --delete flag on the command."); + foreach ($this->deletable as $id => $title) { + $this->output->writeLn("- $title"); + } + } +} diff --git a/libs/Format/Confluence/PublisherUtilities.php b/libs/Format/Confluence/PublisherUtilities.php new file mode 100644 index 0000000..8a0cb5e --- /dev/null +++ b/libs/Format/Confluence/PublisherUtilities.php @@ -0,0 +1,53 @@ + '', '.html' => '']), '/'); + } + + public static function shouldUpdate($local, $local_content, $published, $threshold) + { + if (!array_key_exists('content', $published)) { + return true; + } + + $trimmed_local = trim($local_content); + $trimmed_distant = trim($published['content']); + + if ($trimmed_local == $trimmed_distant) { + return false; + } + + // I consider that if the files are 98% identical you + // don't need to update. This will work for false positives. + // But sadly will miss if it's just a typo update + // This is configurable with `update_threshold` + $threshold = 100 - $threshold; + + if ($threshold < 100) { + similar_text($trimmed_local, $trimmed_distant, $percent); + if ($percent > $threshold) { + return false; + } + } + + //DEBUG + if (getenv('DEBUG') && strtolower(getenv('DEBUG')) != 'false') { + $prefix = 'static/export/'; + if (!is_dir($prefix)) { + mkdir($prefix, 0777, true); + } + $url = $local->getFile()->getUrl(); + file_put_contents($prefix . strtr($url, ['/' => '_', '.html' => '_local.html']), $trimmed_local); + file_put_contents($prefix . strtr($url, ['/' => '_', '.html' => '_distant.html']), $trimmed_distant); + } + + return true; + } +}