feat: org CRUD (#3380)
* feat: add org schema * feat: org manage UI * feat: OrgInfoModal * feat: org tree view * feat: org management * fix: init root org * feat: org permission for app * feat: org support for dataset * fix: disable org role control * styles: opt type signatures * fix: remove unused permission * feat: delete org collaborator
This commit is contained in:
174
packages/service/support/permission/org/controllers.ts
Normal file
174
packages/service/support/permission/org/controllers.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
|
||||
import type {
|
||||
OrgMemberSchemaType,
|
||||
OrgSchemaType
|
||||
} from '@fastgpt/global/support/user/team/org/type';
|
||||
import type { ClientSession } from 'mongoose';
|
||||
import { MongoOrgModel } from './orgSchema';
|
||||
import { MongoOrgMemberModel } from './orgMemberSchema';
|
||||
|
||||
// if role1 > role2, return 1
|
||||
// if role1 < role2, return -1
|
||||
// else return 0
|
||||
// export const compareRole = (role1: OrgMemberRole, role2: OrgMemberRole) => {
|
||||
// if (role1 === OrgMemberRole.owner) {
|
||||
// if (role2 === OrgMemberRole.owner) {
|
||||
// return 0;
|
||||
// }
|
||||
// return 1;
|
||||
// }
|
||||
// if (role2 === OrgMemberRole.owner) {
|
||||
// return -1;
|
||||
// }
|
||||
// if (role1 === OrgMemberRole.admin) {
|
||||
// if (role2 === OrgMemberRole.admin) {
|
||||
// return 0;
|
||||
// }
|
||||
// return 1;
|
||||
// }
|
||||
// if (role2 === OrgMemberRole.admin) {
|
||||
// return -1;
|
||||
// }
|
||||
// return 0;
|
||||
// };
|
||||
|
||||
// export const checkOrgRole = (role: OrgMemberRole, targetRole: OrgMemberRole) => {
|
||||
// return compareRole(role, targetRole) >= 0;
|
||||
// };
|
||||
|
||||
export const getOrgsByTeamId = async (teamId: string) => {
|
||||
const orgs = await MongoOrgModel.find({
|
||||
teamId
|
||||
})
|
||||
.populate<{ members: OrgMemberSchemaType }>('members')
|
||||
.lean();
|
||||
|
||||
return orgs;
|
||||
};
|
||||
|
||||
export const getOrgsByTmbId = async ({ teamId, tmbId }: { teamId: string; tmbId: string }) =>
|
||||
MongoOrgMemberModel.find({ teamId, tmbId }, 'orgId').lean();
|
||||
|
||||
export const getChildrenByOrg = async ({
|
||||
org,
|
||||
teamId,
|
||||
session
|
||||
}: {
|
||||
org: OrgSchemaType;
|
||||
teamId: string;
|
||||
session?: ClientSession;
|
||||
}) => {
|
||||
const children = await MongoOrgModel.find(
|
||||
{ teamId, path: { $regex: `^${org.path}/${org._id}` } },
|
||||
undefined,
|
||||
{
|
||||
session
|
||||
}
|
||||
).lean();
|
||||
return children;
|
||||
};
|
||||
|
||||
export const getOrgAndChildren = async ({
|
||||
orgId,
|
||||
teamId,
|
||||
session
|
||||
}: {
|
||||
orgId: string;
|
||||
teamId: string;
|
||||
session?: ClientSession;
|
||||
}) => {
|
||||
const org = await MongoOrgModel.findOne({ _id: orgId, teamId }, undefined, { session }).lean();
|
||||
if (!org) {
|
||||
return Promise.reject(TeamErrEnum.orgNotExist);
|
||||
}
|
||||
const children = await getChildrenByOrg({ org, teamId, session });
|
||||
return { org, children };
|
||||
};
|
||||
|
||||
export async function createRootOrg({
|
||||
teamId,
|
||||
session
|
||||
}: {
|
||||
teamId: string;
|
||||
session?: ClientSession;
|
||||
}) {
|
||||
// Create the root org
|
||||
const [org] = await MongoOrgModel.create(
|
||||
[
|
||||
{
|
||||
teamId,
|
||||
name: 'ROOT',
|
||||
path: ''
|
||||
}
|
||||
],
|
||||
{ session }
|
||||
);
|
||||
// Find the team's owner
|
||||
// const owner = await MongoTeamMember.findOne({ teamId, role: 'owner' }, undefined);
|
||||
// if (!owner) {
|
||||
// return Promise.reject(TeamErrEnum.unAuthTeam);
|
||||
// }
|
||||
|
||||
// Set the owner as the org admin
|
||||
// await MongoOrgMemberModel.create(
|
||||
// [
|
||||
// {
|
||||
// orgId: org._id,
|
||||
// tmbId: owner._id
|
||||
|
||||
// }
|
||||
// ],
|
||||
// { session }
|
||||
// );
|
||||
}
|
||||
|
||||
// export const getOrgMemberRole = async ({
|
||||
// orgId,
|
||||
// tmbId
|
||||
// }: {
|
||||
// orgId: string;
|
||||
// tmbId: string;
|
||||
// }): Promise<OrgMemberRole | undefined> => {
|
||||
// let role: OrgMemberRole | undefined;
|
||||
// const orgMember = await MongoOrgMemberModel.findOne({
|
||||
// orgId,
|
||||
// tmbId
|
||||
// })
|
||||
// .populate('orgId')
|
||||
// .lean();
|
||||
// if (orgMember) {
|
||||
// role = OrgMemberRole[orgMember.role];
|
||||
// } else {
|
||||
// return role;
|
||||
// }
|
||||
// if (role === OrgMemberRole.owner) {
|
||||
// return role;
|
||||
// }
|
||||
// // Check the parent orgs
|
||||
// const org = orgMember.orgId as unknown as OrgSchemaType;
|
||||
// if (!org) {
|
||||
// return Promise.reject(TeamErrEnum.orgNotExist);
|
||||
// }
|
||||
// const parentIds = org.path.split('/').filter((id) => id);
|
||||
// if (parentIds.length === 0) {
|
||||
// return role;
|
||||
// }
|
||||
// const parentOrgMembers = await MongoOrgMemberModel.find({
|
||||
// orgId: {
|
||||
// $in: parentIds
|
||||
// },
|
||||
// tmbId
|
||||
// }).lean();
|
||||
// // Update the role to the highest role
|
||||
// for (const parentOrgMember of parentOrgMembers) {
|
||||
// const parentRole = OrgMemberRole[parentOrgMember.role];
|
||||
// if (parentRole === OrgMemberRole.owner) {
|
||||
// role = parentRole;
|
||||
// break;
|
||||
// }
|
||||
// if (parentRole === OrgMemberRole.admin && role === OrgMemberRole.member) {
|
||||
// role = parentRole;
|
||||
// }
|
||||
// }
|
||||
// return role;
|
||||
// };
|
||||
58
packages/service/support/permission/org/orgMemberSchema.ts
Normal file
58
packages/service/support/permission/org/orgMemberSchema.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { OrgCollectionName } from '@fastgpt/global/support/user/team/org/constant';
|
||||
import { connectionMongo, getMongoModel } from '../../../common/mongo';
|
||||
import {
|
||||
TeamCollectionName,
|
||||
TeamMemberCollectionName
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
import { OrgMemberSchemaType } from '@fastgpt/global/support/user/team/org/type';
|
||||
const { Schema } = connectionMongo;
|
||||
|
||||
export const OrgMemberCollectionName = 'team_org_members';
|
||||
|
||||
export const OrgMemberSchema = new Schema({
|
||||
teamId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamCollectionName,
|
||||
required: true
|
||||
},
|
||||
orgId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: OrgCollectionName,
|
||||
required: true
|
||||
},
|
||||
tmbId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamMemberCollectionName,
|
||||
required: true
|
||||
}
|
||||
// role: {
|
||||
// type: String,
|
||||
// enum: Object.values(OrgMemberRole),
|
||||
// required: true,
|
||||
// default: OrgMemberRole.member
|
||||
// }
|
||||
});
|
||||
|
||||
try {
|
||||
OrgMemberSchema.index(
|
||||
{
|
||||
teamId: 1,
|
||||
orgId: 1,
|
||||
tmbId: 1
|
||||
},
|
||||
{
|
||||
unique: true
|
||||
}
|
||||
);
|
||||
OrgMemberSchema.index({
|
||||
teamId: 1,
|
||||
tmbId: 1
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
export const MongoOrgMemberModel = getMongoModel<OrgMemberSchemaType>(
|
||||
OrgMemberCollectionName,
|
||||
OrgMemberSchema
|
||||
);
|
||||
69
packages/service/support/permission/org/orgSchema.ts
Normal file
69
packages/service/support/permission/org/orgSchema.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { TeamCollectionName } from '@fastgpt/global/support/user/team/constant';
|
||||
import { OrgCollectionName } from '@fastgpt/global/support/user/team/org/constant';
|
||||
import type { OrgSchemaType } from '@fastgpt/global/support/user/team/org/type';
|
||||
import { connectionMongo, getMongoModel } from '../../../common/mongo';
|
||||
import { ResourcePermissionCollectionName } from '../schema';
|
||||
import { OrgMemberCollectionName } from './orgMemberSchema';
|
||||
const { Schema } = connectionMongo;
|
||||
|
||||
function requiredStringPath(this: OrgSchemaType) {
|
||||
return typeof this.path !== 'string';
|
||||
}
|
||||
|
||||
export const OrgSchema = new Schema(
|
||||
{
|
||||
teamId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: TeamCollectionName,
|
||||
required: true
|
||||
},
|
||||
path: {
|
||||
type: String,
|
||||
required: requiredStringPath // allow empty string, but not null
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
avatar: String,
|
||||
description: String,
|
||||
updateTime: {
|
||||
type: Date,
|
||||
default: () => new Date()
|
||||
}
|
||||
},
|
||||
{
|
||||
// Auto update updateTime
|
||||
timestamps: {
|
||||
updatedAt: 'updateTime'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
OrgSchema.virtual('members', {
|
||||
ref: OrgMemberCollectionName,
|
||||
localField: '_id',
|
||||
foreignField: 'orgId'
|
||||
});
|
||||
OrgSchema.virtual('permission', {
|
||||
ref: ResourcePermissionCollectionName,
|
||||
localField: '_id',
|
||||
foreignField: 'orgId',
|
||||
justOne: true
|
||||
});
|
||||
|
||||
try {
|
||||
OrgSchema.index(
|
||||
{
|
||||
teamId: 1,
|
||||
path: 1
|
||||
},
|
||||
{
|
||||
unique: true
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
export const MongoOrgModel = getMongoModel<OrgSchemaType>(OrgCollectionName, OrgSchema);
|
||||
Reference in New Issue
Block a user