edit users
This commit is contained in:
@@ -32,7 +32,7 @@ export async function createUser(
|
||||
};
|
||||
}
|
||||
|
||||
await refreshNuxtData('users');
|
||||
await refreshNuxtData('admin-resources');
|
||||
|
||||
toast.success('Create user', {
|
||||
description: 'Successfully created user',
|
||||
|
||||
@@ -29,7 +29,7 @@ export async function deleteUser(
|
||||
};
|
||||
}
|
||||
|
||||
await refreshNuxtData('users');
|
||||
await refreshNuxtData('admin-resources');
|
||||
|
||||
toast.success('Delete user', {
|
||||
description: 'Successfully delete user',
|
||||
|
||||
46
frontend/lib/api/admin/editUser.ts
Normal file
46
frontend/lib/api/admin/editUser.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { toast } from 'vue-sonner';
|
||||
import type { ApiResponse } from '#shared/types/api';
|
||||
import type { AuthUser } from '#shared/types/auth';
|
||||
import { getApiHeaders } from '..';
|
||||
|
||||
/** Admin function to edit an existing user */
|
||||
export async function editUser(
|
||||
user: AuthUser & { password: string | null }
|
||||
): Promise<{ success: true; user: AuthUser } | { success: false }> {
|
||||
const { data, error } = await useFetch<ApiResponse<AuthUser>>(
|
||||
getApiUrl('admin/users'),
|
||||
{
|
||||
method: 'PATCH',
|
||||
headers: getApiHeaders(),
|
||||
body: JSON.stringify({
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
password: user.password,
|
||||
admin: user.admin,
|
||||
}),
|
||||
responseType: 'json',
|
||||
}
|
||||
);
|
||||
|
||||
if (data.value == null) {
|
||||
toast.error('Edit user', {
|
||||
description: error.value?.data ?? 'Failed to edit user',
|
||||
});
|
||||
|
||||
return {
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
await refreshNuxtData('admin-resources');
|
||||
|
||||
toast.success('Edit user', {
|
||||
description: 'Successfully edited user',
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
user: data.value.data,
|
||||
};
|
||||
}
|
||||
56
frontend/lib/api/admin/fetchAll.ts
Normal file
56
frontend/lib/api/admin/fetchAll.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import type { ApiResponse } from '~/shared/types/api';
|
||||
import type { UserWarren, Warren } from '~/shared/types/warrens';
|
||||
import { getApiHeaders } from '..';
|
||||
import type { AdminResources, AuthUserWithWarrens } from '~/shared/types/admin';
|
||||
import type { AuthUser } from '~/shared/types/auth';
|
||||
|
||||
export async function fetchAllAdminResources(): Promise<
|
||||
| {
|
||||
success: true;
|
||||
data: AdminResources;
|
||||
}
|
||||
| { success: false }
|
||||
> {
|
||||
const { data } = await useFetch<
|
||||
ApiResponse<{
|
||||
users: AuthUser[];
|
||||
userWarrens: UserWarren[];
|
||||
warrens: Warren[];
|
||||
}>
|
||||
>(getApiUrl('admin/all'), {
|
||||
method: 'GET',
|
||||
headers: getApiHeaders(),
|
||||
responseType: 'json',
|
||||
deep: false,
|
||||
});
|
||||
|
||||
if (data.value == null) {
|
||||
return {
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
const users: Record<string, AuthUserWithWarrens> = data.value.data.users
|
||||
.map((u) => ({
|
||||
...u,
|
||||
warrens: [],
|
||||
}))
|
||||
.reduce((acc, u) => ({ ...acc, [u.id]: u }), {});
|
||||
const warrens: Record<string, Warren> = {};
|
||||
|
||||
for (const warren of data.value.data.warrens) {
|
||||
warrens[warren.id] = warren;
|
||||
}
|
||||
|
||||
for (const userWarren of data.value.data.userWarrens) {
|
||||
users[userWarren.userId].warrens.push(userWarren);
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
users: Object.values(users),
|
||||
warrens,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,13 +1,20 @@
|
||||
export function getAuthHeader(): ['authorization', string] | null {
|
||||
const authSession = useAuthSession().value;
|
||||
if (authSession == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ['authorization', `${authSession.type} ${authSession.id}`];
|
||||
}
|
||||
export function getApiHeaders(
|
||||
includeAuth: boolean = true
|
||||
): Record<string, string> {
|
||||
const headers: Record<string, string> = {};
|
||||
|
||||
if (includeAuth) {
|
||||
const authSession = useAuthSession().value;
|
||||
|
||||
if (authSession != null) {
|
||||
headers['authorization'] = `${authSession.type} ${authSession.id}`;
|
||||
const header = getAuthHeader();
|
||||
if (header != null) {
|
||||
headers[header[0]] = header[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { toast } from 'vue-sonner';
|
||||
import type { DirectoryEntry } from '#shared/types';
|
||||
import type { ApiResponse } from '#shared/types/api';
|
||||
import type { Warren } from '#shared/types/warrens';
|
||||
import { getApiHeaders } from '.';
|
||||
import { getApiHeaders, getAuthHeader } from '.';
|
||||
|
||||
export async function getWarrens(): Promise<Record<string, Warren>> {
|
||||
const { data, error } = await useFetch<ApiResponse<{ warrens: Warren[] }>>(
|
||||
@@ -201,9 +201,9 @@ export async function uploadToWarren(
|
||||
body.append('files', file);
|
||||
}
|
||||
|
||||
const headers = getApiHeaders();
|
||||
for (const [key, value] of Object.entries(headers)) {
|
||||
xhr.setRequestHeader(key, value);
|
||||
const header = getAuthHeader();
|
||||
if (header != null) {
|
||||
xhr.setRequestHeader(header[0], header[1]);
|
||||
}
|
||||
|
||||
xhr.send(body);
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
import z from 'zod';
|
||||
import { boolean, object, string } from 'yup';
|
||||
import { registerSchema } from './auth';
|
||||
|
||||
export const createUserSchema = registerSchema.extend({
|
||||
admin: z
|
||||
.boolean()
|
||||
.default(false)
|
||||
.prefault(() => false),
|
||||
export const createUserSchema = registerSchema.concat(
|
||||
object({
|
||||
admin: boolean().default(false),
|
||||
})
|
||||
);
|
||||
export const editUserSchema = object({
|
||||
name: string().trim().min(1).required('required'),
|
||||
email: string().email().trim().required('required'),
|
||||
password: string()
|
||||
.trim()
|
||||
.min(12)
|
||||
.max(32)
|
||||
.transform((s: string) => (s.length > 0 ? s : undefined))
|
||||
.optional(),
|
||||
admin: boolean().required('required'),
|
||||
});
|
||||
|
||||
@@ -1,23 +1,13 @@
|
||||
import z from 'zod';
|
||||
import { object, string } from 'yup';
|
||||
|
||||
export const registerSchema = z.object({
|
||||
name: z.string('This field is required').trim().min(1),
|
||||
email: z
|
||||
.email({
|
||||
error: 'This field is required',
|
||||
pattern: z.regexes.rfc5322Email,
|
||||
})
|
||||
.trim(),
|
||||
password: z.string('This field is required').trim().min(12).max(32),
|
||||
export const registerSchema = object({
|
||||
name: string().trim().min(1).required('required'),
|
||||
email: string().trim().email('Expected a valid email').required('required'),
|
||||
password: string().trim().min(12).max(32).required('required'),
|
||||
});
|
||||
|
||||
export const loginSchema = z.object({
|
||||
email: z
|
||||
.email({
|
||||
error: 'This field is required',
|
||||
pattern: z.regexes.rfc5322Email,
|
||||
})
|
||||
.trim(),
|
||||
export const loginSchema = object({
|
||||
email: string().trim().email('Expected a valid email').required('required'),
|
||||
// Don't include the min and max here to let bad actors waste their time
|
||||
password: z.string('This field is required').trim(),
|
||||
password: string().trim().required('required'),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user