From d4fdb73989a3721dfa663d3607efb739115d012d Mon Sep 17 00:00:00 2001 From: mrflos Date: Wed, 31 Jul 2024 19:01:59 +0300 Subject: [PATCH] fix(duplication): various fixes from @seballot code review --- handlers/DuplicateHandler.php | 9 +- includes/controllers/ApiController.php | 2 +- includes/services/DuplicationManager.php | 37 ++- includes/services/ImportFilesManager.php | 286 ----------------------- includes/services/PageManager.php | 3 +- 5 files changed, 22 insertions(+), 315 deletions(-) delete mode 100644 includes/services/ImportFilesManager.php diff --git a/handlers/DuplicateHandler.php b/handlers/DuplicateHandler.php index 1e0f8bd3b..77fefbe42 100644 --- a/handlers/DuplicateHandler.php +++ b/handlers/DuplicateHandler.php @@ -1,5 +1,6 @@ getService(AclService::class)->hasAccess('read', $this->wiki->GetPageTag())) { // if no read access to the page - if ($contenu = $this->getService(PageManager::class)->getOne('PageLogin')) { + if ($content = $this->getService(PageManager::class)->getOne('PageLogin')) { // si une page PageLogin existe, on l'affiche - $error .= $this->wiki->Format($contenu['body']); + $error .= $this->wiki->Format($content['body']); } else { // sinon on affiche le formulaire d'identification minimal $error .= '
' . "\n" @@ -61,7 +62,7 @@ public function run() $this->wiki->Redirect($this->wiki->href('', $data['pageTag'])); return; - } catch (\Throwable $th) { + } catch (Throwable $th) { $error .= $this->render('@templates\alert-message-with-back.twig', [ 'type' => 'warning', 'message' => $th->getMessage(), @@ -137,4 +138,4 @@ public function run() 'toExternalWiki' => $toExternalWiki, ]); } -} +} \ No newline at end of file diff --git a/includes/controllers/ApiController.php b/includes/controllers/ApiController.php index 4d7f08883..b8705a083 100644 --- a/includes/controllers/ApiController.php +++ b/includes/controllers/ApiController.php @@ -940,4 +940,4 @@ public function archivesAction() { return $this->getService(ArchiveController::class)->manageArchiveAction(); } -} +} \ No newline at end of file diff --git a/includes/services/DuplicationManager.php b/includes/services/DuplicationManager.php index 1a7396b73..05cae2a23 100644 --- a/includes/services/DuplicationManager.php +++ b/includes/services/DuplicationManager.php @@ -56,7 +56,7 @@ private function getLocalFileUploadPath() * * @return array keys of fields that may contain attachments to import */ - public function getUploadFieldsFromEntry($id) + private function getUploadFieldsFromEntry($id) { $fields = []; $entry = $this->wiki->services->get(EntryManager::class)->getOne($id); @@ -65,11 +65,8 @@ public function getUploadFieldsFromEntry($id) $form = $formManager->getOne($entry['id_typeannonce']); // find fields that are textareas foreach ($form['prepared'] as $field) { - if ($field instanceof TextareaField or $field instanceof ImageField or $field instanceof FileField) { - $fields[] = [ - 'id' => $field->getPropertyName(), - 'type' => $field->getType(), - ]; + if ($field instanceof TextareaField || $field instanceof ImageField || $field instanceof FileField) { + $fields[] = $field; } } } @@ -77,7 +74,7 @@ public function getUploadFieldsFromEntry($id) return $fields; } - public function findFilesInUploadField($fieldValue) + private function findFilesInUploadField($fieldValue) { $f = $this->uploadPath . '/' . $fieldValue; if ($f !== $this->uploadPath . '/' && file_exists($f)) { @@ -98,7 +95,7 @@ public function findFilesInUploadField($fieldValue) * * @return array files */ - public function findFilesInWikiText($tag, $wikiText) + private function findFilesInWikiText($tag, $wikiText) { $filesMatched = []; $regex = '#\{\{attach.*file="(.*)".*\}\}#Ui'; @@ -166,12 +163,12 @@ public function findFiles($tag = '') $fields = $this->getUploadFieldsFromEntry($tag); $entry = $this->wiki->services->get(EntryManager::class)->getOne($tag); foreach ($fields as $f) { - if ($f['type'] == 'image' || $f['type'] == 'fichier') { - if (!empty($fi = $this->findFilesInUploadField($entry[$f['id']]))) { + if ($f instanceof ImageField || $f instanceof FileField) { + if (!empty($fi = $this->findFilesInUploadField($entry[$f->getPropertyName()]))) { $files[] = $fi; } - } elseif ($f['type'] == 'textelong') { - if (!empty($fi = $this->findFilesInWikiText($tag, $entry[$f['id']]))) { + } elseif ($f instanceof TextareaField) { + if (!empty($fi = $this->findFilesInWikiText($tag, $entry[$f->getPropertyName()]))) { $files = array_merge($files, $fi); } } @@ -242,17 +239,17 @@ public function duplicateLocally($data) } switch ($data['type']) { case 'list': - $list = $this->wiki->services->get(ListManager::class)->getOne($this->wiki->getPageTag()); + $list = $this->wiki->services->get(ListManager::class)->getOne($data['originalTag']); $this->wiki->services->get(ListManager::class)->create($data['pageTitle'], $list['label'], $data['pageTag']); break; case 'entry': - $files = $this->duplicateFiles($this->wiki->getPageTag(), $data['pageTag']); + $files = $this->duplicateFiles($data['originalTag'], $data['pageTag']); $entry = $this->wiki->services->get(EntryManager::class)->getOne($this->wiki->getPageTag()); $fields = $this->getUploadFieldsFromEntry($this->wiki->GetPageTag()); foreach ($fields as $f) { foreach ($files as $fi) { - $entry[$f['id']] = str_replace($fi['originalFile'], $fi['duplicatedFile'], $entry[$f['id']]); + $entry[$f->getPropertyName()] = str_replace($fi['originalFile'], $fi['duplicatedFile'], $entry[$f->getPropertyName()]); } } $entry['id_fiche'] = $data['pageTag']; @@ -264,7 +261,7 @@ public function duplicateLocally($data) default: case 'page': $newBody = $this->wiki->page['body']; - $files = $this->duplicateFiles($this->wiki->getPageTag(), $data['pageTag']); + $files = $this->duplicateFiles($data['originalTag'], $data['pageTag']); foreach ($files as $f) { $newBody = str_replace($f['originalFile'], $f['duplicatedFile'], $newBody); } @@ -292,7 +289,7 @@ public function duplicateLocally($data) 'http://outils-reseaux.org/_vocabulary/tag', ]; foreach ($properties as $prop) { - $values = $this->wiki->services->get(TripleStore::class)->getAll($this->wiki->GetPageTag(), $prop, '', ''); + $values = $this->wiki->services->get(TripleStore::class)->getAll($data['originalTag'], $prop, '', ''); foreach ($values as $val) { $this->wiki->services->get(TripleStore::class)->create($data['pageTag'], $prop, $val['value'], '', ''); } @@ -303,15 +300,11 @@ public function importDistantContent($tag, $request) { if ($this->wiki->services->get(PageManager::class)->getOne($tag)) { throw new Exception(_t('ACEDITOR_LINK_PAGE_ALREADY_EXISTS')); - - return; } $req = $request->request->all(); foreach (['pageContent', 'sourceUrl', 'originalTag', 'type'] as $key) { if (empty($req[$key])) { throw new Exception(_t('NOT_FOUND_IN_REQUEST', $key)); - - return; } } foreach ($req['files'] as $fileUrl) { @@ -361,4 +354,4 @@ public function humanFilesize($bytes, $decimals = 2) return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor - 1] . 'B'; } -} +} \ No newline at end of file diff --git a/includes/services/ImportFilesManager.php b/includes/services/ImportFilesManager.php deleted file mode 100644 index d18cf40af..000000000 --- a/includes/services/ImportFilesManager.php +++ /dev/null @@ -1,286 +0,0 @@ -wiki = $wiki; - $this->uploadPath = null; - } - - /** - * Get the local path to files uploads (usually "files"). - * - * @return string local path to files uploads - */ - private function getLocalFileUploadPath() - { - if ($this->uploadPath !== null) { - return $this->uploadPath; - } - - $attachConfig = $this->wiki->config['attach_config']; - - if (!is_array($attachConfig)) { - $attachConfig = []; - } - - if (empty($attachConfig['upload_path'])) { - $this->uploadPath = 'files'; - } else { - $this->uploadPath = $attachConfig['upload_path']; - } - - return $this->uploadPath; - } - - /** - * Download file url to local wiki using cURL. - * - * @param string $from file url - * @param string $to local path - * @param bool $overwrite overwrite existing file ? (default:false) - * - * @return void - */ - private function cURLDownload($from, $to, $overwrite = false) - { - $output = ''; - if (file_exists($to)) { - if ($overwrite) { - $output .= _t('FILE') . ' ' . $to . ' ' . _t('FILE_OVERWRITE') . '.'; - } else { - $output .= _t('FILE') . ' ' . $to . ' ' . _t('FILE_NO_OVERWRITE') . '.'; - - return $output; - } - } - - // Do cURL transfer - $fp = fopen($to, 'wb'); - $ch = curl_init($from); - curl_setopt($ch, CURLOPT_FILE, $fp); - curl_setopt($ch, CURLOPT_HEADER, 0); - curl_setopt($ch, CURLOPT_FAILONERROR, true); - curl_exec($ch); - $err = curl_error($ch); - curl_close($ch); - fclose($fp); - - if ($err) { - unlink($to); - throw new \Exception($output . _t('ERROR_DOWNLOADING') . ' ' . $from . ': ' . $err . "\n" . _t('REMOVING_CORRUPTED_FILE') . ' ' . $to); - } - - return $output; - } - - /** - * Return fields that may contain attachments to import (body for wikipage, or textelong fields for bazar entries). - * - * @param array $wikiPage page or entry content as an array - * - * @return array keys of $wikiPage that may contain attachments to import - */ - public function getTextFieldsFromWikiPage($wikiPage) - { - $fields = []; - if (!empty($wikiPage['tag'])) { // classic wiki page - $fields[] = 'body'; - } elseif (!empty($wikiPage['id_fiche'])) { // bazar entry - $formManager = $this->wiki->services->get(FormManager::class); - $form = $formManager->getOne($wikiPage['id_typeannonce']); - // find fields that are textareas - foreach ($form['prepared'] as $field) { - if ($field instanceof TextareaField) { - $fields[] = $field->getName(); - } - } - } - - return $fields; - } - - /** - * Get attachements from raw page content. - * - * @param string $tag page id - * - * @return array attachments filenames - */ - public function findDirectLinkAttachements($tag = '') - { - if (empty(trim($tag))) { - $tag = $this->wiki->GetPageTag(); - } - $rawContent = $this->wiki->services->get(PageManager::class)->getOne($tag)['body']; - $regex = '#\{\{attach.*file="(.*)".*\}\}#Ui'; - preg_match_all( - $regex, - $rawContent, - $attachments - ); - if (is_array($attachments[1])) { - $filesMatched = []; - foreach ($attachments[1] as $a) { - $ext = pathinfo($a, PATHINFO_EXTENSION); - $filename = pathinfo($a, PATHINFO_FILENAME); - $searchPattern = '`^' . $tag . '_' . $filename . '_\d{14}_\d{14}\.' . $ext . '_?$`'; - $path = $this->getLocalFileUploadPath(); - $fh = opendir($path); - while (($file = readdir($fh)) !== false) { - if (strcmp($file, '.') == 0 || strcmp($file, '..') == 0 || is_dir($file)) { - continue; - } - if (preg_match($searchPattern, $file)) { - $filePath = $path . '/' . $file; - $size = filesize($filePath); - $humanSize = $this->humanFilesize($size); - $filesMatched[] = ['path' => $filePath, 'size' => $size, 'humanSize' => $humanSize]; - } - } - } - } - - return $filesMatched; - } - - public function humanFilesize($bytes, $decimals = 2) - { - $factor = floor((strlen($bytes) - 1) / 3); - if ($factor > 0) { - $sz = 'KMGT'; - } - - return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor - 1] . 'B'; - } - - /** - * Generate distant file url and download to local file path. - * - * @param string $remoteUrl distant file url - * @param string $filename file name - * @param bool $overwrite overwrite existing file ? (default:false) - * - * @return void - */ - public function downloadDirectLinkAttachment($remoteUrl, $filename, $overwrite = false) - { - $remoteFileUrl = $remoteUrl . '/files/' . $filename; - $saveFileLoc = $this->getLocalFileUploadPath() . '/' . $filename; - - return $this->cURLDownload($remoteFileUrl, $saveFileLoc, $overwrite); - } - - /** - * Find file attachments in page or bazar entry - * It finds attachments linked with /download links. - * - * @param string $remoteUrl distant url - * @param array $wikiPage page or entry content as an array - * @param bool $transform transform attachments urls for their new location (default:false) - * - * @return array all file attachments - */ - public function findHiddenAttachments($remoteUrl, &$wikiPage, $transform = false) - { - preg_match_all( - '#(?:href|src)="' . preg_quote($remoteUrl, '#') . '\?.+/download&(?:amp;)?file=(?P.*)"#Ui', - $wikiPage['html_output'], - $htmlMatches - ); - $attachments = $htmlMatches['filename']; - - $wikiRegex = '#="' . preg_quote($remoteUrl, '#') - . '(?P\?.+/download&(?:amp;)?file=(?P.*))"#Ui'; - - $contentKeys = $this->getTextFieldsFromWikiPage($wikiPage); - foreach ($contentKeys as $key) { - preg_match_all($wikiRegex, $wikiPage[$key], $wikiMatches); - $attachments = array_merge($attachments, $wikiMatches['filename']); - } - - $attachments = array_unique($attachments); - - if ($transform) { - foreach ($contentKeys as $key) { - $wikiPage[$key] = preg_replace($wikiRegex, '="' . $this->wiki->getBaseUrl() . '${trail}"', $wikiPage[$key]); - } - } - - return $attachments; - } - - /** - * Generate local path and download hidden attachments - * It downloads attachments linked with /download links. - * - * @param string $remoteUrl distant url - * @param string $pageTag page tag - * @param string $lastPageUpdate last update time - * @param string $filename file name - * @param bool $overwrite overwrite existing file ? (default:false) - * - * @return array all file attachments - */ - public function downloadHiddenAttachment($remoteUrl, $pageTag, $lastPageUpdate, $filename, $overwrite = false) - { - if (!class_exists('attach')) { - require_once 'tools/attach/libs/attach.lib.php'; - } - - $this->wiki->tag = $pageTag; - $this->wiki->page = ['tag' => $pageTag, 'time' => $lastPageUpdate]; - - $remoteFileUrl = $remoteUrl . '?' . $pageTag . '/download&file=' . $filename; - $att = new \attach($this->wiki); - $att->file = $filename; - $newFilename = $att->GetFullFilename(true); - - $this->cURLDownload($remoteFileUrl, $newFilename, $overwrite); - } - - /** - * All type of attachment related to a page or a bazar entry. - * - * @param string $remoteUrl distant url - * @param array $wikiPage page or entry content as an array - * @param bool $overwrite overwrite existing file ? (default:false) - * - * @return void - */ - public function downloadAttachments($remoteUrl, &$wikiPage, $overwrite = false) - { - // Handle Pictures and file attachments - $attachments = $this->findDirectLinkAttachements($remoteUrl, $wikiPage, true); - - if (count($attachments)) { - foreach ($attachments as $image) { - $this->downloadDirectLinkAttachment($remoteUrl, $image, $overwrite); - } - } - - // Downloading hidden attachments - $attachments = $this->findHiddenAttachments($remoteUrl, $wikiPage, true); - - if (!empty($attachments)) { - foreach ($attachments as $attachment) { - $this->downloadHiddenAttachment($remoteUrl, $wikiPage['id_fiche'], date('Y-m-d H:i:s'), $attachment, $overwrite); - } - } - } -} diff --git a/includes/services/PageManager.php b/includes/services/PageManager.php index e4f355a13..3c9ae63d2 100644 --- a/includes/services/PageManager.php +++ b/includes/services/PageManager.php @@ -298,7 +298,6 @@ public function deleteOrphaned($tag) $this->dbService->query("DELETE FROM {$this->dbService->prefixTable('links')} WHERE from_tag='{$this->dbService->escape($tag)}' "); $this->dbService->query("DELETE FROM {$this->dbService->prefixTable('acls')} WHERE page_tag='{$this->dbService->escape($tag)}' "); $this->dbService->query("DELETE FROM {$this->dbService->prefixTable('triples')} WHERE `resource`='{$this->dbService->escape($tag)}' and `property`='" . TripleStore::TYPE_URI . "' and `value`='" . EntryManager::TRIPLES_ENTRY_ID . "'"); - $this->dbService->query("DELETE FROM {$this->dbService->prefixTable('triples')} WHERE `resource`='{$this->dbService->escape($tag)}' and `property`='" . TripleStore::TYPE_URI . "' and `value`='" . EntryManager::TRIPLES_ENTRY_ID . "'"); $this->dbService->query("DELETE FROM {$this->dbService->prefixTable('triples')} WHERE `resource`='{$this->dbService->escape($tag)}' and `property`='http://outils-reseaux.org/_vocabulary/metadata'"); $this->dbService->query("DELETE FROM {$this->dbService->prefixTable('referrers')} WHERE page_tag='{$this->dbService->escape($tag)}' "); $this->tagsManager->deleteAll($tag); @@ -515,4 +514,4 @@ private function duplicate($sourceTag, $destinationTag): bool return $result; } -} +} \ No newline at end of file