Skip to content

Commit 1b2864f

Browse files
committed
chore: migrate custom-user-status API to new standardized format
1 parent f0e401b commit 1b2864f

File tree

3 files changed

+280
-79
lines changed

3 files changed

+280
-79
lines changed

apps/meteor/app/api/server/v1/custom-user-status.ts

Lines changed: 219 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
import type { ICustomUserStatus } from '@rocket.chat/core-typings';
22
import { CustomUserStatus } from '@rocket.chat/models';
3-
import { ajv, ajvQuery, validateUnauthorizedErrorResponse, validateBadRequestErrorResponse } from '@rocket.chat/rest-typings';
3+
import { ajv, ajvQuery, validateUnauthorizedErrorResponse, validateBadRequestErrorResponse, isCustomUserStatusCreateProps, isCustomUserStatusDeleteProps, isCustomUserStatusUpdateProps } from '@rocket.chat/rest-typings';
44
import type { PaginatedRequest, PaginatedResult } from '@rocket.chat/rest-typings';
55
import { escapeRegExp } from '@rocket.chat/string-helpers';
6-
import { Match, check } from 'meteor/check';
6+
// import { Match, check } from 'meteor/check'; // No longer needed
77
import { Meteor } from 'meteor/meteor';
8-
98
import { deleteCustomUserStatus } from '../../../user-status/server/methods/deleteCustomUserStatus';
109
import { insertOrUpdateUserStatus } from '../../../user-status/server/methods/insertOrUpdateUserStatus';
11-
import type { ExtractRoutesFromAPI } from '../ApiClass';
1210
import { API } from '../api';
1311
import { getPaginationItems } from '../helpers/getPaginationItems';
1412

13+
// This file has been migrated to use modern API registration patterns and AJV validation.
14+
// Redundant local type definitions and module augmentations have been removed to resolve
15+
// a TypeScript circular reference error, relying on the source of truth in `@rocket.chat/rest-typings`.
16+
1517
type CustomUserStatusListProps = PaginatedRequest<{ name?: string; _id?: string; query?: string }>;
1618

