From 7541885637107aefd58f5cf4611ef6a40fc49adb Mon Sep 17 00:00:00 2001 From: aynsix Date: Fri, 20 Sep 2019 16:01:48 +0400 Subject: [PATCH 01/28] buildsubdef with worker --- bin/console | 6 ++-- lib/Alchemy/Phrasea/Border/Manager.php | 4 ++- .../Controller/Prod/StoryController.php | 6 +++- .../Controller/Prod/ToolsController.php | 3 +- .../Core/Event/Record/RecordEvents.php | 2 ++ .../Event/Record/SubdefinitionBuildEvent.php | 34 +++++++++++++++++++ .../Event/Subscriber/RecordEditSubscriber.php | 16 ++++++--- lib/Alchemy/Phrasea/Media/SubdefGenerator.php | 18 ++++++++++ .../Phrasea/Media/SubdefSubstituer.php | 3 +- .../Phrasea/TaskManager/Job/ArchiveJob.php | 7 ++-- lib/classes/record/adapter.php | 6 ++-- 11 files changed, 90 insertions(+), 15 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Core/Event/Record/SubdefinitionBuildEvent.php diff --git a/bin/console b/bin/console index 552cb672d0..02f4ccee61 100755 --- a/bin/console +++ b/bin/console @@ -133,9 +133,9 @@ $cli->command(new QueryParseCommand()); $cli->command(new QuerySampleCommand()); $cli->command(new FindConceptsCommand()); -$cli->command($cli['alchemy_worker.commands.run_dispatcher_command']); -$cli->command($cli['alchemy_worker.commands.run_worker_command']); -$cli->command($cli['alchemy_worker.commands.show_configuration']); +//$cli->command($cli['alchemy_worker.commands.run_dispatcher_command']); +//$cli->command($cli['alchemy_worker.commands.run_worker_command']); +//$cli->command($cli['alchemy_worker.commands.show_configuration']); $cli->loadPlugins(); diff --git a/lib/Alchemy/Phrasea/Border/Manager.php b/lib/Alchemy/Phrasea/Border/Manager.php index d8abc9ac99..55c28d9cbf 100644 --- a/lib/Alchemy/Phrasea/Border/Manager.php +++ b/lib/Alchemy/Phrasea/Border/Manager.php @@ -14,6 +14,8 @@ namespace Alchemy\Phrasea\Border; use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Border\Checker\CheckerInterface; use Alchemy\Phrasea\Border\Attribute\AttributeInterface; +use Alchemy\Phrasea\Core\Event\Record\RecordEvents; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionBuildEvent; use Alchemy\Phrasea\Exception\RuntimeException; use Alchemy\Phrasea\Metadata\Tag\TfArchivedate; use Alchemy\Phrasea\Metadata\Tag\TfQuarantine; @@ -333,7 +335,7 @@ class Manager $this->app['phraseanet.metadata-setter']->replaceMetadata($newMetadata, $element); if(!$nosubdef) { - $element->rebuild_subdefs(); + $this->app['dispatcher']->dispatch(RecordEvents::SUBDEFINITION_BUILD, new SubdefinitionBuildEvent($element, true)); } return $element; diff --git a/lib/Alchemy/Phrasea/Controller/Prod/StoryController.php b/lib/Alchemy/Phrasea/Controller/Prod/StoryController.php index 9a65ed61fa..19acc22a27 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/StoryController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/StoryController.php @@ -14,6 +14,8 @@ use Alchemy\Phrasea\Application\Helper\EntityManagerAware; use Alchemy\Phrasea\Controller\Controller; use Alchemy\Phrasea\Controller\RecordsRequest; use Alchemy\Phrasea\Controller\Exception as ControllerException; +use Alchemy\Phrasea\Core\Event\Record\RecordEvents; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionBuildEvent; use Alchemy\Phrasea\Core\Event\RecordEdit; use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Model\Entities\StoryWZ; @@ -68,7 +70,9 @@ class StoryController extends Controller break; } - $story->set_metadatas($metadatas)->rebuild_subdefs(); + $recordAdapter = $story->set_metadatas($metadatas); + // tell phraseanet to rebuild subdef + $this->dispatch(RecordEvents::SUBDEFINITION_BUILD, new SubdefinitionBuildEvent($recordAdapter)); $storyWZ = new StoryWZ(); $storyWZ->setUser($this->getAuthenticatedUser()); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php b/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php index 872f385455..2318cf0638 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php @@ -16,6 +16,7 @@ use Alchemy\Phrasea\Application\Helper\SubDefinitionSubstituerAware; use Alchemy\Phrasea\Controller\Controller; use Alchemy\Phrasea\Controller\RecordsRequest; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionBuildEvent; use Alchemy\Phrasea\Exception\RuntimeException; use Alchemy\Phrasea\Metadata\PhraseanetMetadataReader; use Alchemy\Phrasea\Metadata\PhraseanetMetadataSetter; @@ -156,7 +157,7 @@ class ToolsController extends Controller } if (!$substituted || $force) { - $record->rebuild_subdefs(); + $this->dispatch(RecordEvents::SUBDEFINITION_BUILD, new SubdefinitionBuildEvent($record)); } } diff --git a/lib/Alchemy/Phrasea/Core/Event/Record/RecordEvents.php b/lib/Alchemy/Phrasea/Core/Event/Record/RecordEvents.php index c55245a7ff..ac725833ac 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Record/RecordEvents.php +++ b/lib/Alchemy/Phrasea/Core/Event/Record/RecordEvents.php @@ -29,6 +29,8 @@ final class RecordEvents const SUB_DEFINITIONS_CREATED = 'record.sub_definitions_created'; const SUB_DEFINITION_CREATION_FAILED = 'record.sub_definition_creation_failed'; + const SUBDEFINITION_BUILD = 'record.subdefinition_build'; + const MEDIA_SUBSTITUTED = 'record.media_substituted'; const STORY_COVER_CHANGED = 'record.story_cover_changed'; diff --git a/lib/Alchemy/Phrasea/Core/Event/Record/SubdefinitionBuildEvent.php b/lib/Alchemy/Phrasea/Core/Event/Record/SubdefinitionBuildEvent.php new file mode 100644 index 0000000000..701e3a2028 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Event/Record/SubdefinitionBuildEvent.php @@ -0,0 +1,34 @@ +isNewRecord = $isNewRecord; + } + + /** + * @return bool + */ + public function isNewRecord() + { + return $this->isNewRecord; + } +} diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php index d5c0c69f54..e58e77cdf7 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php @@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\Core\Event\Subscriber; use Alchemy\Phrasea\Core\Event\Record\CollectionChangedEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionBuildEvent; use Alchemy\Phrasea\Core\Event\RecordEdit; use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Metadata\Tag\TfEditdate; @@ -26,10 +27,11 @@ class RecordEditSubscriber implements EventSubscriberInterface public static function getSubscribedEvents() { return array( - PhraseaEvents::RECORD_EDIT => 'onEdit', - PhraseaEvents::RECORD_UPLOAD => 'onEdit', - RecordEvents::ROTATE => 'onRecordChange', - RecordEvents::COLLECTION_CHANGED => 'onCollectionChanged', + PhraseaEvents::RECORD_EDIT => 'onEdit', + PhraseaEvents::RECORD_UPLOAD => 'onEdit', + RecordEvents::ROTATE => 'onRecordChange', + RecordEvents::COLLECTION_CHANGED => 'onCollectionChanged', + RecordEvents::SUBDEFINITION_BUILD => 'onBuildSubdefs', ); } @@ -49,6 +51,12 @@ class RecordEditSubscriber implements EventSubscriberInterface $recordAdapter->clearStampCache(); } + public function onBuildSubdefs(SubdefinitionBuildEvent $event) + { + $recordAdapter = $this->convertToRecordAdapter($event->getRecord()); + $recordAdapter->rebuild_subdefs(); + } + public function onEdit(RecordEdit $event) { static $into = false; diff --git a/lib/Alchemy/Phrasea/Media/SubdefGenerator.php b/lib/Alchemy/Phrasea/Media/SubdefGenerator.php index 2dede228c5..7710069948 100644 --- a/lib/Alchemy/Phrasea/Media/SubdefGenerator.php +++ b/lib/Alchemy/Phrasea/Media/SubdefGenerator.php @@ -167,6 +167,24 @@ class SubdefGenerator ); } + /** + * set a logger to use + * @param LoggerInterface $logger + */ + public function setLogger(LoggerInterface $logger) + { + $this->logger = $logger; + } + + /** + * to get the logger + * @return LoggerInterface + */ + public function getLogger() + { + return $this->logger; + } + private function generateSubdef(\record_adapter $record, \databox_subdef $subdef_class, $pathdest) { $start = microtime(true); diff --git a/lib/Alchemy/Phrasea/Media/SubdefSubstituer.php b/lib/Alchemy/Phrasea/Media/SubdefSubstituer.php index 2259fa572d..1d096cf785 100644 --- a/lib/Alchemy/Phrasea/Media/SubdefSubstituer.php +++ b/lib/Alchemy/Phrasea/Media/SubdefSubstituer.php @@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\Media; use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Core\Event\Record\MediaSubstitutedEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionBuildEvent; use Alchemy\Phrasea\Filesystem\FilesystemService; use MediaAlchemyst\Alchemyst; use MediaAlchemyst\Exception\ExceptionInterface as MediaAlchemystException; @@ -79,7 +80,7 @@ class SubdefSubstituer $record->write_metas(); if ($shouldSubdefsBeRebuilt) { - $record->rebuild_subdefs(); + $this->dispatcher->dispatch(RecordEvents::SUBDEFINITION_BUILD, new SubdefinitionBuildEvent($record)); } $this->dispatcher->dispatch(RecordEvents::MEDIA_SUBSTITUTED, new MediaSubstitutedEvent($record)); diff --git a/lib/Alchemy/Phrasea/TaskManager/Job/ArchiveJob.php b/lib/Alchemy/Phrasea/TaskManager/Job/ArchiveJob.php index 532eb8bbb5..db1f6b083a 100644 --- a/lib/Alchemy/Phrasea/TaskManager/Job/ArchiveJob.php +++ b/lib/Alchemy/Phrasea/TaskManager/Job/ArchiveJob.php @@ -12,6 +12,8 @@ namespace Alchemy\Phrasea\TaskManager\Job; use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Core\Event\Record\RecordEvents; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionBuildEvent; use Alchemy\Phrasea\Exception\RuntimeException; use Alchemy\Phrasea\Border\File; use Alchemy\Phrasea\Border\Manager as borderManager; @@ -1001,7 +1003,7 @@ class ArchiveJob extends AbstractJob { // quick fix to reconnect if mysql is lost $app->getApplicationBox()->get_connection(); - $databox->get_connection(); + $collection->get_connection(); $status = \databox_status::operation_or($stat0, $stat1); @@ -1032,7 +1034,8 @@ class ArchiveJob extends AbstractJob } $story->setStatus(\databox_status::operation_or($stat0, $stat1)); - $story->rebuild_subdefs(); + + $app['dispatcher']->dispatch(RecordEvents::SUBDEFINITION_BUILD, new SubdefinitionBuildEvent($story)); unset($media); diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php index c4045d9fc5..9d7beb2c1a 100644 --- a/lib/classes/record/adapter.php +++ b/lib/classes/record/adapter.php @@ -19,6 +19,7 @@ use Alchemy\Phrasea\Core\Event\Record\OriginalNameChangedEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; use Alchemy\Phrasea\Core\Event\Record\StatusChangedEvent; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionBuildEvent; use Alchemy\Phrasea\Core\PhraseaTokens; use Alchemy\Phrasea\Databox\Subdef\MediaSubdefRepository; use Alchemy\Phrasea\Filesystem\FilesystemService; @@ -284,7 +285,7 @@ class record_adapter implements RecordInterface, cache_cacheableInterface $this->getDataboxConnection()->executeUpdate($sql, ['type' => $type, 'record_id' => $this->getRecordId()]); if ($old_type !== $type) { - $this->rebuild_subdefs(); + $this->dispatch(RecordEvents::SUBDEFINITION_BUILD, new SubdefinitionBuildEvent($this)); } $this->type = $type; @@ -341,7 +342,8 @@ class record_adapter implements RecordInterface, cache_cacheableInterface array(':mime' => $mime, ':record_id' => $this->getRecordId()) )) { - $this->rebuild_subdefs(); + $this->dispatch(RecordEvents::SUBDEFINITION_BUILD, new SubdefinitionBuildEvent($this)); + $this->delete_data_from_cache(); } From c712cb7cc3bba2957a4398105576f95cb777b2fa Mon Sep 17 00:00:00 2001 From: aynsix Date: Fri, 20 Sep 2019 16:03:54 +0400 Subject: [PATCH 02/28] retrieve rabbitmq configuration from configuration.yml --- .../WorkerConfigurationServiceProvider.php | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/lib/Alchemy/Phrasea/Core/Provider/WorkerConfigurationServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/WorkerConfigurationServiceProvider.php index 1b2e15d4f0..9931d4649f 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/WorkerConfigurationServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/WorkerConfigurationServiceProvider.php @@ -32,11 +32,12 @@ class WorkerConfigurationServiceProvider implements ServiceProviderInterface $app['alchemy_queues.queues'] = $app->share(function (Application $app) { $defaultConfiguration = [ 'worker-queue' => [ - 'registry' => 'alchemy_worker.queue_registry', - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'vhost' => '/' + 'registry' => 'alchemy_worker.queue_registry', + 'host' => 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'password' => 'guest', + 'vhost' => '/' ] ]; @@ -46,19 +47,22 @@ class WorkerConfigurationServiceProvider implements ServiceProviderInterface $queueConfigurations = $configuration->get(['workers', 'queue'], $defaultConfiguration); - $queueConfiguration = reset($queueConfigurations); - $queueKey = key($queueConfigurations); + $config = []; - if (! isset($queueConfiguration['name'])) { - if (! is_string($queueKey)) { - throw new \RuntimeException('Invalid queue configuration: configuration has no key or name.'); + foreach($queueConfigurations as $name => $queueConfiguration) { + $queueKey = $name; + + if (! isset($queueConfiguration['name'])) { + if (! is_string($queueKey)) { + throw new \RuntimeException('Invalid queue configuration: configuration has no key or name.'); + } + + $queueConfiguration['name'] = $queueKey; } - $queueConfiguration['name'] = $queueKey; + $config[$queueConfiguration['name']] = $queueConfiguration ; } - $config = [ $queueConfiguration['name'] => $queueConfiguration ]; - return $config; } catch (RuntimeException $exception) { From 65d7affcb53619e9ce406d8d2e75d0a4b7206e68 Mon Sep 17 00:00:00 2001 From: aynsix Date: Fri, 20 Sep 2019 16:15:49 +0400 Subject: [PATCH 03/28] export mail : make it event oriented to facilitate worker treatement --- .../Controller/Prod/ExportController.php | 47 +++++--------- .../Phrasea/Core/Event/ExportMailEvent.php | 53 +++++++++++++++ .../Event/Subscriber/ExportSubscriber.php | 65 ++++++++++++++++++- lib/Alchemy/Phrasea/Core/PhraseaEvents.php | 3 +- .../Phrasea/Controller/Prod/ExportTest.php | 3 +- 5 files changed, 137 insertions(+), 34 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Core/Event/ExportMailEvent.php diff --git a/lib/Alchemy/Phrasea/Controller/Prod/ExportController.php b/lib/Alchemy/Phrasea/Controller/Prod/ExportController.php index df6f2a9f19..f4692c99ac 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/ExportController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/ExportController.php @@ -15,6 +15,7 @@ use Alchemy\Phrasea\Application\Helper\FilesystemAware; use Alchemy\Phrasea\Application\Helper\NotifierAware; use Alchemy\Phrasea\Controller\Controller; use Alchemy\Phrasea\Core\Event\ExportFailureEvent; +use Alchemy\Phrasea\Core\Event\ExportMailEvent; use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Exception\InvalidArgumentException; use Alchemy\Phrasea\Model\Manipulator\TokenManipulator; @@ -193,42 +194,26 @@ class ExportController extends Controller $token = $this->getTokenManipulator()->createEmailExportToken(serialize($list)); if (count($destMails) > 0) { - //zip documents - \set_export::build_zip( - $this->app, - $token, - $list, - $this->app['tmp.download.path'].'/'. $token->getValue() . '.zip' - ); + $emitterId = $this->getAuthenticatedUser()->getId(); - $remaingEmails = $destMails; + $tokenValue = $token->getValue(); $url = $this->app->url('prepare_download', ['token' => $token->getValue(), 'anonymous' => false, 'type' => \Session_Logger::EVENT_EXPORTMAIL]); - $user = $this->getAuthenticatedUser(); - $emitter = new Emitter($user->getDisplayName(), $user->getEmail()); + $params = [ + 'url' => $url, + 'textmail' => $request->request->get('textmail'), + 'reading_confirm' => !!$request->request->get('reading_confirm', false), + 'ssttid' => $ssttid = $request->request->get('ssttid', ''), + 'lst' => $lst = $request->request->get('lst', ''), + ]; - foreach ($destMails as $key => $mail) { - try { - $receiver = new Receiver(null, trim($mail)); - } catch (InvalidArgumentException $e) { - continue; - } - - $mail = MailRecordsExport::create($this->app, $receiver, $emitter, $request->request->get('textmail')); - $mail->setButtonUrl($url); - $mail->setExpiration($token->getExpiration()); - - $this->deliver($mail, !!$request->request->get('reading_confirm', false)); - unset($remaingEmails[$key]); - } - - //some mails failed - if (count($remaingEmails) > 0) { - foreach ($remaingEmails as $mail) { - $this->dispatch(PhraseaEvents::EXPORT_MAIL_FAILURE, new ExportFailureEvent($this->getAuthenticatedUser(), $ssttid, $lst, \eventsmanager_notify_downloadmailfail::MAIL_FAIL, $mail)); - } - } + $this->dispatch(PhraseaEvents::EXPORT_MAIL_CREATE, new ExportMailEvent( + $emitterId, + $tokenValue, + $destMails, + $params + )); } return $this->app->json([ diff --git a/lib/Alchemy/Phrasea/Core/Event/ExportMailEvent.php b/lib/Alchemy/Phrasea/Core/Event/ExportMailEvent.php new file mode 100644 index 0000000000..3acafb4c70 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Event/ExportMailEvent.php @@ -0,0 +1,53 @@ +emitterUserId = $emitterUserId; + $this->tokenValue = $tokenValue; + $this->destinationMails = $destMails; + $this->params = $params; + } + + public function getTokenValue() + { + return $this->tokenValue; + } + + public function getDestinationMails() + { + return $this->destinationMails; + } + + public function getEmitterUserId() + { + return $this->emitterUserId; + } + + public function getParams() + { + return $this->params; + } +} diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/ExportSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/ExportSubscriber.php index fca66dab4a..d3c05a64b6 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/ExportSubscriber.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/ExportSubscriber.php @@ -12,7 +12,15 @@ namespace Alchemy\Phrasea\Core\Event\Subscriber; use Alchemy\Phrasea\Core\Event\ExportFailureEvent; +use Alchemy\Phrasea\Core\Event\ExportMailEvent; use Alchemy\Phrasea\Core\PhraseaEvents; +use Alchemy\Phrasea\Exception\InvalidArgumentException; +use Alchemy\Phrasea\Model\Entities\Token; +use Alchemy\Phrasea\Model\Repositories\TokenRepository; +use Alchemy\Phrasea\Model\Repositories\UserRepository; +use Alchemy\Phrasea\Notification\Emitter; +use Alchemy\Phrasea\Notification\Mail\MailRecordsExport; +use Alchemy\Phrasea\Notification\Receiver; class ExportSubscriber extends AbstractNotificationSubscriber { @@ -39,10 +47,65 @@ class ExportSubscriber extends AbstractNotificationSubscriber $this->app['event-manager']->notify($params['usr_id'], 'eventsmanager_notify_downloadmailfail', $datas, $mailed); } + public function onCreateExportMail(ExportMailEvent $event) + { + $destMails = $event->getDestinationMails(); + + $params = $event->getParams(); + + /** @var UserRepository $userRepository */ + $userRepository = $this->app['repo.users']; + + $user = $userRepository->find($event->getEmitterUserId()); + + /** @var TokenRepository $tokenRepository */ + $tokenRepository = $this->app['repo.tokens']; + + /** @var Token $token */ + $token = $tokenRepository->findValidToken($event->getTokenValue()); + + $list = unserialize($token->getData()); + + //zip documents + \set_export::build_zip( + $this->app, + $token, + $list, + $this->app['tmp.download.path'].'/'. $token->getValue() . '.zip' + ); + + $remaingEmails = $destMails; + + $emitter = new Emitter($user->getDisplayName(), $user->getEmail()); + + foreach ($destMails as $key => $mail) { + try { + $receiver = new Receiver(null, trim($mail)); + } catch (InvalidArgumentException $e) { + continue; + } + + $mail = MailRecordsExport::create($this->app, $receiver, $emitter, $params['textmail']); + $mail->setButtonUrl($params['url']); + $mail->setExpiration($token->getExpiration()); + + $this->deliver($mail, $params['reading_confirm']); + unset($remaingEmails[$key]); + } + + //some mails failed + if (count($remaingEmails) > 0) { + foreach ($remaingEmails as $mail) { + $this->app['dispatcher']->dispatch(PhraseaEvents::EXPORT_MAIL_FAILURE, new ExportFailureEvent($user, $params['ssttid'], $params['lst'], \eventsmanager_notify_downloadmailfail::MAIL_FAIL, $mail)); + } + } + } + public static function getSubscribedEvents() { return [ - PhraseaEvents::EXPORT_MAIL_FAILURE => 'onMailExportFailure' + PhraseaEvents::EXPORT_MAIL_FAILURE => 'onMailExportFailure', + PhraseaEvents::EXPORT_MAIL_CREATE => 'onCreateExportMail', ]; } } diff --git a/lib/Alchemy/Phrasea/Core/PhraseaEvents.php b/lib/Alchemy/Phrasea/Core/PhraseaEvents.php index 97c9c10ba5..90adac69dd 100644 --- a/lib/Alchemy/Phrasea/Core/PhraseaEvents.php +++ b/lib/Alchemy/Phrasea/Core/PhraseaEvents.php @@ -48,7 +48,8 @@ final class PhraseaEvents const BRIDGE_UPLOAD_FAILURE = 'bridge.upload-failure'; const EXPORT_MAIL_FAILURE = 'export.mail-failure'; - const EXPORT_CREATE = 'export.create'; + const EXPORT_CREATE = 'export.create'; + const EXPORT_MAIL_CREATE = 'export.mail-create'; const RECORD_EDIT = 'record.edit'; const RECORD_UPLOAD = 'record.upload'; diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Prod/ExportTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Prod/ExportTest.php index da278639c2..925caa9945 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Prod/ExportTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Prod/ExportTest.php @@ -165,7 +165,8 @@ class ExportTest extends \PhraseanetAuthenticatedWebTestCase */ public function testExportMail() { - $this->mockNotificationDeliverer('Alchemy\Phrasea\Notification\Mail\MailRecordsExport'); + // deliver method removed in the listener +// $this->mockNotificationDeliverer('Alchemy\Phrasea\Notification\Mail\MailRecordsExport'); $this->getClient()->request('POST', '/prod/export/mail/', [ 'lst' => $this->getRecord1()->getId(), From 9aaf66dd7c0e14519e56d7991c36200b0f9322f0 Mon Sep 17 00:00:00 2001 From: aynsix Date: Fri, 20 Sep 2019 16:55:03 +0400 Subject: [PATCH 04/28] initialize webhook with worker --- .../Model/Manipulator/WebhookEventManipulator.php | 6 +++--- lib/Alchemy/Phrasea/Webhook/WebhookPublisher.php | 2 +- .../Phrasea/Webhook/WebhookPublisherInterface.php | 10 ++++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Webhook/WebhookPublisherInterface.php diff --git a/lib/Alchemy/Phrasea/Model/Manipulator/WebhookEventManipulator.php b/lib/Alchemy/Phrasea/Model/Manipulator/WebhookEventManipulator.php index 40e7f812a7..30d20d1045 100644 --- a/lib/Alchemy/Phrasea/Model/Manipulator/WebhookEventManipulator.php +++ b/lib/Alchemy/Phrasea/Model/Manipulator/WebhookEventManipulator.php @@ -12,7 +12,7 @@ namespace Alchemy\Phrasea\Model\Manipulator; use Alchemy\Phrasea\Model\Entities\WebhookEvent; -use Alchemy\Phrasea\Webhook\WebhookPublisher; +use Alchemy\Phrasea\Webhook\WebhookPublisherInterface; use Doctrine\Common\Persistence\ObjectManager; use Doctrine\ORM\EntityRepository; @@ -29,11 +29,11 @@ class WebhookEventManipulator implements ManipulatorInterface private $repository; /** - * @var WebhookPublisher + * @var WebhookPublisherInterface */ private $publisher; - public function __construct(ObjectManager $om, EntityRepository $repo, WebhookPublisher $publisher) + public function __construct(ObjectManager $om, EntityRepository $repo, WebhookPublisherInterface $publisher) { $this->om = $om; $this->repository = $repo; diff --git a/lib/Alchemy/Phrasea/Webhook/WebhookPublisher.php b/lib/Alchemy/Phrasea/Webhook/WebhookPublisher.php index 4304a5319f..2beaec292f 100644 --- a/lib/Alchemy/Phrasea/Webhook/WebhookPublisher.php +++ b/lib/Alchemy/Phrasea/Webhook/WebhookPublisher.php @@ -19,7 +19,7 @@ use Alchemy\Queue\MessageQueueRegistry; * Class WebhookPublisher publishes webhook event notifications in message queues * @package Alchemy\Phrasea\Webhook */ -class WebhookPublisher +class WebhookPublisher implements WebhookPublisherInterface { /** * @var MessageQueueRegistry diff --git a/lib/Alchemy/Phrasea/Webhook/WebhookPublisherInterface.php b/lib/Alchemy/Phrasea/Webhook/WebhookPublisherInterface.php new file mode 100644 index 0000000000..f8b4751ef0 --- /dev/null +++ b/lib/Alchemy/Phrasea/Webhook/WebhookPublisherInterface.php @@ -0,0 +1,10 @@ + Date: Fri, 20 Sep 2019 18:01:23 +0400 Subject: [PATCH 05/28] user webhook: registration and delete --- .../Phrasea/Account/AccountService.php | 4 +-- .../Authentication/RegistrationService.php | 9 +++--- .../Controller/Admin/UserController.php | 4 +-- .../Controller/Root/AccountController.php | 6 ++-- .../Subscriber/WebhookUserEventSubscriber.php | 2 +- .../Phrasea/Core/Event/User/DeletedEvent.php | 8 ++++++ lib/Alchemy/Phrasea/Core/Version.php | 2 +- lib/Alchemy/Phrasea/Helper/User/Edit.php | 4 ++- .../Phrasea/Model/Entities/WebhookEvent.php | 28 +++++++++++++++++++ .../Model/Manipulator/UserManipulator.php | 10 ++++--- .../Phrasea/Functional/UserDeletionTest.php | 2 +- 11 files changed, 61 insertions(+), 18 deletions(-) diff --git a/lib/Alchemy/Phrasea/Account/AccountService.php b/lib/Alchemy/Phrasea/Account/AccountService.php index 4c0e594e64..567a404a94 100644 --- a/lib/Alchemy/Phrasea/Account/AccountService.php +++ b/lib/Alchemy/Phrasea/Account/AccountService.php @@ -167,11 +167,11 @@ class AccountService * @param string $login * @throws AccountException */ - public function deleteAccount($login = null) + public function deleteAccount($login = null, array $grantedBaseIdList = array()) { $user = $this->getUserOrCurrentUser($login); - $this->userManipulator->delete($user); + $this->userManipulator->delete($user, $grantedBaseIdList); } /** diff --git a/lib/Alchemy/Phrasea/Authentication/RegistrationService.php b/lib/Alchemy/Phrasea/Authentication/RegistrationService.php index 7ffdf8c489..2ffe87f0cd 100644 --- a/lib/Alchemy/Phrasea/Authentication/RegistrationService.php +++ b/lib/Alchemy/Phrasea/Authentication/RegistrationService.php @@ -328,11 +328,9 @@ class RegistrationService $autoReg = $acl->get_granted_base(); - $granted = []; foreach ($autoReg as $baseId => $collection) { $granted[$baseId] = $collection->get_label($this->app['locale']); - } - if(count($granted) > 0) { + $this->app['manipulator.webhook-event']->create( WebhookEvent::USER_REGISTRATION_GRANTED, WebhookEvent::USER_REGISTRATION_TYPE, @@ -340,8 +338,11 @@ class RegistrationService 'user_id' => $user->getId(), 'granted' => $granted, 'rejected' => [] - ] + ], + [$baseId] ); + + unset($granted); } diff --git a/lib/Alchemy/Phrasea/Controller/Admin/UserController.php b/lib/Alchemy/Phrasea/Controller/Admin/UserController.php index 35ff646b8c..a1487603d8 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/UserController.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/UserController.php @@ -515,9 +515,9 @@ class UserController extends Controller $denyColl[] = $label; $hookData['rejected'][$bas] = $label; } - } - $this->app['manipulator.webhook-event']->create($hookName, $hookType, $hookData); + $this->app['manipulator.webhook-event']->create($hookName, $hookType, $hookData, [$bas]); + } if ($user->hasMailNotificationsActivated() && (0 !== count($acceptColl) || 0 !== count($denyColl))) { $message = ''; diff --git a/lib/Alchemy/Phrasea/Controller/Root/AccountController.php b/lib/Alchemy/Phrasea/Controller/Root/AccountController.php index a6b305fe22..14117f0f01 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/AccountController.php +++ b/lib/Alchemy/Phrasea/Controller/Root/AccountController.php @@ -518,7 +518,9 @@ class AccountController extends Controller $this->getApiApplicationManipulator()->deleteApiApplications($applications); - // revoke access and delete phraseanet user account + // get list of old granted base_id then revoke access and delete phraseanet user account + + $oldGrantedBaseIds = array_keys($this->app->getAclForUser($user)->get_granted_base()); $list = array_keys($this->app['repo.collections-registry']->getBaseIdMap()); @@ -535,7 +537,7 @@ class AccountController extends Controller $mail = MailSuccessAccountDelete::create($this->app, $receiver); - $this->app['manipulator.user']->delete($user); + $this->app['manipulator.user']->delete($user, [$user->getId() => $oldGrantedBaseIds]); $this->deliver($mail); } diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/WebhookUserEventSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/WebhookUserEventSubscriber.php index a2f935bf89..74c1c6c23a 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/WebhookUserEventSubscriber.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/WebhookUserEventSubscriber.php @@ -45,7 +45,7 @@ class WebhookUserEventSubscriber implements EventSubscriberInterface 'user_id' => $event->getUserId(), 'email' => $event->getEmailAddress(), 'login' => $event->getLogin() - ]); + ], $event->getGrantedBaseIds()); } public static function getSubscribedEvents() diff --git a/lib/Alchemy/Phrasea/Core/Event/User/DeletedEvent.php b/lib/Alchemy/Phrasea/Core/Event/User/DeletedEvent.php index b67ba45b24..1528917245 100644 --- a/lib/Alchemy/Phrasea/Core/Event/User/DeletedEvent.php +++ b/lib/Alchemy/Phrasea/Core/Event/User/DeletedEvent.php @@ -36,4 +36,12 @@ class DeletedEvent extends UserEvent { return $this->args['email']; } + + /** + * @return array + */ + public function getGrantedBaseIds() + { + return $this->args['grantedBaseIds']; + } } diff --git a/lib/Alchemy/Phrasea/Core/Version.php b/lib/Alchemy/Phrasea/Core/Version.php index 0e15108724..eef6327696 100644 --- a/lib/Alchemy/Phrasea/Core/Version.php +++ b/lib/Alchemy/Phrasea/Core/Version.php @@ -16,7 +16,7 @@ class Version /** * @var string */ - private $number = '4.1.0-alpha.15a'; + private $number = '4.1.0-alpha.16a'; /** * @var string diff --git a/lib/Alchemy/Phrasea/Helper/User/Edit.php b/lib/Alchemy/Phrasea/Helper/User/Edit.php index 5c760a55de..f89ccbe383 100644 --- a/lib/Alchemy/Phrasea/Helper/User/Edit.php +++ b/lib/Alchemy/Phrasea/Helper/User/Edit.php @@ -73,10 +73,12 @@ class Edit extends \Alchemy\Phrasea\Helper\Helper { $list = array_keys($this->app->getAclForUser($this->app->getAuthenticatedUser())->get_granted_base([\ACL::CANADMIN])); + $oldGrantedBaseIds = array_keys($this->app->getAclForUser($user)->get_granted_base()); + $this->app->getAclForUser($user)->revoke_access_from_bases($list); if ($this->app->getAclForUser($user)->is_phantom()) { - $this->app['manipulator.user']->delete($user); + $this->app['manipulator.user']->delete($user, [$user->getId() => $oldGrantedBaseIds]); } return $this; diff --git a/lib/Alchemy/Phrasea/Model/Entities/WebhookEvent.php b/lib/Alchemy/Phrasea/Model/Entities/WebhookEvent.php index 275650f1b3..a1091f531f 100644 --- a/lib/Alchemy/Phrasea/Model/Entities/WebhookEvent.php +++ b/lib/Alchemy/Phrasea/Model/Entities/WebhookEvent.php @@ -68,6 +68,14 @@ class WebhookEvent */ private $created; + /** + * List of collection base_id concerned + * @var array + * + * @ORM\Column(name="collection_base_ids", type="json_array", nullable=true) + */ + private $collectionBaseIds; + /** * @param \DateTime $created * @@ -175,4 +183,24 @@ class WebhookEvent return $this; } + + /** + * @param array $collectionBaseIds + * + * @return $this + */ + public function setCollectionBaseIds(array $collectionBaseIds) + { + $this->collectionBaseIds = $collectionBaseIds; + + return $this; + } + + /** + * @return array + */ + public function getCollectionBaseIds() + { + return $this->collectionBaseIds; + } } diff --git a/lib/Alchemy/Phrasea/Model/Manipulator/UserManipulator.php b/lib/Alchemy/Phrasea/Model/Manipulator/UserManipulator.php index 8104c04c47..51bb1de9b6 100644 --- a/lib/Alchemy/Phrasea/Model/Manipulator/UserManipulator.php +++ b/lib/Alchemy/Phrasea/Model/Manipulator/UserManipulator.php @@ -126,8 +126,9 @@ class UserManipulator implements ManipulatorInterface * Deletes a user. * * @param User|User[] $users + * @param array $grantedBaseIdList List of the old granted base_id per userId [user_id => [base_id, ...] ] */ - public function delete($users) + public function delete($users, array $grantedBaseIdList = array()) { /** @var User $user */ foreach ($this->makeTraversable($users) as $user) { @@ -146,9 +147,10 @@ class UserManipulator implements ManipulatorInterface new DeletedEvent( null, array( - 'user_id'=>$old_id, - 'login'=>$old_login, - 'email'=>$old_email + 'user_id' => $old_id, + 'login' => $old_login, + 'email' => $old_email, + 'grantedBaseIds' => isset($grantedBaseIdList[$old_id]) ? $grantedBaseIdList[$old_id] : [] ) ) ); diff --git a/tests/Alchemy/Tests/Phrasea/Functional/UserDeletionTest.php b/tests/Alchemy/Tests/Phrasea/Functional/UserDeletionTest.php index 2db0eefa19..5ac42170c7 100644 --- a/tests/Alchemy/Tests/Phrasea/Functional/UserDeletionTest.php +++ b/tests/Alchemy/Tests/Phrasea/Functional/UserDeletionTest.php @@ -79,7 +79,7 @@ class UserDeletionTest extends \PhraseanetAuthenticatedWebTestCase $apiLog = $apiLogManipulator->create($account, new Request(), new Response()); $apiLogId = $apiLog->getId(); - $this->userManipulator->delete($this->user, true); + $this->userManipulator->delete($this->user); $this->assertTrue($this->user->isDeleted(), 'User was not properly deleted'); $apiLogRepository->clear(); From c2524e50dce52b805b390b3d735d868dbefb38de Mon Sep 17 00:00:00 2001 From: aynsix Date: Fri, 20 Sep 2019 18:04:05 +0400 Subject: [PATCH 06/28] feed webhook --- .../Core/Event/Subscriber/FeedEntrySubscriber.php | 3 ++- .../Model/Manipulator/WebhookEventManipulator.php | 6 +++++- .../Phrasea/Webhook/Processor/FeedEntryProcessor.php | 11 +++++------ .../Webhook/Processor/FeedEntryProcessorTest.php | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/FeedEntrySubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/FeedEntrySubscriber.php index 03a72a95b4..6a8b0cdaf4 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/FeedEntrySubscriber.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/FeedEntrySubscriber.php @@ -31,7 +31,8 @@ class FeedEntrySubscriber extends AbstractNotificationSubscriber $this->app['manipulator.webhook-event']->create( WebhookEvent::NEW_FEED_ENTRY, WebhookEvent::FEED_ENTRY_TYPE, - array_merge(array('feed_id' => $entry->getFeed()->getId()), $params) + array_merge(array('feed_id' => $entry->getFeed()->getId()), $params), + $entry->getFeed()->getBaseId() ? [$entry->getFeed()->getBaseId()] : [] ); $datas = json_encode($params); diff --git a/lib/Alchemy/Phrasea/Model/Manipulator/WebhookEventManipulator.php b/lib/Alchemy/Phrasea/Model/Manipulator/WebhookEventManipulator.php index 40e7f812a7..63cf52c3f5 100644 --- a/lib/Alchemy/Phrasea/Model/Manipulator/WebhookEventManipulator.php +++ b/lib/Alchemy/Phrasea/Model/Manipulator/WebhookEventManipulator.php @@ -40,7 +40,7 @@ class WebhookEventManipulator implements ManipulatorInterface $this->publisher = $publisher; } - public function create($eventName, $type, array $data) + public function create($eventName, $type, array $data, array $collectionBaseIds = array()) { $event = new WebhookEvent(); @@ -48,6 +48,10 @@ class WebhookEventManipulator implements ManipulatorInterface $event->setType($type); $event->setData($data); + if (count($collectionBaseIds) > 0) { + $event->setCollectionBaseIds($collectionBaseIds); + } + $this->update($event); $this->publisher->publishWebhookEvent($event); diff --git a/lib/Alchemy/Phrasea/Webhook/Processor/FeedEntryProcessor.php b/lib/Alchemy/Phrasea/Webhook/Processor/FeedEntryProcessor.php index 7fd4500c49..c873bbb680 100644 --- a/lib/Alchemy/Phrasea/Webhook/Processor/FeedEntryProcessor.php +++ b/lib/Alchemy/Phrasea/Webhook/Processor/FeedEntryProcessor.php @@ -34,17 +34,16 @@ class FeedEntryProcessor implements ProcessorInterface { $data = $event->getData(); - if (!isset($data->entry_id)) { + if (!isset($data['entry_id'])) { return null; } - $entry = $this->entryRepository->find($data->entry_id); + $entry = $this->entryRepository->find($data['entry_id']); if (null === $entry) { return null; } - $data = $event->getData(); $feed = $entry->getFeed(); $query = $this->userQuery; @@ -54,8 +53,8 @@ class FeedEntryProcessor implements ProcessorInterface ->include_templates(false) ->email_not_null(true); - if ($feed->getCollection($this->app)) { - $query->on_base_ids([$feed->getCollection($this->app)->get_base_id()]); + if ($feed->getCollection($this->application)) { + $query->on_base_ids([$feed->getCollection($this->application)->get_base_id()]); } $start = 0; @@ -76,7 +75,7 @@ class FeedEntryProcessor implements ProcessorInterface return [ 'event' => $event->getName(), - 'users_were_notified' => isset($data->notify_email) ?: (bool) $data->notify_email, + 'users_were_notified' => isset($data['notify_email']) ? (bool) $data['notify_email'] : false, 'feed' => [ 'id' => $feed->getId(), 'title' => $feed->getTitle(), diff --git a/tests/Alchemy/Tests/Phrasea/Webhook/Processor/FeedEntryProcessorTest.php b/tests/Alchemy/Tests/Phrasea/Webhook/Processor/FeedEntryProcessorTest.php index 60b518e443..39c3ae57d4 100644 --- a/tests/Alchemy/Tests/Phrasea/Webhook/Processor/FeedEntryProcessorTest.php +++ b/tests/Alchemy/Tests/Phrasea/Webhook/Processor/FeedEntryProcessorTest.php @@ -59,6 +59,6 @@ class FeedEntryProcessorTest extends \PhraseanetTestCase self::$DI['app']['repo.feed-entries'], self::$DI['app']['phraseanet.user-query'] ); - $this->assertEquals($processor->process($event), null); + $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $processor->process($event)); } } From 74e2724686a2348b8c923d1a268ca2eb840accb0 Mon Sep 17 00:00:00 2001 From: aynsix Date: Fri, 20 Sep 2019 18:06:13 +0400 Subject: [PATCH 07/28] order webhook --- .../Core/Event/Subscriber/OrderSubscriber.php | 22 ++++++++++++++---- .../Order/Controller/BaseOrderController.php | 6 +++-- lib/Alchemy/Phrasea/Order/OrderDelivery.php | 23 +++++++++++++++---- .../Phrasea/Order/ValidationNotifier.php | 9 +++++--- .../ValidationNotifier/CompositeNotifier.php | 13 +++++++---- .../Order/ValidationNotifier/MailNotifier.php | 9 +++++--- .../ValidationNotifier/WebhookNotifier.php | 15 +++++++----- 7 files changed, 70 insertions(+), 27 deletions(-) diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/OrderSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/OrderSubscriber.php index 142537f418..01f7e7b235 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/OrderSubscriber.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/OrderSubscriber.php @@ -41,13 +41,13 @@ class OrderSubscriber extends AbstractNotificationSubscriber public function onCreate(OrderEvent $event) { - $base_ids = array_unique(array_map(function (OrderElement $element) { + $baseIds = array_unique(array_map(function (OrderElement $element) { return $element->getBaseId(); }, iterator_to_array($event->getOrder()->getElements()))); $query = $this->app['phraseanet.user-query']; /** @var User[] $users */ - $users = $query->on_base_ids($base_ids) + $users = $query->on_base_ids($baseIds) ->who_have_right([\ACL::ORDER_MASTER]) ->execute()->get_results(); @@ -60,10 +60,12 @@ class OrderSubscriber extends AbstractNotificationSubscriber 'order_id' => $event->getOrder()->getId(), ]); - $notifier = $this->notifierRegistry->getNotifier($event->getOrder()->getNotificationMethod()); + // notify by webhook + $notifier = $this->notifierRegistry->getNotifier(Order::NOTIFY_WEBHOOK); - $notifier->notifyCreation($event->getOrder(), $event->getOrder()->getUser()); + $notifier->notifyCreation($event->getOrder(), $event->getOrder()->getUser(), $baseIds); + // notify by mail $notifier = $this->notifierRegistry->getNotifier(Order::NOTIFY_MAIL); foreach ($users as $user) { @@ -85,7 +87,13 @@ class OrderSubscriber extends AbstractNotificationSubscriber public function onDeliver(OrderDeliveryEvent $event) { + // notify by webhook + $notifier = $this->notifierRegistry->getNotifier(Order::NOTIFY_WEBHOOK); + $notifier->notifyDelivery($event->getDelivery(), $event->getDelivery()->getPartialOrder()->getBaseIds()); + $notified = false; + + // actually NotificationMethod is always by mail $notifier = $this->notifierRegistry->getNotifier($event->getOrder()->getNotificationMethod()); $notificationData = json_encode([ 'from' => $event->getDelivery()->getAdmin()->getId(), @@ -109,7 +117,13 @@ class OrderSubscriber extends AbstractNotificationSubscriber public function onDeny(OrderDeliveryEvent $event) { + // notify by webhook + $notifier = $this->notifierRegistry->getNotifier(Order::NOTIFY_WEBHOOK); + $notifier->notifyDenial($event->getDelivery(), $event->getDelivery()->getPartialOrder()->getBaseIds()); + $notified = false; + + // actually NotificationMethod is always by mail $notifier = $this->notifierRegistry->getNotifier($event->getOrder()->getNotificationMethod()); $notificationData = json_encode([ 'from' => $event->getDelivery()->getAdmin()->getId(), diff --git a/lib/Alchemy/Phrasea/Order/Controller/BaseOrderController.php b/lib/Alchemy/Phrasea/Order/Controller/BaseOrderController.php index 5b2e90d4cb..cf3c84e981 100644 --- a/lib/Alchemy/Phrasea/Order/Controller/BaseOrderController.php +++ b/lib/Alchemy/Phrasea/Order/Controller/BaseOrderController.php @@ -172,7 +172,7 @@ class BaseOrderController extends Controller $manager->persist($element); } - $delivery = new OrderDelivery($order, $acceptor, count($basketElements)); + $delivery = new OrderDelivery($order, $acceptor, count($basketElements), $partialOrder); $this->dispatch(PhraseaEvents::ORDER_DELIVER, new OrderDeliveryEvent($delivery)); } @@ -198,11 +198,13 @@ class BaseOrderController extends Controller $elements = $this->findRequestedElements($order_id, $elementIds, $acceptor); $order = $this->findOr404($order_id); + $partialOrder = new PartialOrder($order, $elements); + $this->getOrderValidator()->deny($acceptor, new PartialOrder($order, $elements)); try { if (!empty($elements)) { - $delivery = new OrderDelivery($order, $acceptor, count($elements)); + $delivery = new OrderDelivery($order, $acceptor, count($elements), $partialOrder); $this->dispatch(PhraseaEvents::ORDER_DENY, new OrderDeliveryEvent($delivery)); } diff --git a/lib/Alchemy/Phrasea/Order/OrderDelivery.php b/lib/Alchemy/Phrasea/Order/OrderDelivery.php index 5d8f3313ff..f36a98525f 100644 --- a/lib/Alchemy/Phrasea/Order/OrderDelivery.php +++ b/lib/Alchemy/Phrasea/Order/OrderDelivery.php @@ -31,16 +31,23 @@ class OrderDelivery */ private $quantity; + /** + * @var PartialOrder + */ + private $partialOrder; + /** * @param Order $deliveredOrder * @param User $manager * @param int $quantity + * @param PartialOrder $partialOrder */ - public function __construct(Order $deliveredOrder, User $manager, $quantity) + public function __construct(Order $deliveredOrder, User $manager, $quantity, PartialOrder $partialOrder) { - $this->order = $deliveredOrder; - $this->admin = $manager; - $this->quantity = $quantity; + $this->order = $deliveredOrder; + $this->admin = $manager; + $this->quantity = $quantity; + $this->partialOrder = $partialOrder; } /** @@ -66,4 +73,12 @@ class OrderDelivery { return $this->quantity; } + + /** + * @return PartialOrder + */ + public function getPartialOrder() + { + return $this->partialOrder; + } } diff --git a/lib/Alchemy/Phrasea/Order/ValidationNotifier.php b/lib/Alchemy/Phrasea/Order/ValidationNotifier.php index e79b9ef888..419f180520 100644 --- a/lib/Alchemy/Phrasea/Order/ValidationNotifier.php +++ b/lib/Alchemy/Phrasea/Order/ValidationNotifier.php @@ -19,20 +19,23 @@ interface ValidationNotifier /** * @param Order $order * @param User $recipient + * @param array $baseIds * @return void */ - public function notifyCreation(Order $order, User $recipient); + public function notifyCreation(Order $order, User $recipient, array $baseIds = array()); /** * @param OrderDelivery $delivery + * @param array $baseIds * @return void */ - public function notifyDelivery(OrderDelivery $delivery); + public function notifyDelivery(OrderDelivery $delivery, array $baseIds = array()); /** * @param OrderDelivery $delivery + * @param array $baseIds * @return void */ - public function notifyDenial(OrderDelivery $delivery); + public function notifyDenial(OrderDelivery $delivery, array $baseIds = array()); } diff --git a/lib/Alchemy/Phrasea/Order/ValidationNotifier/CompositeNotifier.php b/lib/Alchemy/Phrasea/Order/ValidationNotifier/CompositeNotifier.php index a3e75cebcb..b38d51a3ca 100644 --- a/lib/Alchemy/Phrasea/Order/ValidationNotifier/CompositeNotifier.php +++ b/lib/Alchemy/Phrasea/Order/ValidationNotifier/CompositeNotifier.php @@ -26,8 +26,9 @@ class CompositeNotifier implements ValidationNotifier /** * @param Order $order * @param User $recipient + * @param array $baseIds */ - public function notifyCreation(Order $order, User $recipient) + public function notifyCreation(Order $order, User $recipient, array $baseIds = array()) { foreach ($this->notifiers as $notifier) { $notifier->notifyCreation($order, $recipient); @@ -36,21 +37,23 @@ class CompositeNotifier implements ValidationNotifier /** * @param OrderDelivery $delivery + * @param array $baseIds */ - public function notifyDelivery(OrderDelivery $delivery) + public function notifyDelivery(OrderDelivery $delivery, array $baseIds = array()) { foreach ($this->notifiers as $notifier) { - $notifier->notifyDelivery($delivery); + $notifier->notifyDelivery($delivery, $baseIds); } } /** * @param OrderDelivery $delivery + * @param array $baseIds */ - public function notifyDenial(OrderDelivery $delivery) + public function notifyDenial(OrderDelivery $delivery, array $baseIds = array()) { foreach ($this->notifiers as $notifier) { - $notifier->notifyDenial($delivery); + $notifier->notifyDenial($delivery, $baseIds); } } } diff --git a/lib/Alchemy/Phrasea/Order/ValidationNotifier/MailNotifier.php b/lib/Alchemy/Phrasea/Order/ValidationNotifier/MailNotifier.php index 8a6541793a..9934fafb08 100644 --- a/lib/Alchemy/Phrasea/Order/ValidationNotifier/MailNotifier.php +++ b/lib/Alchemy/Phrasea/Order/ValidationNotifier/MailNotifier.php @@ -46,8 +46,9 @@ class MailNotifier implements ValidationNotifier /** * @param Order $order * @param User $recipient + * @param array $baseIds */ - public function notifyCreation(Order $order, User $recipient) + public function notifyCreation(Order $order, User $recipient, array $baseIds = array()) { $mail = MailInfoNewOrder::create($this->application, Receiver::fromUser($recipient)); @@ -58,8 +59,9 @@ class MailNotifier implements ValidationNotifier /** * @param OrderDelivery $delivery + * @param array $baseIds */ - public function notifyDelivery(OrderDelivery $delivery) + public function notifyDelivery(OrderDelivery $delivery, array $baseIds = array()) { $order = $delivery->getOrder(); @@ -85,8 +87,9 @@ class MailNotifier implements ValidationNotifier /** * @param OrderDelivery $delivery + * @param array $baseIds */ - public function notifyDenial(OrderDelivery $delivery) + public function notifyDenial(OrderDelivery $delivery, array $baseIds = array()) { $sender = Emitter::fromUser($delivery->getAdmin()); $recipient = Receiver::fromUser($delivery->getOrder()->getUser()); diff --git a/lib/Alchemy/Phrasea/Order/ValidationNotifier/WebhookNotifier.php b/lib/Alchemy/Phrasea/Order/ValidationNotifier/WebhookNotifier.php index 3634e8e907..4762ff43ec 100644 --- a/lib/Alchemy/Phrasea/Order/ValidationNotifier/WebhookNotifier.php +++ b/lib/Alchemy/Phrasea/Order/ValidationNotifier/WebhookNotifier.php @@ -47,21 +47,23 @@ class WebhookNotifier implements ValidationNotifier /** * @param Order $order * @param User $recipient + * @param array $baseIds */ - public function notifyCreation(Order $order, User $recipient) + public function notifyCreation(Order $order, User $recipient, array $baseIds = array()) { $eventData = [ 'order_id' => $order->getId(), 'user_id' => $recipient->getId(), ]; - $this->getManipulator()->create(WebhookEvent::ORDER_CREATED, WebhookEvent::ORDER_TYPE, $eventData); + $this->getManipulator()->create(WebhookEvent::ORDER_CREATED, WebhookEvent::ORDER_TYPE, $eventData, $baseIds); } /** * @param OrderDelivery $delivery + * @param array $baseIds */ - public function notifyDelivery(OrderDelivery $delivery) + public function notifyDelivery(OrderDelivery $delivery, array $baseIds = array()) { $eventData = [ 'order_id' => $delivery->getOrder()->getId(), @@ -69,13 +71,14 @@ class WebhookNotifier implements ValidationNotifier 'quantity' => $delivery->getQuantity() ]; - $this->getManipulator()->create(WebhookEvent::ORDER_DELIVERED, WebhookEvent::ORDER_TYPE, $eventData); + $this->getManipulator()->create(WebhookEvent::ORDER_DELIVERED, WebhookEvent::ORDER_TYPE, $eventData, $baseIds); } /** * @param OrderDelivery $delivery + * @param array $baseIds */ - public function notifyDenial(OrderDelivery $delivery) + public function notifyDenial(OrderDelivery $delivery, array $baseIds = array()) { $eventData = [ 'order_id' => $delivery->getOrder()->getId(), @@ -83,6 +86,6 @@ class WebhookNotifier implements ValidationNotifier 'quantity' => $delivery->getQuantity() ]; - $this->getManipulator()->create(WebhookEvent::ORDER_DENIED, WebhookEvent::ORDER_TYPE, $eventData); + $this->getManipulator()->create(WebhookEvent::ORDER_DENIED, WebhookEvent::ORDER_TYPE, $eventData, $baseIds); } } From e6fe8f98b68056c8e34d6d83331da1a242845a57 Mon Sep 17 00:00:00 2001 From: aynsix Date: Tue, 24 Sep 2019 11:28:31 +0400 Subject: [PATCH 08/28] change event name --- lib/Alchemy/Phrasea/Border/Manager.php | 4 ++-- .../Phrasea/Controller/Prod/StoryController.php | 4 ++-- .../Phrasea/Controller/Prod/ToolsController.php | 4 ++-- .../Phrasea/Core/Event/Record/RecordEvents.php | 2 +- ...BuildEvent.php => SubdefinitionCreateEvent.php} | 2 +- .../Core/Event/Subscriber/RecordEditSubscriber.php | 14 +++++++------- lib/Alchemy/Phrasea/Media/SubdefSubstituer.php | 4 ++-- lib/Alchemy/Phrasea/TaskManager/Job/ArchiveJob.php | 4 ++-- lib/classes/record/adapter.php | 6 +++--- 9 files changed, 22 insertions(+), 22 deletions(-) rename lib/Alchemy/Phrasea/Core/Event/Record/{SubdefinitionBuildEvent.php => SubdefinitionCreateEvent.php} (92%) diff --git a/lib/Alchemy/Phrasea/Border/Manager.php b/lib/Alchemy/Phrasea/Border/Manager.php index 55c28d9cbf..d017d206e6 100644 --- a/lib/Alchemy/Phrasea/Border/Manager.php +++ b/lib/Alchemy/Phrasea/Border/Manager.php @@ -15,7 +15,7 @@ use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Border\Checker\CheckerInterface; use Alchemy\Phrasea\Border\Attribute\AttributeInterface; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; -use Alchemy\Phrasea\Core\Event\Record\SubdefinitionBuildEvent; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent; use Alchemy\Phrasea\Exception\RuntimeException; use Alchemy\Phrasea\Metadata\Tag\TfArchivedate; use Alchemy\Phrasea\Metadata\Tag\TfQuarantine; @@ -335,7 +335,7 @@ class Manager $this->app['phraseanet.metadata-setter']->replaceMetadata($newMetadata, $element); if(!$nosubdef) { - $this->app['dispatcher']->dispatch(RecordEvents::SUBDEFINITION_BUILD, new SubdefinitionBuildEvent($element, true)); + $this->app['dispatcher']->dispatch(RecordEvents::SUBDEFINITION_CREATE, new SubdefinitionCreateEvent($element, true)); } return $element; diff --git a/lib/Alchemy/Phrasea/Controller/Prod/StoryController.php b/lib/Alchemy/Phrasea/Controller/Prod/StoryController.php index 19acc22a27..a90f0a0ed1 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/StoryController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/StoryController.php @@ -15,7 +15,7 @@ use Alchemy\Phrasea\Controller\Controller; use Alchemy\Phrasea\Controller\RecordsRequest; use Alchemy\Phrasea\Controller\Exception as ControllerException; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; -use Alchemy\Phrasea\Core\Event\Record\SubdefinitionBuildEvent; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent; use Alchemy\Phrasea\Core\Event\RecordEdit; use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Model\Entities\StoryWZ; @@ -72,7 +72,7 @@ class StoryController extends Controller $recordAdapter = $story->set_metadatas($metadatas); // tell phraseanet to rebuild subdef - $this->dispatch(RecordEvents::SUBDEFINITION_BUILD, new SubdefinitionBuildEvent($recordAdapter)); + $this->dispatch(RecordEvents::SUBDEFINITION_CREATE, new SubdefinitionCreateEvent($recordAdapter)); $storyWZ = new StoryWZ(); $storyWZ->setUser($this->getAuthenticatedUser()); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php b/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php index 2318cf0638..65f72a8a36 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php @@ -16,7 +16,7 @@ use Alchemy\Phrasea\Application\Helper\SubDefinitionSubstituerAware; use Alchemy\Phrasea\Controller\Controller; use Alchemy\Phrasea\Controller\RecordsRequest; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; -use Alchemy\Phrasea\Core\Event\Record\SubdefinitionBuildEvent; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent; use Alchemy\Phrasea\Exception\RuntimeException; use Alchemy\Phrasea\Metadata\PhraseanetMetadataReader; use Alchemy\Phrasea\Metadata\PhraseanetMetadataSetter; @@ -157,7 +157,7 @@ class ToolsController extends Controller } if (!$substituted || $force) { - $this->dispatch(RecordEvents::SUBDEFINITION_BUILD, new SubdefinitionBuildEvent($record)); + $this->dispatch(RecordEvents::SUBDEFINITION_CREATE, new SubdefinitionCreateEvent($record)); } } diff --git a/lib/Alchemy/Phrasea/Core/Event/Record/RecordEvents.php b/lib/Alchemy/Phrasea/Core/Event/Record/RecordEvents.php index ac725833ac..e68f4afa84 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Record/RecordEvents.php +++ b/lib/Alchemy/Phrasea/Core/Event/Record/RecordEvents.php @@ -29,7 +29,7 @@ final class RecordEvents const SUB_DEFINITIONS_CREATED = 'record.sub_definitions_created'; const SUB_DEFINITION_CREATION_FAILED = 'record.sub_definition_creation_failed'; - const SUBDEFINITION_BUILD = 'record.subdefinition_build'; + const SUBDEFINITION_CREATE = 'record.subdefinition_create'; const MEDIA_SUBSTITUTED = 'record.media_substituted'; diff --git a/lib/Alchemy/Phrasea/Core/Event/Record/SubdefinitionBuildEvent.php b/lib/Alchemy/Phrasea/Core/Event/Record/SubdefinitionCreateEvent.php similarity index 92% rename from lib/Alchemy/Phrasea/Core/Event/Record/SubdefinitionBuildEvent.php rename to lib/Alchemy/Phrasea/Core/Event/Record/SubdefinitionCreateEvent.php index 701e3a2028..cbb36f4184 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Record/SubdefinitionBuildEvent.php +++ b/lib/Alchemy/Phrasea/Core/Event/Record/SubdefinitionCreateEvent.php @@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\Core\Event\Record; use Alchemy\Phrasea\Model\RecordInterface; -class SubdefinitionBuildEvent extends RecordEvent +class SubdefinitionCreateEvent extends RecordEvent { private $isNewRecord; diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php index e58e77cdf7..6c971002e5 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php @@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\Core\Event\Subscriber; use Alchemy\Phrasea\Core\Event\Record\CollectionChangedEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; -use Alchemy\Phrasea\Core\Event\Record\SubdefinitionBuildEvent; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent; use Alchemy\Phrasea\Core\Event\RecordEdit; use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Metadata\Tag\TfEditdate; @@ -27,11 +27,11 @@ class RecordEditSubscriber implements EventSubscriberInterface public static function getSubscribedEvents() { return array( - PhraseaEvents::RECORD_EDIT => 'onEdit', - PhraseaEvents::RECORD_UPLOAD => 'onEdit', - RecordEvents::ROTATE => 'onRecordChange', - RecordEvents::COLLECTION_CHANGED => 'onCollectionChanged', - RecordEvents::SUBDEFINITION_BUILD => 'onBuildSubdefs', + PhraseaEvents::RECORD_EDIT => 'onEdit', + PhraseaEvents::RECORD_UPLOAD => 'onEdit', + RecordEvents::ROTATE => 'onRecordChange', + RecordEvents::COLLECTION_CHANGED => 'onCollectionChanged', + RecordEvents::SUBDEFINITION_CREATE => 'onSubdefinitionCreate', ); } @@ -51,7 +51,7 @@ class RecordEditSubscriber implements EventSubscriberInterface $recordAdapter->clearStampCache(); } - public function onBuildSubdefs(SubdefinitionBuildEvent $event) + public function onSubdefinitionCreate(SubdefinitionCreateEvent $event) { $recordAdapter = $this->convertToRecordAdapter($event->getRecord()); $recordAdapter->rebuild_subdefs(); diff --git a/lib/Alchemy/Phrasea/Media/SubdefSubstituer.php b/lib/Alchemy/Phrasea/Media/SubdefSubstituer.php index 1d096cf785..8f7aa61e90 100644 --- a/lib/Alchemy/Phrasea/Media/SubdefSubstituer.php +++ b/lib/Alchemy/Phrasea/Media/SubdefSubstituer.php @@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\Media; use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Core\Event\Record\MediaSubstitutedEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; -use Alchemy\Phrasea\Core\Event\Record\SubdefinitionBuildEvent; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent; use Alchemy\Phrasea\Filesystem\FilesystemService; use MediaAlchemyst\Alchemyst; use MediaAlchemyst\Exception\ExceptionInterface as MediaAlchemystException; @@ -80,7 +80,7 @@ class SubdefSubstituer $record->write_metas(); if ($shouldSubdefsBeRebuilt) { - $this->dispatcher->dispatch(RecordEvents::SUBDEFINITION_BUILD, new SubdefinitionBuildEvent($record)); + $this->dispatcher->dispatch(RecordEvents::SUBDEFINITION_CREATE, new SubdefinitionCreateEvent($record)); } $this->dispatcher->dispatch(RecordEvents::MEDIA_SUBSTITUTED, new MediaSubstitutedEvent($record)); diff --git a/lib/Alchemy/Phrasea/TaskManager/Job/ArchiveJob.php b/lib/Alchemy/Phrasea/TaskManager/Job/ArchiveJob.php index db1f6b083a..de418a4e71 100644 --- a/lib/Alchemy/Phrasea/TaskManager/Job/ArchiveJob.php +++ b/lib/Alchemy/Phrasea/TaskManager/Job/ArchiveJob.php @@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\TaskManager\Job; use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; -use Alchemy\Phrasea\Core\Event\Record\SubdefinitionBuildEvent; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent; use Alchemy\Phrasea\Exception\RuntimeException; use Alchemy\Phrasea\Border\File; use Alchemy\Phrasea\Border\Manager as borderManager; @@ -1035,7 +1035,7 @@ class ArchiveJob extends AbstractJob $story->setStatus(\databox_status::operation_or($stat0, $stat1)); - $app['dispatcher']->dispatch(RecordEvents::SUBDEFINITION_BUILD, new SubdefinitionBuildEvent($story)); + $app['dispatcher']->dispatch(RecordEvents::SUBDEFINITION_CREATE, new SubdefinitionCreateEvent($story)); unset($media); diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php index 9d7beb2c1a..7c91e2e135 100644 --- a/lib/classes/record/adapter.php +++ b/lib/classes/record/adapter.php @@ -19,7 +19,7 @@ use Alchemy\Phrasea\Core\Event\Record\OriginalNameChangedEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; use Alchemy\Phrasea\Core\Event\Record\StatusChangedEvent; -use Alchemy\Phrasea\Core\Event\Record\SubdefinitionBuildEvent; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent; use Alchemy\Phrasea\Core\PhraseaTokens; use Alchemy\Phrasea\Databox\Subdef\MediaSubdefRepository; use Alchemy\Phrasea\Filesystem\FilesystemService; @@ -285,7 +285,7 @@ class record_adapter implements RecordInterface, cache_cacheableInterface $this->getDataboxConnection()->executeUpdate($sql, ['type' => $type, 'record_id' => $this->getRecordId()]); if ($old_type !== $type) { - $this->dispatch(RecordEvents::SUBDEFINITION_BUILD, new SubdefinitionBuildEvent($this)); + $this->dispatch(RecordEvents::SUBDEFINITION_CREATE, new SubdefinitionCreateEvent($this)); } $this->type = $type; @@ -342,7 +342,7 @@ class record_adapter implements RecordInterface, cache_cacheableInterface array(':mime' => $mime, ':record_id' => $this->getRecordId()) )) { - $this->dispatch(RecordEvents::SUBDEFINITION_BUILD, new SubdefinitionBuildEvent($this)); + $this->dispatch(RecordEvents::SUBDEFINITION_CREATE, new SubdefinitionCreateEvent($this)); $this->delete_data_from_cache(); } From 4cac08c48fddd2251c915e3f76cd3aa38d18e324 Mon Sep 17 00:00:00 2001 From: aynsix Date: Wed, 25 Sep 2019 11:29:07 +0400 Subject: [PATCH 09/28] ask to write metadata only if record has subdefs --- lib/classes/record/adapter.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php index 7c91e2e135..8475ff1d9c 100644 --- a/lib/classes/record/adapter.php +++ b/lib/classes/record/adapter.php @@ -1107,8 +1107,11 @@ class record_adapter implements RecordInterface, cache_cacheableInterface $this->set_xml($xml); unset($xml); - $this->write_metas(); - $this->dispatch(RecordEvents::METADATA_CHANGED, new MetadataChangedEvent($this)); + // if there is yet subdefs, ask to write metadata + if (count($this->getMediaSubdefRepository()->findByRecordIdsAndNames([$this->getRecordId()])) > 1 ) { + $this->write_metas(); + $this->dispatch(RecordEvents::METADATA_CHANGED, new MetadataChangedEvent($this)); + } return $this; } From e50b60306c3cd5dec7feff20a9083d5778e7a7f4 Mon Sep 17 00:00:00 2001 From: aynsix Date: Wed, 25 Sep 2019 14:45:48 +0400 Subject: [PATCH 10/28] revert: 4cac08c48fddd2 do not use this approach --- lib/classes/record/adapter.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php index 8475ff1d9c..7c91e2e135 100644 --- a/lib/classes/record/adapter.php +++ b/lib/classes/record/adapter.php @@ -1107,11 +1107,8 @@ class record_adapter implements RecordInterface, cache_cacheableInterface $this->set_xml($xml); unset($xml); - // if there is yet subdefs, ask to write metadata - if (count($this->getMediaSubdefRepository()->findByRecordIdsAndNames([$this->getRecordId()])) > 1 ) { - $this->write_metas(); - $this->dispatch(RecordEvents::METADATA_CHANGED, new MetadataChangedEvent($this)); - } + $this->write_metas(); + $this->dispatch(RecordEvents::METADATA_CHANGED, new MetadataChangedEvent($this)); return $this; } From 194b0b0f5ce9473934a9c54c352002589030caa0 Mon Sep 17 00:00:00 2001 From: aynsix Date: Thu, 26 Sep 2019 15:04:08 +0400 Subject: [PATCH 11/28] incorporate subdefWebhook into phraseanet --- lib/Alchemy/Phrasea/Application.php | 2 + .../WebhookSubdefEventSubscriber.php | 78 +++++++++++++++++++ .../Phrasea/Webhook/EventProcessorFactory.php | 8 +- .../Processor/SubdefEventProcessor.php | 17 ++++ 4 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Core/Event/Subscriber/WebhookSubdefEventSubscriber.php create mode 100644 lib/Alchemy/Phrasea/Webhook/Processor/SubdefEventProcessor.php diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php index 13c7728f86..08b96eb888 100644 --- a/lib/Alchemy/Phrasea/Application.php +++ b/lib/Alchemy/Phrasea/Application.php @@ -88,6 +88,7 @@ use Alchemy\Phrasea\Media\PermalinkMediaResolver; use Alchemy\Phrasea\Media\TechnicalDataServiceProvider; use Alchemy\Phrasea\Model\Entities\User; use Alchemy\QueueProvider\QueueServiceProvider; +use Alchemy\Phrasea\Core\Event\Subscriber\WebhookSubdefEventSubscriber; use Alchemy\WorkerProvider\WorkerServiceProvider; use Doctrine\DBAL\Event\ConnectionEventArgs; use MediaVorus\Media\MediaInterface; @@ -742,6 +743,7 @@ class Application extends SilexApplication $dispatcher->addSubscriber(new LazaretSubscriber($app)); $dispatcher->addSubscriber(new ValidationSubscriber($app)); $dispatcher->addSubscriber(new WebhookUserEventSubscriber($app)); + $dispatcher->addSubscriber(new WebhookSubdefEventSubscriber($app['manipulator.webhook-event'])); return $dispatcher; }) diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/WebhookSubdefEventSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/WebhookSubdefEventSubscriber.php new file mode 100644 index 0000000000..d3c06cdd72 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/WebhookSubdefEventSubscriber.php @@ -0,0 +1,78 @@ +webhookManipulator = $manipulator; + } + + public function onSubdefCreated(SubDefinitionCreatedEvent $event) + { + $eventData = [ + 'databox_id' => $event->getRecord()->getDataboxId(), + 'record_id' => $event->getRecord()->getRecordId(), + 'subdef' => $event->getSubDefinitionName() + ]; + + $this->webhookManipulator->create( + WebhookEvent::RECORD_SUBDEF_CREATED, + WebhookEvent::RECORD_SUBDEF_TYPE, + $eventData + ); + } + + public function onSubdefCreationFailed(SubDefinitionCreationFailedEvent $event) + { + $eventData = [ + 'databox_id' => $event->getRecord()->getDataboxId(), + 'record_id' => $event->getRecord()->getRecordId(), + 'subdef' => $event->getSubDefinitionName() + ]; + + $this->webhookManipulator->create( + WebhookEvent::RECORD_SUBDEF_FAILED, + WebhookEvent::RECORD_SUBDEF_TYPE, + $eventData + ); + } + + public function onSubdefsCreated(SubDefinitionsCreatedEvent $event) + { + $eventData = [ + 'databox_id' => $event->getRecord()->getDataboxId(), + 'record_id' => $event->getRecord()->getRecordId(), + 'subdef_count' => count($event->getMedia()) + ]; + + $this->webhookManipulator->create( + WebhookEvent::RECORD_SUBDEFS_CREATED, + WebhookEvent::RECORD_SUBDEF_TYPE, + $eventData + ); + } + + public static function getSubscribedEvents() + { + return [ + RecordEvents::SUB_DEFINITION_CREATED => 'onSubdefCreated', + RecordEvents::SUB_DEFINITIONS_CREATED => 'onSubdefsCreated', + RecordEvents::SUB_DEFINITION_CREATION_FAILED => 'onSubdefCreationFailed' + ]; + } +} diff --git a/lib/Alchemy/Phrasea/Webhook/EventProcessorFactory.php b/lib/Alchemy/Phrasea/Webhook/EventProcessorFactory.php index 90edefc10c..79109a624c 100644 --- a/lib/Alchemy/Phrasea/Webhook/EventProcessorFactory.php +++ b/lib/Alchemy/Phrasea/Webhook/EventProcessorFactory.php @@ -12,6 +12,7 @@ use Alchemy\Phrasea\Webhook\Processor\ProcessorFactory; use Alchemy\Phrasea\Webhook\Processor\ProcessorInterface; use Alchemy\Phrasea\Webhook\Processor\UserDeletedProcessorFactory; use Alchemy\Phrasea\Webhook\Processor\UserRegistrationProcessorFactory; +use Alchemy\Phrasea\Webhook\Processor\SubdefEventProcessor; class EventProcessorFactory { @@ -29,7 +30,10 @@ class EventProcessorFactory $this->registerFactory(WebhookEvent::FEED_ENTRY_TYPE, new FeedEntryProcessorFactory($app)); $this->registerFactory(WebhookEvent::USER_REGISTRATION_TYPE, new UserRegistrationProcessorFactory($app)); $this->registerFactory(WebhookEvent::ORDER_TYPE, new OrderNotificationProcessorFactory($app)); - $this->registerFactory(WebhookEvent::USER_DELETED_TYPE, new UserDeletedProcessorFactory($app)); + $this->registerFactory(WebhookEvent::USER_DELETED_TYPE, new UserDeletedProcessorFactory()); + $this->registerCallableFactory(WebhookEvent::RECORD_SUBDEF_TYPE, function () { + return new SubdefEventProcessor(); + }); } /** @@ -43,7 +47,7 @@ class EventProcessorFactory /** * @param string $eventType - * @param callback|callable $callable + * @param callback|callable|\Closure $callable */ public function registerCallableFactory($eventType, $callable) { diff --git a/lib/Alchemy/Phrasea/Webhook/Processor/SubdefEventProcessor.php b/lib/Alchemy/Phrasea/Webhook/Processor/SubdefEventProcessor.php new file mode 100644 index 0000000000..4a442ed5db --- /dev/null +++ b/lib/Alchemy/Phrasea/Webhook/Processor/SubdefEventProcessor.php @@ -0,0 +1,17 @@ + $event->getName(), + 'data' => $event->getData() + ]; + } +} From 5fc4d85aef4383d343ff7b05f2193496e38eb156 Mon Sep 17 00:00:00 2001 From: aynsix Date: Thu, 26 Sep 2019 15:30:59 +0400 Subject: [PATCH 12/28] fix --- lib/Alchemy/Phrasea/Application.php | 2 -- .../Phrasea/Core/Provider/WebhookServiceProvider.php | 10 +++++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php index 08b96eb888..13c7728f86 100644 --- a/lib/Alchemy/Phrasea/Application.php +++ b/lib/Alchemy/Phrasea/Application.php @@ -88,7 +88,6 @@ use Alchemy\Phrasea\Media\PermalinkMediaResolver; use Alchemy\Phrasea\Media\TechnicalDataServiceProvider; use Alchemy\Phrasea\Model\Entities\User; use Alchemy\QueueProvider\QueueServiceProvider; -use Alchemy\Phrasea\Core\Event\Subscriber\WebhookSubdefEventSubscriber; use Alchemy\WorkerProvider\WorkerServiceProvider; use Doctrine\DBAL\Event\ConnectionEventArgs; use MediaVorus\Media\MediaInterface; @@ -743,7 +742,6 @@ class Application extends SilexApplication $dispatcher->addSubscriber(new LazaretSubscriber($app)); $dispatcher->addSubscriber(new ValidationSubscriber($app)); $dispatcher->addSubscriber(new WebhookUserEventSubscriber($app)); - $dispatcher->addSubscriber(new WebhookSubdefEventSubscriber($app['manipulator.webhook-event'])); return $dispatcher; }) diff --git a/lib/Alchemy/Phrasea/Core/Provider/WebhookServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/WebhookServiceProvider.php index 4b280c92f0..968ec607e1 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/WebhookServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/WebhookServiceProvider.php @@ -2,6 +2,7 @@ namespace Alchemy\Phrasea\Core\Provider; +use Alchemy\Phrasea\Core\Event\Subscriber\WebhookSubdefEventSubscriber; use Alchemy\Phrasea\Webhook\EventProcessorFactory; use Alchemy\Phrasea\Webhook\EventProcessorWorker; use Alchemy\Phrasea\Webhook\WebhookInvoker; @@ -10,6 +11,7 @@ use Alchemy\Worker\CallableWorkerFactory; use Alchemy\Worker\TypeBasedWorkerResolver; use Silex\Application; use Silex\ServiceProviderInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; class WebhookServiceProvider implements ServiceProviderInterface { @@ -69,6 +71,12 @@ class WebhookServiceProvider implements ServiceProviderInterface public function boot(Application $app) { - // no-op + $app['dispatcher'] = $app->share( + $app->extend('dispatcher', function (EventDispatcherInterface $dispatcher) use ($app) { + $dispatcher->addSubscriber(new WebhookSubdefEventSubscriber($app['manipulator.webhook-event'])); + + return $dispatcher; + }) + ); } } From 56c44a1b3f7735a3e9539024d1dd4c4d2d581aea Mon Sep 17 00:00:00 2001 From: aynsix Date: Thu, 26 Sep 2019 18:05:03 +0400 Subject: [PATCH 13/28] fix --- .../Subscriber/WebhookSubdefEventSubscriber.php | 17 +++++++---------- .../Core/Provider/WebhookServiceProvider.php | 16 +++++++++------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/WebhookSubdefEventSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/WebhookSubdefEventSubscriber.php index d3c06cdd72..ca5d88b2ab 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/WebhookSubdefEventSubscriber.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/WebhookSubdefEventSubscriber.php @@ -7,19 +7,16 @@ use Alchemy\Phrasea\Core\Event\Record\SubDefinitionCreatedEvent; use Alchemy\Phrasea\Core\Event\Record\SubDefinitionCreationFailedEvent; use Alchemy\Phrasea\Core\Event\Record\SubDefinitionsCreatedEvent; use Alchemy\Phrasea\Model\Entities\WebhookEvent; -use Alchemy\Phrasea\Model\Manipulator\WebhookEventManipulator; +use Silex\Application; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class WebhookSubdefEventSubscriber implements EventSubscriberInterface { - /** - * @var WebhookEventManipulator - */ - private $webhookManipulator; + private $app; - public function __construct(WebhookEventManipulator $manipulator) + public function __construct(Application $app) { - $this->webhookManipulator = $manipulator; + $this->app = $app; } public function onSubdefCreated(SubDefinitionCreatedEvent $event) @@ -30,7 +27,7 @@ class WebhookSubdefEventSubscriber implements EventSubscriberInterface 'subdef' => $event->getSubDefinitionName() ]; - $this->webhookManipulator->create( + $this->app['manipulator.webhook-event']->create( WebhookEvent::RECORD_SUBDEF_CREATED, WebhookEvent::RECORD_SUBDEF_TYPE, $eventData @@ -45,7 +42,7 @@ class WebhookSubdefEventSubscriber implements EventSubscriberInterface 'subdef' => $event->getSubDefinitionName() ]; - $this->webhookManipulator->create( + $this->app['manipulator.webhook-event']->create( WebhookEvent::RECORD_SUBDEF_FAILED, WebhookEvent::RECORD_SUBDEF_TYPE, $eventData @@ -60,7 +57,7 @@ class WebhookSubdefEventSubscriber implements EventSubscriberInterface 'subdef_count' => count($event->getMedia()) ]; - $this->webhookManipulator->create( + $this->app['manipulator.webhook-event']->create( WebhookEvent::RECORD_SUBDEFS_CREATED, WebhookEvent::RECORD_SUBDEF_TYPE, $eventData diff --git a/lib/Alchemy/Phrasea/Core/Provider/WebhookServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/WebhookServiceProvider.php index 968ec607e1..43a5aeafa4 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/WebhookServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/WebhookServiceProvider.php @@ -11,7 +11,7 @@ use Alchemy\Worker\CallableWorkerFactory; use Alchemy\Worker\TypeBasedWorkerResolver; use Silex\Application; use Silex\ServiceProviderInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; class WebhookServiceProvider implements ServiceProviderInterface { @@ -60,6 +60,14 @@ class WebhookServiceProvider implements ServiceProviderInterface return $resolver; } ); + + $app['dispatcher'] = $app->share( + $app->extend('dispatcher', function (EventDispatcher $dispatcher, Application $app) { + $dispatcher->addSubscriber(new WebhookSubdefEventSubscriber($app)); + + return $dispatcher; + }) + ); } private function createAlias(Application $app, $alias, $targetServiceKey) @@ -71,12 +79,6 @@ class WebhookServiceProvider implements ServiceProviderInterface public function boot(Application $app) { - $app['dispatcher'] = $app->share( - $app->extend('dispatcher', function (EventDispatcherInterface $dispatcher) use ($app) { - $dispatcher->addSubscriber(new WebhookSubdefEventSubscriber($app['manipulator.webhook-event'])); - return $dispatcher; - }) - ); } } From 029cb23863326abc5c221ba98dfebdba541824f9 Mon Sep 17 00:00:00 2001 From: aynsix Date: Thu, 26 Sep 2019 18:15:41 +0400 Subject: [PATCH 14/28] update test --- .../Phrasea/Model/Repositories/WebhookEventRepositoryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Alchemy/Tests/Phrasea/Model/Repositories/WebhookEventRepositoryTest.php b/tests/Alchemy/Tests/Phrasea/Model/Repositories/WebhookEventRepositoryTest.php index 7d21844d66..d27c00738e 100644 --- a/tests/Alchemy/Tests/Phrasea/Model/Repositories/WebhookEventRepositoryTest.php +++ b/tests/Alchemy/Tests/Phrasea/Model/Repositories/WebhookEventRepositoryTest.php @@ -12,6 +12,6 @@ class WebhookEventRepositoryTest extends \PhraseanetTestCase { $events = self::$DI['app']['orm.em']->getRepository('Phraseanet:WebhookEvent')->findUnprocessedEvents(); // I have no clue as to why this magic number is here, probably best to discard test - $this->assertCount(6, $events); + $this->assertCount(41, $events); } } From 2163f0452dc8a3c6ec0c7197769619ceb614ccdc Mon Sep 17 00:00:00 2001 From: aynsix Date: Wed, 30 Oct 2019 14:19:13 +0400 Subject: [PATCH 15/28] PHRAS-2797 retrieve available subdef in event record.sub_definitions_created --- lib/Alchemy/Phrasea/Media/SubdefGenerator.php | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/lib/Alchemy/Phrasea/Media/SubdefGenerator.php b/lib/Alchemy/Phrasea/Media/SubdefGenerator.php index 9ab4d7ebe0..9612e3bc19 100644 --- a/lib/Alchemy/Phrasea/Media/SubdefGenerator.php +++ b/lib/Alchemy/Phrasea/Media/SubdefGenerator.php @@ -18,6 +18,7 @@ use Alchemy\Phrasea\Core\Event\Record\SubDefinitionCreationEvent; use Alchemy\Phrasea\Core\Event\Record\SubDefinitionsCreationEvent; use Alchemy\Phrasea\Core\Event\Record\SubDefinitionCreationFailedEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; +use Alchemy\Phrasea\Databox\Subdef\MediaSubdefRepository; use Alchemy\Phrasea\Filesystem\FilesystemService; use Alchemy\Phrasea\Media\Subdef\Specification\PdfSpecification; use MediaAlchemyst\Alchemyst; @@ -170,13 +171,35 @@ class SubdefGenerator unset($this->tmpFilePath); } - $this->dispatch( - RecordEvents::SUB_DEFINITIONS_CREATED, - new SubDefinitionsCreatedEvent( - $record, - $mediaCreated - ) - ); + // if we created subdef one by one + if (count($wanted_subdefs) == 1) { + $mediaSubdefRepository = $this->getMediaSubdefRepository($record->getDataboxId()); + $mediaSubdefs = $mediaSubdefRepository->findByRecordIdsAndNames([$record->getRecordId()]); + $medias = []; + foreach ($mediaSubdefs as $subdef) { + try { + $medias[$subdef->get_name()] = $this->mediavorus->guess($subdef->getRealPath()); + } catch (MediaVorusFileNotFoundException $e) { + + } + } + + $this->dispatch( + RecordEvents::SUB_DEFINITIONS_CREATED, + new SubDefinitionsCreatedEvent( + $record, + $medias + ) + ); + } else { + $this->dispatch( + RecordEvents::SUB_DEFINITIONS_CREATED, + new SubDefinitionsCreatedEvent( + $record, + $mediaCreated + ) + ); + } } /** @@ -294,4 +317,14 @@ class SubdefGenerator $i = floor(log($bytes, 1024)); return round($bytes / pow(1024, $i), [0,0,2,2,3][$i]).['B','kB','MB','GB'][$i]; } + + /** + * @param $databoxId + * + * @return MediaSubdefRepository|Object + */ + private function getMediaSubdefRepository($databoxId) + { + return $this->app['provider.repo.media_subdef']->getRepositoryForDatabox($databoxId); + } } From 378f67c203d5930a91ee259fffc48cf4fd408d3f Mon Sep 17 00:00:00 2001 From: aynsix Date: Mon, 4 Nov 2019 17:19:18 +0400 Subject: [PATCH 16/28] PHRAS-2769 delete record --- lib/Alchemy/Phrasea/Controller/Prod/RecordController.php | 6 ++++-- lib/Alchemy/Phrasea/Core/Event/Record/RecordEvents.php | 6 ++++-- .../Core/Event/Subscriber/RecordEditSubscriber.php | 8 ++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Prod/RecordController.php b/lib/Alchemy/Phrasea/Controller/Prod/RecordController.php index 0a948d6d1d..8e9a609811 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/RecordController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/RecordController.php @@ -14,6 +14,8 @@ use Alchemy\Phrasea\Application\Helper\EntityManagerAware; use Alchemy\Phrasea\Application\Helper\SearchEngineAware; use Alchemy\Phrasea\Controller\Controller; use Alchemy\Phrasea\Controller\RecordsRequest; +use Alchemy\Phrasea\Core\Event\Record\DeleteEvent; +use Alchemy\Phrasea\Core\Event\Record\RecordEvents; use Alchemy\Phrasea\Core\Event\RecordEdit; use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Model\Entities\BasketElement; @@ -234,7 +236,7 @@ class RecordController extends Controller if($trashCollectionsBySbasId[$sbasId] !== null) { if($record->getCollection()->get_coll_id() == $trashCollectionsBySbasId[$sbasId]->get_coll_id()) { // record is already in trash so delete it - $record->delete(); + $this->getEventDispatcher()->dispatch(RecordEvents::DELETE, new DeleteEvent($record)); } else { // move to trash collection $record->move_to_collection($trashCollectionsBySbasId[$sbasId], $this->getApplicationBox()); @@ -247,7 +249,7 @@ class RecordController extends Controller } } else { // no trash collection, delete - $record->delete(); + $this->getEventDispatcher()->dispatch(RecordEvents::DELETE, new DeleteEvent($record)); } } catch (\Exception $e) { } diff --git a/lib/Alchemy/Phrasea/Core/Event/Record/RecordEvents.php b/lib/Alchemy/Phrasea/Core/Event/Record/RecordEvents.php index e68f4afa84..1399b1c8f5 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Record/RecordEvents.php +++ b/lib/Alchemy/Phrasea/Core/Event/Record/RecordEvents.php @@ -13,8 +13,10 @@ namespace Alchemy\Phrasea\Core\Event\Record; final class RecordEvents { - const CREATED = 'record.created'; - const DELETED = 'record.deleted'; + const CREATED = 'record.created'; + const DELETED = 'record.deleted'; + const DELETE = 'record.delete'; + // Change const COLLECTION_CHANGED = 'record.collection_changed'; const METADATA_CHANGED = 'record.metadata_changed'; diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php index 6c971002e5..8307749eb5 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\Core\Event\Subscriber; use Alchemy\Phrasea\Core\Event\Record\CollectionChangedEvent; +use Alchemy\Phrasea\Core\Event\Record\DeleteEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent; @@ -32,6 +33,7 @@ class RecordEditSubscriber implements EventSubscriberInterface RecordEvents::ROTATE => 'onRecordChange', RecordEvents::COLLECTION_CHANGED => 'onCollectionChanged', RecordEvents::SUBDEFINITION_CREATE => 'onSubdefinitionCreate', + RecordEvents::DELETE => 'onDelete', ); } @@ -57,6 +59,12 @@ class RecordEditSubscriber implements EventSubscriberInterface $recordAdapter->rebuild_subdefs(); } + public function onDelete(DeleteEvent $event) + { + $recordAdapter = $this->convertToRecordAdapter($event->getRecord()); + $recordAdapter->delete(); + } + public function onEdit(RecordEdit $event) { static $into = false; From 97b579efc3ded6eb70f0d3c70f97a9fe8be5f15a Mon Sep 17 00:00:00 2001 From: aynsix Date: Mon, 4 Nov 2019 17:51:18 +0400 Subject: [PATCH 17/28] PHRAS-2769 add DeleteEvent file --- lib/Alchemy/Phrasea/Core/Event/Record/DeleteEvent.php | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 lib/Alchemy/Phrasea/Core/Event/Record/DeleteEvent.php diff --git a/lib/Alchemy/Phrasea/Core/Event/Record/DeleteEvent.php b/lib/Alchemy/Phrasea/Core/Event/Record/DeleteEvent.php new file mode 100644 index 0000000000..8d8bfdb379 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Event/Record/DeleteEvent.php @@ -0,0 +1,7 @@ + Date: Tue, 5 Nov 2019 15:38:36 +0400 Subject: [PATCH 18/28] upgrade version to 18a --- lib/Alchemy/Phrasea/Core/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Alchemy/Phrasea/Core/Version.php b/lib/Alchemy/Phrasea/Core/Version.php index c525bf815c..19011867d9 100644 --- a/lib/Alchemy/Phrasea/Core/Version.php +++ b/lib/Alchemy/Phrasea/Core/Version.php @@ -16,7 +16,7 @@ class Version /** * @var string */ - private $number = '4.1.0-alpha.17a'; + private $number = '4.1.0-alpha.18a'; /** * @var string From cfa854f307edb356f8c79a67e84fa16f645a21da Mon Sep 17 00:00:00 2001 From: aynsix Date: Thu, 19 Dec 2019 16:09:35 +0400 Subject: [PATCH 19/28] start subdef creation after first write meta --- lib/Alchemy/Phrasea/Border/Manager.php | 19 +++++++------- .../Event/Record/MetadataChangedEvent.php | 25 +++++++++++++++++++ .../Metadata/PhraseanetMetadataSetter.php | 4 +-- .../TaskManager/Job/WriteMetadataJob.php | 16 +++++++++++- lib/classes/record/adapter.php | 14 +++++++++-- 5 files changed, 64 insertions(+), 14 deletions(-) diff --git a/lib/Alchemy/Phrasea/Border/Manager.php b/lib/Alchemy/Phrasea/Border/Manager.php index d017d206e6..543f97ebd6 100644 --- a/lib/Alchemy/Phrasea/Border/Manager.php +++ b/lib/Alchemy/Phrasea/Border/Manager.php @@ -14,8 +14,6 @@ namespace Alchemy\Phrasea\Border; use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Border\Checker\CheckerInterface; use Alchemy\Phrasea\Border\Attribute\AttributeInterface; -use Alchemy\Phrasea\Core\Event\Record\RecordEvents; -use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent; use Alchemy\Phrasea\Exception\RuntimeException; use Alchemy\Phrasea\Metadata\Tag\TfArchivedate; use Alchemy\Phrasea\Metadata\Tag\TfQuarantine; @@ -112,6 +110,9 @@ class Manager if (($visa->isValid() || $forceBehavior === self::FORCE_RECORD) && $forceBehavior !== self::FORCE_LAZARET) { + // Write UUID + $file->getUUID(false, true); + $this->addMediaAttributes($file); $element = $this->createRecord($file, $nosubdef); @@ -119,14 +120,14 @@ class Manager $code = self::RECORD_CREATED; } else { + // Write UUID + $file->getUUID(false, true); + $element = $this->createLazaret($file, $visa, $session, $forceBehavior === self::FORCE_LAZARET); $code = self::LAZARET_CREATED; } - // Write UUID - $file->getUUID(false, true); - if (is_callable($callable)) { $callable($element, $visa, $code); } @@ -332,12 +333,12 @@ class Manager } } - $this->app['phraseanet.metadata-setter']->replaceMetadata($newMetadata, $element); - - if(!$nosubdef) { - $this->app['dispatcher']->dispatch(RecordEvents::SUBDEFINITION_CREATE, new SubdefinitionCreateEvent($element, true)); + if ($nosubdef) { + $element->setNoSubdef(); } + $this->app['phraseanet.metadata-setter']->replaceMetadata($newMetadata, $element, true, $nosubdef);// true for $isNewRecord + return $element; } diff --git a/lib/Alchemy/Phrasea/Core/Event/Record/MetadataChangedEvent.php b/lib/Alchemy/Phrasea/Core/Event/Record/MetadataChangedEvent.php index 65326b894b..5a3ed5c2ef 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Record/MetadataChangedEvent.php +++ b/lib/Alchemy/Phrasea/Core/Event/Record/MetadataChangedEvent.php @@ -11,6 +11,31 @@ namespace Alchemy\Phrasea\Core\Event\Record; +use Alchemy\Phrasea\Model\RecordInterface; + class MetadataChangedEvent extends RecordEvent { + private $isNewRecord; + private $nosubdef; + + public function __construct(RecordInterface $record, $isNewRecord = false, $nosubdef = false) + { + parent::__construct($record); + + $this->isNewRecord = $isNewRecord; + $this->nosubdef = $nosubdef; + } + + /** + * @return bool + */ + public function isNewRecord() + { + return $this->isNewRecord; + } + + public function isNosubdef() + { + return $this->nosubdef; + } } diff --git a/lib/Alchemy/Phrasea/Metadata/PhraseanetMetadataSetter.php b/lib/Alchemy/Phrasea/Metadata/PhraseanetMetadataSetter.php index c72c884203..afa459f154 100644 --- a/lib/Alchemy/Phrasea/Metadata/PhraseanetMetadataSetter.php +++ b/lib/Alchemy/Phrasea/Metadata/PhraseanetMetadataSetter.php @@ -34,7 +34,7 @@ class PhraseanetMetadataSetter * @param \record_adapter $record * @throws \Exception_InvalidArgument */ - public function replaceMetadata($metadataCollection, \record_adapter $record) + public function replaceMetadata($metadataCollection, \record_adapter $record, $isNewRecord = false, $nosubdef = false) { $metaStructure = $this->repository->find($record->getDataboxId())->get_meta_structure()->get_elements(); @@ -82,7 +82,7 @@ class PhraseanetMetadataSetter } if (! empty($metadataInRecordFormat)) { - $record->set_metadatas($metadataInRecordFormat, true); + $record->set_metadatas($metadataInRecordFormat, true, $isNewRecord, $nosubdef); } } diff --git a/lib/Alchemy/Phrasea/TaskManager/Job/WriteMetadataJob.php b/lib/Alchemy/Phrasea/TaskManager/Job/WriteMetadataJob.php index 795b0b2a83..7631044cf2 100644 --- a/lib/Alchemy/Phrasea/TaskManager/Job/WriteMetadataJob.php +++ b/lib/Alchemy/Phrasea/TaskManager/Job/WriteMetadataJob.php @@ -12,6 +12,8 @@ namespace Alchemy\Phrasea\TaskManager\Job; use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Core\Event\Record\RecordEvents; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent; use Alchemy\Phrasea\Core\PhraseaTokens; use Alchemy\Phrasea\Metadata\TagFactory; use Alchemy\Phrasea\TaskManager\Editor\WriteMetadataEditor; @@ -69,7 +71,7 @@ class WriteMetadataJob extends AbstractJob foreach ($jobData->getApplication()->getDataboxes() as $databox) { $connection = $databox->get_connection(); - $statement = $connection->prepare('SELECT record_id, coll_id, jeton FROM record WHERE (jeton & :token > 0)'); + $statement = $connection->prepare('SELECT record_id, coll_id, work, jeton FROM record WHERE (jeton & :token > 0)'); $statement->execute(['token' => PhraseaTokens::WRITE_META]); $rs = $statement->fetchAll(\PDO::FETCH_ASSOC); $statement->closeCursor(); @@ -203,6 +205,13 @@ class WriteMetadataJob extends AbstractJob 'record_id' => $record_id, 'token' => PhraseaTokens::WRITE_META, ]); + + // write meta for the document is finished + // if it's a new record, order to create subdef + if (count($record->get_subdefs()) == 3 && count($subdefs) == 1 && isset($subdefs['document']) && $row['work'] != 1) { + $this->getDispatcher($jobData->getApplication())->dispatch(RecordEvents::SUBDEFINITION_CREATE, new SubdefinitionCreateEvent($record, true)); + } + $statement->closeCursor(); } } @@ -217,6 +226,11 @@ class WriteMetadataJob extends AbstractJob return $app['exiftool.writer']; } + private function getDispatcher(Application $app) + { + return $app['dispatcher']; + } + /** * @param \databox $databox * @param string $subdefType diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php index 7c91e2e135..ebf9c0d4e8 100644 --- a/lib/classes/record/adapter.php +++ b/lib/classes/record/adapter.php @@ -1083,7 +1083,7 @@ class record_adapter implements RecordInterface, cache_cacheableInterface * * @return record_adapter */ - public function set_metadatas(array $metadatas, $force_readonly = false) + public function set_metadatas(array $metadatas, $force_readonly = false, $isNewRecord = false, $nosubdef = false) { $databox_descriptionStructure = $this->getDatabox()->get_meta_structure(); @@ -1108,7 +1108,7 @@ class record_adapter implements RecordInterface, cache_cacheableInterface unset($xml); $this->write_metas(); - $this->dispatch(RecordEvents::METADATA_CHANGED, new MetadataChangedEvent($this)); + $this->dispatch(RecordEvents::METADATA_CHANGED, new MetadataChangedEvent($this, $isNewRecord, $nosubdef)); return $this; } @@ -1175,6 +1175,16 @@ class record_adapter implements RecordInterface, cache_cacheableInterface return $this; } + public function setNoSubdef() + { + $this->getDataboxConnection()->executeUpdate( + 'UPDATE record SET work = 1 WHERE record_id= :record_id', + ['record_id' => $this->getRecordId()] + ); + + return $this; + } + private function dispatch($eventName, RecordEvent $event) { $this->app['dispatcher']->dispatch($eventName, $event); From db0489c05e271fff58cd648a09a839a95b4837e7 Mon Sep 17 00:00:00 2001 From: aynsix Date: Thu, 20 Feb 2020 11:11:18 +0300 Subject: [PATCH 20/28] Revert "start subdef creation after first write meta" This reverts commit cfa854f307edb356f8c79a67e84fa16f645a21da. --- lib/Alchemy/Phrasea/Border/Manager.php | 19 +++++++------- .../Event/Record/MetadataChangedEvent.php | 25 ------------------- .../Metadata/PhraseanetMetadataSetter.php | 4 +-- .../TaskManager/Job/WriteMetadataJob.php | 16 +----------- lib/classes/record/adapter.php | 14 ++--------- 5 files changed, 14 insertions(+), 64 deletions(-) diff --git a/lib/Alchemy/Phrasea/Border/Manager.php b/lib/Alchemy/Phrasea/Border/Manager.php index 543f97ebd6..d017d206e6 100644 --- a/lib/Alchemy/Phrasea/Border/Manager.php +++ b/lib/Alchemy/Phrasea/Border/Manager.php @@ -14,6 +14,8 @@ namespace Alchemy\Phrasea\Border; use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Border\Checker\CheckerInterface; use Alchemy\Phrasea\Border\Attribute\AttributeInterface; +use Alchemy\Phrasea\Core\Event\Record\RecordEvents; +use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent; use Alchemy\Phrasea\Exception\RuntimeException; use Alchemy\Phrasea\Metadata\Tag\TfArchivedate; use Alchemy\Phrasea\Metadata\Tag\TfQuarantine; @@ -110,9 +112,6 @@ class Manager if (($visa->isValid() || $forceBehavior === self::FORCE_RECORD) && $forceBehavior !== self::FORCE_LAZARET) { - // Write UUID - $file->getUUID(false, true); - $this->addMediaAttributes($file); $element = $this->createRecord($file, $nosubdef); @@ -120,14 +119,14 @@ class Manager $code = self::RECORD_CREATED; } else { - // Write UUID - $file->getUUID(false, true); - $element = $this->createLazaret($file, $visa, $session, $forceBehavior === self::FORCE_LAZARET); $code = self::LAZARET_CREATED; } + // Write UUID + $file->getUUID(false, true); + if (is_callable($callable)) { $callable($element, $visa, $code); } @@ -333,11 +332,11 @@ class Manager } } - if ($nosubdef) { - $element->setNoSubdef(); - } + $this->app['phraseanet.metadata-setter']->replaceMetadata($newMetadata, $element); - $this->app['phraseanet.metadata-setter']->replaceMetadata($newMetadata, $element, true, $nosubdef);// true for $isNewRecord + if(!$nosubdef) { + $this->app['dispatcher']->dispatch(RecordEvents::SUBDEFINITION_CREATE, new SubdefinitionCreateEvent($element, true)); + } return $element; } diff --git a/lib/Alchemy/Phrasea/Core/Event/Record/MetadataChangedEvent.php b/lib/Alchemy/Phrasea/Core/Event/Record/MetadataChangedEvent.php index 5a3ed5c2ef..65326b894b 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Record/MetadataChangedEvent.php +++ b/lib/Alchemy/Phrasea/Core/Event/Record/MetadataChangedEvent.php @@ -11,31 +11,6 @@ namespace Alchemy\Phrasea\Core\Event\Record; -use Alchemy\Phrasea\Model\RecordInterface; - class MetadataChangedEvent extends RecordEvent { - private $isNewRecord; - private $nosubdef; - - public function __construct(RecordInterface $record, $isNewRecord = false, $nosubdef = false) - { - parent::__construct($record); - - $this->isNewRecord = $isNewRecord; - $this->nosubdef = $nosubdef; - } - - /** - * @return bool - */ - public function isNewRecord() - { - return $this->isNewRecord; - } - - public function isNosubdef() - { - return $this->nosubdef; - } } diff --git a/lib/Alchemy/Phrasea/Metadata/PhraseanetMetadataSetter.php b/lib/Alchemy/Phrasea/Metadata/PhraseanetMetadataSetter.php index afa459f154..c72c884203 100644 --- a/lib/Alchemy/Phrasea/Metadata/PhraseanetMetadataSetter.php +++ b/lib/Alchemy/Phrasea/Metadata/PhraseanetMetadataSetter.php @@ -34,7 +34,7 @@ class PhraseanetMetadataSetter * @param \record_adapter $record * @throws \Exception_InvalidArgument */ - public function replaceMetadata($metadataCollection, \record_adapter $record, $isNewRecord = false, $nosubdef = false) + public function replaceMetadata($metadataCollection, \record_adapter $record) { $metaStructure = $this->repository->find($record->getDataboxId())->get_meta_structure()->get_elements(); @@ -82,7 +82,7 @@ class PhraseanetMetadataSetter } if (! empty($metadataInRecordFormat)) { - $record->set_metadatas($metadataInRecordFormat, true, $isNewRecord, $nosubdef); + $record->set_metadatas($metadataInRecordFormat, true); } } diff --git a/lib/Alchemy/Phrasea/TaskManager/Job/WriteMetadataJob.php b/lib/Alchemy/Phrasea/TaskManager/Job/WriteMetadataJob.php index 7631044cf2..795b0b2a83 100644 --- a/lib/Alchemy/Phrasea/TaskManager/Job/WriteMetadataJob.php +++ b/lib/Alchemy/Phrasea/TaskManager/Job/WriteMetadataJob.php @@ -12,8 +12,6 @@ namespace Alchemy\Phrasea\TaskManager\Job; use Alchemy\Phrasea\Application; -use Alchemy\Phrasea\Core\Event\Record\RecordEvents; -use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent; use Alchemy\Phrasea\Core\PhraseaTokens; use Alchemy\Phrasea\Metadata\TagFactory; use Alchemy\Phrasea\TaskManager\Editor\WriteMetadataEditor; @@ -71,7 +69,7 @@ class WriteMetadataJob extends AbstractJob foreach ($jobData->getApplication()->getDataboxes() as $databox) { $connection = $databox->get_connection(); - $statement = $connection->prepare('SELECT record_id, coll_id, work, jeton FROM record WHERE (jeton & :token > 0)'); + $statement = $connection->prepare('SELECT record_id, coll_id, jeton FROM record WHERE (jeton & :token > 0)'); $statement->execute(['token' => PhraseaTokens::WRITE_META]); $rs = $statement->fetchAll(\PDO::FETCH_ASSOC); $statement->closeCursor(); @@ -205,13 +203,6 @@ class WriteMetadataJob extends AbstractJob 'record_id' => $record_id, 'token' => PhraseaTokens::WRITE_META, ]); - - // write meta for the document is finished - // if it's a new record, order to create subdef - if (count($record->get_subdefs()) == 3 && count($subdefs) == 1 && isset($subdefs['document']) && $row['work'] != 1) { - $this->getDispatcher($jobData->getApplication())->dispatch(RecordEvents::SUBDEFINITION_CREATE, new SubdefinitionCreateEvent($record, true)); - } - $statement->closeCursor(); } } @@ -226,11 +217,6 @@ class WriteMetadataJob extends AbstractJob return $app['exiftool.writer']; } - private function getDispatcher(Application $app) - { - return $app['dispatcher']; - } - /** * @param \databox $databox * @param string $subdefType diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php index e8dc587451..f58d54abea 100644 --- a/lib/classes/record/adapter.php +++ b/lib/classes/record/adapter.php @@ -1083,7 +1083,7 @@ class record_adapter implements RecordInterface, cache_cacheableInterface * * @return record_adapter */ - public function set_metadatas(array $metadatas, $force_readonly = false, $isNewRecord = false, $nosubdef = false) + public function set_metadatas(array $metadatas, $force_readonly = false) { $databox_descriptionStructure = $this->getDatabox()->get_meta_structure(); @@ -1108,7 +1108,7 @@ class record_adapter implements RecordInterface, cache_cacheableInterface unset($xml); $this->write_metas(); - $this->dispatch(RecordEvents::METADATA_CHANGED, new MetadataChangedEvent($this, $isNewRecord, $nosubdef)); + $this->dispatch(RecordEvents::METADATA_CHANGED, new MetadataChangedEvent($this)); return $this; } @@ -1175,16 +1175,6 @@ class record_adapter implements RecordInterface, cache_cacheableInterface return $this; } - public function setNoSubdef() - { - $this->getDataboxConnection()->executeUpdate( - 'UPDATE record SET work = 1 WHERE record_id= :record_id', - ['record_id' => $this->getRecordId()] - ); - - return $this; - } - private function dispatch($eventName, RecordEvent $event) { $this->app['dispatcher']->dispatch($eventName, $event); From 597216429aeacdb180d13aaf04718fada2d110eb Mon Sep 17 00:00:00 2001 From: aynsix Date: Thu, 12 Mar 2020 16:16:41 +0300 Subject: [PATCH 21/28] fix right access and right on story elements per user --- lib/Alchemy/Phrasea/Helper/User/Edit.php | 4 ++-- lib/classes/record/adapter.php | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/Alchemy/Phrasea/Helper/User/Edit.php b/lib/Alchemy/Phrasea/Helper/User/Edit.php index 2c7513fb3f..bc687af303 100644 --- a/lib/Alchemy/Phrasea/Helper/User/Edit.php +++ b/lib/Alchemy/Phrasea/Helper/User/Edit.php @@ -583,8 +583,8 @@ class Edit extends \Alchemy\Phrasea\Helper\Helper $user = $this->app['repo.users']->find($usr_id); $this->app->getAclForUser($user)->revoke_access_from_bases($delete) - ->give_access_to_base($create) - ->give_access_to_sbas($create_sbas); + ->give_access_to_sbas($create_sbas) // give access to sbas before bas + ->give_access_to_base($create); foreach ($update as $base_id => $rights) { $this->app->getAclForUser($user) diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php index 8e181c5d2e..88a32c6560 100644 --- a/lib/classes/record/adapter.php +++ b/lib/classes/record/adapter.php @@ -1735,7 +1735,9 @@ class record_adapter implements RecordInterface, cache_cacheableInterface throw new Exception('This record is not a grouping'); } - $selections = $this->getDatabox()->getRecordRepository()->findChildren([$this->getRecordId()], null, $offset, $max_items); + $user = $this->getAuthenticatedUser(); + + $selections = $this->getDatabox()->getRecordRepository()->findChildren([$this->getRecordId()], $user, $offset, $max_items); return reset($selections); } @@ -1745,7 +1747,9 @@ class record_adapter implements RecordInterface, cache_cacheableInterface */ public function get_grouping_parents() { - $selections = $this->getDatabox()->getRecordRepository()->findParents([$this->getRecordId()]); + $user = $this->getAuthenticatedUser(); + + $selections = $this->getDatabox()->getRecordRepository()->findParents([$this->getRecordId()], $user); return reset($selections); } @@ -1948,4 +1952,15 @@ class record_adapter implements RecordInterface, cache_cacheableInterface { return $this->app['provider.repo.media_subdef']->getRepositoryForDatabox($this->getDataboxId()); } + + /** + * @return User|null + */ + protected function getAuthenticatedUser() + { + /** @var \Alchemy\Phrasea\Authentication\Authenticator $authenticator */ + $authenticator = $this->app['authentication']; + + return $authenticator->getUser(); + } } From fbc4e01ef33b0297b40e9d1fffe89b99f343c0fa Mon Sep 17 00:00:00 2001 From: Harrys Ravalomanana Date: Tue, 17 Mar 2020 15:34:24 +0400 Subject: [PATCH 22/28] PHRAS-2978 #comment update feedback expiration date #time 6h --- .../Controller/Prod/PushController.php | 35 +++++++++++++++- .../Phrasea/ControllerProvider/Prod/Push.php | 3 ++ templates/web/prod/Tooltip/Basket.html.twig | 6 ++- templates/web/prod/WorkZone/Basket.html.twig | 40 +++++++++++++++---- 4 files changed, 74 insertions(+), 10 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Prod/PushController.php b/lib/Alchemy/Phrasea/Controller/Prod/PushController.php index 6e650aefaa..c1fd5d8751 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/PushController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/PushController.php @@ -98,7 +98,7 @@ class PushController extends Controller $Basket->setUser($user_receiver); $Basket->setPusher($this->getAuthenticatedUser()); $Basket->markUnread(); - + $manager->persist($Basket); foreach ($pusher->get_elements() as $element) { @@ -600,6 +600,38 @@ class PushController extends Controller ); } + public function updateExpirationAction(Request $request) + { + $ret = [ + 'success' => false, + 'message' => $this->app->trans('Unable to save the expiration date') + ]; + if (is_null($request->request->get('date'))) { + $ret['message'] = $this->app->trans('The provided date is null!'); + return $this->app->json($ret); + } + $repository = $this->app['repo.baskets']; + $manager = $this->getEntityManager(); + $manager->beginTransaction(); + try { + $basket = $repository->findUserBasket($request->request->get('basket_id'), $this->app->getAuthenticatedUser(), true); + $date = new \DateTime($request->request->get('date')); + $validation = $basket->getValidation(); + if (is_null($validation)) { + return $this->app->json($ret); + } + $validation->setExpires($date); + $manager->persist($validation); + $manager->flush(); + $manager->commit(); + $ret['message'] = $this->app->trans('Expiration date successfully updated!'); + } catch (\Exception $e) { + $ret['message'] = $e->getMessage(); + $manager->rollback(); + } + return $this->app->json($ret); + } + private function formatUser(User $user) { $subtitle = array_filter([$user->getJob(), $user->getCompany()]); @@ -734,4 +766,5 @@ class PushController extends Controller { return $this->app['random.medium']; } + } diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Push.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Push.php index 48352e1e39..40b93220c0 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Push.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Push.php @@ -59,6 +59,9 @@ class Push implements ControllerProviderInterface, ServiceProviderInterface $controllers->post('/validate/', 'controller.prod.push:validateAction') ->bind('prod_push_validate'); + $controllers->post('/update-expiration/', 'controller.prod.push:updateExpirationAction') + ->bind('prod_push_do_update_expiration'); + $controllers->get('/user/{usr_id}/', 'controller.prod.push:getUserAction') ->assert('usr_id', '\d+'); diff --git a/templates/web/prod/Tooltip/Basket.html.twig b/templates/web/prod/Tooltip/Basket.html.twig index 9905cbf49c..49eeec04ba 100644 --- a/templates/web/prod/Tooltip/Basket.html.twig +++ b/templates/web/prod/Tooltip/Basket.html.twig @@ -11,7 +11,11 @@ {% if basket.getValidation() %} {% set dateExpired = app['date-formatter'].getPrettyString(basket.getValidation().getExpires()) %} - {{ 'workzone:feedback:expiration' | trans }} : {{ dateExpired }} + {% if date(dateExpired) < date() %} + {{ 'workzone:feedback:expiration-closed' | trans }} : + {% else %} + {{ 'workzone:feedback:expiration-open' | trans }} : + {% endif %} {{ dateExpired }} {% endif %}
diff --git a/templates/web/prod/WorkZone/Basket.html.twig b/templates/web/prod/WorkZone/Basket.html.twig index fb028812d5..d46d0f2f55 100644 --- a/templates/web/prod/WorkZone/Basket.html.twig +++ b/templates/web/prod/WorkZone/Basket.html.twig @@ -1,4 +1,4 @@ - +
@@ -101,13 +101,19 @@ {% set dateExpired = app['date-formatter'].getPrettyString(basket.getValidation().getExpires()) %}
- {{ 'workzone:feedback:expiration' | trans }} : + {% if date(dateExpired) < date() %} + {{ 'workzone:feedback:expiration-closed' | trans }} : + {% else %} + {{ 'workzone:feedback:expiration-open' | trans }} : + {% endif %} +
- - - + + +
+

