remove mark

This commit is contained in:
2025-12-04 10:31:37 +08:00
parent 46aa293cce
commit 2a55f2d3ef
35 changed files with 1837 additions and 726 deletions

184
src/auth/models/org.ts Normal file
View File

@@ -0,0 +1,184 @@
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>('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);