Files
rspade_system/app/RSpade/Core/Js/Permission.js
root 8ef798c30f Add client-side Permission class and resolved_permissions to rsxapp
Refactor date/time classes to reduce code redundancy

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-13 08:35:06 +00:00

130 lines
3.9 KiB
JavaScript
Executable File

/**
* Permission - Client-side permission checking
*
* Provides permission and role checking for JavaScript using pre-resolved
* permissions from window.rsxapp.resolved_permissions. This mirrors the
* PHP Permission class functionality for client-side UI logic.
*
* The resolved_permissions array is computed server-side by applying:
* 1. Role default permissions
* 2. Supplementary GRANTs (added)
* 3. Supplementary DENYs (removed)
*
* This ensures JS permission checks match PHP exactly.
*
* Usage:
* // Check authentication
* if (Permission.is_logged_in()) { ... }
*
* // Check specific permission
* if (Permission.has_permission(User_Model.PERM_EDIT_DATA)) { ... }
*
* // Check multiple permissions
* if (Permission.has_any_permission([User_Model.PERM_EDIT_DATA, User_Model.PERM_VIEW_DATA])) { ... }
* if (Permission.has_all_permissions([User_Model.PERM_MANAGE_SITE_USERS, User_Model.PERM_VIEW_USER_ACTIVITY])) { ... }
*
* // Check role level
* if (Permission.has_role(User_Model.ROLE_MANAGER)) { ... }
*
* // Check if can admin a role (for UI showing role assignment options)
* if (Permission.can_admin_role(User_Model.ROLE_USER)) { ... }
*/
class Permission {
/**
* Check if user is logged in
*
* @returns {boolean}
*/
static is_logged_in() {
return window.rsxapp?.is_auth === true;
}
/**
* Get current user object or null
*
* @returns {Object|null}
*/
static get_user() {
return window.rsxapp?.user ?? null;
}
/**
* Check if current user has a specific permission
*
* @param {number} permission - Permission constant (e.g., User_Model.PERM_EDIT_DATA)
* @returns {boolean}
*/
static has_permission(permission) {
const permissions = window.rsxapp?.resolved_permissions ?? [];
return permissions.includes(permission);
}
/**
* Check if current user has ANY of the specified permissions
*
* @param {number[]} permissions - Array of permission constants
* @returns {boolean}
*/
static has_any_permission(permissions) {
const resolved = window.rsxapp?.resolved_permissions ?? [];
return permissions.some(p => resolved.includes(p));
}
/**
* Check if current user has ALL of the specified permissions
*
* @param {number[]} permissions - Array of permission constants
* @returns {boolean}
*/
static has_all_permissions(permissions) {
const resolved = window.rsxapp?.resolved_permissions ?? [];
return permissions.every(p => resolved.includes(p));
}
/**
* Check if current user has at least the specified role level
*
* "At least" means same or higher privilege (lower role_id number).
* Example: has_role(ROLE_MANAGER) returns true for Site Admins and above.
*
* @param {number} role_id - Role constant (e.g., User_Model.ROLE_MANAGER)
* @returns {boolean}
*/
static has_role(role_id) {
const user = window.rsxapp?.user;
if (!user) {
return false;
}
// Lower role_id = higher privilege
return user.role_id <= role_id;
}
/**
* Check if current user can administer users with the given role
*
* Prevents privilege escalation - users can only assign roles
* at or below their own permission level.
*
* @param {number} role_id - Role constant (e.g., User_Model.ROLE_USER)
* @returns {boolean}
*/
static can_admin_role(role_id) {
const user = window.rsxapp?.user;
if (!user) {
return false;
}
const can_admin = user.role_id__can_admin_roles ?? [];
return can_admin.includes(role_id);
}
/**
* Get all resolved permissions for current user
*
* @returns {number[]} Array of permission IDs
*/
static get_resolved_permissions() {
return window.rsxapp?.resolved_permissions ?? [];
}
}