diff --git a/frontend/src/api/users.js b/frontend/src/api/users.js
index aa3d8a1e1..90123e733 100644
--- a/frontend/src/api/users.js
+++ b/frontend/src/api/users.js
@@ -11,6 +11,7 @@ const usersURLs = {
users: `${userPrefix}`,
self: `${userPrefix}/self`,
userID: id => `${userPrefix}/${id}`,
+ password: id => `${userPrefix}/${id}/password`,
};
export default {
@@ -42,6 +43,10 @@ export default {
let response = await apiReq.put(usersURLs.userID(user.id), user);
return response.data;
},
+ async changePassword(id, password) {
+ let response = await apiReq.put(usersURLs.password(id), password);
+ return response.data;
+ },
async delete(id) {
let response = await apiReq.delete(usersURLs.userID(id));
return response.data;
diff --git a/frontend/src/components/Admin/AdminSidebar.vue b/frontend/src/components/Admin/AdminSidebar.vue
index 0e98a94b3..e1799ef8d 100644
--- a/frontend/src/components/Admin/AdminSidebar.vue
+++ b/frontend/src/components/Admin/AdminSidebar.vue
@@ -27,8 +27,10 @@
- Jane Smith
- Admin
+ {{ user.fullName }}
+
+ {{ user.admin ? "Admin" : "User" }}
@@ -50,7 +52,7 @@
-
+
- {{$t('settings.homepage.home-page')}}
+ {{ $t("settings.homepage.home-page") }}
-
+
-1) {
- console.log("New User", this.editedItem);
api.users.update(this.editedItem);
} else {
api.users.create(this.editedItem);
diff --git a/frontend/src/pages/Admin/Profile/index.vue b/frontend/src/pages/Admin/Profile/index.vue
index 509a2a886..22d9fbf94 100644
--- a/frontend/src/pages/Admin/Profile/index.vue
+++ b/frontend/src/pages/Admin/Profile/index.vue
@@ -1,50 +1,98 @@
-
-
-
-
-
-
-
-
-
- Profile
-
- User ID: {{ user.id }}
-
-
-
-
-
-
-
-
-
-
-
-
- mdi-lock
- {{ $t("settings.change-password") }}
-
-
-
- mdi-content-save
- {{ $t("general.save") }}
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+ Profile
+
+ User ID: {{ user.id }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ mdi-content-save
+ {{ $t("general.save") }}
+
+
+
+
+
+
+
+ Reset Password
+
+
+
+
+
+
+
+
+
+
+
+
+
+ mdi-lock
+ {{ $t("settings.change-password") }}
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/pages/Admin/index.vue b/frontend/src/pages/Admin/index.vue
index 7913d20a4..5f0528fca 100644
--- a/frontend/src/pages/Admin/index.vue
+++ b/frontend/src/pages/Admin/index.vue
@@ -4,15 +4,70 @@
+
diff --git a/frontend/src/store/modules/userSettings.js b/frontend/src/store/modules/userSettings.js
index 39c8406de..59a210dfb 100644
--- a/frontend/src/store/modules/userSettings.js
+++ b/frontend/src/store/modules/userSettings.js
@@ -21,6 +21,7 @@ const state = {
isDark: false,
isLoggedIn: false,
token: "",
+ userData: {},
};
const mutations = {
@@ -46,6 +47,10 @@ const mutations = {
axios.defaults.headers.common["Authorization"] = `Bearer ${payload}`;
state.token = payload;
},
+
+ setUserData(state, payload) {
+ state.userData = payload;
+ },
};
const actions = {
@@ -58,7 +63,6 @@ const actions = {
}
},
-
async initTheme({ dispatch, getters }) {
//If theme is empty resetTheme
if (Object.keys(getters.getActiveTheme).length === 0) {
@@ -77,6 +81,7 @@ const getters = {
getIsDark: state => state.isDark,
getIsLoggedIn: state => state.isLoggedIn,
getToken: state => state.token,
+ getUserData: state => state.userData,
};
export default {
diff --git a/mealie/core/config.py b/mealie/core/config.py
index d322ca232..68afb33ea 100644
--- a/mealie/core/config.py
+++ b/mealie/core/config.py
@@ -46,6 +46,7 @@ NEXTCLOUD_DIR = MIGRATION_DIR.joinpath("nextcloud")
CHOWDOWN_DIR = MIGRATION_DIR.joinpath("chowdown")
TEMPLATE_DIR = DATA_DIR.joinpath("templates")
SQLITE_DIR = DATA_DIR.joinpath("db")
+RECIPE_DATA_DIR = DATA_DIR.joinpath("recipes")
TEMP_DIR = DATA_DIR.joinpath(".temp")
REQUIRED_DIRS = [
@@ -58,6 +59,7 @@ REQUIRED_DIRS = [
SQLITE_DIR,
NEXTCLOUD_DIR,
CHOWDOWN_DIR,
+ RECIPE_DATA_DIR
]
ensure_dirs()
diff --git a/mealie/db/database.py b/mealie/db/database.py
index b74c968c7..4c437bc0e 100644
--- a/mealie/db/database.py
+++ b/mealie/db/database.py
@@ -61,6 +61,15 @@ class _Users(BaseDocument):
self.primary_key = "id"
self.sql_model = User
+ def update_password(self, session, id, password: str):
+ entry = self._query_one(session=session, match_value=id)
+ entry.update_password(password)
+ return_data = entry.dict()
+ session.commit()
+
+ return return_data
+
+
class Database:
def __init__(self) -> None:
diff --git a/mealie/db/models/users.py b/mealie/db/models/users.py
index ae03d15b9..a24eab08d 100644
--- a/mealie/db/models/users.py
+++ b/mealie/db/models/users.py
@@ -42,3 +42,6 @@ class User(SqlAlchemyBase, BaseMixins):
self.email = email
self.family = family
self.admin = admin
+
+ def update_password(self, password):
+ self.password = password
diff --git a/mealie/routes/users/auth.py b/mealie/routes/users/auth.py
index 368f37036..21378d70f 100644
--- a/mealie/routes/users/auth.py
+++ b/mealie/routes/users/auth.py
@@ -8,6 +8,7 @@ from fastapi_login.exceptions import InvalidCredentialsException
from routes.deps import manager, query_user
from schema.user import UserInDB
from sqlalchemy.orm.session import Session
+from schema.snackbar import SnackResponse
router = APIRouter(prefix="/api/auth", tags=["Auth"])
@@ -29,4 +30,4 @@ def token(
access_token = manager.create_access_token(
data=dict(sub=email), expires=timedelta(hours=2)
)
- return {"access_token": access_token, "token_type": "bearer"}
+ return SnackResponse.success("User Successfully Logged In", {"access_token": access_token, "token_type": "bearer"})
diff --git a/mealie/routes/users/crud.py b/mealie/routes/users/crud.py
index 5eec6d796..513fe66e7 100644
--- a/mealie/routes/users/crud.py
+++ b/mealie/routes/users/crud.py
@@ -1,11 +1,12 @@
from datetime import timedelta
-from core.security import get_password_hash
+from core.security import get_password_hash, verify_password
from db.database import db
from db.db_setup import generate_session
from fastapi import APIRouter, Depends
from routes.deps import manager, query_user
-from schema.user import UserBase, UserIn, UserInDB, UserOut
+from schema.snackbar import SnackResponse
+from schema.user import ChangePassword, UserBase, UserIn, UserInDB, UserOut
from sqlalchemy.orm.session import Session
router = APIRouter(prefix="/api/users", tags=["Users"])
@@ -17,12 +18,11 @@ async def create_user(
current_user=Depends(manager),
session: Session = Depends(generate_session),
):
- """ Returns a list of all user in the Database """
new_user.password = get_password_hash(new_user.password)
data = db.users.create(session, new_user.dict())
- return data
+ return SnackResponse.success(f"User Created: {new_user.full_name}", data)
@router.get("", response_model=list[UserOut])
@@ -38,7 +38,7 @@ async def get_all_users(
@router.get("/self", response_model=UserOut)
-async def get_user_by_id(
+async def get_logged_in_user(
current_user: UserInDB = Depends(manager),
session: Session = Depends(generate_session),
):
@@ -69,8 +69,30 @@ async def update_user(
access_token = manager.create_access_token(
data=dict(sub=email), expires=timedelta(hours=2)
)
- return {"access_token": access_token, "token_type": "bearer"}
- return
+ access_token = {"access_token": access_token, "token_type": "bearer"}
+
+ return SnackResponse.success("User Updated", access_token)
+
+
+@router.put("/{id}/password")
+async def update_password(
+ id: int,
+ password_change: ChangePassword,
+ current_user: UserInDB = Depends(manager),
+ session: Session = Depends(generate_session),
+):
+ """ Resets the User Password"""
+
+ match_passwords = verify_password(
+ password_change.current_password, current_user.password
+ )
+ match_id = current_user.id == id
+
+ if match_passwords and match_id:
+ new_password = get_password_hash(password_change.new_password)
+ db.users.update_password(session, id, new_password)
+
+ return SnackResponse.success("Password Updated")
@router.delete("/{id}")
@@ -81,5 +103,9 @@ async def delete_user(
):
""" Removes a user from the database. Must be the current user or a super user"""
+ if id == 1:
+ return SnackResponse.error("Error! Cannot Delete Super User")
+
if current_user.id == id or current_user.admin:
- return db.users.delete(session, id)
+ db.users.delete(session, id)
+ return SnackResponse.error(f"User Deleted")
diff --git a/mealie/schema/user.py b/mealie/schema/user.py
index e80e9e4ad..25986f260 100644
--- a/mealie/schema/user.py
+++ b/mealie/schema/user.py
@@ -5,6 +5,11 @@ from fastapi_camelcase import CamelModel
# from pydantic import EmailStr
+class ChangePassword(CamelModel):
+ current_password: str
+ new_password: str
+
+
class UserBase(CamelModel):
full_name: Optional[str] = None
email: str