import { DataTypes, Model, Op, Sequelize } from 'sequelize'; import { useContextKey } from '@kevisual/context'; import { SyncOpts, User } from './user.ts'; type AddUserOpts = { role: string; }; export enum OrgRole { admin = 'admin', member = 'member', owner = 'owner', } export class Org extends Model { declare id: string; declare username: string; declare description: string; declare users: { role: string; uid: string }[]; /** * operateId 是真实操作者的id * @param user * @param opts */ async addUser(user: User, opts?: { operateId?: string; role: string; needPermission?: boolean; isAdmin?: boolean }) { const hasUser = this.users.find((u) => u.uid === user.id); if (hasUser) { return; } if (user.type !== 'user') { throw Error('Only user can be added to org'); } if (opts?.needPermission) { if (opts?.isAdmin) { } else { const adminUsers = this.users.filter((u) => u.role === 'admin' || u.role === 'owner'); const adminIds = adminUsers.map((u) => u.uid); const hasPermission = adminIds.includes(opts.operateId); if (!hasPermission) { throw Error('No permission'); } } } try { await user.expireOrgs(); } catch (e) { console.error('expireOrgs', e); } const users = [...this.users]; if (opts?.role === 'owner') { const orgOwner = users.find((u) => u.role === 'owner'); if (opts.isAdmin) { } else { if (!opts.operateId) { throw Error('operateId is required'); } const owner = await User.findByPk(opts?.operateId); if (!owner) { throw Error('operateId is not found'); } if (orgOwner?.uid !== owner.id) { throw Error('No permission'); } } if (orgOwner) { orgOwner.role = 'admin'; } users.push({ role: 'owner', uid: user.id }); } else { users.push({ role: opts?.role || 'member', uid: user.id }); } await Org.update({ users }, { where: { id: this.id } }); } /** * operateId 是真实操作者的id * @param user * @param opts */ async removeUser(user: User, opts?: { operateId?: string; needPermission?: boolean; isAdmin?: boolean }) { if (opts?.needPermission) { if (opts?.isAdmin) { } else { const adminUsers = this.users.filter((u) => u.role === 'admin' || u.role === 'owner'); const adminIds = adminUsers.map((u) => u.uid); const hasPermission = adminIds.includes(opts.operateId); if (!hasPermission) { throw Error('No permission'); } } } await user.expireOrgs(); const users = this.users.filter((u) => u.uid !== user.id || u.role === 'owner'); await Org.update({ users }, { where: { id: this.id } }); } /** * operateId 是真实操作者的id * @param user * @param opts */ async getUsers(opts?: { operateId: string; needPermission?: boolean; isAdmin?: boolean }) { const usersIds = this.users.map((u) => u.uid); const orgUser = this.users; if (opts?.needPermission) { // 不在组织内或者不是管理员,如果需要权限,返回空 if (opts.isAdmin) { } else { const hasPermission = usersIds.includes(opts.operateId); if (!hasPermission) { return { hasPermission: false, users: [], }; } } } const _users = await User.findAll({ where: { id: { [Op.in]: usersIds, }, }, }); const users = _users.map((u) => { const role = orgUser.find((r) => r.uid === u.id)?.role; return { id: u.id, username: u.username, role: role, }; }); return { users }; } /** * 检测用户是否在组织内,且角色为role * @param user * @param opts */ async getInRole(userId: string, role = 'admin') { const user = this.users.find((u) => u.uid === userId && u.role === role); return !!user; } } /** * 组织模型,在sequelize之后初始化 */ export const OrgInit = async (newSequelize?: any, tableName?: string, sync?: SyncOpts) => { const sequelize = useContextKey('sequelize'); Org.init( { id: { type: DataTypes.UUID, primaryKey: true, defaultValue: DataTypes.UUIDV4, }, username: { type: DataTypes.STRING, allowNull: false, unique: true, }, description: { type: DataTypes.STRING, allowNull: true, }, users: { type: DataTypes.JSONB, allowNull: true, defaultValue: [], }, }, { sequelize: newSequelize || sequelize, modelName: tableName || 'cf_org', paranoid: true, }, ); if (sync) { await Org.sync({ alter: true, logging: false, ...sync }).catch((e) => { console.error('Org sync', e); }); return Org; } return Org; }; export const OrgModel = useContextKey('OrgModel', () => Org);