chore: Add OpenAPI Support to emoji-custom.create API (#36523)

Co-authored-by: Matheus Cardoso <matheus@cardo.so>
Co-authored-by: Guilherme Gazzo <guilherme@gazzo.xyz>
pull/38906/merge
Ahmed Nasser 1 day ago committed by GitHub
parent a4e3c1635d
commit 39f2e87e1c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 6
      .changeset/weak-terms-shave.md
  2. 2
      apps/meteor/app/api/server/definition.ts
  3. 100
      apps/meteor/app/api/server/v1/emoji-custom.ts
  4. 3
      packages/rest-typings/src/v1/emojiCustom.ts

@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": patch
"@rocket.chat/rest-typings": patch
---
Add OpenAPI support for the Rocket.Chat emoji-custom.create API endpoints by migrating to a modern chained route definition syntax and utilizing shared AJV schemas for validation to enhance API documentation and ensure type safety through response validation.

@ -312,7 +312,7 @@ export type TypedThis<TOptions extends TypedOptions, TPath extends string = ''>
query: Record<string, unknown>;
}>;
bodyParams: TOptions['body'] extends ValidateFunction<infer Body> ? Body : never;
request: Request;
requestIp?: string;
route: string;
response: Response;

@ -1,7 +1,7 @@
import { Media } from '@rocket.chat/core-services';
import type { IEmojiCustom } from '@rocket.chat/core-typings';
import { EmojiCustom } from '@rocket.chat/models';
import { isEmojiCustomList } from '@rocket.chat/rest-typings';
import { ajv, isEmojiCustomList } from '@rocket.chat/rest-typings';
import { escapeRegExp } from '@rocket.chat/string-helpers';
import { Meteor } from 'meteor/meteor';
@ -11,6 +11,7 @@ import { insertOrUpdateEmoji } from '../../../emoji-custom/server/lib/insertOrUp
import { uploadEmojiCustomWithBuffer } from '../../../emoji-custom/server/lib/uploadEmojiCustom';
import { deleteEmojiCustom } from '../../../emoji-custom/server/methods/deleteEmojiCustom';
import { settings } from '../../../settings/server';
import type { ExtractRoutesFromAPI } from '../ApiClass';
import { API } from '../api';
import { getPaginationItems } from '../helpers/getPaginationItems';
import { findEmojisCustom } from '../lib/emoji-custom';
@ -103,45 +104,73 @@ API.v1.addRoute(
},
);
API.v1.addRoute(
const emojiCustomCreateEndpoints = API.v1.post(
'emoji-custom.create',
{ authRequired: true },
{
async post() {
const emoji = await getUploadFormData(
{
request: this.request,
authRequired: true,
response: {
400: ajv.compile({
type: 'object',
properties: {
success: { type: 'boolean', enum: [false] },
stack: { type: 'string' },
error: { type: 'string' },
errorType: { type: 'string' },
details: { type: 'string' },
},
{ field: 'emoji', sizeLimit: settings.get('FileUpload_MaxFileSize') },
);
required: ['success'],
additionalProperties: false,
}),
200: ajv.compile<void>({
type: 'object',
properties: {
success: {
type: 'boolean',
enum: [true],
},
},
required: ['success'],
additionalProperties: false,
}),
},
},
async function action() {
const emoji = await getUploadFormData(
{
request: this.request,
},
{
field: 'emoji',
sizeLimit: settings.get('FileUpload_MaxFileSize'),
},
);
const { fields, fileBuffer, mimetype } = emoji;
const { fields, fileBuffer, mimetype } = emoji;
const isUploadable = await Media.isImage(fileBuffer);
if (!isUploadable) {
throw new Meteor.Error('emoji-is-not-image', "Emoji file provided cannot be uploaded since it's not an image");
}
const isUploadable = await Media.isImage(fileBuffer);
if (!isUploadable) {
throw new Meteor.Error('emoji-is-not-image', "Emoji file provided cannot be uploaded since it's not an image");
}
const [, extension] = mimetype.split('/');
fields.extension = extension;
const [, extension] = mimetype.split('/');
fields.extension = extension;
try {
const emojiData = await insertOrUpdateEmoji(this.userId, {
...fields,
newFile: true,
aliases: fields.aliases || '',
name: fields.name,
extension: fields.extension,
});
try {
const emojiData = await insertOrUpdateEmoji(this.userId, {
...fields,
newFile: true,
aliases: fields.aliases || '',
name: fields.name,
extension: fields.extension,
});
await uploadEmojiCustomWithBuffer(this.userId, fileBuffer, mimetype, emojiData);
} catch (err) {
SystemLogger.error({ err });
return API.v1.failure();
}
await uploadEmojiCustomWithBuffer(this.userId, fileBuffer, mimetype, emojiData);
} catch (err) {
SystemLogger.error({ err });
return API.v1.failure();
}
return API.v1.success();
},
return API.v1.success();
},
);
@ -219,3 +248,12 @@ API.v1.addRoute(
},
},
);
type EmojiCustomCreateEndpoints = ExtractRoutesFromAPI<typeof emojiCustomCreateEndpoints>;
export type EmojiCustomEndpoints = EmojiCustomCreateEndpoints;
declare module '@rocket.chat/rest-typings' {
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface
interface Endpoints extends EmojiCustomCreateEndpoints {}
}

@ -63,9 +63,6 @@ export type EmojiCustomEndpoints = {
'/v1/emoji-custom.delete': {
POST: (params: emojiCustomDeleteProps) => void;
};
'/v1/emoji-custom.create': {
POST: (params: { emoji: ICustomEmojiDescriptor }) => void;
};
'/v1/emoji-custom.update': {
POST: (params: { emoji: ICustomEmojiDescriptor }) => void;
};

Loading…
Cancel
Save