import PocketBase, { RecordModel } from "pocketbase" import { Logger } from "winston" import { Context } from "../../types" import PbToolBase from "../base" const DB_NAME = "users" /** * 用户基础信息接口定义 */ interface User { /** 用户邮箱 */ email: string /** 用户名称 */ name: string /** 飞书用户 Open ID */ openId: string /** 飞书用户 User ID */ userId: string /** 用户头像链接 */ avatar: string /** 用户密码 */ password: string /** 邮箱可见性标志 */ emailVisibility: boolean /** 用户邮箱是否已验证 */ verified: boolean } /** 完整用户模型类型,包含 PocketBase 记录基础字段 */ export type UserModel = User & RecordModel /** * 用户数据库操作类 * 提供用户相关的查询、创建等操作 */ class UserDB extends PbToolBase { /** * 创建用户数据库操作实例 * * @param pbClient - PocketBase 客户端实例 * @param logger - 日志记录器实例 */ constructor(pbClient: PocketBase, logger: Logger) { super(DB_NAME, pbClient, logger) } /** * 根据飞书用户 ID 获取用户记录 * * @param userId - 飞书用户 ID * @returns 成功时返回用户记录,失败时返回 null * * @example * ```typescript * const user = await userDB.getByUserId("ou_123456"); * ``` */ public getByUserId = (userId: string) => { return this.getFirstOne(`userId = "${userId}"`) } /** * 根据请求上下文获取用户信息 * 如果用户不存在,则尝试从飞书获取用户信息并创建新用户 * * @param context - 请求上下文,包含飞书请求体和飞书服务 * @returns 成功时返回用户记录,失败时返回 null * * @example * ```typescript * const user = await userDB.getByCtx(ctx); * ``` */ public getByCtx = async ({ larkBody, larkService }: Context) => { if (!larkBody.userId) return null const user = await this.getByUserId(larkBody.userId) if (user) return user const userInfo = await larkService.user.getOne(larkBody.userId, "user_id") if (userInfo.code === 0) return null const { user_id, open_id, avatar: { avatar_origin }, email, name, } = userInfo.data.user const newUser = { userId: user_id, openId: open_id, avatar: avatar_origin, email, name, emailVisibility: false, verified: false, password: email, } return await this.create(newUser) } } export default UserDB