{{ 'prod:workzone:basket:updated-message' | trans }}

{% endif %} @@ -135,7 +141,24 @@ From 5e8dda54a503e58a0a125f6a8cfda24fe8c0e5b4 Mon Sep 17 00:00:00 2001 From: Harrys Ravalomanana Date: Tue, 17 Mar 2020 15:45:59 +0400 Subject: [PATCH 23/28] Add translation --- resources/locales/messages.de.xlf | 96 ++++++++++++++--------- resources/locales/messages.en.xlf | 110 +++++++++++++++++---------- resources/locales/messages.fr.xlf | 114 +++++++++++++++++----------- resources/locales/messages.nl.xlf | 96 ++++++++++++++--------- resources/locales/validators.de.xlf | 2 +- resources/locales/validators.en.xlf | 2 +- resources/locales/validators.fr.xlf | 2 +- resources/locales/validators.nl.xlf | 2 +- 8 files changed, 268 insertions(+), 156 deletions(-) diff --git a/resources/locales/messages.de.xlf b/resources/locales/messages.de.xlf index 9ca23ed2d7..8972dae59c 100644 --- a/resources/locales/messages.de.xlf +++ b/resources/locales/messages.de.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. @@ -192,8 +192,9 @@ %nb_records% records %nb_records% Datensätze + prod/WorkZone/Basket.html.twig prod/Tooltip/Story.html.twig - prod/Tooltip/Basket.html.twig + prod/Tooltip/Basket.html.twig %nb_view% vue @@ -1689,7 +1690,7 @@ Certaines donnees du panier ont change Einige Daten des Sammelkorbs wurden verändert - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig Certaines donnees du reportage ont change @@ -3165,6 +3166,11 @@ Einstellungen von ausführbaren Programme Form/Configuration/MainConfigurationFormType.php + + Expiration date successfully updated! + Expiration date successfully updated! + Controller/Prod/PushController.php + Export Exportieren @@ -6685,6 +6691,11 @@ Die folgende Fehler wurden festgestellt user/import/view.html.twig + + The provided date is null! + The provided date is null! + Controller/Prod/PushController.php + The publication has been stopped Veröffentlichung wurde gestoppt @@ -7046,6 +7057,11 @@ Controller/Root/LoginController.php Controller/Api/OAuth2Controller.php + + Unable to save the expiration date + Unable to save the expiration date + Controller/Prod/PushController.php + Unable to send the documents Es ist nicht möglich Dokumente zu senden @@ -11718,7 +11734,13 @@ prod:workzone:basket:creation-date prod:workzone:basket:creation-date - prod/Tooltip/Basket.html.twig + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + + prod:workzone:basket:updated-message + prod:workzone:basket:updated-message + prod/WorkZone/Basket.html.twig prod:workzone:facetstab:search_and_facets_sort_options @@ -11826,7 +11848,7 @@ Aktualisieren prod/WorkZone/Story.html.twig prod/WorkZone/Macros.html.twig - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig prod/results/feeds.html.twig prod/results/feeds.html.twig @@ -13397,128 +13419,134 @@ workzone:datepicker:april workzone:datepicker:april - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:august workzone:datepicker:august - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:closeText workzone:datepicker:closeText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:currentText workzone:datepicker:currentText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:december workzone:datepicker:december - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:february workzone:datepicker:february - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:friday workzone:datepicker:friday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:january workzone:datepicker:january - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:july workzone:datepicker:july - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:june workzone:datepicker:june - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:march workzone:datepicker:march - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:may workzone:datepicker:may - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:monday workzone:datepicker:monday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:nextText workzone:datepicker:nextText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:november workzone:datepicker:november - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:october workzone:datepicker:october - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:prevText workzone:datepicker:prevText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:saturday workzone:datepicker:saturday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:september workzone:datepicker:september - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:sunday workzone:datepicker:sunday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:thursday workzone:datepicker:thursday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:tuesday workzone:datepicker:tuesday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:wednesday workzone:datepicker:wednesday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig - - workzone:feedback:expiration - workzone:feedback:expiration - prod/WorkZone/Basket.html.twig - prod/Tooltip/Basket.html.twig + + workzone:feedback:expiration-closed + workzone:feedback:expiration-closed + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + + workzone:feedback:expiration-open + workzone:feedback:expiration-open + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig workzone:feedback:update workzone:feedback:update - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig yes diff --git a/resources/locales/messages.en.xlf b/resources/locales/messages.en.xlf index 301050bb79..4c9560d4e9 100644 --- a/resources/locales/messages.en.xlf +++ b/resources/locales/messages.en.xlf @@ -1,14 +1,14 @@ - + - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.
- - + + Form/Login/PhraseaAuthenticationForm.php Form/Configuration/EmailFormType.php @@ -192,8 +192,9 @@ %nb_records% records %nb_records% records + prod/WorkZone/Basket.html.twig prod/Tooltip/Story.html.twig - prod/Tooltip/Basket.html.twig + prod/Tooltip/Basket.html.twig %nb_view% vue @@ -1690,7 +1691,7 @@ Certaines donnees du panier ont change This basket has been updated - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig Certaines donnees du reportage ont change @@ -3168,6 +3169,11 @@ Executables setting Form/Configuration/MainConfigurationFormType.php + + Expiration date successfully updated! + Expiration date successfully updated! + Controller/Prod/PushController.php + Export Export @@ -6688,6 +6694,11 @@ The following errors have been detected user/import/view.html.twig + + The provided date is null! + The provided date is null! + Controller/Prod/PushController.php + The publication has been stopped The publication has been stopped. @@ -7049,6 +7060,11 @@ Controller/Root/LoginController.php Controller/Api/OAuth2Controller.php + + Unable to save the expiration date + Unable to save the expiration date + Controller/Prod/PushController.php + Unable to send the documents Unable to send the documents @@ -11721,10 +11737,16 @@ It is possible to place several search areas Delete Selection prod/actions/Push.html.twig - + prod:workzone:basket:creation-date Creation - prod/Tooltip/Basket.html.twig + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + + prod:workzone:basket:updated-message + prod:workzone:basket:updated-message + prod/WorkZone/Basket.html.twig prod:workzone:facetstab:search_and_facets_sort_options @@ -11832,7 +11854,7 @@ It is possible to place several search areas Refresh prod/WorkZone/Story.html.twig prod/WorkZone/Macros.html.twig - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig prod/results/feeds.html.twig prod/results/feeds.html.twig @@ -13403,128 +13425,134 @@ It is possible to place several search areas workzone:datepicker:april April - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:august August - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:closeText workzone:datepicker:closeText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:currentText workzone:datepicker:currentText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:december December - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:february February - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:friday Friday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:january January - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:july July - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:june June - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:march March - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:may May - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:monday Monday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig - + workzone:datepicker:nextText Next - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:november November - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:october October - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig - + workzone:datepicker:prevText Previous - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:saturday Saturday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:september September - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:sunday Sunday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:thursday Thursday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:tuesday Tuesday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:wednesday Wednesday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig - - workzone:feedback:expiration - Feedback open Until - prod/WorkZone/Basket.html.twig - prod/Tooltip/Basket.html.twig + + workzone:feedback:expiration-closed + workzone:feedback:expiration-closed + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig - + + workzone:feedback:expiration-open + workzone:feedback:expiration-open + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + workzone:feedback:update Update Date - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig yes diff --git a/resources/locales/messages.fr.xlf b/resources/locales/messages.fr.xlf index a8166562ca..be1a6c9a97 100644 --- a/resources/locales/messages.fr.xlf +++ b/resources/locales/messages.fr.xlf @@ -1,14 +1,14 @@ - + - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.
- - + + Form/Login/PhraseaAuthenticationForm.php Form/Configuration/EmailFormType.php @@ -192,8 +192,9 @@ %nb_records% records %nb_records% enregistrement(s) + prod/WorkZone/Basket.html.twig prod/Tooltip/Story.html.twig - prod/Tooltip/Basket.html.twig + prod/Tooltip/Basket.html.twig %nb_view% vue @@ -1689,7 +1690,7 @@ Certaines donnees du panier ont change Certaines données du panier ont changé - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig Certaines donnees du reportage ont change @@ -3165,6 +3166,11 @@ Paramètres d'exécutables Form/Configuration/MainConfigurationFormType.php + + Expiration date successfully updated! + Expiration date successfully updated! + Controller/Prod/PushController.php + Export Exporter @@ -6687,6 +6693,11 @@ Pour les utilisateurs authentifiés, la demande de validation est également dis Les erreurs suivantes ont été détectées. user/import/view.html.twig + + The provided date is null! + The provided date is null! + Controller/Prod/PushController.php + The publication has been stopped La publication a été suspendue @@ -7048,6 +7059,11 @@ Pour les utilisateurs authentifiés, la demande de validation est également dis Controller/Root/LoginController.php Controller/Api/OAuth2Controller.php + + Unable to save the expiration date + Unable to save the expiration date + Controller/Prod/PushController.php + Unable to send the documents Impossible d'envoyer les documents @@ -11724,10 +11740,16 @@ Si vous recevez cet e-mail sans l'avoir sollicité, merci de l'ignorer ou de le Supprimer la selection prod/actions/Push.html.twig - + prod:workzone:basket:creation-date Date de création - prod/Tooltip/Basket.html.twig + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + + prod:workzone:basket:updated-message + prod:workzone:basket:updated-message + prod/WorkZone/Basket.html.twig prod:workzone:facetstab:search_and_facets_sort_options @@ -11835,7 +11857,7 @@ Si vous recevez cet e-mail sans l'avoir sollicité, merci de l'ignorer ou de le Rafraîchir prod/WorkZone/Story.html.twig prod/WorkZone/Macros.html.twig - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig prod/results/feeds.html.twig prod/results/feeds.html.twig @@ -13406,128 +13428,134 @@ Si vous recevez cet e-mail sans l'avoir sollicité, merci de l'ignorer ou de le workzone:datepicker:april Avril - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:august Aout - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig - + workzone:datepicker:closeText Clore - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig - + workzone:datepicker:currentText courant - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:december Décembre - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:february Février - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:friday Vendredi - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:january Janvier - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:july Juillet - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:june Juin - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:march Mars - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:may Mai - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:monday Lundi - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig - + workzone:datepicker:nextText Suivant - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:november Novembre - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:october Octobre - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig - + workzone:datepicker:prevText Précédent - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:saturday Samedi - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:september Septembre - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:sunday Dimanche - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:thursday Jeudi - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:tuesday Mardi - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:wednesday Mercredi - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig - - workzone:feedback:expiration - Validation ouverte jusqu'au - prod/WorkZone/Basket.html.twig - prod/Tooltip/Basket.html.twig + + workzone:feedback:expiration-closed + workzone:feedback:expiration-closed + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig - + + workzone:feedback:expiration-open + workzone:feedback:expiration-open + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + workzone:feedback:update Valider - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig yes diff --git a/resources/locales/messages.nl.xlf b/resources/locales/messages.nl.xlf index c61524de6a..d5fff61be3 100644 --- a/resources/locales/messages.nl.xlf +++ b/resources/locales/messages.nl.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. @@ -196,8 +196,9 @@ %nb_records% records %nb_records% records + prod/WorkZone/Basket.html.twig prod/Tooltip/Story.html.twig - prod/Tooltip/Basket.html.twig + prod/Tooltip/Basket.html.twig %nb_view% vue @@ -1694,7 +1695,7 @@ Certaines donnees du panier ont change Sommige gegevens in het mandje zijn veranderd - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig Certaines donnees du reportage ont change @@ -3175,6 +3176,11 @@ Executables instellingen Form/Configuration/MainConfigurationFormType.php + + Expiration date successfully updated! + Expiration date successfully updated! + Controller/Prod/PushController.php + Export Exporteer @@ -6695,6 +6701,11 @@ De volgende fouten werden opgemerkt user/import/view.html.twig + + The provided date is null! + The provided date is null! + Controller/Prod/PushController.php + The publication has been stopped Het programma is gestopt @@ -7056,6 +7067,11 @@ Controller/Root/LoginController.php Controller/Api/OAuth2Controller.php + + Unable to save the expiration date + Unable to save the expiration date + Controller/Prod/PushController.php + Unable to send the documents Documenten kunnen niet worden verstuurd @@ -11728,7 +11744,13 @@ prod:workzone:basket:creation-date prod:workzone:basket:creation-date - prod/Tooltip/Basket.html.twig + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + + prod:workzone:basket:updated-message + prod:workzone:basket:updated-message + prod/WorkZone/Basket.html.twig prod:workzone:facetstab:search_and_facets_sort_options @@ -11836,7 +11858,7 @@ vernieuwen prod/WorkZone/Story.html.twig prod/WorkZone/Macros.html.twig - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig prod/results/feeds.html.twig prod/results/feeds.html.twig @@ -13407,128 +13429,134 @@ workzone:datepicker:april workzone:datepicker:april - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:august workzone:datepicker:august - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:closeText workzone:datepicker:closeText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:currentText workzone:datepicker:currentText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:december workzone:datepicker:december - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:february workzone:datepicker:february - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:friday workzone:datepicker:friday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:january workzone:datepicker:january - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:july workzone:datepicker:july - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:june workzone:datepicker:june - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:march workzone:datepicker:march - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:may workzone:datepicker:may - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:monday workzone:datepicker:monday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:nextText workzone:datepicker:nextText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:november workzone:datepicker:november - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:october workzone:datepicker:october - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:prevText workzone:datepicker:prevText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:saturday workzone:datepicker:saturday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:september workzone:datepicker:september - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:sunday workzone:datepicker:sunday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:thursday workzone:datepicker:thursday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:tuesday workzone:datepicker:tuesday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:wednesday workzone:datepicker:wednesday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig - - workzone:feedback:expiration - workzone:feedback:expiration - prod/WorkZone/Basket.html.twig - prod/Tooltip/Basket.html.twig + + workzone:feedback:expiration-closed + workzone:feedback:expiration-closed + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + + workzone:feedback:expiration-open + workzone:feedback:expiration-open + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig workzone:feedback:update workzone:feedback:update - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig yes diff --git a/resources/locales/validators.de.xlf b/resources/locales/validators.de.xlf index b7398ca514..4797cbcafd 100644 --- a/resources/locales/validators.de.xlf +++ b/resources/locales/validators.de.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. diff --git a/resources/locales/validators.en.xlf b/resources/locales/validators.en.xlf index f8d0a54e1d..398448e7d5 100644 --- a/resources/locales/validators.en.xlf +++ b/resources/locales/validators.en.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. diff --git a/resources/locales/validators.fr.xlf b/resources/locales/validators.fr.xlf index 6f350ddd76..8d7c716ebd 100644 --- a/resources/locales/validators.fr.xlf +++ b/resources/locales/validators.fr.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. diff --git a/resources/locales/validators.nl.xlf b/resources/locales/validators.nl.xlf index 2218c1ff00..0f8bf37ddc 100644 --- a/resources/locales/validators.nl.xlf +++ b/resources/locales/validators.nl.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. From a1deb3c28ffffefb42c249d5bae9d31735e9ac03 Mon Sep 17 00:00:00 2001 From: Harrys Ravalomanana Date: Tue, 17 Mar 2020 18:35:36 +0400 Subject: [PATCH 24/28] PHRAS-2978 fix date format --- lib/Alchemy/Phrasea/Controller/Prod/PushController.php | 2 +- lib/classes/phraseadate.php | 10 ++++++++++ templates/web/prod/WorkZone/Basket.html.twig | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Prod/PushController.php b/lib/Alchemy/Phrasea/Controller/Prod/PushController.php index c1fd5d8751..c9726d5faf 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/PushController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/PushController.php @@ -615,7 +615,7 @@ class PushController extends Controller $manager->beginTransaction(); try { $basket = $repository->findUserBasket($request->request->get('basket_id'), $this->app->getAuthenticatedUser(), true); - $date = new \DateTime($request->request->get('date')); + $date = new \DateTime($request->request->get('date') . " 23:59:59"); $validation = $basket->getValidation(); if (is_null($validation)) { return $this->app->json($ret); diff --git a/lib/classes/phraseadate.php b/lib/classes/phraseadate.php index 6acca8b75f..a9732e7822 100644 --- a/lib/classes/phraseadate.php +++ b/lib/classes/phraseadate.php @@ -120,6 +120,16 @@ class phraseadate } } + public function getTranslatedDate(DateTime $date = null) + { + $fmt = new IntlDateFormatter( + $this->app['locale'] ?: 'en', + NULL, NULL, NULL, NULL, 'dd MMMM yyyy' + ); + + return $fmt->format($date); + } + /** * * @param DateTime $date diff --git a/templates/web/prod/WorkZone/Basket.html.twig b/templates/web/prod/WorkZone/Basket.html.twig index d46d0f2f55..181382e612 100644 --- a/templates/web/prod/WorkZone/Basket.html.twig +++ b/templates/web/prod/WorkZone/Basket.html.twig @@ -99,7 +99,7 @@

