166 lines
5.2 KiB
TypeScript
166 lines
5.2 KiB
TypeScript
/**
|
|
* QuickCreate Permission Service
|
|
*
|
|
* Checks if the current user has permission to create records.
|
|
* Uses custom API: asset_lite.api.user_roles.has_create_permission
|
|
* which uses ignore_permissions=True to query Custom DocPerm
|
|
*/
|
|
|
|
// Cache for permissions to avoid repeated API calls
|
|
const permissionCache: Map<string, boolean> = new Map();
|
|
let userRolesCache: string[] | null = null;
|
|
let cacheTimestamp: number = 0;
|
|
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
|
|
|
|
/**
|
|
* Get current user's roles using custom API
|
|
* Uses: asset_lite.api.user_roles.get_user_roles
|
|
*/
|
|
export const getUserRoles = async (): Promise<string[]> => {
|
|
// Check cache
|
|
const now = Date.now();
|
|
if (userRolesCache && (now - cacheTimestamp) < CACHE_DURATION) {
|
|
console.log('[PermissionService] Using cached roles:', userRolesCache);
|
|
return userRolesCache;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('/api/method/asset_lite.api.user_roles.get_user_roles', {
|
|
method: 'GET',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
credentials: 'include',
|
|
});
|
|
const data = await response.json();
|
|
|
|
if (data.message && Array.isArray(data.message)) {
|
|
userRolesCache = data.message;
|
|
cacheTimestamp = now;
|
|
console.log('[PermissionService] User roles fetched:', data.message);
|
|
return data.message;
|
|
}
|
|
|
|
console.warn('[PermissionService] Unexpected roles response:', data);
|
|
return [];
|
|
} catch (err) {
|
|
console.error('[PermissionService] Error fetching user roles:', err);
|
|
return [];
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Check if user has specific roles using custom API
|
|
* Uses: asset_lite.api.user_roles.check_has_role
|
|
*/
|
|
export const checkHasRole = async (roles: string[]): Promise<boolean> => {
|
|
try {
|
|
const response = await fetch('/api/method/asset_lite.api.user_roles.check_has_role', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
credentials: 'include',
|
|
body: JSON.stringify({
|
|
roles: roles.join(',')
|
|
})
|
|
});
|
|
|
|
const data = await response.json();
|
|
return data.message?.has_role === true;
|
|
} catch (err) {
|
|
console.error('[PermissionService] Error checking roles:', err);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Check if user has create permission for a doctype
|
|
* Uses custom API: asset_lite.api.user_roles.has_create_permission
|
|
* This API uses ignore_permissions=True to query Custom DocPerm
|
|
*
|
|
* @param doctype - The doctype to check permission for
|
|
* @returns Promise<boolean> - true if user can create, false otherwise
|
|
*/
|
|
export const hasCreatePermission = async (doctype: string): Promise<boolean> => {
|
|
// Check cache first
|
|
const cacheKey = `create_${doctype}`;
|
|
if (permissionCache.has(cacheKey)) {
|
|
const cached = permissionCache.get(cacheKey)!;
|
|
console.log(`[PermissionService] ${doctype} (cached): ${cached}`);
|
|
return cached;
|
|
}
|
|
|
|
console.log(`[PermissionService] Checking create permission for: ${doctype}`);
|
|
|
|
try {
|
|
// Use custom API that has ignore_permissions=True
|
|
const response = await fetch('/api/method/asset_lite.api.user_roles.has_create_permission', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
credentials: 'include',
|
|
body: JSON.stringify({ doctype })
|
|
});
|
|
|
|
const data = await response.json();
|
|
console.log(`[PermissionService] has_create_permission response for ${doctype}:`, data);
|
|
|
|
// Check response
|
|
const hasPermission = data.message?.has_permission === true;
|
|
|
|
if (hasPermission) {
|
|
console.log(`[PermissionService] ${doctype}: Permission GRANTED via ${data.message?.reason} (role: ${data.message?.role})`);
|
|
} else {
|
|
console.log(`[PermissionService] ${doctype}: Permission DENIED - ${data.message?.reason}`);
|
|
}
|
|
|
|
// Cache the result
|
|
permissionCache.set(cacheKey, hasPermission);
|
|
|
|
return hasPermission;
|
|
} catch (err) {
|
|
console.error(`[PermissionService] Error checking permission for ${doctype}:`, err);
|
|
|
|
// Fallback: Check if System Manager
|
|
try {
|
|
const isAdmin = await checkHasRole(['System Manager', 'Administrator']);
|
|
if (isAdmin) {
|
|
console.log('[PermissionService] Fallback: User is admin, granting permission');
|
|
permissionCache.set(cacheKey, true);
|
|
return true;
|
|
}
|
|
} catch (e) {
|
|
console.error('[PermissionService] Fallback check failed:', e);
|
|
}
|
|
|
|
// On error, default to false (safer)
|
|
permissionCache.set(cacheKey, false);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Clear permission cache
|
|
* Call this when user logs in/out or permissions change
|
|
*/
|
|
export const clearPermissionCache = (): void => {
|
|
permissionCache.clear();
|
|
userRolesCache = null;
|
|
cacheTimestamp = 0;
|
|
console.log('[PermissionService] Cache cleared');
|
|
};
|
|
|
|
/**
|
|
* Preload permissions for multiple doctypes
|
|
* Useful for initial page load
|
|
*
|
|
* @param doctypes - Array of doctypes to preload permissions for
|
|
*/
|
|
export const preloadPermissions = async (doctypes: string[]): Promise<void> => {
|
|
console.log('[PermissionService] Preloading permissions for:', doctypes);
|
|
await Promise.all(doctypes.map(doctype => hasCreatePermission(doctype)));
|
|
};
|
|
|
|
export default {
|
|
getUserRoles,
|
|
checkHasRole,
|
|
hasCreatePermission,
|
|
clearPermissionCache,
|
|
preloadPermissions,
|
|
}; |