feature/password-reset (#227)

* add reset default password

* add warning

* add version tag

* bumb version

* remove old footer

Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
Hayden 2021-03-28 16:14:14 -08:00 committed by GitHub
commit ab60306335
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 95 additions and 70 deletions

View file

@ -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

View file

@ -34,8 +34,8 @@
<AddRecipeFab v-if="loggedIn" />
</v-slide-x-reverse-transition>
<router-view></router-view>
<FlashMessage :position="'right bottom'"></FlashMessage>
</v-main>
<FlashMessage :position="'right bottom'"></FlashMessage>
</v-app>
</template>

View file

@ -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;
},
};

View file

@ -72,6 +72,32 @@
<v-list-item-title>{{ nav.title }}</v-list-item-title>
</v-list-item>
</v-list>
<v-list nav dense class="fixedBottom">
<v-list-item href="">
<v-list-item-icon class="mr-3 pt-1">
<v-icon :color="newVersionAvailable ? 'red--text' : ''">
mdi-information
</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>
{{ $t("settings.current") }}
{{ version }}
</v-list-item-title>
<v-list-item-subtitle>
<a
href="https://github.com/hay-kot/mealie/releases/latest"
target="_blank"
:class="newVersionAvailable ? 'red--text' : 'green--text'"
>
{{ $t("settings.latest") }}
{{ latestVersion }}
</a>
</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-list>
</v-navigation-drawer>
</div>
</template>
@ -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;
},
},
};
</script>
<style>
.fixedBottom {
position: fixed !important;
bottom: 0 !important;
width: 100%;
}
</style>

View file

@ -93,6 +93,9 @@
</v-card-text>
<v-card-actions>
<v-btn color="info" text @click="resetPassword">
Reset Password
</v-btn>
<v-spacer></v-spacer>
<v-btn color="grey" text @click="close">
{{ $t("general.cancel") }}
@ -269,6 +272,10 @@ export default {
}
await this.initialize();
},
resetPassword() {
console.log(this.activeId);
api.users.resetPassword(this.editedItem.id );
},
},
};
</script>

View file

@ -1,75 +1,21 @@
<template>
<div>
<v-container height="100%">
<AdminSidebar />
<v-container>
<v-slide-x-transition hide-on-leave>
<router-view></router-view>
</v-slide-x-transition>
<AdminSidebar />
</v-container>
<!-- <v-footer absolute>
<div class="flex text-center" cols="12">
{{ $t("settings.current") }}
{{ version }} |
{{ $t("settings.latest") }}
{{ latestVersion }}
·
<a href="https://hay-kot.github.io/mealie/" target="_blank">
{{ $t("settings.explore-the-docs") }}
</a>
·
<a
href="https://hay-kot.github.io/mealie/contributors/non-coders/"
target="_blank"
>
{{ $t("settings.contribute") }}
</a>
</div>
</v-footer> -->
</div>
</template>
<script>
import AdminSidebar from "@/components/Admin/AdminSidebar";
import axios from "axios";
import api from "@/api";
export default {
components: {
AdminSidebar,
},
data() {
return {
latestVersion: null,
version: null,
};
},
async mounted() {
this.getVersion();
let versionData = await api.meta.get_version();
this.version = versionData.version;
},
computed: {
newVersion() {
if ((this.latestVersion != null) & (this.latestVersion != this.version)) {
return true;
} else {
return false;
}
},
},
methods: {
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;
},
},
};
</script>

View file

@ -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

View file

@ -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,