Add curator roles/permissions with Users admin, and fix lineage branch joins.
Staff accounts use admin/curator roles and fine-grained flags; transitions connect source-to-target with color gradients and stream cutout masks so overlaps stay seamless. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
bfa21989c9
commit
0466b77328
@@ -39,11 +39,41 @@ function localizedPath(path: string, params?: URLSearchParams): string {
|
||||
|
||||
const fetchCredentials: RequestInit = { credentials: 'include' };
|
||||
|
||||
export type AuthRole = 'user' | 'curator';
|
||||
export type AuthRole = 'user' | 'admin' | 'curator';
|
||||
|
||||
export type StaffPermission =
|
||||
| 'images'
|
||||
| 'checkup'
|
||||
| 'curator_notes'
|
||||
| 'translations'
|
||||
| 'influences'
|
||||
| 'tours'
|
||||
| 'users';
|
||||
|
||||
export const ALL_STAFF_PERMISSIONS: StaffPermission[] = [
|
||||
'images',
|
||||
'checkup',
|
||||
'curator_notes',
|
||||
'translations',
|
||||
'influences',
|
||||
'tours',
|
||||
'users',
|
||||
];
|
||||
|
||||
export interface AuthState {
|
||||
role: AuthRole;
|
||||
username?: string;
|
||||
permissions?: StaffPermission[];
|
||||
}
|
||||
|
||||
export interface StaffUser {
|
||||
id: number;
|
||||
username: string;
|
||||
role: 'admin' | 'curator';
|
||||
permissions: StaffPermission[];
|
||||
is_active: boolean;
|
||||
created_at: string;
|
||||
last_login_at: string | null;
|
||||
}
|
||||
|
||||
async function fetchJson<T>(url: string, init?: RequestInit): Promise<T> {
|
||||
@@ -337,6 +367,52 @@ export interface PaintingCheckupData {
|
||||
}
|
||||
|
||||
export const api = {
|
||||
listUsers: () => fetchJson<{ users: StaffUser[]; permissions: StaffPermission[] }>(`${API}/users`),
|
||||
|
||||
createUser: (body: {
|
||||
username: string;
|
||||
password: string;
|
||||
role: 'admin' | 'curator';
|
||||
permissions: StaffPermission[];
|
||||
}) =>
|
||||
fetch(`${API}/users`, {
|
||||
...fetchCredentials,
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
}).then(async (res) => {
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (!res.ok) throw new Error(data.error || `Create failed: ${res.status}`);
|
||||
return data as { user: StaffUser };
|
||||
}),
|
||||
|
||||
updateUser: (
|
||||
id: number,
|
||||
body: Partial<{ role: 'admin' | 'curator'; permissions: StaffPermission[]; is_active: boolean }>
|
||||
) =>
|
||||
fetch(`${API}/users/${id}`, {
|
||||
...fetchCredentials,
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
}).then(async (res) => {
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (!res.ok) throw new Error(data.error || `Update failed: ${res.status}`);
|
||||
return data as { user: StaffUser };
|
||||
}),
|
||||
|
||||
resetUserPassword: (id: number, password: string) =>
|
||||
fetch(`${API}/users/${id}/password`, {
|
||||
...fetchCredentials,
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ password }),
|
||||
}).then(async (res) => {
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (!res.ok) throw new Error(data.error || `Password reset failed: ${res.status}`);
|
||||
return data as { ok: boolean };
|
||||
}),
|
||||
|
||||
getBounds: () => fetchJson<YearBounds>(`${API}/bounds`),
|
||||
|
||||
getCatalogBootstrap: (start?: number, end?: number) => {
|
||||
|
||||
Reference in New Issue
Block a user