From 7caae35531800f47882edc9825cdd5064edc40a8 Mon Sep 17 00:00:00 2001 From: Giuseppe Criscione <18699708+giuscris@users.noreply.github.com> Date: Sun, 6 Oct 2024 14:32:20 +0200 Subject: [PATCH 1/5] Add user image icons --- panel/assets/icons/svg/user-image-slash.svg | 1 + panel/assets/icons/svg/user-image.svg | 1 + 2 files changed, 2 insertions(+) create mode 100644 panel/assets/icons/svg/user-image-slash.svg create mode 100644 panel/assets/icons/svg/user-image.svg diff --git a/panel/assets/icons/svg/user-image-slash.svg b/panel/assets/icons/svg/user-image-slash.svg new file mode 100644 index 00000000..7bbb48ee --- /dev/null +++ b/panel/assets/icons/svg/user-image-slash.svg @@ -0,0 +1 @@ + diff --git a/panel/assets/icons/svg/user-image.svg b/panel/assets/icons/svg/user-image.svg new file mode 100644 index 00000000..4d6c1558 --- /dev/null +++ b/panel/assets/icons/svg/user-image.svg @@ -0,0 +1 @@ + From ea4b1bb54af29e0ab90ac3d39e178cdb15b84460 Mon Sep 17 00:00:00 2001 From: Giuseppe Criscione <18699708+giuscris@users.noreply.github.com> Date: Sun, 6 Oct 2024 14:34:03 +0200 Subject: [PATCH 2/5] Add `deleteUserImage` modal --- panel/modals/deleteUserImage.yaml | 17 +++++++++++++++++ panel/translations/en.yaml | 2 ++ 2 files changed, 19 insertions(+) create mode 100644 panel/modals/deleteUserImage.yaml diff --git a/panel/modals/deleteUserImage.yaml b/panel/modals/deleteUserImage.yaml new file mode 100644 index 00000000..e55dea06 --- /dev/null +++ b/panel/modals/deleteUserImage.yaml @@ -0,0 +1,17 @@ +title: '{{panel.user.image.delete}}' + +message: '{{panel.user.image.delete.prompt}}' + +buttons: + dismiss: + action: dismiss + icon: times-circle + label: '{{panel.modal.action.cancel}}' + variant: secondary + + delete: + action: submit + icon: trash + label: '{{panel.modal.action.delete}}' + align: right + variant: danger diff --git a/panel/translations/en.yaml b/panel/translations/en.yaml index c24debe1..4532d916 100644 --- a/panel/translations/en.yaml +++ b/panel/translations/en.yaml @@ -329,6 +329,8 @@ panel.user.colorScheme.light: Light panel.user.email: Email panel.user.fullname: Full name panel.user.image: Image +panel.user.image.delete: Delete user image +panel.user.image.delete.prompt: Are you sure you want to delete the user image? This action can’t be undone. panel.user.image.uploaded: User image uploaded panel.user.language: Language panel.user.lastAccess: Last access From f259861541066c59abc39b47be108abd27410c85 Mon Sep 17 00:00:00 2001 From: Giuseppe Criscione <18699708+giuscris@users.noreply.github.com> Date: Sun, 6 Oct 2024 14:35:55 +0200 Subject: [PATCH 3/5] Add `Users@deleteImage` action --- .../src/Panel/Controllers/UsersController.php | 61 +++++++++++++++---- formwork/src/Users/User.php | 5 ++ panel/routes.php | 10 ++- panel/translations/en.yaml | 2 + 4 files changed, 64 insertions(+), 14 deletions(-) diff --git a/formwork/src/Panel/Controllers/UsersController.php b/formwork/src/Panel/Controllers/UsersController.php index 05cd10f8..63de627e 100644 --- a/formwork/src/Panel/Controllers/UsersController.php +++ b/formwork/src/Panel/Controllers/UsersController.php @@ -21,7 +21,6 @@ use Formwork\Utils\Arr; use Formwork\Utils\Exceptions\FileNotFoundException; use Formwork\Utils\FileSystem; -use RuntimeException; class UsersController extends AbstractController { @@ -101,7 +100,10 @@ public function delete(RouteParams $routeParams): RedirectResponse ); } FileSystem::delete(FileSystem::joinPaths($this->config->get('system.users.paths.accounts'), $user->username() . '.yaml')); - $this->deleteImage($user); + + if (!$user->hasDefaultImage()) { + $this->deleteUserImage($user); + } } catch (TranslatedException $e) { $this->panel()->notify($e->getTranslatedMessage(), 'error'); return $this->redirectToReferer(default: '/users/'); @@ -116,6 +118,37 @@ public function delete(RouteParams $routeParams): RedirectResponse return $this->redirect($this->generateRoute('panel.users')); } + /** + * Users@deleteImage action + */ + public function deleteImage(RouteParams $routeParams): RedirectResponse + { + $user = $this->site->users()->get($routeParams->get('user')); + + if ($user === null) { + $this->panel()->notify($this->translate('panel.users.user.notFound'), 'error'); + return $this->redirectToReferer(default: '/users/'); + } + + if ($this->user()->canChangeOptionsOf($user)) { + try { + $this->deleteUserImage($user); + + $userData = $user->data(); + Arr::remove($userData, 'image'); + Yaml::encodeToFile($userData, FileSystem::joinPaths($this->config->get('system.users.paths.accounts'), $user->username() . '.yaml')); + + $this->panel()->notify($this->translate('panel.user.image.deleted'), 'success'); + } catch (TranslatedException $e) { + $this->panel()->notify($e->getTranslatedMessage(), 'error'); + } + } else { + $this->panel()->notify($this->translate('panel.users.user.cannotEdit', $user->username()), 'error'); + } + + return $this->redirect($this->generateRoute('panel.users.profile', ['user' => $user->username()])); + } + /** * Users@profile action */ @@ -162,6 +195,8 @@ public function profile(RouteParams $routeParams): Response $this->modal('deleteUser'); + $this->modal('deleteUserImage'); + return new Response($this->view('users.profile', [ 'title' => $this->translate('panel.users.userProfile', $user->username()), 'user' => $user, @@ -214,7 +249,7 @@ protected function updateUser(User $user, FieldCollection $fieldCollection): voi if ($field->name() === 'image') { $file = $field->value(); // Handle incoming files - if ($file && ($image = $this->uploadImage($user, $file, $field->acceptMimeTypes())) !== null) { + if ($file && ($image = $this->uploadUserImage($user, $file, $field->acceptMimeTypes())) !== null) { Arr::set($userData, 'image', $image); } continue; @@ -231,7 +266,7 @@ protected function updateUser(User $user, FieldCollection $fieldCollection): voi * * @param array $mimeTypes */ - protected function uploadImage(User $user, UploadedFile $file, array $mimeTypes): ?string + protected function uploadUserImage(User $user, UploadedFile $file, array $mimeTypes): ?string { $imagesPath = FileSystem::joinPaths($this->config->get('system.users.paths.images')); @@ -247,7 +282,9 @@ protected function uploadImage(User $user, UploadedFile $file, array $mimeTypes) $image->square($userImageSize)->save(); // Delete old image - $this->deleteImage($user); + if (!$user->hasDefaultImage()) { + $this->deleteUserImage($user); + } $this->panel()->notify($this->translate('panel.user.image.uploaded'), 'success'); return $uploadedFile->name(); @@ -259,16 +296,16 @@ protected function uploadImage(User $user, UploadedFile $file, array $mimeTypes) /** * Delete the image of a given user */ - protected function deleteImage(User $user): void + protected function deleteUserImage(User $user): void { - $image = $user->image()->path(); - - if ($image === $this->panel->realUri('/assets/images/user-image.svg')) { - throw new RuntimeException('Cannot delete default user image'); + if ($user->hasDefaultImage()) { + throw new TranslatedException('Cannot delete default user image', 'panel.user.image.cannotDelete.defaultImage'); } - if (FileSystem::isFile($image, assertExists: false)) { - FileSystem::delete($image); + $path = $user->image()->path(); + + if (FileSystem::isFile($path, assertExists: false)) { + FileSystem::delete($path); } } } diff --git a/formwork/src/Users/User.php b/formwork/src/Users/User.php index 51c722d9..9765cc5d 100644 --- a/formwork/src/Users/User.php +++ b/formwork/src/Users/User.php @@ -92,6 +92,11 @@ public function image(): Image return $this->image = $file; } + public function hasDefaultImage(): bool + { + return $this->image()->path() === FileSystem::joinPaths($this->config->get('system.panel.paths.assets'), 'images/user-image.svg'); + } + public function role(): Role { return $this->role; diff --git a/panel/routes.php b/panel/routes.php index bdc24105..0b4f5315 100644 --- a/panel/routes.php +++ b/panel/routes.php @@ -209,13 +209,19 @@ ], 'panel.users.delete' => [ - 'path' => '/users/{user}/delete/', + 'path' => '/users/{user:[a-z0-9_-]+}/delete/', 'action' => 'Formwork\Panel\Controllers\UsersController@delete', 'methods' => ['POST'], ], + 'panel.users.deleteImage' => [ + 'path' => '/users/{user:[a-z0-9_-]+}/image/delete/', + 'action' => 'Formwork\Panel\Controllers\UsersController@deleteImage', + 'methods' => ['POST'], + ], + 'panel.users.profile' => [ - 'path' => '/users/{user}/profile/', + 'path' => '/users/{user:[a-z0-9_-]+}/profile/', 'action' => 'Formwork\Panel\Controllers\UsersController@profile', 'methods' => ['GET', 'POST'], ], diff --git a/panel/translations/en.yaml b/panel/translations/en.yaml index 4532d916..dd09d21e 100644 --- a/panel/translations/en.yaml +++ b/panel/translations/en.yaml @@ -329,8 +329,10 @@ panel.user.colorScheme.light: Light panel.user.email: Email panel.user.fullname: Full name panel.user.image: Image +panel.user.image.cannotDelete.defaultImage: Cannot delete the default user image panel.user.image.delete: Delete user image panel.user.image.delete.prompt: Are you sure you want to delete the user image? This action can’t be undone. +panel.user.image.deleted: User image deleted panel.user.image.uploaded: User image uploaded panel.user.language: Language panel.user.lastAccess: Last access From d9422d49af90368db5ca7fb3c2b37101c6974500 Mon Sep 17 00:00:00 2001 From: Giuseppe Criscione <18699708+giuscris@users.noreply.github.com> Date: Sun, 6 Oct 2024 14:37:33 +0200 Subject: [PATCH 4/5] Add dropdown to delete image --- panel/src/scss/components/_users.scss | 17 ++++++++++++++--- panel/translations/en.yaml | 1 + panel/views/users/profile.php | 10 ++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/panel/src/scss/components/_users.scss b/panel/src/scss/components/_users.scss index 4477c208..f73431f8 100644 --- a/panel/src/scss/components/_users.scss +++ b/panel/src/scss/components/_users.scss @@ -4,7 +4,7 @@ } .user-summary-image { - overflow: hidden; + position: relative; width: 12rem; height: 12rem; border-radius: $border-radius-round; @@ -13,9 +13,20 @@ box-shadow: $box-shadow-sm; } +.user-summary-image .dropdown { + position: absolute; + top: 0; + right: -1.5rem; +} + +.user-summary-image .dropdown-button { + background-color: var(--color-tooltip-light); +} + .user-summary-image img { - width: 100%; - height: 100%; + width: 12rem; + height: 12rem; + border-radius: $border-radius-round; } .users-list { diff --git a/panel/translations/en.yaml b/panel/translations/en.yaml index dd09d21e..4d6bc292 100644 --- a/panel/translations/en.yaml +++ b/panel/translations/en.yaml @@ -329,6 +329,7 @@ panel.user.colorScheme.light: Light panel.user.email: Email panel.user.fullname: Full name panel.user.image: Image +panel.user.image.actions: Actions panel.user.image.cannotDelete.defaultImage: Cannot delete the default user image panel.user.image.delete: Delete user image panel.user.image.delete.prompt: Are you sure you want to delete the user image? This action can’t be undone. diff --git a/panel/views/users/profile.php b/panel/views/users/profile.php index 65a27a93..9c0b094f 100644 --- a/panel/views/users/profile.php +++ b/panel/views/users/profile.php @@ -1,6 +1,5 @@ layout('panel') ?>
-
translate('panel.users.user') ?>
user()->canChangeOptionsOf($user)) : ?> @@ -10,10 +9,17 @@
-
<?= $panel->user()->username() ?> + user()->canChangeOptionsOf($user) && !$user->hasDefaultImage()) : ?> + +
escape($user->fullname()) ?>
From cd8b833f5dd0ab52cc1f2288f696a87d73c6437a Mon Sep 17 00:00:00 2001 From: Giuseppe Criscione <18699708+giuscris@users.noreply.github.com> Date: Sun, 6 Oct 2024 14:37:44 +0200 Subject: [PATCH 5/5] Update translations --- panel/translations/de.yaml | 5 +++++ panel/translations/es.yaml | 5 +++++ panel/translations/fr.yaml | 5 +++++ panel/translations/it.yaml | 5 +++++ panel/translations/pt.yaml | 5 +++++ panel/translations/ru.yaml | 5 +++++ 6 files changed, 30 insertions(+) diff --git a/panel/translations/de.yaml b/panel/translations/de.yaml index 372de0fa..3a4b6063 100644 --- a/panel/translations/de.yaml +++ b/panel/translations/de.yaml @@ -329,6 +329,11 @@ panel.user.colorScheme.light: Hell panel.user.email: E-Mail panel.user.fullname: Vollständiger Name panel.user.image: Bild +panel.user.image.actions: Aktionen +panel.user.image.cannotDelete.defaultImage: Das Standard-Benutzerbild kann nicht gelöscht werden +panel.user.image.delete: Benutzerbild löschen +panel.user.image.delete.prompt: Sind Sie sicher, dass Sie das Benutzerbild löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden. +panel.user.image.deleted: Benutzerbild gelöscht panel.user.image.uploaded: Benutzerbild hochgeladen panel.user.language: Sprache panel.user.lastAccess: Letzter Zugriff diff --git a/panel/translations/es.yaml b/panel/translations/es.yaml index f545a024..c3f01126 100644 --- a/panel/translations/es.yaml +++ b/panel/translations/es.yaml @@ -329,6 +329,11 @@ panel.user.colorScheme.light: Claro panel.user.email: Correo electrónico panel.user.fullname: Nombre completo panel.user.image: Imagen +panel.user.image.actions: Acciones +panel.user.image.cannotDelete.defaultImage: No se puede eliminar la imagen predeterminada del usuario +panel.user.image.delete: Eliminar imagen del usuario +panel.user.image.delete.prompt: ¿Está seguro de que desea eliminar la imagen del usuario? Esta acción no se puede deshacer. +panel.user.image.deleted: Imagen del usuario eliminada panel.user.image.uploaded: Imagen de usuario cargada panel.user.language: Idioma panel.user.lastAccess: Último acceso diff --git a/panel/translations/fr.yaml b/panel/translations/fr.yaml index 3382a34b..4ff46a2a 100644 --- a/panel/translations/fr.yaml +++ b/panel/translations/fr.yaml @@ -329,6 +329,11 @@ panel.user.colorScheme.light: Clair panel.user.email: Adresse de messagerie panel.user.fullname: Nom complet panel.user.image: Photo de profil +panel.user.image.actions: Actions +panel.user.image.cannotDelete.defaultImage: Impossible de supprimer l’image par défaut de l’utilisateur +panel.user.image.delete: Supprimer l'image de l’utilisateur +panel.user.image.delete.prompt: Êtes-vous sûr de vouloir supprimer l’image de l’utilisateur ? Cette action ne peut pas être annulée. +panel.user.image.deleted: Image de l’utilisateur supprimée panel.user.image.uploaded: Photo de profil téléversée avec succès. panel.user.language: Langue panel.user.lastAccess: Dernier accès diff --git a/panel/translations/it.yaml b/panel/translations/it.yaml index 2be53ea3..13e58c38 100644 --- a/panel/translations/it.yaml +++ b/panel/translations/it.yaml @@ -329,6 +329,11 @@ panel.user.colorScheme.light: Chiara panel.user.email: E-mail panel.user.fullname: Nome completo panel.user.image: Immagine +panel.user.image.actions: Azioni +panel.user.image.cannotDelete.defaultImage: Impossibile eliminare l’immagine utente predefinita +panel.user.image.delete: Elimina immagine utente +panel.user.image.delete.prompt: Sei sicuro di voler eliminare l’immagine utente? Questa azione non può essere annullata. +panel.user.image.deleted: Immagine utente eliminata panel.user.image.uploaded: Immagine caricata panel.user.language: Lingua panel.user.lastAccess: Ultimo accesso diff --git a/panel/translations/pt.yaml b/panel/translations/pt.yaml index 340fa3af..9c0878ab 100644 --- a/panel/translations/pt.yaml +++ b/panel/translations/pt.yaml @@ -329,6 +329,11 @@ panel.user.colorScheme.light: Claro panel.user.email: E'mail panel.user.fullname: Nome completo panel.user.image: Imagem +panel.user.image.actions: Ações +panel.user.image.cannotDelete.defaultImage: Não é possível eliminar a imagem padrão do utilizador +panel.user.image.delete: Eliminar imagem do utilizador +panel.user.image.delete.prompt: Tem a certeza de que quer eliminar a imagem do utilizador? Esta ação não pode ser desfeita. +panel.user.image.deleted: Imagem do utilizador eliminada panel.user.image.uploaded: Imagem do utilizador enviada panel.user.language: Idioma panel.user.lastAccess: Último acesso diff --git a/panel/translations/ru.yaml b/panel/translations/ru.yaml index a29debca..dc8af2d3 100644 --- a/panel/translations/ru.yaml +++ b/panel/translations/ru.yaml @@ -329,6 +329,11 @@ panel.user.colorScheme.light: Светлая panel.user.email: Email panel.user.fullname: Полное имя panel.user.image: Аватар +panel.user.image.actions: Действия +panel.user.image.cannotDelete.defaultImage: Невозможно удалить изображение пользователя по умолчанию +panel.user.image.delete: Удалить изображение пользователя +panel.user.image.delete.prompt: Вы уверены, что хотите удалить изображение пользователя? Это действие нельзя отменить. +panel.user.image.deleted: Изображение пользователя удалено panel.user.image.uploaded: Аватар закачанный panel.user.language: Язык panel.user.lastAccess: Последний доступ