- 项目总群:≥3 人 appchat/create 自动建群(chatid=pgc+projectId),成员 diff 增删同步;DROP project_group_chats;推送改 appchat/send 群发、无群降级逐人 - 任务负责人:tasks.owner_userid(新建/编辑任务通讯录选人),task_set_owner 分配即预建 tgc 任务群发介绍,群主链接只归属负责人 - 任务编辑 task_update:基础字段+截图任务数量/关键词/说明,contents 调平只删 available 尾行 - 删除「一键推送」:task-one-click-push-service 整体移除(recordCardAck 移入 wecom-callback-events) - 负责人后台视角:users.wecom_userid 绑定,lib/owner-scope 行级过滤(undefined=全量/""=空范围/非空=过滤),~30 action 补 managerGate/taskOwnerGate,owner 登录仅见工作台/任务中心/数据回收/复盘报表 - 任务绑定客户群+进群活码:tasks 增 customer_chat_id/name、join_config_id、join_qr_code 4 列,join_way add/update/get/del(换绑走 update 保 config_id 活码不变),后台「客户群」弹窗,portal 认领后扫码自助进群(满员自动开新群) - 迁移 0013/0014/0015;催办支持按任务;企微可信域名 IP 验证文件 - 288 测试全绿;真机全链路验收通过(列群/活码四端点/portal 渲染/解绑清空)
196 lines
6.5 KiB
TypeScript
196 lines
6.5 KiB
TypeScript
import {
|
|
createPasswordRecord,
|
|
getRequestPrincipal,
|
|
managerForbidden,
|
|
normalizeUsername,
|
|
type UserRole,
|
|
validatePassword,
|
|
validateUsername,
|
|
} from "../../../lib/user-auth";
|
|
import { ensureSchema, getRawDb } from "../../../lib/mvp-db";
|
|
|
|
type UserRow = {
|
|
id: string;
|
|
username: string;
|
|
role: UserRole;
|
|
wecom_userid: string | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
};
|
|
|
|
async function manager(request: Request) {
|
|
const principal = await getRequestPrincipal(request);
|
|
if (!principal || principal.kind !== "user") return null;
|
|
return ["super_admin", "admin"].includes(principal.user.role)
|
|
? principal.user
|
|
: null;
|
|
}
|
|
|
|
async function listUsers() {
|
|
const result = await getRawDb()
|
|
.prepare(
|
|
`SELECT id, username, role, wecom_userid, created_at, updated_at
|
|
FROM users
|
|
ORDER BY CASE role WHEN 'super_admin' THEN 1 WHEN 'admin' THEN 2 ELSE 3 END,
|
|
created_at ASC`,
|
|
)
|
|
.all<UserRow>();
|
|
return result.results;
|
|
}
|
|
|
|
export async function GET(request: Request) {
|
|
await ensureSchema();
|
|
if (!(await manager(request))) return managerForbidden();
|
|
return Response.json({ users: await listUsers() });
|
|
}
|
|
|
|
export async function POST(request: Request) {
|
|
await ensureSchema();
|
|
const currentUser = await manager(request);
|
|
if (!currentUser) return managerForbidden();
|
|
try {
|
|
const body = (await request.json()) as {
|
|
action?: string;
|
|
username?: string;
|
|
password?: string;
|
|
role?: UserRole;
|
|
userId?: string;
|
|
wecomUserid?: string;
|
|
};
|
|
const db = getRawDb();
|
|
|
|
if (body.action === "create") {
|
|
const password = String(body.password ?? "");
|
|
if (!validatePassword(password)) {
|
|
return Response.json({ error: "密码需为8—72位" }, { status: 400 });
|
|
}
|
|
const passwordRecord = await createPasswordRecord(password);
|
|
const username = normalizeUsername(body.username);
|
|
const role = body.role === "admin" ? "admin" : "user";
|
|
const wecomUserid = String(body.wecomUserid ?? "")
|
|
.trim()
|
|
.slice(0, 128);
|
|
if (!validateUsername(username)) {
|
|
return Response.json(
|
|
{ error: "账号需为2—32位中文、字母、数字或 _ . @ + -" },
|
|
{ status: 400 },
|
|
);
|
|
}
|
|
if (currentUser.role !== "super_admin" && role !== "user") {
|
|
return managerForbidden();
|
|
}
|
|
await db
|
|
.prepare(
|
|
`INSERT INTO users
|
|
(id, username, password_hash, password_salt, password_iterations, role, wecom_userid)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
)
|
|
.bind(
|
|
crypto.randomUUID(),
|
|
username,
|
|
passwordRecord.passwordHash,
|
|
passwordRecord.passwordSalt,
|
|
passwordRecord.passwordIterations,
|
|
role,
|
|
wecomUserid,
|
|
)
|
|
.run();
|
|
} else if (body.action === "set_wecom") {
|
|
const wecomUserid = String(body.wecomUserid ?? "")
|
|
.trim()
|
|
.slice(0, 128);
|
|
const target = await db
|
|
.prepare("SELECT id, role FROM users WHERE id = ?")
|
|
.bind(String(body.userId ?? ""))
|
|
.first<{ id: string; role: UserRole }>();
|
|
if (!target) {
|
|
return Response.json({ error: "没有找到这个账号" }, { status: 404 });
|
|
}
|
|
if (target.role === "super_admin") {
|
|
return Response.json(
|
|
{ error: "不能修改超级管理员账号" },
|
|
{ status: 403 },
|
|
);
|
|
}
|
|
if (currentUser.role !== "super_admin" && target.role !== "user") {
|
|
return managerForbidden();
|
|
}
|
|
await db
|
|
.prepare(
|
|
`UPDATE users SET wecom_userid = ?, updated_at = CURRENT_TIMESTAMP
|
|
WHERE id = ?`,
|
|
)
|
|
.bind(wecomUserid, target.id)
|
|
.run();
|
|
} else if (body.action === "reset_password") {
|
|
const password = String(body.password ?? "");
|
|
if (!validatePassword(password)) {
|
|
return Response.json({ error: "密码需为8—72位" }, { status: 400 });
|
|
}
|
|
const passwordRecord = await createPasswordRecord(password);
|
|
const target = await db
|
|
.prepare("SELECT id, role FROM users WHERE id = ?")
|
|
.bind(String(body.userId ?? ""))
|
|
.first<{ id: string; role: UserRole }>();
|
|
if (!target) {
|
|
return Response.json({ error: "没有找到这个账号" }, { status: 404 });
|
|
}
|
|
if (
|
|
target.role === "super_admin" &&
|
|
!(currentUser.role === "super_admin" && target.id === currentUser.id)
|
|
) {
|
|
return Response.json({ error: "不能修改其他超级管理员账号" }, { status: 403 });
|
|
}
|
|
if (currentUser.role !== "super_admin" && target.role !== "user") {
|
|
return managerForbidden();
|
|
}
|
|
await db.batch([
|
|
db
|
|
.prepare(
|
|
`UPDATE users SET
|
|
password_hash = ?, password_salt = ?, password_iterations = ?,
|
|
updated_at = CURRENT_TIMESTAMP
|
|
WHERE id = ?`,
|
|
)
|
|
.bind(
|
|
passwordRecord.passwordHash,
|
|
passwordRecord.passwordSalt,
|
|
passwordRecord.passwordIterations,
|
|
target.id,
|
|
),
|
|
db.prepare("DELETE FROM auth_sessions WHERE user_id = ?").bind(target.id),
|
|
]);
|
|
} else if (body.action === "delete") {
|
|
const target = await db
|
|
.prepare("SELECT id, role FROM users WHERE id = ?")
|
|
.bind(String(body.userId ?? ""))
|
|
.first<{ id: string; role: UserRole }>();
|
|
if (!target) {
|
|
return Response.json({ error: "没有找到这个账号" }, { status: 404 });
|
|
}
|
|
if (target.id === currentUser.id) {
|
|
return Response.json({ error: "不能删除当前登录账号" }, { status: 400 });
|
|
}
|
|
if (target.role === "super_admin") {
|
|
return Response.json({ error: "不能删除超级管理员账号" }, { status: 403 });
|
|
}
|
|
if (currentUser.role !== "super_admin" && target.role !== "user") {
|
|
return managerForbidden();
|
|
}
|
|
await db.batch([
|
|
db.prepare("DELETE FROM auth_sessions WHERE user_id = ?").bind(target.id),
|
|
db.prepare("DELETE FROM users WHERE id = ? AND role <> 'super_admin'").bind(target.id),
|
|
]);
|
|
} else {
|
|
return Response.json({ error: "不支持的操作" }, { status: 400 });
|
|
}
|
|
return Response.json({ users: await listUsers() });
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : "操作失败";
|
|
return Response.json(
|
|
{ error: message.includes("UNIQUE") ? "这个登录账号已存在" : message },
|
|
{ status: message.includes("UNIQUE") ? 409 : 500 },
|
|
);
|
|
}
|
|
}
|