|
1 | 1 | import { MeteorError, Team, api, Calendar } from '@rocket.chat/core-services'; |
2 | | -import type { IExportOperation, ILoginToken, IPersonalAccessToken, IUser, UserStatus } from '@rocket.chat/core-typings'; |
| 2 | +import type { IExportOperation, ILoginToken, IPersonalAccessToken, IUser, IUserSettings, UserStatus } from '@rocket.chat/core-typings'; |
3 | 3 | import { Users, Subscriptions, Sessions } from '@rocket.chat/models'; |
4 | 4 | import { |
5 | | - isUserCreateParamsPOST, |
6 | 5 | isUserSetActiveStatusParamsPOST, |
7 | 6 | isUserDeactivateIdleParamsPOST, |
8 | 7 | isUsersInfoParamsGetProps, |
@@ -300,51 +299,6 @@ API.v1.addRoute( |
300 | 299 | }, |
301 | 300 | ); |
302 | 301 |
|
303 | | -API.v1.addRoute( |
304 | | - 'users.create', |
305 | | - { authRequired: true, validateParams: isUserCreateParamsPOST }, |
306 | | - { |
307 | | - async post() { |
308 | | - // New change made by pull request #5152 |
309 | | - if (typeof this.bodyParams.joinDefaultChannels === 'undefined') { |
310 | | - this.bodyParams.joinDefaultChannels = true; |
311 | | - } |
312 | | - |
313 | | - if (this.bodyParams.name && !validateNameChars(this.bodyParams.name)) { |
314 | | - return API.v1.failure('Name contains invalid characters'); |
315 | | - } |
316 | | - |
317 | | - if (this.bodyParams.customFields) { |
318 | | - validateCustomFields(this.bodyParams.customFields); |
319 | | - } |
320 | | - |
321 | | - if (this.bodyParams.freeSwitchExtension && !(await canEditExtension(this.bodyParams.freeSwitchExtension))) { |
322 | | - return API.v1.failure('Setting user voice call extension is not allowed', 'error-action-not-allowed'); |
323 | | - } |
324 | | - |
325 | | - const newUserId = await saveUser(this.userId, this.bodyParams); |
326 | | - const userId = typeof newUserId !== 'string' ? this.userId : newUserId; |
327 | | - |
328 | | - if (this.bodyParams.customFields) { |
329 | | - await saveCustomFieldsWithoutValidation(userId, this.bodyParams.customFields); |
330 | | - } |
331 | | - |
332 | | - if (typeof this.bodyParams.active !== 'undefined') { |
333 | | - await executeSetUserActiveStatus(this.userId, userId, this.bodyParams.active); |
334 | | - } |
335 | | - |
336 | | - const { fields } = await this.parseJsonQuery(); |
337 | | - |
338 | | - const user = await Users.findOneById(userId, { projection: fields }); |
339 | | - if (!user) { |
340 | | - return API.v1.failure('User not found'); |
341 | | - } |
342 | | - |
343 | | - return API.v1.success({ user }); |
344 | | - }, |
345 | | - }, |
346 | | -); |
347 | | - |
348 | 302 | API.v1.addRoute( |
349 | 303 | 'users.delete', |
350 | 304 | { authRequired: true, permissionsRequired: ['delete-user'] }, |
@@ -753,6 +707,55 @@ API.v1.addRoute( |
753 | 707 | }, |
754 | 708 | ); |
755 | 709 |
|
| 710 | +type UserCreateParamsPOST = { |
| 711 | + email: string; |
| 712 | + name: string; |
| 713 | + password: string; |
| 714 | + username: string; |
| 715 | + active?: boolean; |
| 716 | + bio?: string; |
| 717 | + nickname?: string; |
| 718 | + statusText?: string; |
| 719 | + roles?: string[]; |
| 720 | + joinDefaultChannels?: boolean; |
| 721 | + requirePasswordChange?: boolean; |
| 722 | + setRandomPassword?: boolean; |
| 723 | + sendWelcomeEmail?: boolean; |
| 724 | + verified?: boolean; |
| 725 | + customFields?: Record<string, any>; |
| 726 | + settings?: IUserSettings; |
| 727 | + freeSwitchExtension?: string; |
| 728 | + /* @deprecated */ |
| 729 | + fields: string; |
| 730 | +}; |
| 731 | + |
| 732 | +const userCreateParamsPostSchema = { |
| 733 | + type: 'object', |
| 734 | + properties: { |
| 735 | + email: { type: 'string' }, |
| 736 | + name: { type: 'string' }, |
| 737 | + password: { type: 'string' }, |
| 738 | + username: { type: 'string' }, |
| 739 | + active: { type: 'boolean', nullable: true }, |
| 740 | + bio: { type: 'string', nullable: true }, |
| 741 | + nickname: { type: 'string', nullable: true }, |
| 742 | + statusText: { type: 'string', nullable: true }, |
| 743 | + roles: { type: 'array', items: { type: 'string' } }, |
| 744 | + joinDefaultChannels: { type: 'boolean', nullable: true }, |
| 745 | + requirePasswordChange: { type: 'boolean', nullable: true }, |
| 746 | + setRandomPassword: { type: 'boolean', nullable: true }, |
| 747 | + sendWelcomeEmail: { type: 'boolean', nullable: true }, |
| 748 | + verified: { type: 'boolean', nullable: true }, |
| 749 | + customFields: { type: 'object' }, |
| 750 | + fields: { type: 'string', nullable: true }, |
| 751 | + freeSwitchExtension: { type: 'string', nullable: true }, |
| 752 | + }, |
| 753 | + additionalProperties: false, |
| 754 | + required: ['email', 'name', 'password', 'username'], |
| 755 | +}; |
| 756 | + |
| 757 | +const isUserCreateParamsPOST = ajv.compile<UserCreateParamsPOST>(userCreateParamsPostSchema); |
| 758 | + |
756 | 759 | const usersEndpoints = API.v1 |
757 | 760 | .post( |
758 | 761 | 'users.createToken', |
@@ -878,6 +881,64 @@ const usersEndpoints = API.v1 |
878 | 881 |
|
879 | 882 | return API.v1.success({ suggestions }); |
880 | 883 | }, |
| 884 | + ) |
| 885 | + .post( |
| 886 | + 'users.create', |
| 887 | + { |
| 888 | + authRequired: true, |
| 889 | + body: isUserCreateParamsPOST, |
| 890 | + response: { |
| 891 | + 200: ajv.compile<{ user: IUser }>({ |
| 892 | + type: 'object', |
| 893 | + properties: { |
| 894 | + user: { $ref: '#/components/schemas/IUser' }, |
| 895 | + success: { type: 'boolean', enum: [true] }, |
| 896 | + }, |
| 897 | + required: ['user', 'success'], |
| 898 | + additionalProperties: false, |
| 899 | + }), |
| 900 | + 400: validateBadRequestErrorResponse, |
| 901 | + 401: validateUnauthorizedErrorResponse, |
| 902 | + }, |
| 903 | + }, |
| 904 | + async function action() { |
| 905 | + // New change made by pull request #5152 |
| 906 | + if (typeof this.bodyParams.joinDefaultChannels === 'undefined') { |
| 907 | + this.bodyParams.joinDefaultChannels = true; |
| 908 | + } |
| 909 | + |
| 910 | + if (this.bodyParams.name && !validateNameChars(this.bodyParams.name)) { |
| 911 | + return API.v1.failure('Name contains invalid characters'); |
| 912 | + } |
| 913 | + |
| 914 | + if (this.bodyParams.customFields) { |
| 915 | + validateCustomFields(this.bodyParams.customFields); |
| 916 | + } |
| 917 | + |
| 918 | + if (this.bodyParams.freeSwitchExtension && !(await canEditExtension(this.bodyParams.freeSwitchExtension))) { |
| 919 | + return API.v1.failure('Setting user voice call extension is not allowed', 'error-action-not-allowed'); |
| 920 | + } |
| 921 | + |
| 922 | + const newUserId = await saveUser(this.userId, this.bodyParams); |
| 923 | + const userId = typeof newUserId !== 'string' ? this.userId : newUserId; |
| 924 | + |
| 925 | + if (this.bodyParams.customFields) { |
| 926 | + await saveCustomFieldsWithoutValidation(userId, this.bodyParams.customFields); |
| 927 | + } |
| 928 | + |
| 929 | + if (typeof this.bodyParams.active !== 'undefined') { |
| 930 | + await executeSetUserActiveStatus(this.userId, userId, this.bodyParams.active); |
| 931 | + } |
| 932 | + |
| 933 | + const { fields } = await this.parseJsonQuery(); |
| 934 | + |
| 935 | + const user = await Users.findOneById(userId, { projection: fields }); |
| 936 | + if (!user) { |
| 937 | + return API.v1.failure('User not found'); |
| 938 | + } |
| 939 | + |
| 940 | + return API.v1.success({ user }); |
| 941 | + }, |
881 | 942 | ); |
882 | 943 |
|
883 | 944 | API.v1.addRoute( |
|
0 commit comments