Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: sync org from wecom, pref: member list pagination #3549

Merged
merged 17 commits into from
Jan 13, 2025
Merged
3 changes: 1 addition & 2 deletions packages/global/common/system/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export type FastGPTConfigFileType = {

export type FastGPTFeConfigsType = {
show_emptyChat?: boolean;
register_method?: ['email' | 'phone'];
register_method?: ['email' | 'phone' | 'sync'];
FinleyGe marked this conversation as resolved.
Show resolved Hide resolved
login_method?: ['email' | 'phone']; // Attention: login method is diffrent with oauth
find_password_method?: ['email' | 'phone'];
bind_notification_method?: ['email' | 'phone'];
Expand Down Expand Up @@ -76,7 +76,6 @@ export type FastGPTFeConfigsType = {
wecom?: {
corpid?: string;
agentid?: string;
secret?: string;
};
microsoft?: {
clientId?: string;
Expand Down
4 changes: 3 additions & 1 deletion packages/global/core/app/type.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import { TeamTagSchema as TeamTagsSchemaType } from '@fastgpt/global/support/use
import { StoreEdgeItemType } from '../workflow/type/edge';
import { AppPermission } from '../../support/permission/app/controller';
import { ParentIdType } from '../../common/parentFolder/type';
import { FlowNodeInputTypeEnum } from 'core/workflow/node/constant';
import { FlowNodeInputTypeEnum } from '../../core/workflow/node/constant';
import { WorkflowTemplateBasicType } from '@fastgpt/global/core/workflow/type';
import { SourceMemberType } from '../../support/user/type';

export type AppSchema = {
_id: string;
Expand Down Expand Up @@ -63,6 +64,7 @@ export type AppListItemType = {
permission: AppPermission;
inheritPermission?: boolean;
private?: boolean;
sourceMember: SourceMemberType;
};

export type AppDetailType = AppSchema & {
Expand Down
3 changes: 3 additions & 0 deletions packages/global/core/app/version.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { TeamMemberStatusEnum } from 'support/user/team/constant';
import { StoreEdgeItemType } from '../workflow/type/edge';
import { AppChatConfigType, AppSchema } from './type';
import { SourceMemberType } from 'support/user/type';

export type AppVersionSchemaType = {
_id: string;
Expand All @@ -20,4 +22,5 @@ export type VersionListItemType = {
time: Date;
isPublish: boolean | undefined;
tmbId: string;
sourceMember: SourceMemberType;
};
2 changes: 2 additions & 0 deletions packages/global/core/dataset/type.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import { DatasetPermission } from '../../support/permission/dataset/controller';
import { Permission } from '../../support/permission/controller';
import { APIFileServer, FeishuServer, YuqueServer } from './apiDataset';
import { SourceMemberType } from 'support/user/type';

export type DatasetSchemaType = {
_id: string;
Expand Down Expand Up @@ -165,6 +166,7 @@ export type DatasetListItemType = {
vectorModel: VectorModelItemType;
inheritPermission: boolean;
private?: boolean;
sourceMember?: SourceMemberType;
};

export type DatasetItemType = Omit<DatasetSchemaType, 'vectorModel' | 'agentModel'> & {
Expand Down
1 change: 1 addition & 0 deletions packages/global/core/workflow/type/node.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export type NodeTemplateListItemType = {
hasTokenFee?: boolean; // 是否配置积分
instructions?: string; // 使用说明
courseUrl?: string; // 教程链接
sourceMember?: SourceMember;
};

export type NodeTemplateListType = {
Expand Down
1 change: 1 addition & 0 deletions packages/global/support/user/team/controller.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type CreateTeamProps = {
avatar?: string;
defaultTeam?: boolean;
memberName?: string;
memberAvatar?: string;
};
export type UpdateTeamProps = Omit<ThirdPartyAccountType, 'externalWorkflowVariable'> & {
name?: string;
Expand Down
8 changes: 3 additions & 5 deletions packages/global/support/user/team/org/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ export const OrgMemberCollectionName = 'team_org_members';

export const getOrgChildrenPath = (org: OrgSchemaType) => `${org.path}/${org.pathId}`;

// export enum OrgMemberRole {
// owner = 'owner',
// admin = 'admin',
// member = 'member'
// }
export enum SyncOrgSourceEnum {
wecom = 'wecom'
}
1 change: 1 addition & 0 deletions packages/global/support/user/team/type.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export type TeamMemberSchema = {
name: string;
role: `${TeamMemberRoleEnum}`;
status: `${TeamMemberStatusEnum}`;
avatar: string;
defaultTeam: boolean;
};

Expand Down
10 changes: 8 additions & 2 deletions packages/global/support/user/type.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { TeamPermission } from '../permission/user/controller';
import { UserStatusEnum } from './constant';
import { TeamMemberStatusEnum } from './team/constant';
import { TeamTmbItemType } from './team/type';

export type UserModelSchema = {
_id: string;
username: string;
password: string;
avatar: string;
promotionRate: number;
inviterId?: string;
openaiKey: string;
Expand All @@ -22,11 +22,17 @@ export type UserModelSchema = {
export type UserType = {
_id: string;
username: string;
avatar: string;
avatar: string; // it should be team member's avatar after 4.8.18
timezone: string;
promotionRate: UserModelSchema['promotionRate'];
team: TeamTmbItemType;
standardInfo?: standardInfoType;
notificationAccount?: string;
permission: TeamPermission;
};

export type SourceMemberType = {
name: string;
avatar: string;
status: `${TeamMemberStatusEnum}`;
};
21 changes: 21 additions & 0 deletions packages/service/common/api/pagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { ApiRequestProps } from '../../type/next';

export function parsePaginationRequest(req: ApiRequestProps) {
const {
pageSize = 10,
pageNum = 1,
offset = 0
} = Object.keys(req.body).includes('pageSize')
? req.body
: Object.keys(req.query).includes('pageSize')
? req.query
: {};
if (!pageSize || (pageNum === undefined && offset === undefined)) {
throw new Error(CommonErrEnum.missingParams);
}
return {
pageSize: Number(pageSize),
offset: offset ? Number(offset) : (Number(pageNum) - 1) * Number(pageSize)
};
}
2 changes: 1 addition & 1 deletion packages/service/common/middle/cors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { NextApiResponse, NextApiRequest } from 'next';
import NextCors from 'nextjs-cors';

export async function withNextCors(req: NextApiRequest, res: NextApiResponse) {
const methods = ['GET', 'eHEAD', 'PUT', 'PATCH', 'POST', 'DELETE'];
const methods = ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'];

const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',');
const origin = req.headers.origin;
Expand Down
9 changes: 2 additions & 7 deletions packages/service/support/permission/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { ParentIdType } from '@fastgpt/global/common/parentFolder/type';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { MemberGroupSchemaType } from '@fastgpt/global/support/permission/memberGroup/type';
import { TeamMemberSchema } from '@fastgpt/global/support/user/team/type';
import { UserModelSchema } from '@fastgpt/global/support/user/type';
import { OrgSchemaType } from '@fastgpt/global/support/user/team/org/type';
import { getOrgIdSetWithParentByTmbId } from './org/controllers';

Expand Down Expand Up @@ -151,13 +150,9 @@ export const getClbsAndGroupsWithInfo = async ({
$exists: true
}
})
.populate<{ tmb: TeamMemberSchema & { user: UserModelSchema } }>({
.populate<{ tmb: TeamMemberSchema }>({
path: 'tmb',
select: 'name userId role',
populate: {
path: 'user',
select: 'avatar'
}
select: 'name userId avatar'
})
.lean(),
MongoResourcePermission.find({
Expand Down
2 changes: 1 addition & 1 deletion packages/service/support/user/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export async function getUserDetail({
return {
_id: user._id,
username: user.username,
avatar: user.avatar,
avatar: tmb.avatar,
timezone: user.timezone,
promotionRate: user.promotionRate,
team: tmb,
Expand Down
11 changes: 4 additions & 7 deletions packages/service/support/user/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ const { Schema } = connectionMongo;
import { hashStr } from '@fastgpt/global/common/string/tools';
import type { UserModelSchema } from '@fastgpt/global/support/user/type';
import { UserStatusEnum, userStatusMap } from '@fastgpt/global/support/user/constant';
import { getRandomUserAvatar } from '@fastgpt/global/support/user/utils';

export const userCollectionName = 'users';

Expand Down Expand Up @@ -33,11 +32,6 @@ const UserSchema = new Schema({
type: Date,
default: () => new Date()
},
avatar: {
type: String,
default: () => getRandomUserAvatar()
},

promotionRate: {
type: Number,
default: 15
Expand All @@ -62,7 +56,10 @@ const UserSchema = new Schema({
ref: userCollectionName
},
fastgpt_sem: Object,
sourceDomain: String
sourceDomain: String,

/** @deprecated */
avatar: String
});

try {
Expand Down
2 changes: 1 addition & 1 deletion packages/service/support/user/team/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ async function getTeamMember(match: Record<string, any>): Promise<TeamTmbItemTyp
teamAvatar: tmb.team.avatar,
teamName: tmb.team.name,
memberName: tmb.name,
avatar: tmb.team.avatar,
avatar: tmb.avatar,
balance: tmb.team.balance,
tmbId: String(tmb._id),
teamDomain: tmb.team?.teamDomain,
Expand Down
6 changes: 5 additions & 1 deletion packages/service/support/user/team/teamMemberSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
TeamMemberCollectionName,
TeamCollectionName
} from '@fastgpt/global/support/user/team/constant';
import { getRandomUserAvatar } from '@fastgpt/global/support/user/utils';

const TeamMemberSchema = new Schema({
teamId: {
Expand Down Expand Up @@ -35,11 +36,14 @@ const TeamMemberSchema = new Schema({
type: Boolean,
default: false
},
avatar: {
type: String,
default: getRandomUserAvatar()
FinleyGe marked this conversation as resolved.
Show resolved Hide resolved
},

// Abandoned
role: {
type: String
// enum: Object.keys(TeamMemberRoleMap) // disable enum validation for old data
}
});

Expand Down
15 changes: 10 additions & 5 deletions packages/web/common/fetch/type.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
export type PaginationProps<T = {}> = T & {
offset: number;
pageSize: number;
};
export type PaginationResponse<T = any> = {
import { RequireOnlyOne } from '@fastgpt/global/common/type/utils';

type PaginationProps<T = {}> = T & {
pageSize: number | string;
} & RequireOnlyOne<{
offset: number | string;
pageNum: number | string;
}>;

type PaginationResponse<T = {}> = {
total: number;
list: T[];
};
80 changes: 48 additions & 32 deletions packages/web/components/common/MySelect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,15 @@ import type { ButtonProps, MenuItemProps } from '@chakra-ui/react';
import MyIcon from '../Icon';
import { useRequest2 } from '../../../hooks/useRequest';
import MyDivider from '../MyDivider';
import { useScrollPagination } from '../../../hooks/useScrollPagination';

/** 选择组件 Props 类型
* value: 选中的值
* placeholder: 占位符
* list: 列表数据
* isLoading: 是否加载中
* ScrollData: 分页滚动数据控制器 [useScrollPagination] 的返回值
* */
export type SelectProps<T = any> = ButtonProps & {
value?: T;
placeholder?: string;
Expand All @@ -34,6 +42,7 @@ export type SelectProps<T = any> = ButtonProps & {
}[];
isLoading?: boolean;
onchange?: (val: T) => any | Promise<any>;
ScrollData?: ReturnType<typeof useScrollPagination>['ScrollData'];
};

const MySelect = <T = any,>(
Expand All @@ -44,6 +53,7 @@ const MySelect = <T = any,>(
list = [],
onchange,
isLoading = false,
ScrollData,
FinleyGe marked this conversation as resolved.
Show resolved Hide resolved
...props
}: SelectProps<T>,
ref: ForwardedRef<{
Expand Down Expand Up @@ -154,39 +164,45 @@ const MySelect = <T = any,>(
maxH={'40vh'}
overflowY={'auto'}
>
{list.map((item, i) => (
<Box key={i}>
<MenuItem
{...menuItemStyles}
{...(value === item.value
? {
ref: SelectedItemRef,
color: 'primary.700',
bg: 'myGray.100',
fontWeight: '600'
{(() => {
const component = list.map((item, i) => (
<Box key={i}>
<MenuItem
{...menuItemStyles}
{...(value === item.value
? {
ref: SelectedItemRef,
color: 'primary.700',
bg: 'myGray.100',
fontWeight: '600'
}
: {
color: 'myGray.900'
})}
onClick={() => {
if (onChange && value !== item.value) {
onChange(item.value);
}
: {
color: 'myGray.900'
})}
onClick={() => {
if (onChange && value !== item.value) {
onChange(item.value);
}
}}
whiteSpace={'pre-wrap'}
fontSize={'sm'}
display={'block'}
>
<Box>{item.label}</Box>
{item.description && (
<Box color={'myGray.500'} fontSize={'xs'}>
{item.description}
</Box>
)}
</MenuItem>
{item.showBorder && <MyDivider my={2} />}
</Box>
))}
}}
whiteSpace={'pre-wrap'}
fontSize={'sm'}
display={'block'}
>
<Box>{item.label}</Box>
{item.description && (
<Box color={'myGray.500'} fontSize={'xs'}>
{item.description}
</Box>
)}
</MenuItem>
{item.showBorder && <MyDivider my={2} />}
</Box>
));
if (ScrollData) {
return <ScrollData>{component}</ScrollData>;
}
return component;
})()}
</MenuList>
</Menu>
</Box>
Expand Down
Loading
Loading