206 lines
6.6 KiB
TypeScript
206 lines
6.6 KiB
TypeScript
import type { PermissionKey, Permission, PermissionScope, PermissionScopeType } from "./api";
|
|
|
|
export const PERMISSION_GROUPS = {
|
|
admin: ["admin_full"] as const,
|
|
projects: ["projects_read", "projects_write"] as const,
|
|
creatives: ["creatives_read", "creatives_write"] as const,
|
|
placements: ["placements_read", "placements_write"] as const,
|
|
analytics: ["analytics_read", "analytics_without_clicks", "analytics_own_creatives"] as const,
|
|
} as const;
|
|
|
|
export type PermissionGroup = keyof typeof PERMISSION_GROUPS;
|
|
|
|
export const PERMISSION_ICONS: Record<PermissionKey, string> = {
|
|
admin_full: "👑",
|
|
projects_read: "📁",
|
|
projects_write: "📁",
|
|
creatives_read: "🎨",
|
|
creatives_write: "🎨",
|
|
placements_read: "📋",
|
|
placements_write: "📋",
|
|
analytics_read: "📊",
|
|
analytics_without_clicks: "📊",
|
|
analytics_own_creatives: "📊",
|
|
};
|
|
|
|
export const PERMISSION_LABELS: Record<PermissionKey, string> = {
|
|
admin_full: "Полный доступ к администрированию",
|
|
projects_read: "Просмотр проектов",
|
|
projects_write: "Управление проектами",
|
|
creatives_read: "Просмотр креативов",
|
|
creatives_write: "Управление креативами",
|
|
placements_read: "Просмотр размещений",
|
|
placements_write: "Управление размещениями",
|
|
analytics_read: "Просмотр аналитики",
|
|
analytics_without_clicks: "Аналитика без кликов",
|
|
analytics_own_creatives: "Аналитика своих креативов",
|
|
};
|
|
|
|
export function hasGlobalPermission(permissions: Permission[], key: PermissionKey): boolean {
|
|
return permissions.some((p) => p.key === key && (!p.scopes || p.scopes.length === 0));
|
|
}
|
|
|
|
export function hasScopedPermission(
|
|
permissions: Permission[],
|
|
key: PermissionKey,
|
|
scopeType: PermissionScopeType,
|
|
scopeId: string
|
|
): boolean {
|
|
const perm = permissions.find((p) => p.key === key);
|
|
if (!perm || !perm.scopes) return false;
|
|
return perm.scopes.some((s) => s.type === scopeType && s.id === scopeId);
|
|
}
|
|
|
|
export function getScopesForPermission(
|
|
permissions: Permission[],
|
|
key: PermissionKey,
|
|
scopeType: PermissionScopeType
|
|
): string[] {
|
|
const perm = permissions.find((p) => p.key === key);
|
|
if (!perm || !perm.scopes) return [];
|
|
return perm.scopes.filter((s) => s.type === scopeType).map((s) => s.id);
|
|
}
|
|
|
|
export function addGlobalPermission(permissions: Permission[], key: PermissionKey): Permission[] {
|
|
const perm = permissions.find((p) => p.key === key);
|
|
if (perm) {
|
|
if (!perm.scopes || perm.scopes.length === 0) {
|
|
return permissions;
|
|
}
|
|
const newPerms = permissions.filter((p) => p.key !== key);
|
|
return [...newPerms, { key, scopes: undefined }];
|
|
}
|
|
return [...permissions, { key, scopes: undefined }];
|
|
}
|
|
|
|
export function removePermission(permissions: Permission[], key: PermissionKey): Permission[] {
|
|
return permissions.filter((p) => p.key !== key);
|
|
}
|
|
|
|
export function setScopedPermission(
|
|
permissions: Permission[],
|
|
key: PermissionKey,
|
|
scopeType: PermissionScopeType,
|
|
scopeIds: string[]
|
|
): Permission[] {
|
|
const existing = permissions.find((p) => p.key === key);
|
|
const otherPerms = permissions.filter((p) => p.key !== key);
|
|
|
|
if (scopeIds.length === 0) {
|
|
return otherPerms;
|
|
}
|
|
|
|
const existingScopes = existing?.scopes?.filter((s) => s.type !== scopeType) || [];
|
|
const newScopes = [...existingScopes, ...scopeIds.map((id) => ({ type: scopeType, id }))];
|
|
|
|
return [...otherPerms, { key, scopes: newScopes }];
|
|
}
|
|
|
|
export function toggleScopedPermission(
|
|
permissions: Permission[],
|
|
key: PermissionKey,
|
|
scopeType: PermissionScopeType,
|
|
scopeId: string
|
|
): Permission[] {
|
|
const existing = permissions.find((p) => p.key === key);
|
|
const otherPerms = permissions.filter((p) => p.key !== key);
|
|
|
|
if (!existing) {
|
|
return [...permissions, { key, scopes: [{ type: scopeType, id: scopeId }] }];
|
|
}
|
|
|
|
const scopes = existing.scopes || [];
|
|
const hasScope = scopes.some((s) => s.type === scopeType && s.id === scopeId);
|
|
|
|
if (hasScope) {
|
|
const filtered = scopes.filter((s) => !(s.type === scopeType && s.id === scopeId));
|
|
if (filtered.length === 0) {
|
|
return otherPerms;
|
|
}
|
|
return [...otherPerms, { key, scopes: filtered }];
|
|
}
|
|
|
|
return [...otherPerms, { key, scopes: [...scopes, { type: scopeType, id: scopeId }] }];
|
|
}
|
|
|
|
export function mergePermissions(
|
|
current: Permission[],
|
|
updates: Permission[]
|
|
): Permission[] {
|
|
const result = new Map<string, Permission>();
|
|
|
|
for (const perm of current) {
|
|
result.set(perm.key, perm);
|
|
}
|
|
|
|
for (const update of updates) {
|
|
const existing = result.get(update.key);
|
|
if (!existing) {
|
|
result.set(update.key, update);
|
|
} else if (!update.scopes || update.scopes.length === 0) {
|
|
result.set(update.key, update);
|
|
} else {
|
|
const existingScopes = existing.scopes || [];
|
|
const newScopes = new Map<string, PermissionScope>();
|
|
|
|
for (const scope of existingScopes) {
|
|
newScopes.set(`${scope.type}:${scope.id}`, scope);
|
|
}
|
|
for (const scope of update.scopes) {
|
|
newScopes.set(`${scope.type}:${scope.id}`, scope);
|
|
}
|
|
result.set(update.key, { key: update.key, scopes: Array.from(newScopes.values()) });
|
|
}
|
|
}
|
|
|
|
return Array.from(result.values());
|
|
}
|
|
|
|
export function calculatePermissionDiff(
|
|
original: Permission[],
|
|
updated: Permission[]
|
|
): { added: Permission[]; removed: Permission[]; modified: Permission[] } {
|
|
const added: Permission[] = [];
|
|
const removed: Permission[] = [];
|
|
const modified: Permission[] = [];
|
|
|
|
const originalKeys = new Set(original.map((p) => p.key));
|
|
const updatedKeys = new Set(updated.map((p) => p.key));
|
|
|
|
for (const perm of updated) {
|
|
if (!originalKeys.has(perm.key)) {
|
|
added.push(perm);
|
|
}
|
|
}
|
|
|
|
for (const perm of original) {
|
|
if (!updatedKeys.has(perm.key)) {
|
|
removed.push(perm);
|
|
}
|
|
}
|
|
|
|
for (const perm of updated) {
|
|
const orig = original.find((p) => p.key === perm.key);
|
|
if (orig && JSON.stringify(orig.scopes) !== JSON.stringify(perm.scopes)) {
|
|
modified.push(perm);
|
|
}
|
|
}
|
|
|
|
return { added, removed, modified };
|
|
}
|
|
|
|
export function isPermissionFullyGlobal(permissions: Permission[], key: PermissionKey): boolean {
|
|
const perm = permissions.find((p) => p.key === key);
|
|
return perm !== undefined && (!perm.scopes || perm.scopes.length === 0);
|
|
}
|
|
|
|
export function getAllScopeIdsForPermission(
|
|
permissions: Permission[],
|
|
key: PermissionKey,
|
|
scopeType: PermissionScopeType
|
|
): string[] {
|
|
const perm = permissions.find((p) => p.key === key);
|
|
if (!perm || !perm.scopes) return [];
|
|
return perm.scopes.filter((s) => s.type === scopeType).map((s) => s.id);
|
|
}
|