/** * Permission - Client-side permission checking * * Provides permission and role checking for JavaScript using pre-resolved * permissions from window.rsxapp.user.resolved_permissions. This mirrors the * PHP Permission class functionality for client-side UI logic. * * The resolved_permissions array is computed server-side via User_Model::toArray() * 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?.user?.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?.user?.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?.user?.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?.user?.resolved_permissions ?? []; } }