const Sequelize = require("sequelize"); const { normalize_for_write, build_search_where } = require("../utils/query_helpers"); const baseModel = require("../../middleware/baseModel"); const tokenLogic = require("../service/biz_token_logic"); const audit = require("../utils/biz_audit"); module.exports = { "POST /biz_user/page": async (ctx) => { const body = ctx.getBody(); const param = body.param || body; const pageOption = param.pageOption || {}; const seachOption = param.seachOption || {}; const pageNum = parseInt(pageOption.page, 10) || 1; const pageSize = parseInt(pageOption.pageSize, 10) || 20; const offset = (pageNum - 1) * pageSize; const biz_user = baseModel.biz_user; const where = build_search_where(biz_user, seachOption); const { count, rows } = await biz_user.findAndCountAll({ where, offset, limit: pageSize, order: [["id", "DESC"]], attributes: { include: [ [ Sequelize.literal( `(SELECT COUNT(*) FROM biz_api_token WHERE biz_api_token.user_id = biz_user.id)` ), "token_count", ], ], }, }); ctx.success({ rows, count }); }, "POST /biz_user/add": async (ctx) => { const body = ctx.getBody(); const biz_user = baseModel.biz_user; const payload = normalize_for_write(biz_user, body, { for_create: true }); const row = await biz_user.create(payload); await audit.logAudit({ admin_user_id: audit.pickAdminId(ctx), biz_user_id: row.id, action: "biz_user.add", resource_type: "biz_user", resource_id: row.id, detail: { name: row.name }, }); const out = row.get({ plain: true }); let plain_token = null; let token_warn = null; let token_error = null; const auto_token = body.auto_create_token !== false; if (auto_token && row.status === "active") { try { const result = await tokenLogic.createToken({ user_id: row.id, token_name: body.initial_token_name || "default", expire_at: body.initial_token_expire_at || tokenLogic.defaultTokenExpireAt(), }); await audit.logAudit({ admin_user_id: audit.pickAdminId(ctx), biz_user_id: row.id, action: "biz_token.create", resource_type: "biz_api_token", resource_id: result.row.id, detail: { token_name: result.row.token_name, via: "biz_user.add" }, }); plain_token = result.plain_token; token_warn = result.warn; } catch (e) { token_error = e.message || String(e); } } ctx.success({ ...out, plain_token, token_warn, token_error, }); }, "POST /biz_user/edit": async (ctx) => { const body = ctx.getBody(); const id = body.id; if (id === undefined || id === null || id === "") throw new Error("缺少 id"); const biz_user = baseModel.biz_user; const payload = normalize_for_write(biz_user, body, { for_create: false }); delete payload.id; await biz_user.update(payload, { where: { id } }); await audit.logAudit({ admin_user_id: audit.pickAdminId(ctx), biz_user_id: body.id, action: "biz_user.edit", resource_type: "biz_user", resource_id: body.id, }); ctx.success({}); }, "POST /biz_user/del": async (ctx) => { const body = ctx.getBody(); const id = body.id !== undefined ? body.id : body; if (id === undefined || id === null || id === "") throw new Error("缺少 id"); const biz_user = baseModel.biz_user; await biz_user.destroy({ where: { id } }); await audit.logAudit({ admin_user_id: audit.pickAdminId(ctx), biz_user_id: body.id, action: "biz_user.del", resource_type: "biz_user", resource_id: body.id, }); ctx.success({}); }, "GET /biz_user/detail": async (ctx) => { const q = ctx.query || {}; const id = q.id || q.ID; if (id === undefined || id === null || id === "") throw new Error("缺少 id"); const biz_user = baseModel.biz_user; const user = await biz_user.findByPk(id); if (!user) { return ctx.fail("用户不存在"); } const subscriptions = await baseModel.biz_subscription.findAll({ where: { user_id: id }, order: [["id", "DESC"]], limit: 10, }); const tokenCount = await baseModel.biz_api_token.count({ where: { user_id: id }, }); const tokens = await baseModel.biz_api_token.findAll({ where: { user_id: id }, order: [["id", "DESC"]], limit: 200, attributes: ["id", "user_id", "plan_id", "token_name", "status", "expire_at", "last_used_at"], }); ctx.success({ user, subscriptions, tokenCount, tokens, }); }, "GET /biz_user/all": async (ctx) => { const biz_user = baseModel.biz_user; const rows = await biz_user.findAll({ limit: 2000, order: [["id", "DESC"]], }); ctx.success(rows); }, "POST /biz_user/disable": async (ctx) => { const body = ctx.getBody(); const id = body.id; if (id == null) return ctx.fail("缺少 id"); const biz_user = baseModel.biz_user; await biz_user.update({ status: "disabled" }, { where: { id } }); await audit.logAudit({ admin_user_id: audit.pickAdminId(ctx), biz_user_id: id, action: "biz_user.disable", resource_type: "biz_user", resource_id: id, }); ctx.success({}); }, "POST /biz_user/enable": async (ctx) => { const body = ctx.getBody(); const id = body.id; if (id == null) return ctx.fail("缺少 id"); const biz_user = baseModel.biz_user; await biz_user.update({ status: "active" }, { where: { id } }); await audit.logAudit({ admin_user_id: audit.pickAdminId(ctx), biz_user_id: id, action: "biz_user.enable", resource_type: "biz_user", resource_id: id, }); ctx.success({}); }, "POST /biz_user/export": async (ctx) => { const body = ctx.getBody(); const param = body.param || body; const biz_user = baseModel.biz_user; const where = build_search_where(biz_user, param.seachOption || {}); const rows = await biz_user.findAll({ where, limit: 10000, order: [["id", "DESC"]], }); ctx.success({ rows }); }, "POST /biz_user/revoke_all_tokens": async (ctx) => { const body = ctx.getBody(); const userId = body.user_id != null ? body.user_id : body.id; if (userId == null) return ctx.fail("缺少 user_id"); const n = await tokenLogic.revokeAllForUser(userId); await audit.logAudit({ admin_user_id: audit.pickAdminId(ctx), biz_user_id: userId, action: "biz_token.revoke_all", resource_type: "biz_user", resource_id: userId, detail: { affected: n }, }); ctx.success({ revoked: n }); }, };