// ==========================================================================
// 所属模块：user - acl
// 生成日期：2024-09-13 13:56:00 +0800 CST
// 生成路径: user/acl.js
// 生成人：Cato
// 功能描述：通过用户token取用户权限组、通过权限组id取具体的权限，再判断用户是否有权限访问对应的路径。
// ==========================================================================

// 对于权限的判断，先取Method，再取Path，最后取Token。
// 通过Token取得用户加入的用户组和用户的权限信息，
// 权限数据在数据库中的权限组表存储为 roleId、name、method、patterns。
// 权限组在用户的存储为 UserID、roleIds（权限组ID数组）。
// 取用户信息中的ruleIds字段，然后根据ruleIds查询用户权限信息
// 判断用户是否有权限访问该路径，如果没有权限，则返回错误信息。

// method在数据库存储的格式为 GET、POST、PUT、DELETE
// patterns在数据库存储的格式为 /api/v1/xxx/xxx
// 当用户拥有更上一级目录的权限时，可以访问该目录下的所有子目录和文件。
// 例如 用户拥有 /api/v1/xxx 的权限，则可以访问 /api/v1/xxx/xxx/xxx 的路径。

// 是否允许公开访问
if (!ALLOW_PUBLIC_ACCESS) {
  // 取 Authorization - Bearer 后面的Token值
  let userToken = payload.get().headers["Authorization"] || payload.get().query["token"] || payload.get().headers["X-Token"] || (payload.get().cookie ? payload.get().cookie["token"] : null);
  if (!userToken) {
    return errMsg(413, "未登录");
  }

  // 判断userToken是否是数组
  if (Array.isArray(userToken)) {
    // userToken = userToken[0]
    // userToken 取不为undefined的第一个值
    userToken = userToken.find(item => item !== undefined)
  }

  // 删除 Bearer 部分
  userToken = userToken.replace("Bearer ", "").replace(/\s/g, "");

  let tokenInfo = jwt_parse(userToken) // 这里需要密钥进行验证
  if (!tokenInfo) {
    return errMsg(413, "身份验证失败");
  }

  // 判断tokenInfo.exp 是否过期
  if (tokenInfo.exp < Date.now() / 1000) {
    return errMsg(413, "身份凭证已过期");
  }

  // response.cookies.setRaw(`token=${userToken}; Path=/; Max-Age=604800; SameSite=Strict; CrossSite=Strict; Priority=High; PartitionKeySite=Main; HttpOnly; Secure`)


  USER_INFO = SQL.query(
    'system_sql',
    "SELECT * FROM sys_users WHERE user_id = ?",
    tokenInfo.uid
  );
  if (USER_INFO.length == 0) {
    return errMsg(413, "用户不存在");
  }

  USER_INFO = USER_INFO[0]

  if (OPERATION_TITLE, OPERATION_TYPE) {
    let location = "未知"
    SQL.push(
      'system_sql', "INSERT INTO log_opers (oper_id, oper_name, business_type, title, method, oper_param, status, oper_ip, oper_url, oper_location) VALUES (?,?,?,?,?,?,?,?,?,?)",
      ex.suid().base58(), tokenInfo.unm, OPERATION_TYPE, OPERATION_TITLE, payload.get().method, payload.get().body?.toString(), 0, payload.get().remote_addr, payload.get().path, location
    )
  }
}