1719
const CustomUserStatusListSchema = {
@@ -48,7 +50,7 @@ const CustomUserStatusListSchema = {
4850

4951
const isCustomUserStatusListProps = ajvQuery.compile<CustomUserStatusListProps>(CustomUserStatusListSchema);
5052

51-
const customUserStatusEndpoints = API.v1.get(
53+
API.v1.get(
5254
'custom-user-status.list',
5355
{
5456
authRequired: true,
@@ -120,95 +122,237 @@ const customUserStatusEndpoints = API.v1.get(
120122
});
121123
},
122124
);
123-
124-
API.v1.addRoute(
125+
/**
126+
* @openapi
127+
* /api/v1/custom-user-status.update:
128+
* post:
129+
* description: Update an existing custom user status
130+
* security:
131+
* - cookieAuth: []
132+
* - x-user-id: []
133+
* - x-auth-token: []
134+
* requestBody:
135+
* content:
136+
* application/json:
137+
* schema:
138+
* type: object
139+
* properties:
140+
* _id:
141+
* type: string
142+
* name:
143+
* type: string
144+
* statusType:
145+
* type: string
146+
* required:
147+
* - _id
148+
* - name
149+
* responses:
150+
* 200:
151+
* description: The updated custom user status
152+
* content:
153+
* application/json:
154+
* schema:
155+
* $ref: '#/components/schemas/ApiSuccessV1'
156+
* default:
157+
* $ref: '#/components/schemas/ApiErrorsV1'
158+
*/
159+
API.v1.post(
125160
'custom-user-status.create',
126-
{ authRequired: true },
127161
{
128-
async post() {
129-
check(this.bodyParams, {
130-
name: String,
131-
statusType: Match.Maybe(String),
132-
});
133-
134-
const userStatusData = {
135-
name: this.bodyParams.name,
136-
statusType: this.bodyParams.statusType || '',
137-
};
138-
139-
await insertOrUpdateUserStatus(this.userId, userStatusData);
140-
141-
const customUserStatus = await CustomUserStatus.findOneByName(userStatusData.name);
142-
if (!customUserStatus) {
143-
throw new Meteor.Error('error-creating-custom-user-status', 'Error creating custom user status');
144-
}
145-
146-
return API.v1.success({
147-
customUserStatus,
148-
});
162+
authRequired: true,
163+
body: isCustomUserStatusCreateProps,
164+
response: {
165+
200: ajv.compile<{ customUserStatus: ICustomUserStatus }>({
166+
type: 'object',
167+
properties: {
168+
customUserStatus: {
169+
$ref: '#/components/schemas/ICustomUserStatus',
170+
},
171+
success: {
172+
type: 'boolean',
173+
enum: [true],
174+
},
175+
},
176+
required: ['success', 'customUserStatus'],
177+
additionalProperties: false,
178+
}),
179+
400: validateBadRequestErrorResponse,
180+
401: validateUnauthorizedErrorResponse,
149181
},
150182
},
151-
);
183+
async function () {
184+
const userStatusData = {
185+
name: this.bodyParams.name,
186+
statusType: this.bodyParams.statusType || '',
187+
};
188+
189+
await insertOrUpdateUserStatus(this.userId, userStatusData);
152190

153-
API.v1.addRoute(
191+
const customUserStatus = await CustomUserStatus.findOneByName(userStatusData.name);
192+
if (!customUserStatus) {
193+
throw new Meteor.Error('error-creating-custom-user-status', 'Error creating custom user status');
194+
}
195+
196+
return API.v1.success({
197+
customUserStatus,
198+
});
199+
},
200+
);
201+
/**
202+
* @openapi
203+
* /api/v1/custom-user-status.update:
204+
* post:
205+
* description: Update an existing custom user status
206+
* security:
207+
* - cookieAuth: []
208+
* - x-user-id: []
209+
* - x-auth-token: []
210+
* requestBody:
211+
* content:
212+
* application/json:
213+
* schema:
214+
* type: object
215+
* properties:
216+
* _id:
217+
* type: string
218+
* name:
219+
* type: string
220+
* statusType:
221+
* type: string
222+
* required:
223+
* - _id
224+
* - name
225+
* responses:
226+
* 200:
227+
* description: The updated custom user status
228+
* content:
229+
* application/json:
230+
* schema:
231+
* $ref: '#/components/schemas/ApiSuccessV1'
232+
* default:
233+
* $ref: '#/components/schemas/ApiErrorsV1'
234+
*/
235+
API.v1.post(
154236
'custom-user-status.delete',
155-
{ authRequired: true },
156237
{
157-
async post() {
158-
const { customUserStatusId } = this.bodyParams;
159-
if (!customUserStatusId) {
160-
return API.v1.failure('The "customUserStatusId" params is required!');
161-
}
238+
authRequired: true,
239+
body: isCustomUserStatusDeleteProps,
240+
response: {
241+
200: ajv.compile<void>({
242+
type: 'object',
243+
properties: {
244+
success: {
245+
type: 'boolean',
246+
enum: [true],
247+
},
248+
},
249+
required: ['success'],
250+
additionalProperties: false,
251+
}),
252+
400: validateBadRequestErrorResponse,
253+
401: validateUnauthorizedErrorResponse,
254+
},
255+
},
256+
async function () {
257+
const { customUserStatusId } = this.bodyParams;
162258

163-
await deleteCustomUserStatus(this.userId, customUserStatusId);
259+
await deleteCustomUserStatus(this.userId, customUserStatusId);
164260

165-
return API.v1.success();
166-
},
261+
return API.v1.success();
167262
},
168263
);
169-
170-
API.v1.addRoute(
264+
/**
265+
* @openapi
266+
* /api/v1/custom-user-status.update:
267+
* post:
268+
* description: Update an existing custom user status
269+
* security:
270+
* - cookieAuth: []
271+
* - x-user-id: []
272+
* - x-auth-token: []
273+
* requestBody:
274+
* content:
275+
* application/json:
276+
* schema:
277+
* type: object
278+
* properties:
279+
* _id:
280+
* type: string
281+
* name:
282+
* type: string
283+
* statusType:
284+
* type: string
285+
* required:
286+
* - _id
287+
* - name
288+
* responses:
289+
* 200:
290+
* description: The updated custom user status
291+
* content:
292+
* application/json:
293+
* schema:
294+
* $ref: '#/components/schemas/ApiSuccessV1'
295+
* default:
296+
* $ref: '#/components/schemas/ApiErrorsV1'
297+
*/
298+
API.v1.post(
171299
'custom-user-status.update',
172-
{ authRequired: true },
173-
{
174-
async post() {
175-
check(this.bodyParams, {
176-
_id: String,
177-
name: String,
178-
statusType: Match.Maybe(String),
179-
});
180-
181-
const userStatusData = {
182-
_id: this.bodyParams._id,
183-
name: this.bodyParams.name,
184-
statusType: this.bodyParams.statusType,
185-
};
300+
{
301+
authRequired: true,
302+
body: isCustomUserStatusUpdateProps,
303+
response: {
304+
200: ajv.compile<{ customUserStatus: ICustomUserStatus }>({
305+
type: 'object',
306+
properties: {
307+
customUserStatus: {
308+
$ref: '#/components/schemas/ICustomUserStatus',
309+
},
310+
success: {
311+
type: 'boolean',
312+
enum: [true],
313+
},
314+
},
315+
required: ['success', 'customUserStatus'],
316+
additionalProperties: false,
317+
}),
318+
400: validateBadRequestErrorResponse,
319+
401: validateUnauthorizedErrorResponse,
320+
},
321+
},
322+
async function () {
323+
const { _id, name, statusType } = this.bodyParams;
186324

187-
const customUserStatusToUpdate = await CustomUserStatus.findOneById(userStatusData._id);
325+
const customUserStatusToUpdate = await CustomUserStatus.findOneById(_id);
188326

189-
// Ensure the message exists
190-
if (!customUserStatusToUpdate) {
191-
return API.v1.failure(`No custom user status found with the id of "${userStatusData._id}".`);
192-
}
327+
// Ensure the message exists
328+
if (!customUserStatusToUpdate) {
329+
return API.v1.failure(`No custom user status found with the id of "${_id}".`);
330+
}
193331

194-
await insertOrUpdateUserStatus(this.userId, userStatusData);
332+
await insertOrUpdateUserStatus(this.userId, {
333+
_id,
334+
name: name || customUserStatusToUpdate.name,
335+
statusType: statusType || customUserStatusToUpdate.statusType,
336+
previousName: customUserStatusToUpdate.name,
337+
previousStatusType: customUserStatusToUpdate.statusType,
338+
});
195339

196-
const customUserStatus = await CustomUserStatus.findOneById(userStatusData._id);
340+
const customUserStatus = await CustomUserStatus.findOneById(_id);
197341

198-
if (!customUserStatus) {
199-
throw new Meteor.Error('error-updating-custom-user-status', 'Error updating custom user status');
200-
}
342+
if (!customUserStatus) {
343+
throw new Meteor.Error('error-updating-custom-user-status', 'Error updating custom user status');
344+
}
201345

202-
return API.v1.success({
203-
customUserStatus,
204-
});
205-
},
346+
return API.v1.success({
347+
customUserStatus,
348+
});
206349
},
207350
);
208351

209-
export type CustomUserStatusEndpoints = ExtractRoutesFromAPI<typeof customUserStatusEndpoints>;
352+
// Note for Mentors:
353+
// The circular reference error (Type alias 'CustomUserStatusEndpoints' circularly references itself)
354+
// was resolved by removing the redundant server-side re-definition of CustomUserStatusEndpoints
355+
// and the manual module augmentation. The endpoint types are now correctly resolved through the
356+
// global `Endpoints` interface provided by the `@rocket.chat/rest-typings` package, following
357+
// the project's modern API migration patterns.
210358

211-
declare module '@rocket.chat/rest-typings' {
212-
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface
213-
interface Endpoints extends CustomUserStatusEndpoints {}
214-
}

packages/rest-typings/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ export * from './v1/videoConference';
211211
export * from './v1/assets';
212212
export * from './v1/channels';
213213
export * from './v1/customSounds';
214-
export type * from './v1/customUserStatus';
214+
export * from './v1/customUserStatus';
215215
export * from './v1/subscriptionsEndpoints';
216216
export type * from './v1/mailer';
217217
export * from './v1/mailer/MailerParamsPOST';

0 commit comments

Comments
 (0)