extension-user-approval

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

User Approval

用户审批

User approval extension for Caffeine AI.
适用于Caffeine AI的用户审批扩展。

Overview

概述

This skill adds approval-based user management. Users request access; admins approve or reject. Approved users gain access to protected features.
该技能新增了基于审批的用户管理功能。用户提交访问请求,管理员进行审批或拒绝。通过审批的用户可访问受保护的功能。

Backend

后端部分

Approval-based user management:
Prerequisite: You must follow extension-authorization first, as this integration depends on it.
There is a prefabricated module
mo:caffeineai-user-approval/approval
that cannot be modified. It provides approval-based user management with role-based access control.
mo
import AccessControl "mo:caffeineai-authorization/access-control";

module {
    public type ApprovalStatus = {
        #approved;
        #rejected;
        #pending;
    };

    public type UserApprovalState = { /* internal state */ };

    public func initState(accessControlState: AccessControl.AccessControlState) : UserApprovalState;

    public func isApproved(state : UserApprovalState, caller : Principal) : Bool;
    public func setApproval(state : UserApprovalState, user : Principal, approval : ApprovalStatus);

    public type UserApprovalInfo = {
        principal : Principal;
        status : ApprovalStatus;
    };

    public func listApprovals(state : UserApprovalState) : [UserApprovalInfo];
}
Usage (all the following functions are required to be added):
motoko
import AccessControl "mo:caffeineai-authorization/access-control";
import MixinAuthorization "mo:caffeineai-authorization/MixinAuthorization";
import UserApproval "mo:caffeineai-user-approval/approval";
import Principal "mo:core/Principal";
import Runtime "mo:core/Runtime";

