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 = { 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 = { 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(); 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(); 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); }