From ea8f95a31cbc0ab4a83aec6279db19a161e0dc8e Mon Sep 17 00:00:00 2001 From: jygaulier Date: Wed, 4 Oct 2023 16:45:16 +0200 Subject: [PATCH 1/4] WIP DO NOT MERGE add: stamp subdefs of class "preview" apply watermark on stamped subdef (cache to be fixed) fix: admin/collection settings (new ux, clean xml) --- .../Controller/Admin/CollectionController.php | 4 +- .../ControllerProvider/Admin/Collection.php | 2 + lib/classes/recordutils/image.php | 57 +- lib/classes/set/export.php | 28 +- .../collection/suggested_value.html.twig | 1220 ++++++----------- 5 files changed, 518 insertions(+), 793 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php b/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php index 89409b6958..d192fafbf6 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php @@ -803,7 +803,9 @@ public function submitSuggestedValues(Request $request, $bas_id) try { if ('' !== trim($prefs)) { $domdoc = new \DOMDocument(); - if (true === @$domdoc->loadXML($prefs)) { + if (true === @$domdoc->loadXML($prefs, LIBXML_NONET | LIBXML_NOBLANKS)) { + $domdoc->formatOutput = true; + $domdoc->saveXML(null, LIBXML_NOEMPTYTAG); $collection->set_prefs($domdoc); $success = true; } diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Collection.php b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Collection.php index 2daaf273f4..1e6e863aad 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Collection.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Collection.php @@ -52,10 +52,12 @@ public function connect(Application $app) ->assert('bas_id', '\d+') ->bind('admin_display_collection'); + /** @uses CollectionController::getSuggestedValues */ $controllers->get('/{bas_id}/suggested-values/', 'controller.admin.collection:getSuggestedValues') ->assert('bas_id', '\d+') ->bind('admin_collection_display_suggested_values'); + /** @uses CollectionController::submitSuggestedValues */ $controllers->post('/{bas_id}/suggested-values/', 'controller.admin.collection:submitSuggestedValues') ->assert('bas_id', '\d+') ->bind('admin_collection_submit_suggested_values'); diff --git a/lib/classes/recordutils/image.php b/lib/classes/recordutils/image.php index 6fd4aa5031..718c782baf 100644 --- a/lib/classes/recordutils/image.php +++ b/lib/classes/recordutils/image.php @@ -15,6 +15,7 @@ use Imagine\Image\Box; use Imagine\Image\ImagineInterface; use Imagine\Image\Palette\RGB; +use Imagine\Image\Palette\Color\ColorInterface; use Imagine\Image\Point; use MediaVorus\Media\Image; use MediaVorus\Media\MediaInterface; @@ -47,19 +48,22 @@ public static function stamp(Application $app, media_subdef $subdef) } $xmlToColor = function ($attr, $ret = [255, 255, 255]) use ($palette) { - try { - $alpha = 100; - $attr = explode(',', $attr); - if (count($attr) == 4) { - // 0..127 -> 100..0 - $alpha = (int)((127 - (int)array_pop($attr)) / 1.27); - } + if($attr !== null) { + try { + $alpha = 100; + $attr = explode(',', $attr); + if (count($attr) == 4) { + // 0..127 -> 100..0 + $alpha = (int)((127 - (int)array_pop($attr)) / 1.27); + } - return $palette->color($attr, $alpha); - } - catch (ImagineException $e) { - return $palette->color($ret); + return $palette->color($attr, $alpha); + } + catch (ImagineException $e) { + return $palette->color($ret); + } } + return null; }; $base_id = $subdef->get_record()->getBaseId(); @@ -287,10 +291,11 @@ public static function stamp(Application $app, media_subdef $subdef) if ($txtline != '') { $wrap = static::wrap($imagine, $fontsize, 0, __DIR__ . '/../../../resources/Fonts/arial.ttf', $txtline, $text_width); $txtblock[] = [ - 'fontsize' => $fontsize, - 'fontcolor' => $xmlToColor($texts->item($i)->getAttribute('color'), [0, 0, 0]), - 'h' => $wrap['toth'], - 'lines' => $wrap['l'] + 'fontsize' => $fontsize, + 'fontcolor' => $xmlToColor($texts->item($i)->getAttribute('color'), [0, 0, 0]), + 'shadowcolor' => $xmlToColor($texts->item($i)->getAttribute('shadow'), [0, 0, 0, 127]), + 'h' => $wrap['toth'], + 'lines' => $wrap['l'], ]; $txth += $wrap['toth']; } @@ -327,10 +332,22 @@ public static function stamp(Application $app, media_subdef $subdef) $draw = $imfg->draw(); $txt_ypos = 0; foreach ($txtblock as $block) { - $font = $imagine->font(__DIR__ . '/../../../resources/Fonts/arial.ttf', $block['fontsize'], $block['fontcolor']); + /** @var ColorInterface $color */ + $color = $block['fontcolor']; + $font = $imagine->font(__DIR__ . '/../../../resources/Fonts/arial.ttf', $block['fontsize'], $color); + $shadowFont = null; + $shadowDelta = 0; + if($block['shadowcolor'] !== null) { + $shadowFont = $imagine->font(__DIR__ . '/../../../resources/Fonts/arial.ttf', $block['fontsize'], $block['shadowcolor']); + $shadowDelta = max(2, (int)($block['fontsize'] / 20)); + } foreach ($block['lines'] as $line) { if ($line['t'] != '') { - $draw->text($line['t'], $font, new Point($logo_reswidth, $txt_ypos), 0); + if($shadowFont) { + $draw->text($line['t'], $shadowFont, new Point($logo_reswidth, $txt_ypos + $shadowDelta), 0); + $draw->text($line['t'], $shadowFont, new Point($logo_reswidth+1, $txt_ypos + $shadowDelta*1.5), 0); + } + $draw->text($line['t'], $font, new Point($logo_reswidth + $shadowDelta, $txt_ypos), 0); } $txt_ypos += $line['h']; } @@ -354,7 +371,7 @@ public static function stamp(Application $app, media_subdef $subdef) $newh = $tables['TOP']['h'] + $image_height + $tables['BOTTOM']['h']; // create the output image - $image_out = $imagine->create(new Box($image_width, $newh), $palette->color("FFFFFF", 64)); + $image_out = $imagine->create(new Box($image_width, $newh), $palette->color("FFFFFF")); // paste the input image into $image_out->paste($image_in, new Point(0, $tables['TOP']['h'])); @@ -414,7 +431,7 @@ public static function stamp(Application $app, media_subdef $subdef) * * @return boolean|string */ - public static function watermark(Application $app, media_subdef $subdef) + public static function watermark(Application $app, media_subdef $subdef, $otherPath = null) { static $palette; @@ -436,7 +453,7 @@ public static function watermark(Application $app, media_subdef $subdef) return false; } - $pathIn = $subdef->getRealPath(); + $pathIn = $otherPath ?? $subdef->getRealPath(); if (!is_file($pathIn)) { return false; diff --git a/lib/classes/set/export.php b/lib/classes/set/export.php index 9975ae7de1..bebc9007d0 100644 --- a/lib/classes/set/export.php +++ b/lib/classes/set/export.php @@ -563,18 +563,32 @@ public function prepare_export(User $user, Filesystem $filesystem, Array $wanted 'to_watermark' => false ]; + $stampedPath = null; + if($this->app['conf']->get(['registry', 'actions', 'export-stamp-choice']) !== true || $stampMethod !== self::NO_STAMP ){ + // stamp is mandatory, or user did not check "no stamp" : we must apply stamp + if($stampMethod === self::STAMP_SYNC) { + // we prepare a direct download, we must stamp now + $path = \recordutils_image::stamp($this->app, $sd[$subdefName]); + if ($path && file_exists($path)) { + $stampedPath = $path; + $tmp_pathfile['path'] = dirname($path); + $tmp_pathfile['file'] = basename($path); + } + } + else { + // we prepare an email or ftp download : the worker will apply stamp + $tmp_pathfile ['to_stamp'] = true; + } + } + if (!$this->app->getAclForUser($user)->has_right_on_base($download_element->getBaseId(), \ACL::NOWATERMARK) && !$this->app->getAclForUser($user)->has_preview_grant($download_element) && $sd[$subdefName]->get_type() == media_subdef::TYPE_IMAGE ) { - $path = recordutils_image::watermark($this->app, $sd[$subdefName]); + $path = recordutils_image::watermark($this->app, $sd[$subdefName], $stampedPath); if (file_exists($path)) { - $tmp_pathfile = [ - 'path' => dirname($path), - 'file' => basename($path), - 'to_stamp' => false, - 'to_watermark' => false - ]; + $tmp_pathfile['path'] = dirname($path); + $tmp_pathfile['file'] = basename($path); $subdef_ok = true; } } diff --git a/templates/web/admin/collection/suggested_value.html.twig b/templates/web/admin/collection/suggested_value.html.twig index ab2a63fdf8..e4b715cc7d 100644 --- a/templates/web/admin/collection/suggested_value.html.twig +++ b/templates/web/admin/collection/suggested_value.html.twig @@ -1,657 +1,406 @@ -
- - - - - - - - -
- - +
+
+ + + + + + + + +
+ + -{% if app['request'].query.get('success') == '1' %} + {% if app['request'].query.get('success') == '1' %}
× {{ 'Successful update' | trans }}
-{% elseif app['request'].query.get('success') == '0' %} + {% elseif app['request'].query.get('success') == '0' %}
× {{ 'An error occured' | trans }}
-{% endif %} - -
- - - - -
-
- {{ 'phraseanet::chargement' | trans }} -
-
-
+ {% endif %} + +
+ + + + +
+
+ {{ 'phraseanet::chargement' | trans }} +
+
+
-
-
- -
+ - From c0fcd608233ba4c3c33ed5f22797b1c6f5729bc8 Mon Sep 17 00:00:00 2001 From: jygaulier Date: Wed, 4 Oct 2023 16:45:16 +0200 Subject: [PATCH 2/4] WIP DO NOT MERGE add: stamp subdefs of class "preview" apply watermark on stamped subdef (cache to be fixed) fix: admin/collection settings (new ux, clean xml) --- .../Controller/Admin/CollectionController.php | 4 +- .../ControllerProvider/Admin/Collection.php | 2 + lib/classes/recordutils/image.php | 57 +- lib/classes/set/export.php | 28 +- .../collection/suggested_value.html.twig | 1220 ++++++----------- 5 files changed, 518 insertions(+), 793 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php b/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php index 89409b6958..d192fafbf6 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php @@ -803,7 +803,9 @@ public function submitSuggestedValues(Request $request, $bas_id) try { if ('' !== trim($prefs)) { $domdoc = new \DOMDocument(); - if (true === @$domdoc->loadXML($prefs)) { + if (true === @$domdoc->loadXML($prefs, LIBXML_NONET | LIBXML_NOBLANKS)) { + $domdoc->formatOutput = true; + $domdoc->saveXML(null, LIBXML_NOEMPTYTAG); $collection->set_prefs($domdoc); $success = true; } diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Collection.php b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Collection.php index 2daaf273f4..1e6e863aad 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Collection.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Collection.php @@ -52,10 +52,12 @@ public function connect(Application $app) ->assert('bas_id', '\d+') ->bind('admin_display_collection'); + /** @uses CollectionController::getSuggestedValues */ $controllers->get('/{bas_id}/suggested-values/', 'controller.admin.collection:getSuggestedValues') ->assert('bas_id', '\d+') ->bind('admin_collection_display_suggested_values'); + /** @uses CollectionController::submitSuggestedValues */ $controllers->post('/{bas_id}/suggested-values/', 'controller.admin.collection:submitSuggestedValues') ->assert('bas_id', '\d+') ->bind('admin_collection_submit_suggested_values'); diff --git a/lib/classes/recordutils/image.php b/lib/classes/recordutils/image.php index 6fd4aa5031..718c782baf 100644 --- a/lib/classes/recordutils/image.php +++ b/lib/classes/recordutils/image.php @@ -15,6 +15,7 @@ use Imagine\Image\Box; use Imagine\Image\ImagineInterface; use Imagine\Image\Palette\RGB; +use Imagine\Image\Palette\Color\ColorInterface; use Imagine\Image\Point; use MediaVorus\Media\Image; use MediaVorus\Media\MediaInterface; @@ -47,19 +48,22 @@ public static function stamp(Application $app, media_subdef $subdef) } $xmlToColor = function ($attr, $ret = [255, 255, 255]) use ($palette) { - try { - $alpha = 100; - $attr = explode(',', $attr); - if (count($attr) == 4) { - // 0..127 -> 100..0 - $alpha = (int)((127 - (int)array_pop($attr)) / 1.27); - } + if($attr !== null) { + try { + $alpha = 100; + $attr = explode(',', $attr); + if (count($attr) == 4) { + // 0..127 -> 100..0 + $alpha = (int)((127 - (int)array_pop($attr)) / 1.27); + } - return $palette->color($attr, $alpha); - } - catch (ImagineException $e) { - return $palette->color($ret); + return $palette->color($attr, $alpha); + } + catch (ImagineException $e) { + return $palette->color($ret); + } } + return null; }; $base_id = $subdef->get_record()->getBaseId(); @@ -287,10 +291,11 @@ public static function stamp(Application $app, media_subdef $subdef) if ($txtline != '') { $wrap = static::wrap($imagine, $fontsize, 0, __DIR__ . '/../../../resources/Fonts/arial.ttf', $txtline, $text_width); $txtblock[] = [ - 'fontsize' => $fontsize, - 'fontcolor' => $xmlToColor($texts->item($i)->getAttribute('color'), [0, 0, 0]), - 'h' => $wrap['toth'], - 'lines' => $wrap['l'] + 'fontsize' => $fontsize, + 'fontcolor' => $xmlToColor($texts->item($i)->getAttribute('color'), [0, 0, 0]), + 'shadowcolor' => $xmlToColor($texts->item($i)->getAttribute('shadow'), [0, 0, 0, 127]), + 'h' => $wrap['toth'], + 'lines' => $wrap['l'], ]; $txth += $wrap['toth']; } @@ -327,10 +332,22 @@ public static function stamp(Application $app, media_subdef $subdef) $draw = $imfg->draw(); $txt_ypos = 0; foreach ($txtblock as $block) { - $font = $imagine->font(__DIR__ . '/../../../resources/Fonts/arial.ttf', $block['fontsize'], $block['fontcolor']); + /** @var ColorInterface $color */ + $color = $block['fontcolor']; + $font = $imagine->font(__DIR__ . '/../../../resources/Fonts/arial.ttf', $block['fontsize'], $color); + $shadowFont = null; + $shadowDelta = 0; + if($block['shadowcolor'] !== null) { + $shadowFont = $imagine->font(__DIR__ . '/../../../resources/Fonts/arial.ttf', $block['fontsize'], $block['shadowcolor']); + $shadowDelta = max(2, (int)($block['fontsize'] / 20)); + } foreach ($block['lines'] as $line) { if ($line['t'] != '') { - $draw->text($line['t'], $font, new Point($logo_reswidth, $txt_ypos), 0); + if($shadowFont) { + $draw->text($line['t'], $shadowFont, new Point($logo_reswidth, $txt_ypos + $shadowDelta), 0); + $draw->text($line['t'], $shadowFont, new Point($logo_reswidth+1, $txt_ypos + $shadowDelta*1.5), 0); + } + $draw->text($line['t'], $font, new Point($logo_reswidth + $shadowDelta, $txt_ypos), 0); } $txt_ypos += $line['h']; } @@ -354,7 +371,7 @@ public static function stamp(Application $app, media_subdef $subdef) $newh = $tables['TOP']['h'] + $image_height + $tables['BOTTOM']['h']; // create the output image - $image_out = $imagine->create(new Box($image_width, $newh), $palette->color("FFFFFF", 64)); + $image_out = $imagine->create(new Box($image_width, $newh), $palette->color("FFFFFF")); // paste the input image into $image_out->paste($image_in, new Point(0, $tables['TOP']['h'])); @@ -414,7 +431,7 @@ public static function stamp(Application $app, media_subdef $subdef) * * @return boolean|string */ - public static function watermark(Application $app, media_subdef $subdef) + public static function watermark(Application $app, media_subdef $subdef, $otherPath = null) { static $palette; @@ -436,7 +453,7 @@ public static function watermark(Application $app, media_subdef $subdef) return false; } - $pathIn = $subdef->getRealPath(); + $pathIn = $otherPath ?? $subdef->getRealPath(); if (!is_file($pathIn)) { return false; diff --git a/lib/classes/set/export.php b/lib/classes/set/export.php index 9975ae7de1..bebc9007d0 100644 --- a/lib/classes/set/export.php +++ b/lib/classes/set/export.php @@ -563,18 +563,32 @@ public function prepare_export(User $user, Filesystem $filesystem, Array $wanted 'to_watermark' => false ]; + $stampedPath = null; + if($this->app['conf']->get(['registry', 'actions', 'export-stamp-choice']) !== true || $stampMethod !== self::NO_STAMP ){ + // stamp is mandatory, or user did not check "no stamp" : we must apply stamp + if($stampMethod === self::STAMP_SYNC) { + // we prepare a direct download, we must stamp now + $path = \recordutils_image::stamp($this->app, $sd[$subdefName]); + if ($path && file_exists($path)) { + $stampedPath = $path; + $tmp_pathfile['path'] = dirname($path); + $tmp_pathfile['file'] = basename($path); + } + } + else { + // we prepare an email or ftp download : the worker will apply stamp + $tmp_pathfile ['to_stamp'] = true; + } + } + if (!$this->app->getAclForUser($user)->has_right_on_base($download_element->getBaseId(), \ACL::NOWATERMARK) && !$this->app->getAclForUser($user)->has_preview_grant($download_element) && $sd[$subdefName]->get_type() == media_subdef::TYPE_IMAGE ) { - $path = recordutils_image::watermark($this->app, $sd[$subdefName]); + $path = recordutils_image::watermark($this->app, $sd[$subdefName], $stampedPath); if (file_exists($path)) { - $tmp_pathfile = [ - 'path' => dirname($path), - 'file' => basename($path), - 'to_stamp' => false, - 'to_watermark' => false - ]; + $tmp_pathfile['path'] = dirname($path); + $tmp_pathfile['file'] = basename($path); $subdef_ok = true; } } diff --git a/templates/web/admin/collection/suggested_value.html.twig b/templates/web/admin/collection/suggested_value.html.twig index ab2a63fdf8..e4b715cc7d 100644 --- a/templates/web/admin/collection/suggested_value.html.twig +++ b/templates/web/admin/collection/suggested_value.html.twig @@ -1,657 +1,406 @@ -
- - - - - - - - -
- - +
+
+ + + + + + + + +
+ + -{% if app['request'].query.get('success') == '1' %} + {% if app['request'].query.get('success') == '1' %}
× {{ 'Successful update' | trans }}
-{% elseif app['request'].query.get('success') == '0' %} + {% elseif app['request'].query.get('success') == '0' %}
× {{ 'An error occured' | trans }}
-{% endif %} - -
- - - - -
-
- {{ 'phraseanet::chargement' | trans }} -
-
-
+ {% endif %} + +
+ + + + +
+
+ {{ 'phraseanet::chargement' | trans }} +
+
+
-
-
- -
+ - From 7a33a2d1392e6fc4d97ca141cd7ade652b49a802 Mon Sep 17 00:00:00 2001 From: jygaulier Date: Wed, 25 Oct 2023 18:26:00 +0200 Subject: [PATCH 3/4] conf.export_stamp_choice now supports 'manage_collection' and 'manage_databox' (and bc true) to restrict right to remove stamp. --- .../Controller/Prod/DownloadController.php | 14 ++- .../Controller/Prod/ExportController.php | 75 +++++++++++-- .../Order/Controller/ApiOrderController.php | 11 +- lib/classes/set/export.php | 103 +++++++++++++++--- templates/web/common/dialog_export.html.twig | 5 +- 5 files changed, 183 insertions(+), 25 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Prod/DownloadController.php b/lib/Alchemy/Phrasea/Controller/Prod/DownloadController.php index c575c86431..80077bea38 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/DownloadController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/DownloadController.php @@ -13,6 +13,7 @@ use Alchemy\Phrasea\Controller\Controller; use Alchemy\Phrasea\Core\Event\ExportEvent; use Alchemy\Phrasea\Core\PhraseaEvents; +use Alchemy\Phrasea\Filesystem\PhraseanetFilesystem; use Alchemy\Phrasea\Model\Manipulator\TokenManipulator; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; @@ -45,11 +46,13 @@ public function checkDownload(Request $request) $list = $download->prepare_export( $this->getAuthenticatedUser(), - $this->app['filesystem'], + $this->getFilesystem(), $subdefs, $request->request->get('type') === 'title' ? true : false, $request->request->get('businessfields'), - $request->request->get('stamp_choice') === "NO_STAMP" ? \set_export::NO_STAMP : \set_export::STAMP_SYNC + \set_export::STAMP_SYNC, + $request->request->get('stamp_choice') === "REMOVE_STAMP", + false ); $list['export_name'] = sprintf('%s.zip', $download->getExportName()); @@ -68,4 +71,11 @@ private function getTokenManipulator() { return $this->app['manipulator.token']; } + /** + * @return PhraseanetFilesystem + */ + private function getFilesystem() + { + return $this->app['filesystem']; + } } diff --git a/lib/Alchemy/Phrasea/Controller/Prod/ExportController.php b/lib/Alchemy/Phrasea/Controller/Prod/ExportController.php index 4ef91b65c5..0b47a076a2 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/ExportController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/ExportController.php @@ -9,6 +9,7 @@ */ namespace Alchemy\Phrasea\Controller\Prod; +use ACL; use Alchemy\Phrasea\Application\Helper\DispatcherAware; use Alchemy\Phrasea\Application\Helper\FilesystemAware; use Alchemy\Phrasea\Application\Helper\NotifierAware; @@ -19,6 +20,8 @@ use Alchemy\Phrasea\Model\Manipulator\TokenManipulator; use Alchemy\Phrasea\WorkerManager\Event\ExportFtpEvent; use Alchemy\Phrasea\WorkerManager\Event\WorkerEvents; +use DOMDocument; +use DOMXPath; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -29,6 +32,15 @@ class ExportController extends Controller use FilesystemAware; use NotifierAware; + /** + * @return ACL + */ + private function getAclForConnectedUser() + { + return $this->getAclForUser($this->getAuthenticatedUser()); + } + + /** * Display form to export documents * @@ -44,17 +56,63 @@ public function displayMultiExport(Request $request) $request->request->get('story') ); + // we must propose "do not stamp" when at least one collection is stamped AND the user has right to + // remove stamp on this collection + $removeable_stamp = false; // true if at least one coll is "unstampable" + $removeable_stamp_by_base = []; // unset: no stamp ; false: stamp not "unstampable" ; true: stamp "unstampable" + + $colls_manageable = array_keys($this->getAclForConnectedUser()->get_granted_base([ACL::COLL_MANAGE])); + $dbox_manageable = array_keys($this->getAclForConnectedUser()->get_granted_sbas([ACL::BAS_MANAGE])); + + foreach($download->get_elements() as $recordAdapter) { + // check collection only once + if(array_key_exists($bid = $recordAdapter->getCollection()->get_base_id(), $removeable_stamp_by_base)) { + continue; + } + // check stamp + $domprefs = new DOMDocument(); + if ( !$domprefs->loadXML($recordAdapter->getCollection()->get_prefs()) ) { + continue; + } + $xpprefs = new DOMXPath($domprefs); + if ($xpprefs->query('/baseprefs/stamp')->length == 0) { + // the collection has no stamp settings + continue; + } + unset($domprefs); + // the collection has stamp, check user's right to remove it + $removeable_stamp_by_base[$bid] = false; + switch ((string)$this->getConf()->get(['registry', 'actions', 'export-stamp-choice'], false)) { + case '1': // == (string)true + // everybody can remove stamp (bc) + $removeable_stamp_by_base[$bid] = $removeable_stamp = true; + break; + case 'manage_collection': + if (in_array($bid, $colls_manageable)) { + $removeable_stamp_by_base[$bid] = $removeable_stamp = true; + } + break; + case 'manage_databox': + if (in_array($recordAdapter->getDatabox()->get_sbas_id(), $dbox_manageable)) { + $removeable_stamp_by_base[$bid] = $removeable_stamp = true; + } + break; + } + } + $this->setSessionFormToken('prodExportDownload'); $this->setSessionFormToken('prodExportEmail'); $this->setSessionFormToken('prodExportFTP'); $this->setSessionFormToken('prodExportOrder'); return new Response($this->render('common/dialog_export.html.twig', [ - 'download' => $download, - 'ssttid' => $request->request->get('ssel'), - 'lst' => $download->serialize_list(), - 'default_export_title' => $this->getConf()->get(['registry', 'actions', 'default-export-title']), - 'choose_export_title' => $this->getConf()->get(['registry', 'actions', 'export-title-choice']) + 'download' => $download, + 'ssttid' => $request->request->get('ssel'), + 'lst' => $download->serialize_list(), + 'default_export_title' => $this->getConf()->get(['registry', 'actions', 'default-export-title']), + 'choose_export_title' => $this->getConf()->get(['registry', 'actions', 'export-title-choice']), + 'removeable_stamp' => $removeable_stamp, + 'removeable_stamp_by_base' => $removeable_stamp_by_base, ])); } @@ -123,7 +181,9 @@ public function exportFtp(Request $request) $request->request->get('obj'), false, $request->request->get('businessfields'), - $request->request->get('stamp_choice') === "NO_STAMP" ? \set_export::NO_STAMP : \set_export::STAMP_ASYNC + \set_export::STAMP_ASYNC, + $request->request->get('stamp_choice') === "REMOVE_STAMP", + false ); $exportFtpId = $download->export_ftp( @@ -181,7 +241,8 @@ public function exportMail(Request $request) (array) $request->request->get('obj'), $request->request->get("type") == "title" ? : false, $request->request->get('businessfields'), - $request->request->get('stamp_choice') === "NO_STAMP" ? \set_export::NO_STAMP : \set_export::STAMP_ASYNC, + \set_export::STAMP_ASYNC, + $request->request->get('stamp_choice') === "REMOVE_STAMP", true ); diff --git a/lib/Alchemy/Phrasea/Order/Controller/ApiOrderController.php b/lib/Alchemy/Phrasea/Order/Controller/ApiOrderController.php index c61e27d1c6..bb802fb966 100644 --- a/lib/Alchemy/Phrasea/Order/Controller/ApiOrderController.php +++ b/lib/Alchemy/Phrasea/Order/Controller/ApiOrderController.php @@ -189,7 +189,16 @@ public function getArchiveAction($orderId) $subdefs = $this->findDataboxSubdefNames(); try { - $exportData = $export->prepare_export($user, $this->getFilesystem(), $subdefs, true, true, false); + $exportData = $export->prepare_export( + $user, + $this->getFilesystem(), + $subdefs, + true, + true, + \set_export::STAMP_SYNC, + false, + false + ); } catch (\Exception $e) { throw new NotFoundHttpException(sprintf('No archive could be downloaded for Order "%d"', $order->getId())); diff --git a/lib/classes/set/export.php b/lib/classes/set/export.php index bebc9007d0..9795b99f1a 100644 --- a/lib/classes/set/export.php +++ b/lib/classes/set/export.php @@ -9,6 +9,8 @@ */ use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Authentication\ACLProvider; +use Alchemy\Phrasea\Core\Configuration\PropertyAccess; use Alchemy\Phrasea\Filesystem\PhraseanetFilesystem as Filesystem; use Alchemy\Phrasea\Model\Entities\Token; use Alchemy\Phrasea\Model\Entities\User; @@ -183,7 +185,7 @@ public function __construct(Application $app, $lst, $sstid, $storyWZid = null) /** @var record_exportElement $download_element */ foreach ($this->get_elements() as $download_element) { - if ($app->getAclForUser($app->getAuthenticatedUser())->has_right_on_base($download_element->getBaseId(), \ACL::CANMODIFRECORD)) { + if ($app->getAclForUser($app->getAuthenticatedUser())->has_right_on_base($download_element->getBaseId(), ACL::CANMODIFRECORD)) { $this->businessFieldsAccess = true; } @@ -235,11 +237,11 @@ public function __construct(Application $app, $lst, $sstid, $storyWZid = null) $display_ftp = []; - $hasadminright = $app->getAclForUser($app->getAuthenticatedUser())->has_right(\ACL::CANADDRECORD) - || $app->getAclForUser($app->getAuthenticatedUser())->has_right(\ACL::CANDELETERECORD) - || $app->getAclForUser($app->getAuthenticatedUser())->has_right(\ACL::CANMODIFRECORD) - || $app->getAclForUser($app->getAuthenticatedUser())->has_right(\ACL::COLL_MANAGE) - || $app->getAclForUser($app->getAuthenticatedUser())->has_right(\ACL::COLL_MODIFY_STRUCT); + $hasadminright = $app->getAclForUser($app->getAuthenticatedUser())->has_right(ACL::CANADDRECORD) + || $app->getAclForUser($app->getAuthenticatedUser())->has_right(ACL::CANDELETERECORD) + || $app->getAclForUser($app->getAuthenticatedUser())->has_right(ACL::CANMODIFRECORD) + || $app->getAclForUser($app->getAuthenticatedUser())->has_right(ACL::COLL_MANAGE) + || $app->getAclForUser($app->getAuthenticatedUser())->has_right(ACL::COLL_MODIFY_STRUCT); $this->ftp_datas = []; @@ -391,6 +393,35 @@ public function get_total_ftp() return $this->total_ftp; } + /** + * @return ACLProvider + */ + private function getAclProvider() + { + return $this->app['acl']; + } + + /** + * Gets ACL for user. + * + * @param User $user + * + * @return ACL + */ + private function getAclForUser(User $user) + { + return $this->getAclProvider()->get($user); + } + + /** + * @return PropertyAccess + */ + protected function getConf() + { + return $this->app['conf']; + } + + const NO_STAMP = 'NO_STAMP'; const STAMP_SYNC = 'STAMP_SYNC'; const STAMP_ASYNC = 'STAMP_ASYNC'; @@ -404,7 +435,7 @@ public function get_total_ftp() * @return array * @throws Exception */ - public function prepare_export(User $user, Filesystem $filesystem, Array $wantedSubdefs, $rename_title, $includeBusinessFields, $stampMethod, $exportEmail = false) + public function prepare_export(User $user, Filesystem $filesystem, Array $wantedSubdefs, $rename_title, $includeBusinessFields, $stampMethod, $removeStamp, $exportEmail) { if (!is_array($wantedSubdefs)) { throw new Exception('No subdefs given'); @@ -422,6 +453,13 @@ public function prepare_export(User $user, Filesystem $filesystem, Array $wanted $size = 0; $unicode = $this->app['unicode']; + // we must propose "do not stamp" when at least one collection is stamped AND the user has right to + // remove stamp on this collection + $stamp_by_base = []; // unset: no stamp ; false: stamp not "unstampable" ; true: stamp "unstampable" + + $colls_manageable = array_keys($this->getAclForUser($user)->get_granted_base([ACL::COLL_MANAGE])); + $dbox_manageable = array_keys($this->getAclForUser($user)->get_granted_sbas([ACL::BAS_MANAGE])); + /** @var record_exportElement $download_element */ foreach ($this->elements as $download_element) { @@ -438,10 +476,49 @@ public function prepare_export(User $user, Filesystem $filesystem, Array $wanted $BF = false; - if ($includeBusinessFields && $this->app->getAclForUser($user)->has_right_on_base($download_element->getBaseId(), \ACL::CANMODIFRECORD)) { + if ($includeBusinessFields && $this->app->getAclForUser($user)->has_right_on_base($download_element->getBaseId(), ACL::CANMODIFRECORD)) { $BF = true; } + // check if stamp can be removed + // check collection only once + if(!array_key_exists($bid = $download_element->getCollection()->get_base_id(), $stamp_by_base)) { + // check stamp + $stamp_by_base[$bid] = self::NO_STAMP; + + $domprefs = new DOMDocument(); + if ($domprefs->loadXML($download_element->getCollection()->get_prefs())) { + $xpprefs = new DOMXPath($domprefs); + if ($xpprefs->query('/baseprefs/stamp')->length != 0) { + // the collection has stamp settings + unset($domprefs); + + // the collection has stamp, check user's right to remove it + $stamp_by_base[$bid] = $stampMethod; + if($removeStamp) { // user asked to remove stamp + switch ((string)$this->getConf()->get(['registry', 'actions', 'export-stamp-choice'], false)) { + case '1': // == (string)true + // everybody can remove stamp (bc) + $stamp_by_base[$bid] = self::NO_STAMP; + break; + case 'manage_collection': + if (in_array($bid, $colls_manageable)) { + $stamp_by_base[$bid] = self::NO_STAMP; + } + break; + case 'manage_databox': + if (in_array($download_element->getDatabox()->get_sbas_id(), $dbox_manageable)) { + $stamp_by_base[$bid] = self::NO_STAMP; + } + break; + } + } + } + } + } + $files[$id]['to_stamp'] = $stamp_by_base[$bid]; + + // $original_name : the original_name WITHOUT extension (ex. "DSC_1234") // $extension : the extension WITHOUT DOT (ex. "jpg") // $export_name : the export name WITHOUT extension, (ex. "Hollydays_2016_DSC_1234") @@ -534,9 +611,9 @@ public function prepare_export(User $user, Filesystem $filesystem, Array $wanted 'to_watermark' => false ]; - if($this->app['conf']->get(['registry', 'actions', 'export-stamp-choice']) !== true || $stampMethod !== self::NO_STAMP ){ + if($files[$id]['to_stamp'] !== self::NO_STAMP){ // stamp is mandatory, or user did not check "no stamp" : we must apply stamp - if($stampMethod === self::STAMP_SYNC) { + if($files[$id]['to_stamp'] === self::STAMP_SYNC) { // we prepare a direct download, we must stamp now $path = \recordutils_image::stamp($this->app, $sd[$subdefName]); if ($path && file_exists($path)) { @@ -564,9 +641,9 @@ public function prepare_export(User $user, Filesystem $filesystem, Array $wanted ]; $stampedPath = null; - if($this->app['conf']->get(['registry', 'actions', 'export-stamp-choice']) !== true || $stampMethod !== self::NO_STAMP ){ + if($files[$id]['to_stamp'] !== self::NO_STAMP){ // stamp is mandatory, or user did not check "no stamp" : we must apply stamp - if($stampMethod === self::STAMP_SYNC) { + if($files[$id]['to_stamp'] === self::STAMP_SYNC) { // we prepare a direct download, we must stamp now $path = \recordutils_image::stamp($this->app, $sd[$subdefName]); if ($path && file_exists($path)) { @@ -581,7 +658,7 @@ public function prepare_export(User $user, Filesystem $filesystem, Array $wanted } } - if (!$this->app->getAclForUser($user)->has_right_on_base($download_element->getBaseId(), \ACL::NOWATERMARK) + if (!$this->app->getAclForUser($user)->has_right_on_base($download_element->getBaseId(), ACL::NOWATERMARK) && !$this->app->getAclForUser($user)->has_preview_grant($download_element) && $sd[$subdefName]->get_type() == media_subdef::TYPE_IMAGE ) { diff --git a/templates/web/common/dialog_export.html.twig b/templates/web/common/dialog_export.html.twig index b99a837708..ef5184f873 100644 --- a/templates/web/common/dialog_export.html.twig +++ b/templates/web/common/dialog_export.html.twig @@ -108,6 +108,7 @@

{{ 'export:: telechargement' | trans }}

+ {# @controller Alchemy\Phrasea\Controller\Prod\DownloadController:checkDownload #}
@@ -156,10 +157,10 @@
{% endif %} - {% if app['conf'].get(['registry', 'actions', 'export-stamp-choice']) == true and download.has_stamp_option() == true %} + {% if removeable_stamp and download.has_stamp_option() == true %}
From d3a46f254fe6a63f0c2b89b9dc02b17d49bce06e Mon Sep 17 00:00:00 2001 From: jygaulier Date: Wed, 25 Oct 2023 19:34:25 +0200 Subject: [PATCH 4/4] fix test --- lib/Alchemy/Phrasea/Controller/Prod/ExportController.php | 4 ++-- lib/classes/set/export.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Prod/ExportController.php b/lib/Alchemy/Phrasea/Controller/Prod/ExportController.php index 0b47a076a2..6ccea28428 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/ExportController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/ExportController.php @@ -61,8 +61,8 @@ public function displayMultiExport(Request $request) $removeable_stamp = false; // true if at least one coll is "unstampable" $removeable_stamp_by_base = []; // unset: no stamp ; false: stamp not "unstampable" ; true: stamp "unstampable" - $colls_manageable = array_keys($this->getAclForConnectedUser()->get_granted_base([ACL::COLL_MANAGE])); - $dbox_manageable = array_keys($this->getAclForConnectedUser()->get_granted_sbas([ACL::BAS_MANAGE])); + $colls_manageable = array_keys($this->getAclForConnectedUser()->get_granted_base([ACL::COLL_MANAGE]) ?? []); + $dbox_manageable = array_keys($this->getAclForConnectedUser()->get_granted_sbas([ACL::BAS_MANAGE]) ?? []); foreach($download->get_elements() as $recordAdapter) { // check collection only once diff --git a/lib/classes/set/export.php b/lib/classes/set/export.php index 9795b99f1a..b72b80f9c8 100644 --- a/lib/classes/set/export.php +++ b/lib/classes/set/export.php @@ -457,8 +457,8 @@ public function prepare_export(User $user, Filesystem $filesystem, Array $wanted // remove stamp on this collection $stamp_by_base = []; // unset: no stamp ; false: stamp not "unstampable" ; true: stamp "unstampable" - $colls_manageable = array_keys($this->getAclForUser($user)->get_granted_base([ACL::COLL_MANAGE])); - $dbox_manageable = array_keys($this->getAclForUser($user)->get_granted_sbas([ACL::BAS_MANAGE])); + $colls_manageable = array_keys($this->getAclForUser($user)->get_granted_base([ACL::COLL_MANAGE]) ?? []); + $dbox_manageable = array_keys($this->getAclForUser($user)->get_granted_sbas([ACL::BAS_MANAGE]) ?? []); /** @var record_exportElement $download_element */ foreach ($this->elements as $download_element) {