From 20822ee8084a1b66bb5507c578bb5bbb0476e48f Mon Sep 17 00:00:00 2001
From: Hayden <64056131+hay-kot@users.noreply.github.com>
Date: Sun, 20 Mar 2022 16:12:49 -0800
Subject: [PATCH] Feature/improve user feedback (#1076)
* add proper type annotations
* fix state management and dead code
* add response messages
---
frontend/pages/user/profile/edit.vue | 31 ++++++++++++++----------
mealie/routes/_base/abc_controller.py | 8 ++++---
mealie/routes/users/_helpers.py | 3 ++-
mealie/routes/users/crud.py | 34 ++++++++++++++++++++-------
4 files changed, 51 insertions(+), 25 deletions(-)
diff --git a/frontend/pages/user/profile/edit.vue b/frontend/pages/user/profile/edit.vue
index 4e4751a1a81f..0be41232c956 100644
--- a/frontend/pages/user/profile/edit.vue
+++ b/frontend/pages/user/profile/edit.vue
@@ -50,7 +50,7 @@
-
+
@@ -60,14 +60,16 @@
:label="$t('user.current-password')"
validate-on-blur
:type="showPassword ? 'text' : 'password'"
- @click:append="showPassword.current = !showPassword.current"
+ :append-icon="showPassword ? $globals.icons.eye : $globals.icons.eyeOff"
+ @click:append="showPassword = !showPassword"
>
-
+
@@ -112,7 +119,7 @@
-
diff --git a/mealie/routes/_base/abc_controller.py b/mealie/routes/_base/abc_controller.py
index 2256483146b2..acfaf474fbd5 100644
--- a/mealie/routes/_base/abc_controller.py
+++ b/mealie/routes/_base/abc_controller.py
@@ -2,11 +2,13 @@ from abc import ABC
from functools import cached_property
from fastapi import Depends
+from pydantic import UUID4
from mealie.core.exceptions import mealie_registered_exceptions
from mealie.repos.all_repositories import AllRepositories
from mealie.routes._base.checks import OperationChecks
from mealie.routes._base.dependencies import SharedDependencies
+from mealie.schema.user.user import GroupInDB, PrivateUser
class BasePublicController(ABC):
@@ -39,15 +41,15 @@ class BaseUserController(ABC):
return AllRepositories(self.deps.session)
@property
- def group_id(self):
+ def group_id(self) -> UUID4:
return self.deps.acting_user.group_id
@property
- def user(self):
+ def user(self) -> PrivateUser:
return self.deps.acting_user
@property
- def group(self):
+ def group(self) -> GroupInDB:
return self.deps.repos.groups.get_one(self.group_id)
@cached_property
diff --git a/mealie/routes/users/_helpers.py b/mealie/routes/users/_helpers.py
index 1669f4e13468..83a5dbb25aa1 100644
--- a/mealie/routes/users/_helpers.py
+++ b/mealie/routes/users/_helpers.py
@@ -1,9 +1,10 @@
from fastapi import HTTPException, status
+from pydantic import UUID4
from mealie.schema.user.user import PrivateUser
-def assert_user_change_allowed(id: int, current_user: PrivateUser):
+def assert_user_change_allowed(id: UUID4, current_user: PrivateUser):
if current_user.id != id and not current_user.admin:
# only admins can edit other users
raise HTTPException(status.HTTP_403_FORBIDDEN, detail="NOT_AN_ADMIN")
diff --git a/mealie/routes/users/crud.py b/mealie/routes/users/crud.py
index 12f88a79d0ac..3d15d486bb67 100644
--- a/mealie/routes/users/crud.py
+++ b/mealie/routes/users/crud.py
@@ -1,13 +1,13 @@
from fastapi import HTTPException, status
from pydantic import UUID4
-from mealie.core import security
from mealie.core.security import hash_password, verify_password
from mealie.routes._base import BaseAdminController, controller
from mealie.routes._base.abc_controller import BaseUserController
from mealie.routes._base.mixins import CrudMixins
from mealie.routes._base.routers import AdminAPIRouter, UserAPIRouter
from mealie.routes.users._helpers import assert_user_change_allowed
+from mealie.schema.response import ErrorResponse, SuccessResponse
from mealie.schema.user import ChangePassword, UserBase, UserIn, UserOut
user_router = UserAPIRouter(prefix="/users", tags=["Users: CRUD"])
@@ -57,23 +57,39 @@ class UserController(BaseUserController):
if not self.user.admin and (new_data.admin or self.user.group != new_data.group):
# prevent a regular user from doing admin tasks on themself
- raise HTTPException(status.HTTP_403_FORBIDDEN)
+ raise HTTPException(
+ status.HTTP_403_FORBIDDEN, ErrorResponse.respond("User doesn't have permission to change group")
+ )
if self.user.id == item_id and self.user.admin and not new_data.admin:
# prevent an admin from demoting themself
- raise HTTPException(status.HTTP_403_FORBIDDEN)
+ raise HTTPException(
+ status.HTTP_403_FORBIDDEN, ErrorResponse.respond("User doesn't have permission to change group")
+ )
- self.repos.users.update(item_id, new_data.dict())
+ try:
+ self.repos.users.update(item_id, new_data.dict())
+ except Exception as e:
+ raise HTTPException(
+ status.HTTP_400_BAD_REQUEST,
+ ErrorResponse.respond("Failed to update user"),
+ ) from e
- if self.user.id == item_id:
- access_token = security.create_access_token(data=dict(sub=str(self.user.id)))
- return {"access_token": access_token, "token_type": "bearer"}
+ return SuccessResponse.respond("User updated")
@user_router.put("/{item_id}/password")
def update_password(self, password_change: ChangePassword):
"""Resets the User Password"""
if not verify_password(password_change.current_password, self.user.password):
- raise HTTPException(status.HTTP_400_BAD_REQUEST)
+ raise HTTPException(status.HTTP_400_BAD_REQUEST, ErrorResponse.respond("Invalid current password"))
self.user.password = hash_password(password_change.new_password)
- return self.repos.users.update_password(self.user.id, self.user.password)
+ try:
+ self.repos.users.update_password(self.user.id, self.user.password)
+ except Exception as e:
+ raise HTTPException(
+ status.HTTP_400_BAD_REQUEST,
+ ErrorResponse.respond("Failed to update password"),
+ ) from e
+
+ return SuccessResponse.respond("Password updated")