Group role (#2993)

* feat: app/dataset support group (#2898)

* pref: member-group (#2862)

* feat: group list ordered by updateTime

* fix: transfer ownership of group when deleting member

* fix: i18n fix

* feat: can not set member as admin/owner when user is not active

* fix: GroupInfoModal hover input do not change color

* fix(fe): searchinput do not scroll

* feat: app collaborator with group, remove default permission

* feat: dataset collaborator with group, remove default permission

* chore(test): pref mock

* chore: remove useless code

* chore: adjust

* fix: add self as collaborator when creating folder

* fix(fe): folder manage menu do not show when user has write permission
only

* fix: dataset folder create

* feat: Add code comment

* Pref: app move (#2952)

* perf: app schema

* doc

---------

Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
This commit is contained in:
Archer
2024-10-25 19:39:11 +08:00
committed by shilin66
parent 8df886452e
commit c6d053e050
60 changed files with 1142 additions and 1094 deletions

View File

@@ -1,7 +1,8 @@
import { MongoMemoryServer } from 'mongodb-memory-server';
import { MongoMemoryReplSet } from 'mongodb-memory-server';
import mongoose from 'mongoose';
import { MockParseHeaderCert } from '@/test/utils';
import { initMockData } from './db/init';
import { parseHeaderCertMock } from '@/test/utils';
import { initMockData, root } from './db/init';
import { faker } from '@faker-js/faker/locale/zh_CN';
jest.mock('nanoid', () => {
return {
@@ -13,24 +14,40 @@ jest.mock('@fastgpt/global/common/string/tools', () => {
return {
hashStr(str: string) {
return str;
},
getNanoid() {
return faker.string.alphanumeric(12);
}
};
});
jest.mock('@fastgpt/service/common/system/log', jest.fn());
jest.mock('@fastgpt/service/common/system/log', () => ({
addLog: {
log: jest.fn(),
warn: jest.fn((...prop) => {
console.warn(prop);
}),
error: jest.fn((...prop) => {
console.error(prop);
}),
info: jest.fn(),
debug: jest.fn()
}
}));
jest.mock('@fastgpt/service/support/permission/controller', () => {
return {
parseHeaderCert: MockParseHeaderCert,
getResourcePermission: jest.requireActual('@fastgpt/service/support/permission/controller')
.getResourcePermission,
getResourceAllClbs: jest.requireActual('@fastgpt/service/support/permission/controller')
.getResourceAllClbs
};
});
jest.setMock(
'@fastgpt/service/support/permission/controller',
(() => {
const origin = jest.requireActual<
typeof import('@fastgpt/service/support/permission/controller')
>('@fastgpt/service/support/permission/controller');
const parse = jest.createMockFromModule('@fastgpt/service/support/permission/controller') as any;
parse.parseHeaderCert = MockParseHeaderCert;
return {
...origin,
parseHeaderCert: parseHeaderCertMock
};
})()
);
jest.mock('@/service/middleware/entry', () => {
return {
@@ -59,11 +76,30 @@ jest.mock('@/service/middleware/entry', () => {
beforeAll(async () => {
// 新建一个内存数据库,然后让 mongoose 连接这个数据库
if (!global.mongod || !global.mongodb) {
const mongod = await MongoMemoryServer.create();
global.mongod = mongod;
const replSet = new MongoMemoryReplSet({
instanceOpts: [
{
storageEngine: 'wiredTiger'
},
{
storageEngine: 'wiredTiger'
}
]
});
replSet.start();
await replSet.waitUntilRunning();
const uri = replSet.getUri();
// const mongod = await MongoMemoryServer.create({
// instance: {
// replSet: 'testset'
// }
// });
// global.mongod = mongod;
global.replSet = replSet;
global.mongodb = mongoose;
await global.mongodb.connect(mongod.getUri(), {
await global.mongodb.connect(uri, {
dbName: 'fastgpt_test',
bufferCommands: true,
maxConnecting: 50,
maxPoolSize: 50,
@@ -77,6 +113,7 @@ beforeAll(async () => {
});
await initMockData();
console.log(root);
}
});
@@ -84,6 +121,9 @@ afterAll(async () => {
if (global.mongodb) {
await global.mongodb.disconnect();
}
if (global.replSet) {
await global.replSet.stop();
}
if (global.mongod) {
await global.mongod.stop();
}

View File

@@ -1,5 +1,6 @@
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
import { DefaultGroupName } from '@fastgpt/global/support/user/team/group/constant';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { MongoMemberGroupModel } from '@fastgpt/service/support/permission/memberGroup/memberGroupSchema';
import { MongoUser } from '@fastgpt/service/support/user/schema';
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
import { MongoTeam } from '@fastgpt/service/support/user/team/teamSchema';
@@ -13,37 +14,43 @@ export const root = {
};
export const initMockData = async () => {
const initRootUser = async () => {
// init root user
const rootUser = await MongoUser.create({
const [rootUser] = await MongoUser.create([
{
username: 'root',
password: '123456'
});
const rootTeam = await MongoTeam.create({
name: 'root-default-team',
ownerId: rootUser._id
});
const rootTeamMember = await MongoTeamMember.create({
}
]);
root.uid = String(rootUser._id);
const [rootTeam] = await MongoTeam.create([
{
name: 'root Team'
}
]);
root.teamId = String(rootTeam._id);
const [rootTmb] = await MongoTeamMember.create([
{
teamId: rootTeam._id,
name: 'owner',
role: 'owner',
userId: rootUser._id,
name: 'root-default-team-member',
status: 'active',
role: TeamMemberRoleEnum.owner
});
const rootApp = await MongoApp.create({
name: 'root-default-app',
status: 'active'
}
]);
root.tmbId = String(rootTmb._id);
await MongoMemberGroupModel.create([
{
name: DefaultGroupName,
teamId: rootTeam._id
}
]);
const [rootApp] = await MongoApp.create([
{
name: 'root Test App',
teamId: rootTeam._id,
tmbId: rootTeam._id,
type: 'advanced'
});
tmbId: rootTmb._id
}
]);
root.uid = rootUser._id;
root.tmbId = rootTeamMember._id;
root.teamId = rootTeam._id;
root.appId = rootApp._id;
};
await initRootUser();
root.appId = String(rootApp._id);
};

View File

@@ -1,4 +1,11 @@
import { MongoMemoryServer } from 'mongodb-memory-server';
import type { MongoMemoryReplSet, MongoMemoryServer } from 'mongodb-memory-server';
declare global {
var mongod: MongoMemoryServer | undefined;
var replSet: MongoMemoryReplSet | undefined;
}
export type RequestResponse<T = any> = {
code: number;
error?: string;
data?: T;
};