diff --git a/package.json b/package.json index 9be21c1..0de005f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/code-center-module", - "version": "0.0.7", + "version": "0.0.9", "description": "", "main": "dist/system.mjs", "module": "dist/system.mjs", diff --git a/src/models/org.ts b/src/models/org.ts index 82b685e..d25c7ae 100644 --- a/src/models/org.ts +++ b/src/models/org.ts @@ -1,16 +1,123 @@ -import { DataTypes, Model, Sequelize } from 'sequelize'; +import { DataTypes, Model, Op, Sequelize } from 'sequelize'; import { useContextKey } from '@kevisual/use-config/context'; -import { SyncOpts } from './user.ts'; +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'); + } + } + } + await user.expireOrgs(); + const users = [...this.users]; + 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 = (newSequelize?: any, tableName?: string, sync?: SyncOpts) => { +export const OrgInit = async (newSequelize?: any, tableName?: string, sync?: SyncOpts) => { const sequelize = useContextKey('sequelize'); Org.init( { @@ -41,7 +148,7 @@ export const OrgInit = (newSequelize?: any, tableName?: string, sync?: SyncOpts) }, ); if (sync) { - Org.sync({ alter: true, logging: false, ...sync }).catch((e) => { + await Org.sync({ alter: true, logging: false, ...sync }).catch((e) => { console.error('Org sync', e); }); return Org; diff --git a/src/models/user.ts b/src/models/user.ts index 805b46a..684e0c5 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -14,6 +14,11 @@ const config = useConfig<{ tokenSecret: string }>(); type UserData = { orgs?: string[]; }; +export enum UserTypes { + 'user' = 'user', + 'org' = 'org', + 'visitor' = 'visitor', +} /** * 用户模型,在sequelize和Org之后初始化 */ @@ -96,10 +101,11 @@ export class User extends Model { await redis.del(`user:${me.id}:orgs`); return newUser; } - createPassword(password: string) { + async createPassword(password: string) { const salt = this.salt; const cPassword = cryptPwd(password, salt); this.password = cPassword; + await this.update({ password: cPassword }); return cPassword; } checkPassword(password: string) { diff --git a/src/scripts/org-test.ts b/src/scripts/org-test.ts new file mode 100644 index 0000000..4e32c3f --- /dev/null +++ b/src/scripts/org-test.ts @@ -0,0 +1,48 @@ +import '../modules/init.ts'; +import { User, UserInit } from '../models/user.ts'; +import { Org, OrgInit } from '../models/org.ts'; +import { where } from 'sequelize'; +import { useContextKey } from '@kevisual/use-config/context'; +const sequelize = useContextKey('sequelize'); +const meUserName = 'o-NDO62XGeyEQoz_Sytz-1UUB7kw'; +const id = '09cef25c-719d-422a-9ec4-2c266cc6e73d'; +const rootId = '14206305-8b5c-44cc-b177-766cfe2e452f'; +const systemOrgId = 'ca129111-4f30-476e-adf5-acf51ed5ce28'; +export const main = async () => { + await UserInit(); + await OrgInit(); + + // const users = await User.findAll(); + // for (const user of users) { + // console.log('user', user.id, user.username); + // } + const me = await User.findByPk(id); + const org = await Org.findOne({ + where: { + username: 'system', + }, + }); + console.log('org', org.toJSON()); + const res = await org.addUser(me, { + operateId: rootId, + // operateId: id, + role: 'admin', + needPermission: true, + }); + // await org.removeUser(me, { + // operateId: rootId, + // }); + process.exit(0); +}; + +// main(); + +const updatePassword = async () => { + await UserInit(); + await OrgInit(); + const user = await User.findByPk(rootId); + await user.createPassword('xxxxxx'); + process.exit(0); +}; + +updatePassword(); \ No newline at end of file