mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
- Fix stale initData comparison in clearStaleSessionIfNeeded that destroyed valid refresh tokens on mobile WebView reopens - Restrict X-Telegram-Init-Data header to auth endpoints only - Close Mini App on auth retry to force fresh initData from Telegram - Merge Connection page error/not-configured states for better UX - Remove unnecessary comments across 40+ files (section dividers, restating comments, noise catch block comments) - Configure ESLint allowEmptyCatch to properly handle intentional empty catch blocks (62 warnings resolved)
237 lines
5.9 KiB
TypeScript
237 lines
5.9 KiB
TypeScript
import apiClient from './client';
|
|
|
|
export interface AdminRole {
|
|
id: number;
|
|
name: string;
|
|
description: string | null;
|
|
level: number;
|
|
permissions: string[];
|
|
color: string | null;
|
|
icon: string | null;
|
|
is_system: boolean;
|
|
is_active: boolean;
|
|
created_at: string;
|
|
updated_at: string;
|
|
user_count?: number;
|
|
}
|
|
|
|
export interface CreateRolePayload {
|
|
name: string;
|
|
description?: string | null;
|
|
level: number;
|
|
permissions: string[];
|
|
color?: string | null;
|
|
icon?: string | null;
|
|
}
|
|
|
|
export interface UpdateRolePayload {
|
|
name?: string;
|
|
description?: string | null;
|
|
level?: number;
|
|
permissions?: string[];
|
|
color?: string | null;
|
|
icon?: string | null;
|
|
is_active?: boolean;
|
|
}
|
|
|
|
export interface UserRoleAssignment {
|
|
id: number;
|
|
user_id: number;
|
|
role_id: number;
|
|
role_name: string;
|
|
assigned_by: number | null;
|
|
assigned_at: string;
|
|
expires_at: string | null;
|
|
user_email: string | null;
|
|
user_first_name: string | null;
|
|
user_telegram_id: number | null;
|
|
}
|
|
|
|
export interface AdminWithRoles {
|
|
user_id: number;
|
|
telegram_id: number | null;
|
|
username: string | null;
|
|
first_name: string | null;
|
|
last_name: string | null;
|
|
email: string | null;
|
|
role_names: string[];
|
|
}
|
|
|
|
export interface AssignRolePayload {
|
|
user_id: number;
|
|
role_id: number;
|
|
expires_at?: string | null;
|
|
}
|
|
|
|
export interface AccessPolicy {
|
|
id: number;
|
|
name: string;
|
|
description: string | null;
|
|
resource: string;
|
|
actions: string[];
|
|
effect: 'allow' | 'deny';
|
|
conditions: Record<string, unknown>;
|
|
priority: number;
|
|
role_id: number | null;
|
|
role_name: string | null;
|
|
is_active: boolean;
|
|
created_by: number | null;
|
|
created_at: string;
|
|
}
|
|
|
|
export interface CreatePolicyPayload {
|
|
name: string;
|
|
description?: string | null;
|
|
resource: string;
|
|
actions: string[];
|
|
effect: 'allow' | 'deny';
|
|
conditions?: Record<string, unknown>;
|
|
priority?: number;
|
|
role_id?: number | null;
|
|
}
|
|
|
|
export interface UpdatePolicyPayload {
|
|
name?: string;
|
|
description?: string | null;
|
|
resource?: string;
|
|
actions?: string[];
|
|
effect?: 'allow' | 'deny';
|
|
conditions?: Record<string, unknown>;
|
|
priority?: number;
|
|
role_id?: number | null;
|
|
is_active?: boolean;
|
|
}
|
|
|
|
export interface AuditLogEntry {
|
|
id: number;
|
|
user_id: number;
|
|
action: string;
|
|
resource_type: string | null;
|
|
resource_id: string | null;
|
|
details: Record<string, unknown> | null;
|
|
ip_address: string | null;
|
|
user_agent: string | null;
|
|
status: string;
|
|
request_method: string | null;
|
|
request_path: string | null;
|
|
created_at: string;
|
|
user_first_name: string | null;
|
|
user_email: string | null;
|
|
}
|
|
|
|
export interface AuditLogFilters {
|
|
user_id?: number;
|
|
action?: string;
|
|
resource_type?: string;
|
|
status?: string;
|
|
date_from?: string;
|
|
date_to?: string;
|
|
offset?: number;
|
|
limit?: number;
|
|
}
|
|
|
|
export interface AuditLogResponse {
|
|
items: AuditLogEntry[];
|
|
total: number;
|
|
offset: number;
|
|
limit: number;
|
|
}
|
|
|
|
export interface PermissionSection {
|
|
section: string;
|
|
actions: string[];
|
|
}
|
|
|
|
const BASE = '/cabinet/admin/rbac';
|
|
|
|
export const rbacApi = {
|
|
// --- Roles ---
|
|
|
|
getRoles: async (): Promise<AdminRole[]> => {
|
|
const response = await apiClient.get<AdminRole[]>(`${BASE}/roles`);
|
|
return response.data;
|
|
},
|
|
|
|
createRole: async (payload: CreateRolePayload): Promise<AdminRole> => {
|
|
const response = await apiClient.post<AdminRole>(`${BASE}/roles`, payload);
|
|
return response.data;
|
|
},
|
|
|
|
updateRole: async (roleId: number, payload: UpdateRolePayload): Promise<AdminRole> => {
|
|
const response = await apiClient.put<AdminRole>(`${BASE}/roles/${roleId}`, payload);
|
|
return response.data;
|
|
},
|
|
|
|
deleteRole: async (roleId: number): Promise<void> => {
|
|
await apiClient.delete(`${BASE}/roles/${roleId}`);
|
|
},
|
|
|
|
// --- Permission Registry ---
|
|
|
|
getPermissionRegistry: async (): Promise<PermissionSection[]> => {
|
|
const response = await apiClient.get<PermissionSection[]>(`${BASE}/permissions`);
|
|
return response.data;
|
|
},
|
|
|
|
// --- RBAC Users ---
|
|
|
|
getRbacUsers: async (): Promise<AdminWithRoles[]> => {
|
|
const response = await apiClient.get<AdminWithRoles[]>(`${BASE}/users`);
|
|
return response.data;
|
|
},
|
|
|
|
// --- Role Users ---
|
|
|
|
getRoleUsers: async (roleId: number): Promise<UserRoleAssignment[]> => {
|
|
const response = await apiClient.get<UserRoleAssignment[]>(`${BASE}/roles/${roleId}/users`);
|
|
return response.data;
|
|
},
|
|
|
|
assignRole: async (payload: AssignRolePayload): Promise<UserRoleAssignment> => {
|
|
const response = await apiClient.post<UserRoleAssignment>(`${BASE}/assignments`, payload);
|
|
return response.data;
|
|
},
|
|
|
|
revokeRole: async (assignmentId: number): Promise<void> => {
|
|
await apiClient.delete(`${BASE}/assignments/${assignmentId}`);
|
|
},
|
|
|
|
// --- Access Policies ---
|
|
|
|
getPolicies: async (): Promise<AccessPolicy[]> => {
|
|
const response = await apiClient.get<AccessPolicy[]>(`${BASE}/policies`);
|
|
return response.data;
|
|
},
|
|
|
|
createPolicy: async (payload: CreatePolicyPayload): Promise<AccessPolicy> => {
|
|
const response = await apiClient.post<AccessPolicy>(`${BASE}/policies`, payload);
|
|
return response.data;
|
|
},
|
|
|
|
updatePolicy: async (policyId: number, payload: UpdatePolicyPayload): Promise<AccessPolicy> => {
|
|
const response = await apiClient.put<AccessPolicy>(`${BASE}/policies/${policyId}`, payload);
|
|
return response.data;
|
|
},
|
|
|
|
deletePolicy: async (policyId: number): Promise<void> => {
|
|
await apiClient.delete(`${BASE}/policies/${policyId}`);
|
|
},
|
|
|
|
// --- Audit Log ---
|
|
|
|
getAuditLog: async (filters?: AuditLogFilters): Promise<AuditLogResponse> => {
|
|
const response = await apiClient.get<AuditLogResponse>(`${BASE}/audit-log`, {
|
|
params: filters,
|
|
});
|
|
return response.data;
|
|
},
|
|
|
|
exportAuditLog: async (filters?: AuditLogFilters): Promise<Blob> => {
|
|
const response = await apiClient.get(`${BASE}/audit-log/export`, {
|
|
params: filters,
|
|
responseType: 'blob',
|
|
});
|
|
return response.data as Blob;
|
|
},
|
|
};
|