actor {
    // Include authorization
    let accessControlState = AccessControl.initState();
    include MixinAuthorization(accessControlState);

    let approvalState = UserApproval.initState(accessControlState);

    public query ({ caller }) func isCallerApproved() : async Bool {
        AccessControl.hasPermission(accessControlState, caller, #admin) or UserApproval.isApproved(approvalState, caller);
    };

    public shared ({ caller }) func requestApproval() : async () {
        UserApproval.requestApproval(approvalState, caller);
    };

    public shared ({ caller }) func setApproval(user : Principal, status : UserApproval.ApprovalStatus) : async () {
        if (not (AccessControl.hasPermission(accessControlState, caller, #admin))) {
            Runtime.trap("Unauthorized: Only admins can perform this action");
        };
        UserApproval.setApproval(approvalState, user, status);
    };

    public query ({ caller }) func listApprovals() : async [UserApproval.UserApprovalInfo] {
        if (not (AccessControl.hasPermission(accessControlState, caller, #admin))) {
            Runtime.trap("Unauthorized: Only admins can perform this action");
        };
        UserApproval.listApprovals(approvalState);
    };

    // In addition to access control guards, add an approval check where needed:
    // Admins should have the permission do use all functionality
    // * Approved users only:
    //   if (not (UserApproval.isApproved(approvalState, caller) or AccessControl.hasPermission(accessControlState, caller, #admin))) {
    //      Runtime.trap("Unauthorized: Only approved users can perform this action");
    //   };
};
On
initState
, existing admins are automatically approved. All other users are pending.
IMPORTANT: Apply the right authorization and/or approval check to each public function.
基于审批的用户管理:
前提条件:由于本集成依赖于授权扩展,您必须先遵循扩展授权的相关指引。
存在一个不可修改的预制模块
mo:caffeineai-user-approval/approval
,它提供了基于角色访问控制的审批式用户管理功能。
mo
import AccessControl "mo:caffeineai-authorization/access-control";

module {
    public type ApprovalStatus = {
        #approved;
        #rejected;
        #pending;
    };

    public type UserApprovalState = { /* internal state */ };

    public func initState(accessControlState: AccessControl.AccessControlState) : UserApprovalState;

    public func isApproved(state : UserApprovalState, caller : Principal) : Bool;
    public func setApproval(state : UserApprovalState, user : Principal, approval : ApprovalStatus);

    public type UserApprovalInfo = {
        principal : Principal;
        status : ApprovalStatus;
    };

    public func listApprovals(state : UserApprovalState) : [UserApprovalInfo];
}
使用方法(以下所有函数均需添加):
motoko
import AccessControl "mo:caffeineai-authorization/access-control";
import MixinAuthorization "mo:caffeineai-authorization/MixinAuthorization";
import UserApproval "mo:caffeineai-user-approval/approval";
import Principal "mo:core/Principal";
import Runtime "mo:core/Runtime";

actor {
    // Include authorization
    let accessControlState = AccessControl.initState();
    include MixinAuthorization(accessControlState);

    let approvalState = UserApproval.initState(accessControlState);

    public query ({ caller }) func isCallerApproved() : async Bool {
        AccessControl.hasPermission(accessControlState, caller, #admin) or UserApproval.isApproved(approvalState, caller);
    };

    public shared ({ caller }) func requestApproval() : async () {
        UserApproval.requestApproval(approvalState, caller);
    };

    public shared ({ caller }) func setApproval(user : Principal, status : UserApproval.ApprovalStatus) : async () {
        if (not (AccessControl.hasPermission(accessControlState, caller, #admin))) {
            Runtime.trap("Unauthorized: Only admins can perform this action");
        };
        UserApproval.setApproval(approvalState, user, status);
    };

    public query ({ caller }) func listApprovals() : async [UserApproval.UserApprovalInfo] {
        if (not (AccessControl.hasPermission(accessControlState, caller, #admin))) {
            Runtime.trap("Unauthorized: Only admins can perform this action");
        };
        UserApproval.listApprovals(approvalState);
    };

    // In addition to access control guards, add an approval check where needed:
    // Admins should have the permission do use all functionality
    // * Approved users only:
    //   if (not (UserApproval.isApproved(approvalState, caller) or AccessControl.hasPermission(accessControlState, caller, #admin))) {
    //      Runtime.trap("Unauthorized: Only approved users can perform this action");
    //   };
};
在调用
initState
时,现有管理员会自动通过审批。所有其他用户状态为待审批。
重要提示:请为每个公共函数添加正确的授权和/或审批校验。

Frontend

前端部分

Approval-based user management:
基于审批的用户管理:

User Approval Flow

用户审批流程

  • Check approval status (
    isCallerApproved
    )
  • If not approved, show option to request approval (
    requestApproval
    )
  • Block access to main features for non-approved users
  • Admins have access to all features of the application
  • Display approval status clearly in the UI
  • 检查审批状态(
    isCallerApproved
  • 若未通过审批,显示提交审批请求的选项(
    requestApproval
  • 阻止未通过审批的用户访问主功能
  • 管理员可访问应用的所有功能
  • 在UI中清晰显示审批状态

Admin Dashboard

管理员控制台

For admin users, provide a dashboard to:
  • List all users with their approval status (
    listApprovals
    )
  • Approve or reject users (
    setApproval
    )
  • View and assign user roles (using
    getCallerUserRole
    and
    assignCallerUserRole
    )
为管理员用户提供控制台以实现以下功能:
  • 列出所有用户及其审批状态(
    listApprovals
  • 审批或拒绝用户(
    setApproval
  • 查看并分配用户角色(使用
    getCallerUserRole
    assignCallerUserRole

Backend Integration

后端集成

The backend already implements the following functionality. The full interface can be found in <backend-interface>
// Check if current user is approved, admins are always approved isCallerApproved(): Promise<boolean>;
// Submit approval request requestApproval(): Promise<void>;
// Get all users and their approval status (admin only) listApprovals(): Promise<Array<UserApprovalInfo>>;
// Approve or reject a user (admin only) setApproval(user: Principal, status: ApprovalStatus): Promise<void>;
// Assign a role to a user (admin only) assignCallerUserRole(user: Principal, role: UserRole): Promise<void>;
// Get current role for a specific user getCallerUserRole(): Promise<UserRole>;
后端已实现以下功能。 完整接口可在<backend-interface>中查看
// 检查当前用户是否已通过审批,管理员始终处于已审批状态 isCallerApproved(): Promise<boolean>;
// 提交审批请求 requestApproval(): Promise<void>;
// 获取所有用户及其审批状态(仅管理员可用) listApprovals(): Promise<Array<UserApprovalInfo>>;
// 审批或拒绝用户(仅管理员可用) setApproval(user: Principal, status: ApprovalStatus): Promise<void>;
// 为用户分配角色(仅管理员可用) assignCallerUserRole(user: Principal, role: UserRole): Promise<void>;
// 获取特定用户的当前角色 getCallerUserRole(): Promise<UserRole>;