1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-08-05 13:35:23 +02:00

feature: add password reset token endpoint to the admin panel (#2171)

* add password reset token endpoint to the admin panel

* add None check on token

* add localization message for passowrd reset link button
This commit is contained in:
Carter 2023-03-12 15:33:36 -05:00 committed by GitHub
parent 1b26ca0cb3
commit 93eb2af087
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 52 additions and 1 deletions

View file

@ -689,6 +689,7 @@
"error-cannot-delete-super-user": "Error! Cannot Delete Super User",
"existing-password-does-not-match": "Existing password does not match",
"full-name": "Full Name",
"generate-password-reset-link": "Generate Password Reset Link",
"invite-only": "Invite Only",
"link-id": "Link ID",
"link-name": "Link Name",

View file

@ -1,5 +1,5 @@
import { BaseCRUDAPI } from "../base/base-clients";
import { UnlockResults, UserIn, UserOut } from "~/lib/api/types/user";
import { ForgotPassword, PasswordResetToken, UnlockResults, UserIn, UserOut } from "~/lib/api/types/user";
const prefix = "/api";
@ -7,6 +7,7 @@ const routes = {
adminUsers: `${prefix}/admin/users`,
adminUsersId: (tag: string) => `${prefix}/admin/users/${tag}`,
adminResetLockedUsers: (force: boolean) => `${prefix}/admin/users/unlock?force=${force ? "true" : "false"}`,
adminPasswordResetToken: `${prefix}/admin/users/password-reset-token`,
};
export class AdminUsersApi extends BaseCRUDAPI<UserIn, UserOut, UserOut> {
@ -16,4 +17,8 @@ export class AdminUsersApi extends BaseCRUDAPI<UserIn, UserOut, UserOut> {
async unlockAllUsers(force = false) {
return await this.requests.post<UnlockResults>(routes.adminResetLockedUsers(force), {});
}
async generatePasswordResetToken(payload: ForgotPassword) {
return await this.requests.post<PasswordResetToken>(routes.adminPasswordResetToken, payload);
}
}

View file

@ -233,3 +233,6 @@ export interface UserIn {
export interface ValidateResetToken {
token: string;
}
export interface PasswordResetToken {
token: string;
}

View file

@ -27,6 +27,13 @@
label="User Group"
:rules="[validators.required]"
></v-select>
<div class="d-flex py-2 pr-2">
<BaseButton type="button" :loading="generatingToken" create @click.prevent="handlePasswordReset">
{{ $t("user.generate-password-reset-link") }}
</BaseButton>
<AppButtonCopy v-if="resetUrl" :copy-text="resetUrl"></AppButtonCopy>
</div>
<AutoForm v-model="user" :items="userForm" update-mode />
</v-card-text>
</v-card>
@ -67,6 +74,9 @@ export default defineComponent({
const userError = ref(false);
const resetUrl = ref<string | null>(null);
const generatingToken = ref(false);
onMounted(async () => {
const { data, error } = await adminApi.users.getOne(userId);
@ -90,6 +100,20 @@ export default defineComponent({
}
}
async function handlePasswordReset() {
if (user.value === null) return;
generatingToken.value = true;
const { response, data } = await adminApi.users.generatePasswordResetToken({ email: user.value.email });
if (response?.status === 201 && data) {
const token: string = data.token;
resetUrl.value = `${window.location.origin}/reset-password?token=${token}`;
}
generatingToken.value = false;
}
return {
user,
userError,
@ -98,6 +122,9 @@ export default defineComponent({
handleSubmit,
groups,
validators,
handlePasswordReset,
resetUrl,
generatingToken,
};
},
});