diff --git a/docs/docs/site-administration/user-management.md b/docs/docs/site-administration/user-management.md
index f50103478..92c47867e 100644
--- a/docs/docs/site-administration/user-management.md
+++ b/docs/docs/site-administration/user-management.md
@@ -39,6 +39,8 @@ As of version v0.4.0 users have limited functionality, but they will offer more
- Mealplan Settings
- Webhooks
+!!! warning
+ As of v0.4.0 any authenticated user is able to perform any action on the backend server through the API. To limit a standard users scope, the pages on the frontend are limited. Proper support for permission structures on the backend API will come in a later version.
## Startup
@@ -81,4 +83,4 @@ You can easily create and manage groups via the frontend in the admin panel unde
User Groups can only be deleted if no users are apart of the group. If you want to delete a group, you must assign the users to another group before removing.
## Password Reset
-// TODO
+If a user forgets their password an administrator is able to reset their password through the user management page. In the user table, select edit. In the popup windows click the "Reset Password" to reset a users password to the default. This is either 'MyPassword' or set through an environment variable. See the [Installation Page](/getting-started/install/) for more details on environmental variables
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 3584609a3..7169d457b 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -34,8 +34,8 @@
-
+
diff --git a/frontend/src/api/users.js b/frontend/src/api/users.js
index aa5c9cacb..c87b44ca3 100644
--- a/frontend/src/api/users.js
+++ b/frontend/src/api/users.js
@@ -9,12 +9,12 @@ const authURLs = {
refresh: `${authPrefix}/refresh`,
};
-
const usersURLs = {
users: `${userPrefix}`,
self: `${userPrefix}/self`,
userID: id => `${userPrefix}/${id}`,
password: id => `${userPrefix}/${id}/password`,
+ resetPassword: id => `${userPrefix}/${id}/reset-password`,
};
export default {
@@ -60,4 +60,8 @@ export default {
let response = await apiReq.delete(usersURLs.userID(id));
return response.data;
},
+ async resetPassword(id) {
+ let response = await apiReq.put(usersURLs.resetPassword(id));
+ return response.data;
+ },
};
diff --git a/frontend/src/components/Admin/AdminSidebar.vue b/frontend/src/components/Admin/AdminSidebar.vue
index 381e2946c..fec699d86 100644
--- a/frontend/src/components/Admin/AdminSidebar.vue
+++ b/frontend/src/components/Admin/AdminSidebar.vue
@@ -72,6 +72,32 @@
{{ nav.title }}
+
+
+
+
+
+ mdi-information
+
+
+
+
+ {{ $t("settings.current") }}
+ {{ version }}
+
+
+
+ {{ $t("settings.latest") }}
+ {{ latestVersion }}
+
+
+
+
+
@@ -80,10 +106,14 @@
import { validators } from "@/mixins/validators";
import { initials } from "@/mixins/initials";
import { user } from "@/mixins/user";
+import api from "@/api";
+import axios from "axios";
export default {
mixins: [validators, initials, user],
data() {
return {
+ latestVersion: null,
+ version: null,
hideImage: false,
showSidebar: false,
mobile: false,
@@ -92,39 +122,39 @@ export default {
{
icon: "mdi-cog",
to: "/admin/settings",
- title: this.$t('settings.site-settings'),
+ title: this.$t("settings.site-settings"),
},
{
icon: "mdi-account-group",
to: "/admin/manage-users",
- title: this.$t('settings.manage-users'),
+ title: this.$t("settings.manage-users"),
},
{
icon: "mdi-backup-restore",
to: "/admin/backups",
- title: this.$t('settings.backup-and-exports'),
+ title: this.$t("settings.backup-and-exports"),
},
{
icon: "mdi-database-import",
to: "/admin/migrations",
- title: this.$t('settings.migrations'),
+ title: this.$t("settings.migrations"),
},
],
baseLinks: [
{
icon: "mdi-account",
to: "/admin/profile",
- title: this.$t('settings.profile'),
+ title: this.$t("settings.profile"),
},
{
icon: "mdi-format-color-fill",
to: "/admin/themes",
- title: this.$t('general.themes'),
+ title: this.$t("general.themes"),
},
{
icon: "mdi-food",
to: "/admin/meal-planner",
- title: this.$t('meal-plan.meal-planner'),
+ title: this.$t("meal-plan.meal-planner"),
},
],
};
@@ -132,12 +162,18 @@ export default {
async mounted() {
this.mobile = this.viewScale();
this.showSidebar = !this.viewScale();
+ this.getVersion();
+ let versionData = await api.meta.get_version();
+ this.version = versionData.version;
},
computed: {
userProfileImage() {
return `api/users/${this.user.id}/image`;
},
+ newVersionAvailable() {
+ return this.latestVersion == this.version ? false : true;
+ },
},
methods: {
@@ -151,9 +187,26 @@ export default {
return false;
}
},
+ async getVersion() {
+ let response = await axios.get(
+ "https://api.github.com/repos/hay-kot/mealie/releases/latest",
+ {
+ headers: {
+ "content-type": "application/json",
+ Authorization: null,
+ },
+ }
+ );
+ this.latestVersion = response.data.tag_name;
+ },
},
};
\ No newline at end of file
diff --git a/frontend/src/components/Admin/ManageUsers/TheUserTable.vue b/frontend/src/components/Admin/ManageUsers/TheUserTable.vue
index bad882719..58b8dbbae 100644
--- a/frontend/src/components/Admin/ManageUsers/TheUserTable.vue
+++ b/frontend/src/components/Admin/ManageUsers/TheUserTable.vue
@@ -93,6 +93,9 @@
+
+ Reset Password
+
{{ $t("general.cancel") }}
@@ -269,6 +272,10 @@ export default {
}
await this.initialize();
},
+ resetPassword() {
+ console.log(this.activeId);
+ api.users.resetPassword(this.editedItem.id );
+ },
},
};
diff --git a/frontend/src/pages/Admin/index.vue b/frontend/src/pages/Admin/index.vue
index b4743cffe..2de038dab 100644
--- a/frontend/src/pages/Admin/index.vue
+++ b/frontend/src/pages/Admin/index.vue
@@ -1,75 +1,21 @@
diff --git a/mealie/core/config.py b/mealie/core/config.py
index fdaaa6e77..3a871055a 100644
--- a/mealie/core/config.py
+++ b/mealie/core/config.py
@@ -4,8 +4,8 @@ from pathlib import Path
import dotenv
-APP_VERSION = "v0.3.0"
-DB_VERSION = "v0.3.0"
+APP_VERSION = "v0.4.0"
+DB_VERSION = "v0.4.0"
CWD = Path(__file__).parent
diff --git a/mealie/routes/users/crud.py b/mealie/routes/users/crud.py
index af16df950..adbf395f7 100644
--- a/mealie/routes/users/crud.py
+++ b/mealie/routes/users/crud.py
@@ -4,7 +4,7 @@ from datetime import timedelta
from fastapi import APIRouter, Depends, File, UploadFile
from fastapi.responses import FileResponse
from mealie.core import security
-from mealie.core.config import USER_DIR
+from mealie.core.config import DEFAULT_PASSWORD, USER_DIR
from mealie.core.security import get_password_hash, verify_password
from mealie.db.database import db
from mealie.db.db_setup import generate_session
@@ -58,6 +58,19 @@ async def get_user_by_id(
return db.users.get(session, id)
+@router.put("/{id}/reset-password")
+async def reset_user_password(
+ id: int,
+ current_user: UserInDB = Depends(get_current_user),
+ session: Session = Depends(generate_session),
+):
+
+ new_password = get_password_hash(DEFAULT_PASSWORD)
+ db.users.update_password(session, id, new_password)
+
+ return SnackResponse.success("Users Password Reset")
+
+
@router.put("/{id}")
async def update_user(
id: int,