From ff9bad2ea00e100f438427c9abcace313493a18a Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Mon, 3 Aug 2020 11:37:07 +0200 Subject: [PATCH] Allows profile to override the avatar of employee --- .gitignore | 1 + classes/Employee.php | 28 ++++-- classes/Profile.php | 10 +++ config/defines.inc.php | 1 + config/defines_uri.inc.php | 1 + img/pr/index.php | 35 ++++++++ .../Image/Uploader/ProfileImageUploader.php | 90 +++++++++++++++++++ .../GetProfileForEditingHandler.php | 49 +++++++++- .../Profile/QueryResult/EditableProfile.php | 22 ++++- .../DataHandler/EmployeeFormDataHandler.php | 2 +- .../DataHandler/ProfileFormDataHandler.php | 28 +++++- .../AdvancedParameters/ProfileController.php | 7 +- .../Profile/ProfileType.php | 7 ++ .../config/services/adapter/image.yml | 6 ++ .../config/services/adapter/profile.yml | 2 + .../services/core/form/form_data_handler.yml | 1 + .../Profiles/Blocks/form.html.twig | 13 +++ .../Profiles/create.html.twig | 4 +- .../Profiles/edit.html.twig | 4 +- 19 files changed, 288 insertions(+), 23 deletions(-) create mode 100644 img/pr/index.php create mode 100644 src/Adapter/Image/Uploader/ProfileImageUploader.php diff --git a/.gitignore b/.gitignore index 84176f4789a51..e0962bdb26e9d 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,7 @@ npm-debug.log.* !/img/m/index.php !/img/os/index.php !/img/p/index.php +!/img/pr/index.php !/img/s/index.php !/img/scenes !/img/st/index.php diff --git a/classes/Employee.php b/classes/Employee.php index 61cabe338d2b8..910d7525dc431 100644 --- a/classes/Employee.php +++ b/classes/Employee.php @@ -599,8 +599,23 @@ public function isSuperAdmin() */ public function getImage() { - $default = Tools::getAdminImageUrl('prestashop-avatar.png'); - $imageUrl = ''; + $defaultSystem = Tools::getAdminImageUrl('prestashop-avatar.png'); + $imageUrl = null; + + // Default from Profile + $profile = new Profile($this->id_profile); + $profilePath = $profile ? ($profile->image_dir . $profile->id . '.jpg') : ''; + $defaultProfile = file_exists($profilePath) + ? Context::getContext()->link->getMediaLink( + str_replace($profile->image_dir, _THEME_PROFILE_DIR_, $profilePath) + ) + : null; + $imageUrl = $imageUrl ?? $defaultProfile; + + // Gravatar + if ($this->has_enabled_gravatar) { + $imageUrl = $imageUrl ?? 'https://www.gravatar.com/avatar/' . md5(strtolower(trim($this->email))) . '?d=' . urlencode($defaultSystem); + } // Local Image $imagePath = $this->image_dir . $this->id . '.jpg'; @@ -610,13 +625,8 @@ public function getImage() ); } - // Default Image - $imageUrl = $imageUrl ?? $default; - - // Gravatar - if ($this->has_enabled_gravatar) { - $imageUrl = 'https://www.gravatar.com/avatar/' . md5(strtolower(trim($this->email))) . '?d=' . urlencode($default); - } + // Default from System + $imageUrl = $imageUrl ?? $defaultSystem; // Hooks Hook::exec( diff --git a/classes/Profile.php b/classes/Profile.php index 3011b76de02bd..81fc98e912344 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -52,6 +52,16 @@ class ProfileCore extends ObjectModel protected static $_cache_accesses = []; + /** + * {@inheritdoc} + */ + public function __construct($id = null, $idLang = null, $idShop = null, $translator = null) + { + parent::__construct($id, $idLang, $idShop, $translator); + + $this->image_dir = _PS_PROFILE_IMG_DIR_; + } + /** * Get all available profiles. * diff --git a/config/defines.inc.php b/config/defines.inc.php index 54e8338d7cc9f..37ca970221db1 100755 --- a/config/defines.inc.php +++ b/config/defines.inc.php @@ -151,6 +151,7 @@ define('_PS_MANU_IMG_DIR_', _PS_IMG_DIR_.'m/'); define('_PS_ORDER_STATE_IMG_DIR_', _PS_IMG_DIR_.'os/'); define('_PS_PROD_IMG_DIR_', _PS_IMG_DIR_.'p/'); +define('_PS_PROFILE_IMG_DIR_', _PS_IMG_DIR_.'pr/'); define('_PS_SHIP_IMG_DIR_', _PS_IMG_DIR_.'s/'); define('_PS_STORE_IMG_DIR_', _PS_IMG_DIR_.'st/'); define('_PS_SUPP_IMG_DIR_', _PS_IMG_DIR_.'su/'); diff --git a/config/defines_uri.inc.php b/config/defines_uri.inc.php index aaec64f75e38d..49f4b177974b6 100644 --- a/config/defines_uri.inc.php +++ b/config/defines_uri.inc.php @@ -49,6 +49,7 @@ define('_THEME_CAT_DIR_', _PS_IMG_.'c/'); define('_THEME_EMPLOYEE_DIR_', _PS_IMG_.'e/'); define('_THEME_PROD_DIR_', _PS_IMG_.'p/'); +define('_THEME_PROFILE_DIR_', _PS_IMG_.'pr/'); define('_THEME_MANU_DIR_', _PS_IMG_.'m/'); define('_THEME_SUP_DIR_', _PS_IMG_.'su/'); define('_THEME_SHIP_DIR_', _PS_IMG_.'s/'); diff --git a/img/pr/index.php b/img/pr/index.php new file mode 100644 index 0000000000000..76cd9dd33aea9 --- /dev/null +++ b/img/pr/index.php @@ -0,0 +1,35 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + */ + +header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); +header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); + +header("Cache-Control: no-store, no-cache, must-revalidate"); +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); + +header("Location: ../"); +exit; diff --git a/src/Adapter/Image/Uploader/ProfileImageUploader.php b/src/Adapter/Image/Uploader/ProfileImageUploader.php new file mode 100644 index 0000000000000..8dc521860f767 --- /dev/null +++ b/src/Adapter/Image/Uploader/ProfileImageUploader.php @@ -0,0 +1,90 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + */ + +declare(strict_types=1); + +namespace PrestaShop\PrestaShop\Adapter\Image\Uploader; + +use Profile; +use Symfony\Component\HttpFoundation\File\UploadedFile; + +/** + * Uploads profile logo image + */ +final class ProfileImageUploader extends AbstractImageUploader +{ + /** + * @var string + */ + private $profileImageDir; + + /** + * @var string + */ + private $tmpImageDir; + + /** + * @param string $profileImageDir + * @param string $tmpImageDir + */ + public function __construct( + string $profileImageDir = _PS_PROFILE_IMG_DIR_, + string $tmpImageDir = _PS_TMP_IMG_DIR_ + ) { + $this->profileImageDir = $profileImageDir; + $this->tmpImageDir = $tmpImageDir; + } + + /** + * {@inheritdoc} + */ + public function upload($profileId, UploadedFile $image) + { + $this->checkImageIsAllowedForUpload($image); + $tempImageName = $this->createTemporaryImage($image); + $this->deleteOldImage($profileId); + + $destination = $this->profileImageDir . $profileId . '.jpg'; + $this->uploadFromTemp($tempImageName, $destination); + } + + /** + * Deletes old image + * + * @param $id + */ + private function deleteOldImage($id) + { + $profile = new Profile($id); + $profile->deleteImage(); + + $currentImage = $this->tmpImageDir . 'profile_mini_' . $id . '.jpg'; + + if (file_exists($currentImage)) { + unlink($currentImage); + } + } +} diff --git a/src/Adapter/Profile/QueryHandler/GetProfileForEditingHandler.php b/src/Adapter/Profile/QueryHandler/GetProfileForEditingHandler.php index b8dfc9751845b..7cbe2c0303356 100644 --- a/src/Adapter/Profile/QueryHandler/GetProfileForEditingHandler.php +++ b/src/Adapter/Profile/QueryHandler/GetProfileForEditingHandler.php @@ -26,28 +26,48 @@ namespace PrestaShop\PrestaShop\Adapter\Profile\QueryHandler; +use PrestaShop\PrestaShop\Adapter\Domain\AbstractObjectModelHandler; use PrestaShop\PrestaShop\Core\Domain\Profile\Exception\ProfileNotFoundException; use PrestaShop\PrestaShop\Core\Domain\Profile\Query\GetProfileForEditing; use PrestaShop\PrestaShop\Core\Domain\Profile\QueryHandler\GetProfileForEditingHandlerInterface; use PrestaShop\PrestaShop\Core\Domain\Profile\QueryResult\EditableProfile; use PrestaShop\PrestaShop\Core\Domain\Profile\ValueObject\ProfileId; +use PrestaShop\PrestaShop\Core\Image\Parser\ImageTagSourceParser; +use PrestaShop\PrestaShop\Core\Image\Parser\ImageTagSourceParserInterface; use Profile; /** * Gets Profile for editing using legacy object model */ -final class GetProfileForEditingHandler implements GetProfileForEditingHandlerInterface +final class GetProfileForEditingHandler extends AbstractObjectModelHandler implements GetProfileForEditingHandlerInterface { + /** + * @var ImageTagSourceParserInterface + */ + private $imageTagSourceParser; + + /** + * @param ImageTagSourceParserInterface $imageTagSourceParser + */ + public function __construct(ImageTagSourceParserInterface $imageTagSourceParser = null) + { + $this->imageTagSourceParser = $imageTagSourceParser ?? new ImageTagSourceParser(__PS_BASE_URI__); + } + /** * {@inheritdoc} */ public function handle(GetProfileForEditing $query) { - $profile = $this->getProfile($query->getProfileId()); + $profileId = $query->getProfileId(); + $profile = $this->getProfile($profileId); + + $avatarUrl = $this->getAvatarUrl($profileId->getValue()); return new EditableProfile( - $query->getProfileId(), - $profile->name + $profileId, + $profile->name, + $avatarUrl ? $avatarUrl['path'] : null ); } @@ -68,4 +88,25 @@ private function getProfile(ProfileId $profileId) return $profile; } + + /** + * @param int $imageId + * + * @return array|null + */ + private function getAvatarUrl(int $imageId): ?array + { + $imagePath = _PS_PROFILE_IMG_DIR_ . $imageId . '.jpg'; + $imageTag = $this->getTmpImageTag($imagePath, $imageId, 'profile'); + $imageSize = $this->getImageSize($imagePath); + + if (empty($imageTag) || null === $imageSize) { + return null; + } + + return [ + 'size' => sprintf('%skB', $imageSize), + 'path' => $this->imageTagSourceParser->parse($imageTag), + ]; + } } diff --git a/src/Core/Domain/Profile/QueryResult/EditableProfile.php b/src/Core/Domain/Profile/QueryResult/EditableProfile.php index 8125c4541b419..3321a2776a3cc 100644 --- a/src/Core/Domain/Profile/QueryResult/EditableProfile.php +++ b/src/Core/Domain/Profile/QueryResult/EditableProfile.php @@ -43,14 +43,24 @@ class EditableProfile */ private $localizedNames; + /** + * @var string|null + */ + private $avatarUrl; + /** * @param ProfileId $profileId * @param string[] $localizedNames + * @param string|null $avatarUrl */ - public function __construct(ProfileId $profileId, array $localizedNames) - { + public function __construct( + ProfileId $profileId, + array $localizedNames, + ?string $avatarUrl = null + ) { $this->profileId = $profileId; $this->localizedNames = $localizedNames; + $this->avatarUrl = $avatarUrl; } /** @@ -68,4 +78,12 @@ public function getLocalizedNames() { return $this->localizedNames; } + + /** + * @return string|null + */ + public function getAvatarUrl() + { + return $this->avatarUrl; + } } diff --git a/src/Core/Form/IdentifiableObject/DataHandler/EmployeeFormDataHandler.php b/src/Core/Form/IdentifiableObject/DataHandler/EmployeeFormDataHandler.php index d676ea28a376b..3382daf27cf8e 100644 --- a/src/Core/Form/IdentifiableObject/DataHandler/EmployeeFormDataHandler.php +++ b/src/Core/Form/IdentifiableObject/DataHandler/EmployeeFormDataHandler.php @@ -126,7 +126,7 @@ public function create(array $data) $data['active'], $data['profile'], isset($data['shop_association']) ? $data['shop_association'] : $this->defaultShopAssociation, - $data['has_enabled_gravatar'] + $data['has_enabled_gravatar'] ?? false )); /** @var UploadedFile $uploadedAvatar */ diff --git a/src/Core/Form/IdentifiableObject/DataHandler/ProfileFormDataHandler.php b/src/Core/Form/IdentifiableObject/DataHandler/ProfileFormDataHandler.php index 8f878664e93d4..4fb46dd0f515f 100644 --- a/src/Core/Form/IdentifiableObject/DataHandler/ProfileFormDataHandler.php +++ b/src/Core/Form/IdentifiableObject/DataHandler/ProfileFormDataHandler.php @@ -26,10 +26,13 @@ namespace PrestaShop\PrestaShop\Core\Form\IdentifiableObject\DataHandler; +use PrestaShop\PrestaShop\Adapter\Image\Uploader\ProfileImageUploader; use PrestaShop\PrestaShop\Core\CommandBus\CommandBusInterface; use PrestaShop\PrestaShop\Core\Domain\Profile\Command\AddProfileCommand; use PrestaShop\PrestaShop\Core\Domain\Profile\Command\EditProfileCommand; use PrestaShop\PrestaShop\Core\Domain\Profile\ValueObject\ProfileId; +use PrestaShop\PrestaShop\Core\Image\Uploader\ImageUploaderInterface; +use Symfony\Component\HttpFoundation\File\UploadedFile; /** * Saves or updates Profile using form data @@ -41,12 +44,21 @@ final class ProfileFormDataHandler implements FormDataHandlerInterface */ private $bus; + /** + * @var ImageUploaderInterface + */ + private $imageUploader; + /** * @param CommandBusInterface $bus + * @param ImageUploaderInterface|null $imageUploader */ - public function __construct(CommandBusInterface $bus) - { + public function __construct( + CommandBusInterface $bus, + ImageUploaderInterface $imageUploader = null + ) { $this->bus = $bus; + $this->imageUploader = $imageUploader ?? new ProfileImageUploader(); } /** @@ -57,6 +69,12 @@ public function create(array $data) /** @var ProfileId $profileId */ $profileId = $this->bus->handle(new AddProfileCommand($data['name'])); + /** @var UploadedFile $uploadedAvatar */ + $uploadedAvatar = $data['avatarUrl'] ?? null; + if (!empty($uploadedAvatar) && $uploadedAvatar instanceof UploadedFile) { + $this->imageUploader->upload($profileId->getValue(), $uploadedAvatar); + } + return $profileId->getValue(); } @@ -65,6 +83,12 @@ public function create(array $data) */ public function update($profileId, array $data) { + /** @var UploadedFile $uploadedAvatar */ + $uploadedAvatar = $data['avatarUrl']; + if ($uploadedAvatar instanceof UploadedFile) { + $this->imageUploader->upload($profileId, $uploadedAvatar); + } + /* @var ProfileId $profileId */ $this->bus->handle(new EditProfileCommand($profileId, $data['name'])); } diff --git a/src/PrestaShopBundle/Controller/Admin/Configure/AdvancedParameters/ProfileController.php b/src/PrestaShopBundle/Controller/Admin/Configure/AdvancedParameters/ProfileController.php index b8c25a9d4c095..4bfc56495440c 100644 --- a/src/PrestaShopBundle/Controller/Admin/Configure/AdvancedParameters/ProfileController.php +++ b/src/PrestaShopBundle/Controller/Admin/Configure/AdvancedParameters/ProfileController.php @@ -192,8 +192,8 @@ public function editAction($profileId, Request $request) } } - /** @var EditableProfile $editableProfiler */ - $editableProfiler = $this->getQueryBus()->handle(new GetProfileForEditing((int) $profileId)); + /** @var EditableProfile $editableProfile */ + $editableProfile = $this->getQueryBus()->handle(new GetProfileForEditing((int) $profileId)); return $this->render('@PrestaShop/Admin/Configure/AdvancedParameters/Profiles/edit.html.twig', [ 'profileForm' => $form->createView(), @@ -201,11 +201,12 @@ public function editAction($profileId, Request $request) 'Edit: %value%', 'Admin.Catalog.Feature', [ - '%value%' => $editableProfiler->getLocalizedNames()[$this->getContextLangId()], + '%value%' => $editableProfile->getLocalizedNames()[$this->getContextLangId()], ] ), 'help_link' => $this->generateSidebarLink('AdminProfiles'), 'enableSidebar' => true, + 'editableProfile' => $editableProfile, ]); } diff --git a/src/PrestaShopBundle/Form/Admin/Configure/AdvancedParameters/Profile/ProfileType.php b/src/PrestaShopBundle/Form/Admin/Configure/AdvancedParameters/Profile/ProfileType.php index 03fed85035593..400f5de1392c7 100644 --- a/src/PrestaShopBundle/Form/Admin/Configure/AdvancedParameters/Profile/ProfileType.php +++ b/src/PrestaShopBundle/Form/Admin/Configure/AdvancedParameters/Profile/ProfileType.php @@ -31,6 +31,7 @@ use PrestaShop\PrestaShop\Core\Domain\Profile\ProfileSettings; use PrestaShopBundle\Form\Admin\Type\TranslatableType; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\FileType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Translation\TranslatorInterface; @@ -78,6 +79,12 @@ public function buildForm(FormBuilderInterface $builder, array $options) ], ], ]) + ->add('avatarUrl', FileType::class, [ + 'required' => false, + 'attr' => [ + 'accept' => 'gif,jpg,jpeg,jpe,png', + ], + ]) ; } } diff --git a/src/PrestaShopBundle/Resources/config/services/adapter/image.yml b/src/PrestaShopBundle/Resources/config/services/adapter/image.yml index b6f65ed7b8e56..b800e6ac337fc 100644 --- a/src/PrestaShopBundle/Resources/config/services/adapter/image.yml +++ b/src/PrestaShopBundle/Resources/config/services/adapter/image.yml @@ -19,6 +19,12 @@ services: - !php/const _PS_EMPLOYEE_IMG_DIR_ - !php/const _PS_TMP_IMG_DIR_ + prestashop.adapter.image.uploader.profile_image_uploader: + class: 'PrestaShop\PrestaShop\Adapter\Image\Uploader\ProfileImageUploader' + arguments: + - !php/const _PS_PROFILE_IMG_DIR_ + - !php/const _PS_TMP_IMG_DIR_ + prestashop.adapter.image.uploader.manufacturer_image_uploader: class: 'PrestaShop\PrestaShop\Adapter\Image\Uploader\ManufacturerImageUploader' diff --git a/src/PrestaShopBundle/Resources/config/services/adapter/profile.yml b/src/PrestaShopBundle/Resources/config/services/adapter/profile.yml index b8cde9ca6b5bd..8118c9bdb4841 100644 --- a/src/PrestaShopBundle/Resources/config/services/adapter/profile.yml +++ b/src/PrestaShopBundle/Resources/config/services/adapter/profile.yml @@ -32,6 +32,8 @@ services: prestashop.adapter.profile.query_handler.get_profile_for_editing_handler: class: 'PrestaShop\PrestaShop\Adapter\Profile\QueryHandler\GetProfileForEditingHandler' + arguments: + - '@prestashop.core.image.parser.image_tag_source_parser' tags: - name: 'tactician.handler' command: 'PrestaShop\PrestaShop\Core\Domain\Profile\Query\GetProfileForEditing' diff --git a/src/PrestaShopBundle/Resources/config/services/core/form/form_data_handler.yml b/src/PrestaShopBundle/Resources/config/services/core/form/form_data_handler.yml index 3df09b2c10d1f..4993a81c26918 100644 --- a/src/PrestaShopBundle/Resources/config/services/core/form/form_data_handler.yml +++ b/src/PrestaShopBundle/Resources/config/services/core/form/form_data_handler.yml @@ -90,6 +90,7 @@ services: class: 'PrestaShop\PrestaShop\Core\Form\IdentifiableObject\DataHandler\ProfileFormDataHandler' arguments: - '@prestashop.core.command_bus' + - '@prestashop.adapter.image.uploader.profile_image_uploader' prestashop.core.form.identifiable_object.data_handler.cms_page_form_data_handler: class: 'PrestaShop\PrestaShop\Core\Form\IdentifiableObject\DataHandler\CmsPageFormDataHandler' diff --git a/src/PrestaShopBundle/Resources/views/Admin/Configure/AdvancedParameters/Profiles/Blocks/form.html.twig b/src/PrestaShopBundle/Resources/views/Admin/Configure/AdvancedParameters/Profiles/Blocks/form.html.twig index 3bd71b2fff33f..95caf19f0abbc 100644 --- a/src/PrestaShopBundle/Resources/views/Admin/Configure/AdvancedParameters/Profiles/Blocks/form.html.twig +++ b/src/PrestaShopBundle/Resources/views/Admin/Configure/AdvancedParameters/Profiles/Blocks/form.html.twig @@ -39,6 +39,19 @@ 'label': 'Name'|trans({}, 'Admin.Global') }) }} + {{ ps.form_group_row(profileForm.avatarUrl, {}, { + 'label': 'Avatar'|trans({}, 'Admin.Global') + }) }} + + {% if avatarUrl is not empty %} +
+ +
+ +
+
+ {% endif %} + {% block profile_form_rest %} {{ form_rest(profileForm) }} {% endblock %} diff --git a/src/PrestaShopBundle/Resources/views/Admin/Configure/AdvancedParameters/Profiles/create.html.twig b/src/PrestaShopBundle/Resources/views/Admin/Configure/AdvancedParameters/Profiles/create.html.twig index a345e174dc712..4d39833fd65ed 100644 --- a/src/PrestaShopBundle/Resources/views/Admin/Configure/AdvancedParameters/Profiles/create.html.twig +++ b/src/PrestaShopBundle/Resources/views/Admin/Configure/AdvancedParameters/Profiles/create.html.twig @@ -28,7 +28,9 @@ {% block content %}
- {% include '@PrestaShop/Admin/Configure/AdvancedParameters/Profiles/Blocks/form.html.twig' %} + {% include '@PrestaShop/Admin/Configure/AdvancedParameters/Profiles/Blocks/form.html.twig' with { + avatarUrl: null + } %}
{% endblock %} diff --git a/src/PrestaShopBundle/Resources/views/Admin/Configure/AdvancedParameters/Profiles/edit.html.twig b/src/PrestaShopBundle/Resources/views/Admin/Configure/AdvancedParameters/Profiles/edit.html.twig index a345e174dc712..93475bd734ff1 100644 --- a/src/PrestaShopBundle/Resources/views/Admin/Configure/AdvancedParameters/Profiles/edit.html.twig +++ b/src/PrestaShopBundle/Resources/views/Admin/Configure/AdvancedParameters/Profiles/edit.html.twig @@ -28,7 +28,9 @@ {% block content %}
- {% include '@PrestaShop/Admin/Configure/AdvancedParameters/Profiles/Blocks/form.html.twig' %} + {% include '@PrestaShop/Admin/Configure/AdvancedParameters/Profiles/Blocks/form.html.twig' with { + avatarUrl: editableProfile.avatarUrl + } %}
{% endblock %}