From fdb67c74d9a1bdd3a9602ec7a5dbe60294dc5769 Mon Sep 17 00:00:00 2001 From: aynsix Date: Wed, 17 Jul 2019 17:16:29 +0400 Subject: [PATCH 01/11] fix port to 4.1 extract xmp:PageImage indesign --- composer.lock | 12 ++++----- lib/Alchemy/Phrasea/Media/SubdefGenerator.php | 26 ++++++++++++++----- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/composer.lock b/composer.lock index 5721974b41..194fd91634 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "64830cb4d53b32b47e02d4a19df9cef2", + "content-hash": "6341722edcd5bfa22e933f5411225144", "packages": [ { "name": "alchemy-fr/tcpdf-clone", @@ -383,16 +383,16 @@ }, { "name": "alchemy/phpexiftool", - "version": "0.7.0", + "version": "0.7.2", "source": { "type": "git", "url": "https://github.com/alchemy-fr/PHPExiftool.git", - "reference": "7372ca4e43473328bf06bca810558fbad7bb2f95" + "reference": "ba1cb51eceb6562d7996023478977a8739de188b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/alchemy-fr/PHPExiftool/zipball/7372ca4e43473328bf06bca810558fbad7bb2f95", - "reference": "7372ca4e43473328bf06bca810558fbad7bb2f95", + "url": "https://api.github.com/repos/alchemy-fr/PHPExiftool/zipball/ba1cb51eceb6562d7996023478977a8739de188b", + "reference": "ba1cb51eceb6562d7996023478977a8739de188b", "shasum": "" }, "require": { @@ -452,7 +452,7 @@ "exiftool", "metadata" ], - "time": "2017-05-18T19:04:04+00:00" + "time": "2019-02-13T13:06:43+00:00" }, { "name": "alchemy/queue-bundle", diff --git a/lib/Alchemy/Phrasea/Media/SubdefGenerator.php b/lib/Alchemy/Phrasea/Media/SubdefGenerator.php index 2dede228c5..88867551a1 100644 --- a/lib/Alchemy/Phrasea/Media/SubdefGenerator.php +++ b/lib/Alchemy/Phrasea/Media/SubdefGenerator.php @@ -61,7 +61,7 @@ class SubdefGenerator public function generateSubdefs(\record_adapter $record, array $wanted_subdefs = null) { - if ($record->get_hd_file() !== null) { + if ($record->get_hd_file() !== null && $record->get_hd_file()->getMimeType() == "application/x-indesign") { $mediaSource = $this->mediavorus->guess($record->get_hd_file()->getPathname()); $metadatas = $mediaSource->getMetadatas(); @@ -69,15 +69,27 @@ class SubdefGenerator if(!isset($this->tmpFilesystem)){ $this->tmpFilesystem = Manager::create(); } - $tmpDir = $this->tmpFilesystem->createTemporaryDirectory(); + $tmpDir = $this->tmpFilesystem->createTemporaryDirectory(0777, 500); - try { - $this->app['filesystem']->dumpFile($tmpDir.'/file.jpg', $metadatas->get('XMP-xmp:PageImage')->getValue()->asString()); - $this->tmpFilePath = $tmpDir.'/file.jpg'; - } catch (\Exception $e) { - $this->logger->error(sprintf('Unable to write temporary file : %s', $e->getMessage())); + $files = $this->app['exiftool.preview-extractor']->extract($record->get_hd_file()->getPathname(), $tmpDir); + + $selected = null; + $size = null; + + foreach ($files as $file) { + if ($file->isDir() || $file->isDot()) { + continue; + } + + if (is_null($selected) || $file->getSize() > $size) { + $selected = $file->getPathname(); + $size = $file->getSize(); + } } + if ($selected) { + $this->tmpFilePath = $selected; + } } } From b0c0f65764b52d5aeb4abf8df1104ec1f61b22e7 Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Mon, 15 Jul 2019 16:23:49 +0200 Subject: [PATCH 02/11] PHRAS-2666_slow-notifications_4.1 removed join on basket_elements where useless !!! WIP !!! --- .../Model/Repositories/BasketRepository.php | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php b/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php index 6304f3eaa6..fa8d23db5f 100644 --- a/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php +++ b/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php @@ -59,16 +59,16 @@ class BasketRepository extends EntityRepository */ public function findActiveByUser(User $user, $sort = null) { - $dql = 'SELECT b - FROM Phraseanet:Basket b - LEFT JOIN b.elements e - WHERE b.user = :usr_id - AND b.archived = false'; + $dql = "SELECT b\n" + . " FROM Phraseanet:Basket b\n" + . " WHERE b.user = :usr_id\n" + . " AND b.archived = false"; if ($sort == 'date') { - $dql .= ' ORDER BY b.created DESC'; - } elseif ($sort == 'name') { - $dql .= ' ORDER BY b.name ASC'; + $dql .= "\n ORDER BY b.created DESC"; + } + elseif ($sort == 'name') { + $dql .= "\n ORDER BY b.name ASC"; } $query = $this->_em->createQuery($dql); @@ -85,19 +85,19 @@ class BasketRepository extends EntityRepository */ public function findUnreadActiveByUser(User $user) { - $dql = 'SELECT b - FROM Phraseanet:Basket b - JOIN b.elements e - LEFT JOIN b.validation s - LEFT JOIN s.participants p - WHERE b.archived = false - AND ( - (b.user = :usr_id_owner AND b.isRead = false) - OR (b.user != :usr_id_ownertwo - AND p.user = :usr_id_participant - AND p.is_aware = false) - ) - AND (s.expires IS NULL OR s.expires > CURRENT_TIMESTAMP())'; + $dql = "SELECT b\n" + . " FROM (Phraseanet:Basket b LEFT JOIN b.validation s)\n" + . " INNER JOIN s.participants p\n" + . " WHERE b.archived = false\n" + . " AND (\n" + . " (b.user = :usr_id_owner AND b.isRead = false)\n" + . " OR \n" + . " (b.user != :usr_id_ownertwo\n" + . " AND p.user = :usr_id_participant\n" + . " AND p.is_aware = false\n" + . " AND s.expires > CURRENT_TIMESTAMP()\n" + . " )\n" + . " )"; $params = [ 'usr_id_owner' => $user->getId(), From 5585893f05a75a871a9c7534eaf078f23069335c Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Mon, 22 Jul 2019 15:24:48 +0200 Subject: [PATCH 03/11] PHRAS-2651_event-to-message_4.1 fix for php7.1 !!! WIP !!! --- .../Controller/Prod/UploadController.php | 8 ++-- .../Model/Repositories/BasketRepository.php | 44 +++++++++---------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Prod/UploadController.php b/lib/Alchemy/Phrasea/Controller/Prod/UploadController.php index 89a0d21910..27d18d5473 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/UploadController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/UploadController.php @@ -367,15 +367,17 @@ class UploadController extends Controller $postMaxSize = PHP_INT_MAX; } + $r = 0; switch (strtolower(substr($postMaxSize, -1))) { /** @noinspection PhpMissingBreakStatementInspection */ case 'g': - $postMaxSize *= 1024; + $r += 10; /** @noinspection PhpMissingBreakStatementInspection */ case 'm': - $postMaxSize *= 1024; + $r += 10; case 'k': - $postMaxSize *= 1024; + $r += 10; + $postMaxSize = ((int)($postMaxSize))<<$r; } return min(UploadedFile::getMaxFilesize(), (int) $postMaxSize); diff --git a/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php b/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php index fa8d23db5f..284b640729 100644 --- a/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php +++ b/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php @@ -120,23 +120,23 @@ class BasketRepository extends EntityRepository */ public function findActiveValidationByUser(User $user, $sort = null) { - $dql = 'SELECT b - FROM Phraseanet:Basket b - JOIN b.elements e - JOIN e.validation_datas v - JOIN b.validation s - JOIN s.participants p - WHERE b.user != ?1 AND p.user = ?2 - AND (s.expires IS NULL OR s.expires > CURRENT_TIMESTAMP()) '; + $dql = "SELECT b\n" + . "FROM Phraseanet:Basket b\n" + . " JOIN b.validation s\n" + . " JOIN s.participants p\n" + . "WHERE b.user != ?1 AND p.user = ?2\n" + . " AND (s.expires IS NULL OR s.expires > CURRENT_TIMESTAMP())"; if ($sort == 'date') { - $dql .= ' ORDER BY b.created DESC'; + $dql .= "\nORDER BY b.created DESC"; } elseif ($sort == 'name') { - $dql .= ' ORDER BY b.name ASC'; + $dql .= "\nORDER BY b.name ASC"; } $query = $this->_em->createQuery($dql); $query->setParameters([1 => $user->getId(), 2 => $user->getId()]); + $sql = $query->getSQL(); + file_put_contents("/tmp/phraseanet-log.txt", sprintf("%s (%d) %s\n", __FILE__, __LINE__, var_export($sql, true)), FILE_APPEND); return $query->getResult(); } @@ -210,30 +210,27 @@ class BasketRepository extends EntityRepository { switch ($type) { case self::RECEIVED: - $dql = 'SELECT b - FROM Phraseanet:Basket b - JOIN b.elements e - WHERE b.user = :usr_id AND b.pusher_id IS NOT NULL'; + $dql = "SELECT b\n" + . "FROM Phraseanet:Basket b\n" + . "WHERE b.user = :usr_id AND b.pusher_id IS NOT NULL"; $params = [ 'usr_id' => $user->getId() ]; break; case self::VALIDATION_DONE: - $dql = 'SELECT b - FROM Phraseanet:Basket b - JOIN b.elements e - JOIN b.validation s - JOIN s.participants p - WHERE b.user != ?1 AND p.user = ?2'; + $dql = "SELECT b\n" + . "FROM Phraseanet:Basket b\n" + . " JOIN b.validation s\n" + . " JOIN s.participants p\n" + . "WHERE b.user != ?1 AND p.user = ?2"; $params = [ - 1 => $user->getId() - , 2 => $user->getId() + 1 => $user->getId(), + 2 => $user->getId() ]; break; case self::VALIDATION_SENT: $dql = 'SELECT b FROM Phraseanet:Basket b - JOIN b.elements e JOIN b.validation v WHERE b.user = :usr_id'; $params = [ @@ -243,7 +240,6 @@ class BasketRepository extends EntityRepository case self::MYBASKETS: $dql = 'SELECT b FROM Phraseanet:Basket b - LEFT JOIN b.elements e LEFT JOIN b.validation s LEFT JOIN s.participants p WHERE (b.user = :usr_id)'; From 2fcbd7e6d7c773eb25ca5ac6ce8617117734539d Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Wed, 24 Jul 2019 20:50:27 +0200 Subject: [PATCH 04/11] PHRAS-2666_slow-notifications_4.1 removed join on basket_elements where useless code style + type hints !!! WIP !!! --- .../Controller/Prod/RootController.php | 14 ++---- .../Controller/Root/AccountController.php | 28 +++++++---- .../Controller/Root/SessionController.php | 25 +++++++--- lib/Alchemy/Phrasea/Helper/WorkZone.php | 23 ++++----- .../Model/Repositories/BasketRepository.php | 47 ++++++++++++++----- lib/classes/ACL.php | 31 +++++++----- .../eventsmanager/notify/orderdeliver.php | 20 +++++--- .../eventsmanager/notify/validationdone.php | 30 ++++++++---- lib/classes/set/export.php | 7 ++- 9 files changed, 148 insertions(+), 77 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Prod/RootController.php b/lib/Alchemy/Phrasea/Controller/Prod/RootController.php index 7e02f54ce8..b89c919ed9 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/RootController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/RootController.php @@ -15,12 +15,9 @@ use Alchemy\Phrasea\Core\Configuration\DisplaySettingService; use Alchemy\Phrasea\Exception\SessionNotFound; use Alchemy\Phrasea\Feed\Aggregate; use Alchemy\Phrasea\Helper; -use Alchemy\Phrasea\Model\Entities\UserSetting; +use Alchemy\Phrasea\Helper\WorkZone as WorkzoneHelper; use Alchemy\Phrasea\Model\Repositories\FeedRepository; -use Symfony\Component\Finder\Finder; -use Symfony\Component\Finder\SplFileInfo; use Symfony\Component\HttpFoundation\Request; -// use Alchemy\Phrasea\Plugin\ActionBarPluginInterface; class RootController extends Controller @@ -43,12 +40,11 @@ class RootController extends Controller public function indexAction(Request $request) { try { \Session_Logger::updateClientInfos($this->app, 1); - } catch (SessionNotFound $e) { + } + catch (SessionNotFound $e) { return $this->app->redirectPath('logout'); } - $css = []; - $user = $this->getAuthenticatedUser(); $cssfile = $this->getSettings()->getUserSetting($user, 'css'); @@ -110,7 +106,7 @@ class RootController extends Controller return $this->render('prod/index.html.twig', [ 'module_name' => 'Production', - 'WorkZone' => new Helper\WorkZone($this->app, $request), + 'WorkZone' => new WorkzoneHelper($this->app, $request), 'module_prod' => $helper, 'search_datas' => $helper->get_search_datas(), 'cssfile' => $cssfile, @@ -123,7 +119,7 @@ class RootController extends Controller 'feeds' => $feeds, 'aggregate' => $aggregate, 'GV_google_api' => $conf->get(['registry', 'webservices', 'google-charts-enabled']), - 'geocodingProviders' => $conf->get(['geocoding-providers']), + 'geocodingProviders' => $conf->get(['geocoding-providers']), 'search_status' => \databox_status::getSearchStatus($this->app), 'thesau_js_list' => $thjslist, 'thesau_json_sbas' => json_encode($sbas), diff --git a/lib/Alchemy/Phrasea/Controller/Root/AccountController.php b/lib/Alchemy/Phrasea/Controller/Root/AccountController.php index a6b305fe22..b4053a6ce1 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/AccountController.php +++ b/lib/Alchemy/Phrasea/Controller/Root/AccountController.php @@ -522,27 +522,35 @@ class AccountController extends Controller $list = array_keys($this->app['repo.collections-registry']->getBaseIdMap()); - $this->app->getAclForUser($user)->revoke_access_from_bases($list); + try { + $this->app->getAclForUser($user)->revoke_access_from_bases($list); + } + catch (\Exception $e) { + // one or more access could not be revoked ? the user will not be phantom + $this->app->addFlash('error', $this->app->trans('phraseanet::error: failed to revoke some user access')); + } if ($this->app->getAclForUser($user)->is_phantom()) { // send confirmation email: the account has been deleted try { $receiver = Receiver::fromUser($user); - } catch (InvalidArgumentException $e) { - $this->app->addFlash('error', $this->app->trans('phraseanet::erreur: echec du serveur de mail')); + $mail = MailSuccessAccountDelete::create($this->app, $receiver); + } + catch (InvalidArgumentException $e) { + $this->app->addFlash('error', $this->app->trans('phraseanet::erreur: echec du serveur de mail')); + $mail = null; } - - $mail = MailSuccessAccountDelete::create($this->app, $receiver); $this->app['manipulator.user']->delete($user); - $this->deliver($mail); + if($mail) { + $this->deliver($mail); + } + + $this->getAuthenticator()->closeAccount(); + $this->app->addFlash('info', $this->app->trans('phraseanet::account The account has been deleted')); } - - $this->getAuthenticator()->closeAccount(); - $this->app->addFlash('info', $this->app->trans('phraseanet::account The account has been deleted')); - } /** diff --git a/lib/Alchemy/Phrasea/Controller/Root/SessionController.php b/lib/Alchemy/Phrasea/Controller/Root/SessionController.php index 5070ca33ba..23e6b2b425 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/SessionController.php +++ b/lib/Alchemy/Phrasea/Controller/Root/SessionController.php @@ -120,7 +120,8 @@ class SessionController extends Controller return $this->app->json($ret); } - } else { + } + else { $ret['status'] = 'disconnected'; return $this->app->json($ret); @@ -128,7 +129,8 @@ class SessionController extends Controller try { $this->getApplicationBox()->get_connection(); - } catch (\Exception $e) { + } + catch (\Exception $e) { return $this->app->json($ret); } @@ -140,7 +142,14 @@ class SessionController extends Controller /** @var \Alchemy\Phrasea\Model\Entities\Session $session */ $session = $this->getSessionRepository()->find($this->getSession()->get('session_id')); - $session->setUpdated(new \DateTime()); + try { + $now = new \DateTime(); + } + catch (\Exception $e) { + // no-op : DateTime() without arg should not fail... + $now = null; // prevent phpstorm warning about undefine var. + } + $session->setUpdated($now); $manager = $this->getEntityManager(); if (!$session->hasModuleId($moduleId)) { @@ -148,8 +157,9 @@ class SessionController extends Controller $module->setModuleId($moduleId); $module->setSession($session); $manager->persist($module); - } else { - $manager->persist($session->getModuleById($moduleId)->setUpdated(new \DateTime())); + } + else { + $manager->persist($session->getModuleById($moduleId)->setUpdated($now)); } $manager->persist($session); @@ -231,7 +241,10 @@ class SessionController extends Controller */ private function getBasketRepository() { - return $this->getEntityManager()->getRepository('Phraseanet:Basket'); + /** @var BasketRepository $ret */ + $ret = $this->getEntityManager()->getRepository('Phraseanet:Basket'); + + return $ret; } /** diff --git a/lib/Alchemy/Phrasea/Helper/WorkZone.php b/lib/Alchemy/Phrasea/Helper/WorkZone.php index 6095a54c9b..8841b264ae 100644 --- a/lib/Alchemy/Phrasea/Helper/WorkZone.php +++ b/lib/Alchemy/Phrasea/Helper/WorkZone.php @@ -11,28 +11,29 @@ namespace Alchemy\Phrasea\Helper; -use Doctrine\Common\Collections\ArrayCollection; use Alchemy\Phrasea\Model\Entities\Basket as BasketEntity; +use Alchemy\Phrasea\Model\Repositories\BasketRepository; +use Alchemy\Phrasea\Model\Repositories\StoryWZRepository; +use Doctrine\Common\Collections\ArrayCollection; class WorkZone extends Helper { - const BASKETS = 'baskets'; - const STORIES = 'stories'; + const BASKETS = 'baskets'; + const STORIES = 'stories'; const VALIDATIONS = 'validations'; /** - * * Returns an ArrayCollection containing three keys : - * - self::BASKETS : an ArrayCollection of the actives baskets - * (Non Archived) + * - self::BASKETS : an ArrayCollection of the actives baskets (Non Archived) * - self::STORIES : an ArrayCollection of working stories * - self::VALIDATIONS : the validation people are waiting from me * - * @return \Doctrine\Common\Collections\ArrayCollection + * @param null|string $sort "date"|"name" + * @return ArrayCollection */ - public function getContent($sort) + public function getContent(string $sort = null) { - /* @var $repo_baskets Alchemy\Phrasea\Model\Repositories\BasketRepository */ + /* @var $repo_baskets BasketRepository */ $repo_baskets = $this->app['repo.baskets']; $sort = in_array($sort, ['date', 'name']) ? $sort : 'name'; @@ -42,7 +43,7 @@ class WorkZone extends Helper $baskets = $repo_baskets->findActiveByUser($this->app->getAuthenticatedUser(), $sort); // force creation of a default basket - if (0 === count($baskets)) { + if (count($baskets) === 0) { $basket = new BasketEntity(); $basket->setName($this->app->trans('Default basket')); @@ -55,7 +56,7 @@ class WorkZone extends Helper $validations = $repo_baskets->findActiveValidationByUser($this->app->getAuthenticatedUser(), $sort); - /* @var $repo_stories Alchemy\Phrasea\Model\Repositories\StoryWZRepository */ + /* @var $repo_stories StoryWZRepository */ $repo_stories = $this->app['repo.story-wz']; $stories = $repo_stories->findByUser($this->app, $this->app->getAuthenticatedUser(), $sort); diff --git a/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php b/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php index 284b640729..fe1d7e9dbb 100644 --- a/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php +++ b/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php @@ -54,13 +54,16 @@ class BasketRepository extends EntityRepository /** * Returns all basket for a given user that are not marked as archived * - * @param User $user + * @param User $user + * @param null|string $sort * @return Basket[] */ - public function findActiveByUser(User $user, $sort = null) + public function findActiveByUser(User $user, string $sort = null) { + // checked : 4 usages, "b.elements" is useless $dql = "SELECT b\n" . " FROM Phraseanet:Basket b\n" + // . " LEFT JOIN b.elements e\n" // . " WHERE b.user = :usr_id\n" . " AND b.archived = false"; @@ -74,20 +77,26 @@ class BasketRepository extends EntityRepository $query = $this->_em->createQuery($dql); $query->setParameters(['usr_id' => $user->getId()]); + $sql = $query->getSQL(); + file_put_contents("/tmp/phraseanet-log.txt", sprintf("%s (%d) %s\n\n", __FILE__, __LINE__, var_export($sql, true)), FILE_APPEND); + return $query->getResult(); } /** * Returns all unread basket for a given user that are not marked as archived * - * @param User $user + * @param User $user * @return Basket[] */ public function findUnreadActiveByUser(User $user) { + // checked : 2 usages, "b.elements" is useless $dql = "SELECT b\n" - . " FROM (Phraseanet:Basket b LEFT JOIN b.validation s)\n" - . " INNER JOIN s.participants p\n" + . " FROM (Phraseanet:Basket b\"" + // . " JOIN b.elements e\n" + . " LEFT JOIN b.validation s)\n" + . " INNER JOIN s.participants p\n" . " WHERE b.archived = false\n" . " AND (\n" . " (b.user = :usr_id_owner AND b.isRead = false)\n" @@ -108,6 +117,9 @@ class BasketRepository extends EntityRepository $query = $this->_em->createQuery($dql); $query->setParameters($params); + $sql = $query->getSQL(); + file_put_contents("/tmp/phraseanet-log.txt", sprintf("%s (%d) %s\n\n", __FILE__, __LINE__, var_export($sql, true)), FILE_APPEND); + return $query->getResult(); } @@ -115,13 +127,17 @@ class BasketRepository extends EntityRepository * Returns all baskets that are in validation session not expired and * where a specified user is participant (not owner) * - * @param User $user + * @param User $user + * @param null|string $sort * @return Basket[] */ public function findActiveValidationByUser(User $user, $sort = null) { + // checked : 2 usages, "b.elements" seems useless. $dql = "SELECT b\n" . "FROM Phraseanet:Basket b\n" + // . " JOIN b.elements e\n" + // . " JOIN e.validation_datas v\n" . " JOIN b.validation s\n" . " JOIN s.participants p\n" . "WHERE b.user != ?1 AND p.user = ?2\n" @@ -136,7 +152,7 @@ class BasketRepository extends EntityRepository $query = $this->_em->createQuery($dql); $query->setParameters([1 => $user->getId(), 2 => $user->getId()]); $sql = $query->getSQL(); - file_put_contents("/tmp/phraseanet-log.txt", sprintf("%s (%d) %s\n", __FILE__, __LINE__, var_export($sql, true)), FILE_APPEND); + file_put_contents("/tmp/phraseanet-log.txt", sprintf("%s (%d) %s\n\n", __FILE__, __LINE__, var_export($sql, true)), FILE_APPEND); return $query->getResult(); } @@ -152,10 +168,11 @@ class BasketRepository extends EntityRepository */ public function findUserBasket($basket_id, User $user, $requireOwner) { - $dql = 'SELECT b - FROM Phraseanet:Basket b - LEFT JOIN b.elements e - WHERE b.id = :basket_id'; + // checked : 3 usages, "b.elements e" seems useless + $dql = "SELECT b\n" + . " FROM Phraseanet:Basket b\n" + // . " LEFT JOIN b.elements e\n" + . " WHERE b.id = :basket_id"; $query = $this->_em->createQuery($dql); $query->setParameters(['basket_id' => $basket_id]); @@ -188,7 +205,7 @@ class BasketRepository extends EntityRepository public function findContainingRecordForUser(\record_adapter $record, User $user) { - + // todo : check "e.sbas_id = e.sbas_id" ??? $dql = 'SELECT b FROM Phraseanet:Basket b JOIN b.elements e @@ -210,16 +227,20 @@ class BasketRepository extends EntityRepository { switch ($type) { case self::RECEIVED: + // todo : check when called, and if "LEFT JOIN b.elements e" is usefull $dql = "SELECT b\n" . "FROM Phraseanet:Basket b\n" + . " JOIN b.elements e\n" . "WHERE b.user = :usr_id AND b.pusher_id IS NOT NULL"; $params = [ 'usr_id' => $user->getId() ]; break; case self::VALIDATION_DONE: + // todo : check when called, and if "LEFT JOIN b.elements e" is usefull $dql = "SELECT b\n" . "FROM Phraseanet:Basket b\n" + . " JOIN b.elements e\n" . " JOIN b.validation s\n" . " JOIN s.participants p\n" . "WHERE b.user != ?1 AND p.user = ?2"; @@ -248,6 +269,7 @@ class BasketRepository extends EntityRepository ]; break; default: + // todo : check when called, and if "LEFT JOIN b.elements e" is usefull $dql = 'SELECT b FROM Phraseanet:Basket b LEFT JOIN b.elements e @@ -293,6 +315,7 @@ class BasketRepository extends EntityRepository */ public function findActiveValidationAndBasketByUser(User $user, $sort = null) { + // todo : check caller and if "LEFT JOIN b.elements e" is usefull $dql = 'SELECT b FROM Phraseanet:Basket b LEFT JOIN b.elements e diff --git a/lib/classes/ACL.php b/lib/classes/ACL.php index cbeb9b5672..570b917e25 100644 --- a/lib/classes/ACL.php +++ b/lib/classes/ACL.php @@ -1115,7 +1115,6 @@ class ACL implements cache_cacheableInterface /** * @param array $base_ids * @return $this - * @throws DBALException * @throws Exception */ public function revoke_access_from_bases(Array $base_ids) @@ -1125,24 +1124,30 @@ class ACL implements cache_cacheableInterface $usr_id = $this->user->getId(); + $errors = 0; foreach ($base_ids as $base_id) { - if (!$stmt_del->execute([':base_id' => $base_id, ':usr_id' => $usr_id])) { - throw new Exception('Error while deleteing some rights'); - } - - $this->app['dispatcher']->dispatch( - AclEvents::ACCESS_TO_BASE_REVOKED, - new AccessToBaseRevokedEvent( - $this, - array( - 'base_id'=>$base_id + if ($stmt_del->execute([':base_id' => $base_id, ':usr_id' => $usr_id])) { + $this->app['dispatcher']->dispatch( + AclEvents::ACCESS_TO_BASE_REVOKED, + new AccessToBaseRevokedEvent( + $this, + [ + 'base_id' => $base_id + ] ) - ) - ); + ); + } + else { + $errors++; + } } $stmt_del->closeCursor(); $this->delete_data_from_cache(self::CACHE_RIGHTS_BAS); + if($errors > 0) { + throw new Exception('Error while deleting some rights'); + } + return $this; } diff --git a/lib/classes/eventsmanager/notify/orderdeliver.php b/lib/classes/eventsmanager/notify/orderdeliver.php index 6e27d431ea..8f4dcd8813 100644 --- a/lib/classes/eventsmanager/notify/orderdeliver.php +++ b/lib/classes/eventsmanager/notify/orderdeliver.php @@ -11,6 +11,9 @@ use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Model\Entities\User; +use Alchemy\Phrasea\Model\Repositories\BasketRepository; +use Alchemy\Phrasea\Model\Repositories\UserRepository; + class eventsmanager_notify_orderdeliver extends eventsmanager_notifyAbstract { @@ -31,9 +34,9 @@ class eventsmanager_notify_orderdeliver extends eventsmanager_notifyAbstract /** * - * @param Array $datas + * @param string[] $data * @param boolean $unread - * @return string + * @return array */ public function datas(array $data, $unread) { @@ -41,24 +44,29 @@ class eventsmanager_notify_orderdeliver extends eventsmanager_notifyAbstract $ssel_id = $data['ssel_id']; $n = $data['n']; - if (null === $user= $this->app['repo.users']->find(($from))) { + /** @var UserRepository $userRepo */ + $userRepo = $this->app['repo.users']; + if( ($user= $userRepo->find(($from))) === null ) { return []; } $sender = $user->getDisplayName(); try { + /** @var BasketRepository $repository */ $repository = $this->app['repo.baskets']; $basket = $repository->findUserBasket($ssel_id, $this->app->getAuthenticatedUser(), false); - } catch (\Exception $e) { + } + catch (\Exception $e) { return []; } + $ret = [ 'text' => $this->app->trans('%user% vous a delivre %quantity% document(s) pour votre commande %title%', ['%user%' => $sender, '%quantity%' => $n, '%title%' => '' - . $basket->getName() . '']) - , 'class' => '' + . $basket->getName() . '']), + 'class' => '' ]; return $ret; diff --git a/lib/classes/eventsmanager/notify/validationdone.php b/lib/classes/eventsmanager/notify/validationdone.php index 6f231f90aa..c5b0c48a5c 100644 --- a/lib/classes/eventsmanager/notify/validationdone.php +++ b/lib/classes/eventsmanager/notify/validationdone.php @@ -11,6 +11,9 @@ use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Model\Entities\User; +use Alchemy\Phrasea\Model\Repositories\BasketRepository; +use Alchemy\Phrasea\Model\Repositories\UserRepository; + class eventsmanager_notify_validationdone extends eventsmanager_notifyAbstract { @@ -31,35 +34,38 @@ class eventsmanager_notify_validationdone extends eventsmanager_notifyAbstract /** * - * @param string $datas + * @param string[] $data * @param boolean $unread - * @return Array + * @return array */ public function datas(array $data, $unread) { $from = $data['from']; $ssel_id = $data['ssel_id']; - if (null === $registered_user = $this->app['repo.users']->find($from)) { + /** @var UserRepository $userRepo */ + $userRepo = $this->app['repo.users']; + if ( ($registered_user = $userRepo->find($from)) === null ) { return []; } $sender = $registered_user->getDisplayName(); try { + /** @var BasketRepository $repository */ $repository = $this->app['repo.baskets']; $basket = $repository->findUserBasket($ssel_id, $this->app->getAuthenticatedUser(), false); - } catch (\Exception $e) { + } + catch (\Exception $e) { return []; } $ret = [ 'text' => $this->app->trans('%user% a envoye son rapport de validation de %title%', ['%user%' => $sender, '%title%' => '' - . $basket->getName() . '' - ]) - , 'class' => '' + . $basket->getName() . '']), + 'class' => '' ]; return $ret; @@ -84,12 +90,18 @@ class eventsmanager_notify_validationdone extends eventsmanager_notifyAbstract } /** - * @param integer $usr_id The id of the user to check + * @param User $user The id of the user to check * * @return boolean */ public function is_available(User $user) { - return $this->app->getAclForUser($user)->has_right(\ACL::CANPUSH); + try { + return $this->app->getAclForUser($user)->has_right(\ACL::CANPUSH); + } + catch (\Exception $e) { + // has_right(unknow_right) ? will not happen ! + return false; + } } } diff --git a/lib/classes/set/export.php b/lib/classes/set/export.php index 433bcb95cb..b9a59a1042 100644 --- a/lib/classes/set/export.php +++ b/lib/classes/set/export.php @@ -9,13 +9,16 @@ */ use Alchemy\Phrasea\Application; -use Alchemy\Phrasea\Model\Serializer\CaptionSerializer; use Alchemy\Phrasea\Model\Entities\Token; use Alchemy\Phrasea\Model\Entities\User; +use Alchemy\Phrasea\Model\Repositories\BasketRepository; +use Alchemy\Phrasea\Model\Repositories\StoryWZRepository; +use Alchemy\Phrasea\Model\Serializer\CaptionSerializer; use Assert\Assertion; use Doctrine\DBAL\Connection; use Symfony\Component\Filesystem\Filesystem; + class set_export extends set_abstract { private static $maxFilenameLength = 256; @@ -60,6 +63,7 @@ class set_export extends set_abstract $remain_hd = []; if ($storyWZid) { + /** @var StoryWZRepository $repository */ $repository = $app['repo.story-wz']; $storyWZ = $repository->findByUserAndId($this->app, $app->getAuthenticatedUser(), $storyWZid); @@ -68,6 +72,7 @@ class set_export extends set_abstract } if ($sstid != "") { + /** @var BasketRepository $repository */ $repository = $app['repo.baskets']; $Basket = $repository->findUserBasket($sstid, $app->getAuthenticatedUser(), false); From 3ae0c9486360ea5f5c06e2601c2f757e0eca3159 Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Thu, 25 Jul 2019 17:33:21 +0200 Subject: [PATCH 05/11] PHRAS-2666_slow-notifications_4.1 fix bad fct arg type "string" !!! WIP !!! --- lib/Alchemy/Phrasea/Helper/WorkZone.php | 2 +- lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Alchemy/Phrasea/Helper/WorkZone.php b/lib/Alchemy/Phrasea/Helper/WorkZone.php index 8841b264ae..345af37fbd 100644 --- a/lib/Alchemy/Phrasea/Helper/WorkZone.php +++ b/lib/Alchemy/Phrasea/Helper/WorkZone.php @@ -31,7 +31,7 @@ class WorkZone extends Helper * @param null|string $sort "date"|"name" * @return ArrayCollection */ - public function getContent(string $sort = null) + public function getContent($sort = null) { /* @var $repo_baskets BasketRepository */ $repo_baskets = $this->app['repo.baskets']; diff --git a/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php b/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php index fe1d7e9dbb..2c863ac3c2 100644 --- a/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php +++ b/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php @@ -58,7 +58,7 @@ class BasketRepository extends EntityRepository * @param null|string $sort * @return Basket[] */ - public function findActiveByUser(User $user, string $sort = null) + public function findActiveByUser(User $user, $sort = null) { // checked : 4 usages, "b.elements" is useless $dql = "SELECT b\n" From 568268a91880e3554be0c25f00255e0b6622c732 Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Thu, 25 Jul 2019 18:16:43 +0200 Subject: [PATCH 06/11] PHRAS-2666_slow-notifications_4.1 revert to fix unit test (?) !!! WIP !!! --- .../Phrasea/Controller/Root/SessionController.php | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Root/SessionController.php b/lib/Alchemy/Phrasea/Controller/Root/SessionController.php index 23e6b2b425..c3585aecbe 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/SessionController.php +++ b/lib/Alchemy/Phrasea/Controller/Root/SessionController.php @@ -94,10 +94,9 @@ class SessionController extends Controller } /** - * Check session state - * - * @param Request $request + * @param Request $request * @return JsonResponse + * @throws \Exception in case "new \DateTime()" fails ? */ public function updateSession(Request $request) { @@ -142,14 +141,7 @@ class SessionController extends Controller /** @var \Alchemy\Phrasea\Model\Entities\Session $session */ $session = $this->getSessionRepository()->find($this->getSession()->get('session_id')); - try { - $now = new \DateTime(); - } - catch (\Exception $e) { - // no-op : DateTime() without arg should not fail... - $now = null; // prevent phpstorm warning about undefine var. - } - $session->setUpdated($now); + $session->setUpdated(new \DateTime()); $manager = $this->getEntityManager(); if (!$session->hasModuleId($moduleId)) { From 31b940239f2890a00fb3571e29487ba21f740b09 Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Thu, 25 Jul 2019 19:34:32 +0200 Subject: [PATCH 07/11] PHRAS-2666_slow-notifications_4.1 fix dql !!! WIP !!! --- .../Model/Repositories/BasketRepository.php | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php b/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php index 2c863ac3c2..b835a821e0 100644 --- a/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php +++ b/lib/Alchemy/Phrasea/Model/Repositories/BasketRepository.php @@ -77,9 +77,6 @@ class BasketRepository extends EntityRepository $query = $this->_em->createQuery($dql); $query->setParameters(['usr_id' => $user->getId()]); - $sql = $query->getSQL(); - file_put_contents("/tmp/phraseanet-log.txt", sprintf("%s (%d) %s\n\n", __FILE__, __LINE__, var_export($sql, true)), FILE_APPEND); - return $query->getResult(); } @@ -93,10 +90,10 @@ class BasketRepository extends EntityRepository { // checked : 2 usages, "b.elements" is useless $dql = "SELECT b\n" - . " FROM (Phraseanet:Basket b\"" + . " FROM Phraseanet:Basket b\n" // . " JOIN b.elements e\n" - . " LEFT JOIN b.validation s)\n" - . " INNER JOIN s.participants p\n" + . " LEFT JOIN b.validation s\n" + . " LEFT JOIN s.participants p\n" . " WHERE b.archived = false\n" . " AND (\n" . " (b.user = :usr_id_owner AND b.isRead = false)\n" @@ -117,9 +114,6 @@ class BasketRepository extends EntityRepository $query = $this->_em->createQuery($dql); $query->setParameters($params); - $sql = $query->getSQL(); - file_put_contents("/tmp/phraseanet-log.txt", sprintf("%s (%d) %s\n\n", __FILE__, __LINE__, var_export($sql, true)), FILE_APPEND); - return $query->getResult(); } @@ -143,6 +137,15 @@ class BasketRepository extends EntityRepository . "WHERE b.user != ?1 AND p.user = ?2\n" . " AND (s.expires IS NULL OR s.expires > CURRENT_TIMESTAMP())"; + $dql = 'SELECT b + FROM Phraseanet:Basket b + JOIN b.elements e + JOIN e.validation_datas v + JOIN b.validation s + JOIN s.participants p + WHERE b.user != ?1 AND p.user = ?2 + AND (s.expires IS NULL OR s.expires > CURRENT_TIMESTAMP()) '; + if ($sort == 'date') { $dql .= "\nORDER BY b.created DESC"; } elseif ($sort == 'name') { @@ -151,8 +154,6 @@ class BasketRepository extends EntityRepository $query = $this->_em->createQuery($dql); $query->setParameters([1 => $user->getId(), 2 => $user->getId()]); - $sql = $query->getSQL(); - file_put_contents("/tmp/phraseanet-log.txt", sprintf("%s (%d) %s\n\n", __FILE__, __LINE__, var_export($sql, true)), FILE_APPEND); return $query->getResult(); } From b3af2c26b2b1c7bf94fd385281858e9fb0c9e301 Mon Sep 17 00:00:00 2001 From: Harrys Ravalomanana Date: Wed, 18 Sep 2019 17:43:42 +0400 Subject: [PATCH 08/11] PHRAS-2686 --- .../Controller/Prod/QueryController.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php b/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php index 1e8724c0ee..66458e9e90 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php @@ -214,7 +214,7 @@ class QueryController extends Controller if (min($d2top, $d2bottom) < 4) { if ($d2bottom < 4) { if($page != 1){ - $string .= ""; + $string .= ""; } for ($i = 1; ($i <= 4 && (($i <= $npages) === true)); $i++) { if ($i == $page) @@ -223,13 +223,13 @@ class QueryController extends Controller $string .= '' . $i . ''; } if ($npages > 4) - $string .= ""; - $string .= ''; + $string .= ""; + $string .= ''; } else { $start = $npages - 4; if (($start) > 0){ - $string .= ''; - $string .= ''; + $string .= ''; + $string .= ''; }else $start = 1; for ($i = ($start); $i <= $npages; $i++) { @@ -239,11 +239,11 @@ class QueryController extends Controller $string .= '' . $i . ''; } if($page < $npages){ - $string .= ""; + $string .= ""; } } } else { - $string .= ''; + $string .= ''; for ($i = ($page - 2); $i <= ($page + 2); $i++) { if ($i == $page) @@ -252,10 +252,10 @@ class QueryController extends Controller $string .= '' . $i . ''; } - $string .= ''; + $string .= ''; } } - $string .= '
'; + $string .= '
'; $explain = $this->render( "prod/results/infos.html.twig", @@ -470,7 +470,6 @@ class QueryController extends Controller $json['results'] = $this->render($template, ['results'=> $result]); } - return $this->app->json($json); } From c16dc45208cec0c9a23e721c468c90ffc14b2869 Mon Sep 17 00:00:00 2001 From: Harrys Ravalomanana Date: Fri, 20 Sep 2019 11:10:26 +0400 Subject: [PATCH 09/11] PHRAS-2686 --- lib/Alchemy/Phrasea/Controller/Prod/QueryController.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php b/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php index 66458e9e90..790e33525d 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php @@ -224,11 +224,11 @@ class QueryController extends Controller } if ($npages > 4) $string .= ""; - $string .= ''; + $string .= ''; } else { $start = $npages - 4; if (($start) > 0){ - $string .= ''; + $string .= ''; $string .= ''; }else $start = 1; @@ -243,7 +243,7 @@ class QueryController extends Controller } } } else { - $string .= ''; + $string .= ''; for ($i = ($page - 2); $i <= ($page + 2); $i++) { if ($i == $page) @@ -252,7 +252,7 @@ class QueryController extends Controller $string .= '' . $i . ''; } - $string .= ''; + $string .= ''; } } $string .= '
'; From d202fe59807c37aec108c7a9ac33ca9d236a98e1 Mon Sep 17 00:00:00 2001 From: Harrys Ravalomanana Date: Fri, 20 Sep 2019 15:20:58 +0400 Subject: [PATCH 10/11] PHRAS-2686 upgrade phraseanet-production-client --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index db6d50a49b..84823d0938 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "normalize-css": "^2.1.0", "npm": "^6.0.0", "npm-modernizr": "^2.8.3", - "phraseanet-production-client": "0.34.63-d", + "phraseanet-production-client": "0.34.72-d", "requirejs": "^2.3.5", "tinymce": "^4.0.28", "underscore": "^1.8.3", diff --git a/yarn.lock b/yarn.lock index 471f86bfba..4cfedda66c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7555,10 +7555,10 @@ phraseanet-common@^0.4.1: js-cookie "^2.1.0" pym.js "^1.3.1" -phraseanet-production-client@0.34.63-d: - version "0.34.63-d" - resolved "https://registry.yarnpkg.com/phraseanet-production-client/-/phraseanet-production-client-0.34.63-d.tgz#0b74aa2188002effedd143d4c16364007daad672" - integrity sha512-kjySO4v4KALrr7UC/6WacSn/2s4pEaiY98iqejoK2rkzZEsuVOUKyuifxfTaX4xkFSfSwf5F0RA2n43JJbDGHA== +phraseanet-production-client@0.34.72-d: + version "0.34.72-d" + resolved "https://registry.yarnpkg.com/phraseanet-production-client/-/phraseanet-production-client-0.34.72-d.tgz#028a5ccd589e696b5433eea9d53d9367966613c8" + integrity sha512-IPaDRqXwyJegoKmzr56bggxTzN4TnmuAqU4O7rDEhh0aqdCiuC8rlH/yzKoLeEIMSrESCw5mBhrI//ccntvv9w== dependencies: "@mapbox/mapbox-gl-language" "^0.9.2" "@turf/turf" "^5.1.6" From dbaca5bb94bca453f57a4321b11ee943be273bda Mon Sep 17 00:00:00 2001 From: aynsix Date: Fri, 27 Sep 2019 11:49:09 +0400 Subject: [PATCH 11/11] reactivate permalink when record moved from TRASH 4.1 --- .../Phrasea/Controller/Prod/MoveCollectionController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Alchemy/Phrasea/Controller/Prod/MoveCollectionController.php b/lib/Alchemy/Phrasea/Controller/Prod/MoveCollectionController.php index c4fe729538..50e2219e0d 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/MoveCollectionController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/MoveCollectionController.php @@ -114,6 +114,7 @@ class MoveCollectionController extends Controller $trashCollectionsBySbasId = []; foreach ($records as $record) { + $oldCollectionId = $record->getCollection()->get_coll_id(); $record->move_to_collection($collection, $this->getApplicationBox()); if ($request->request->get("chg_coll_son") == "1") { @@ -130,7 +131,7 @@ class MoveCollectionController extends Controller $trashCollectionsBySbasId[$sbasId] = $record->getDatabox()->getTrashCollection(); } if ($trashCollectionsBySbasId[$sbasId] !== null) { - if ($record->getCollection()->get_coll_id() == $trashCollectionsBySbasId[$sbasId]->get_coll_id() && $collection->get_coll_id() !== $trashCollectionsBySbasId[$sbasId]->get_coll_id()) { + if ($oldCollectionId == $trashCollectionsBySbasId[$sbasId]->get_coll_id() && $collection->get_coll_id() !== $trashCollectionsBySbasId[$sbasId]->get_coll_id()) { // record is already in trash so active it foreach ($record->get_subdefs() as $subdef) { if (($pl = $subdef->get_permalink())) {