{% trans with {'%nb_records%' : nb_records} %}%nb_records% records{% endtrans %}
- {% set dateExpired = app['date-formatter'].getPrettyString(basket.getValidation().getExpires()) %} + {% set dateExpired = app['date-formatter'].getTranslatedDate(basket.getValidation().getExpires()) %}
{% if date(dateExpired) < date() %} {{ 'workzone:feedback:expiration-closed' | trans }} : From 026148c58223bf65532c8687a7cb16c983b8188a Mon Sep 17 00:00:00 2001 From: Harrys Ravalomanana Date: Tue, 17 Mar 2020 18:40:05 +0400 Subject: [PATCH 25/28] PHRAS-2978 fix design --- templates/web/prod/WorkZone/Basket.html.twig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/templates/web/prod/WorkZone/Basket.html.twig b/templates/web/prod/WorkZone/Basket.html.twig index 181382e612..9f9995d634 100644 --- a/templates/web/prod/WorkZone/Basket.html.twig +++ b/templates/web/prod/WorkZone/Basket.html.twig @@ -111,7 +111,7 @@ - +

{{ 'prod:workzone:basket:updated-message' | trans }}

@@ -156,6 +156,7 @@ }, success: function (data) { $('.message').css('opacity',1); + $('.submit-validation').addClass('hidden'); setTimeout(function(){ $('.message').css('opacity',0); }, 2000); }, }); @@ -177,7 +178,10 @@ }; - $( ".feed-datepicker" ).datepicker( $.datepicker.regional[ 'default' ]); + $(".feed-datepicker" ).datepicker( $.datepicker.regional[ 'default' ]); + $(".feed-datepicker" ).change(function() { + $('.submit-validation').removeClass('hidden'); + }) }) From fba38da25cdeb70d06f66cc42c647b73d81496b5 Mon Sep 17 00:00:00 2001 From: Nicolas Maillat Date: Wed, 18 Mar 2020 01:33:39 +0000 Subject: [PATCH 26/28] Translated using Weblate (English) Currently translated at 98.9% (2451 of 2476 strings) --- resources/locales/messages.en.xlf | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/resources/locales/messages.en.xlf b/resources/locales/messages.en.xlf index 4c9560d4e9..4b5369e3e6 100644 --- a/resources/locales/messages.en.xlf +++ b/resources/locales/messages.en.xlf @@ -1,4 +1,4 @@ - +
@@ -7,8 +7,8 @@
- - + + Form/Login/PhraseaAuthenticationForm.php Form/Configuration/EmailFormType.php @@ -13432,14 +13432,14 @@ It is possible to place several search areas August prod/WorkZone/Basket.html.twig - + workzone:datepicker:closeText - workzone:datepicker:closeText + Close prod/WorkZone/Basket.html.twig - + workzone:datepicker:currentText - workzone:datepicker:currentText + Current prod/WorkZone/Basket.html.twig @@ -13543,9 +13543,9 @@ It is possible to place several search areas prod/WorkZone/Basket.html.twig prod/Tooltip/Basket.html.twig - + workzone:feedback:expiration-open - workzone:feedback:expiration-open + Feedback open until prod/WorkZone/Basket.html.twig prod/Tooltip/Basket.html.twig From 936c24329b4fc88950fdbee2b866897fe92d431a Mon Sep 17 00:00:00 2001 From: Nicolas Maillat Date: Wed, 18 Mar 2020 00:42:53 +0000 Subject: [PATCH 27/28] Translated using Weblate (French) Currently translated at 98.9% (2451 of 2476 strings) --- resources/locales/messages.fr.xlf | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/resources/locales/messages.fr.xlf b/resources/locales/messages.fr.xlf index be1a6c9a97..d830633044 100644 --- a/resources/locales/messages.fr.xlf +++ b/resources/locales/messages.fr.xlf @@ -1,4 +1,4 @@ - +
@@ -7,8 +7,8 @@
- - + + Form/Login/PhraseaAuthenticationForm.php Form/Configuration/EmailFormType.php @@ -13540,15 +13540,15 @@ Si vous recevez cet e-mail sans l'avoir sollicité, merci de l'ignorer ou de le Mercredi prod/WorkZone/Basket.html.twig
- + workzone:feedback:expiration-closed - workzone:feedback:expiration-closed + Validation close depuis prod/WorkZone/Basket.html.twig prod/Tooltip/Basket.html.twig - + workzone:feedback:expiration-open - workzone:feedback:expiration-open + validation ouverte jusqu'au prod/WorkZone/Basket.html.twig prod/Tooltip/Basket.html.twig From 4277bd5d064b48068781a1574e1ec37622639b04 Mon Sep 17 00:00:00 2001 From: aynsix Date: Wed, 18 Mar 2020 14:48:19 +0300 Subject: [PATCH 28/28] add command system:apply-rights --- bin/console | 2 + .../Phrasea/Command/ApplyRightsCommand.php | 89 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 lib/Alchemy/Phrasea/Command/ApplyRightsCommand.php diff --git a/bin/console b/bin/console index 0f315afa68..c49fc89052 100755 --- a/bin/console +++ b/bin/console @@ -57,6 +57,7 @@ use Alchemy\Phrasea\Command\User\UserCreateCommand; use Alchemy\Phrasea\Command\User\UserPasswordCommand; use Alchemy\Phrasea\Command\User\UserListCommand; use Alchemy\Phrasea\Command\UpgradeDBDatas; +use Alchemy\Phrasea\Command\ApplyRightsCommand; require_once __DIR__ . '/../lib/autoload.php'; @@ -93,6 +94,7 @@ $cli->command(new \module_console_aboutLicense('about:license')); $cli->command(new CheckConfig('check:config')); $cli->command(new UpgradeDBDatas('system:upgrade-datas')); +$cli->command(new ApplyRightsCommand('system:apply-rights')); $cli->command(new \module_console_systemMailCheck('system:mail-check')); $cli->command(new \module_console_systemBackupDB('system:backup-db')); diff --git a/lib/Alchemy/Phrasea/Command/ApplyRightsCommand.php b/lib/Alchemy/Phrasea/Command/ApplyRightsCommand.php new file mode 100644 index 0000000000..bcf0b3d0e7 --- /dev/null +++ b/lib/Alchemy/Phrasea/Command/ApplyRightsCommand.php @@ -0,0 +1,89 @@ +setDescription('Apply right on databox, inject appbox:basusr to dboxes:collusr') + ->addOption('user_id', null, InputOption::VALUE_REQUIRED, 'the user ID to apply rights') + ; + + return $this; + } + + protected function doExecute(InputInterface $input, OutputInterface $output) + { + $userId = $input->getOption('user_id'); + $userRepository = $this->container['repo.users']; + + if ($userId) { + if (($user = $userRepository->find($userId)) === null) { + $output->writeln('user not found!'); + + return 0; + } + + $this->injectRightsSbas($user); + } else { + foreach ($userRepository->findAll() as $user) { + $this->injectRightsSbas($user); + } + } + + $output->writeln('Apply right on databox finished!'); + + return 0; + } + + private function injectRightsSbas(User $user) + { + $userAcl = $this->container->getAclForUser($user); + + foreach ($userAcl->get_granted_sbas() as $databox) { + + $userAcl->delete_injected_rights_sbas($databox); + + $sql = "INSERT INTO collusr + (site, usr_id, coll_id, mask_and, mask_xor, ord) + VALUES (:site_id, :usr_id, :coll_id, :mask_and, :mask_xor, :ord)"; + $stmt = $databox->get_connection()->prepare($sql); + $iord = 0; + + // fix collusr if user has right on collection + foreach ($userAcl->get_granted_base([], [$databox->get_sbas_id()]) as $collection) { + try { + $stmt->execute([ + ':site_id' => $this->container['conf']->get(['main', 'key']), + ':usr_id' => $user->getId(), + ':coll_id' => $collection->get_coll_id(), + ':mask_and' => $userAcl->get_mask_and($collection->get_base_id()), + ':mask_xor' => $userAcl->get_mask_xor($collection->get_base_id()), + ':ord' => $iord++ + ]); + } catch (DBALException $e) { + + } + } + + $stmt->closeCursor(); + } + } +}