mirror of
https://github.com/RocketChat/Rocket.Chat.git
synced 2025-12-28 06:47:25 +00:00
feat: Add OpenAPI Support to Permissions API (#35985)
Co-authored-by: Matheus Cardoso <matheus@cardo.so> Co-authored-by: Guilherme Gazzo <guilherme@gazzo.xyz>
This commit is contained in:
parent
e16efff972
commit
dc6acda84b
6
.changeset/tough-ravens-shop.md
Normal file
6
.changeset/tough-ravens-shop.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@rocket.chat/meteor": patch
|
||||
"@rocket.chat/rest-typings": patch
|
||||
---
|
||||
|
||||
Add OpenAPI support for the Rocket.Chat Permissions API endpoints by migrating to a centralized syntax and utilizing shared AJV schemas for validation. This will enhance API documentation and ensure type safety through response validation.
|
||||
@ -1,17 +1,101 @@
|
||||
import type { IPermission } from '@rocket.chat/core-typings';
|
||||
import { Permissions, Roles } from '@rocket.chat/models';
|
||||
import { isBodyParamsValidPermissionUpdate } from '@rocket.chat/rest-typings';
|
||||
import {
|
||||
ajv,
|
||||
validateUnauthorizedErrorResponse,
|
||||
validateBadRequestErrorResponse,
|
||||
validateForbiddenErrorResponse,
|
||||
} from '@rocket.chat/rest-typings';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
|
||||
import { permissionsGetMethod } from '../../../authorization/server/streamer/permissions';
|
||||
import { notifyOnPermissionChangedById } from '../../../lib/server/lib/notifyListener';
|
||||
import type { ExtractRoutesFromAPI } from '../ApiClass';
|
||||
import { API } from '../api';
|
||||
|
||||
API.v1.addRoute(
|
||||
'permissions.listAll',
|
||||
{ authRequired: true },
|
||||
{
|
||||
async get() {
|
||||
type PermissionsListAllProps = {
|
||||
updatedSince?: string;
|
||||
};
|
||||
|
||||
type PermissionsUpdateProps = {
|
||||
permissions: { _id: string; roles: string[] }[];
|
||||
};
|
||||
|
||||
const permissionListAllSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
updatedSince: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
},
|
||||
},
|
||||
required: [],
|
||||
additionalProperties: false,
|
||||
};
|
||||
|
||||
const permissionUpdatePropsSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
permissions: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
_id: { type: 'string' },
|
||||
roles: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
uniqueItems: true,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
required: ['_id', 'roles'],
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['permissions'],
|
||||
additionalProperties: false,
|
||||
};
|
||||
|
||||
const isPermissionsListAll = ajv.compile<PermissionsListAllProps>(permissionListAllSchema);
|
||||
|
||||
const isBodyParamsValidPermissionUpdate = ajv.compile<PermissionsUpdateProps>(permissionUpdatePropsSchema);
|
||||
|
||||
const permissionsEndpoints = API.v1
|
||||
.get(
|
||||
'permissions.listAll',
|
||||
{
|
||||
authRequired: true,
|
||||
query: isPermissionsListAll,
|
||||
response: {
|
||||
200: ajv.compile<{
|
||||
update: IPermission[];
|
||||
remove: IPermission[];
|
||||
}>({
|
||||
type: 'object',
|
||||
properties: {
|
||||
update: {
|
||||
type: 'array',
|
||||
items: { $ref: '#/components/schemas/IPermission' },
|
||||
},
|
||||
remove: {
|
||||
type: 'array',
|
||||
items: { $ref: '#/components/schemas/IPermission' },
|
||||
},
|
||||
success: {
|
||||
type: 'boolean',
|
||||
enum: [true],
|
||||
description: 'Indicates if the request was successful.',
|
||||
},
|
||||
},
|
||||
required: ['update', 'remove', 'success'],
|
||||
additionalProperties: false,
|
||||
}),
|
||||
400: validateBadRequestErrorResponse,
|
||||
401: validateUnauthorizedErrorResponse,
|
||||
},
|
||||
},
|
||||
async function action() {
|
||||
const { updatedSince } = this.queryParams;
|
||||
|
||||
let updatedSinceDate: Date | undefined;
|
||||
@ -36,14 +120,38 @@ API.v1.addRoute(
|
||||
|
||||
return API.v1.success(result);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
API.v1.addRoute(
|
||||
'permissions.update',
|
||||
{ authRequired: true, permissionsRequired: ['access-permissions'] },
|
||||
{
|
||||
async post() {
|
||||
)
|
||||
.post(
|
||||
'permissions.update',
|
||||
{
|
||||
authRequired: true,
|
||||
permissionsRequired: ['access-permissions'],
|
||||
body: isBodyParamsValidPermissionUpdate,
|
||||
response: {
|
||||
200: ajv.compile<{
|
||||
permissions: IPermission[];
|
||||
}>({
|
||||
type: 'object',
|
||||
properties: {
|
||||
permissions: {
|
||||
type: 'array',
|
||||
items: { $ref: '#/components/schemas/IPermission' },
|
||||
},
|
||||
success: {
|
||||
type: 'boolean',
|
||||
enum: [true],
|
||||
description: 'Indicates if the request was successful.',
|
||||
},
|
||||
},
|
||||
required: ['permissions', 'success'],
|
||||
additionalProperties: false,
|
||||
}),
|
||||
400: validateBadRequestErrorResponse,
|
||||
401: validateUnauthorizedErrorResponse,
|
||||
403: validateForbiddenErrorResponse,
|
||||
},
|
||||
},
|
||||
async function action() {
|
||||
const { bodyParams } = this;
|
||||
|
||||
if (!isBodyParamsValidPermissionUpdate(bodyParams)) {
|
||||
@ -76,5 +184,11 @@ API.v1.addRoute(
|
||||
permissions: result,
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
);
|
||||
|
||||
export type PermissionsEndpoints = ExtractRoutesFromAPI<typeof permissionsEndpoints>;
|
||||
|
||||
declare module '@rocket.chat/rest-typings' {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface
|
||||
interface Endpoints extends PermissionsEndpoints {}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import type { ICustomSound } from './ICustomSound';
|
||||
import type { IInvite } from './IInvite';
|
||||
import type { IMessage } from './IMessage';
|
||||
import type { IOAuthApps } from './IOAuthApps';
|
||||
import type { IPermission } from './IPermission';
|
||||
import type { ISubscription } from './ISubscription';
|
||||
|
||||
export const schemas = typia.json.schemas<[ISubscription | IInvite | ICustomSound | IMessage | IOAuthApps], '3.0'>();
|
||||
export const schemas = typia.json.schemas<[ISubscription | IInvite | ICustomSound | IMessage | IOAuthApps | IPermission], '3.0'>();
|
||||
|
||||
@ -35,7 +35,6 @@ import type { MiscEndpoints } from './v1/misc';
|
||||
import type { ModerationEndpoints } from './v1/moderation';
|
||||
import type { OAuthAppsEndpoint } from './v1/oauthapps';
|
||||
import type { OmnichannelEndpoints } from './v1/omnichannel';
|
||||
import type { PermissionsEndpoints } from './v1/permissions';
|
||||
import type { PresenceEndpoints } from './v1/presence';
|
||||
import type { PushEndpoints } from './v1/push';
|
||||
import type { RolesEndpoints } from './v1/roles';
|
||||
@ -79,7 +78,6 @@ export interface Endpoints
|
||||
StatisticsEndpoints,
|
||||
LicensesEndpoints,
|
||||
MiscEndpoints,
|
||||
PermissionsEndpoints,
|
||||
PresenceEndpoints,
|
||||
InstancesEndpoints,
|
||||
IntegrationsEndpoints,
|
||||
@ -214,7 +212,6 @@ export type UrlParams<T extends string> = string extends T
|
||||
export type MethodOf<TPathPattern extends PathPattern> = TPathPattern extends any ? keyof Endpoints[TPathPattern] : never;
|
||||
|
||||
export * from './apps';
|
||||
export * from './v1/permissions';
|
||||
export * from './v1/presence';
|
||||
export * from './v1/roles';
|
||||
export * from './v1/settings';
|
||||
|
||||
@ -1,68 +0,0 @@
|
||||
import type { IPermission } from '@rocket.chat/core-typings';
|
||||
import Ajv from 'ajv';
|
||||
|
||||
const ajv = new Ajv({
|
||||
coerceTypes: true,
|
||||
});
|
||||
|
||||
type PermissionsListAllProps = {
|
||||
updatedSince?: string;
|
||||
};
|
||||
|
||||
const permissionListAllSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
updatedSince: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
},
|
||||
},
|
||||
required: [],
|
||||
additionalProperties: false,
|
||||
};
|
||||
|
||||
export const isPermissionsListAll = ajv.compile<PermissionsListAllProps>(permissionListAllSchema);
|
||||
|
||||
type PermissionsUpdateProps = {
|
||||
permissions: { _id: string; roles: string[] }[];
|
||||
};
|
||||
|
||||
const permissionUpdatePropsSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
permissions: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
_id: { type: 'string' },
|
||||
roles: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
uniqueItems: true,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
required: ['_id', 'roles'],
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['permissions'],
|
||||
additionalProperties: false,
|
||||
};
|
||||
|
||||
export const isBodyParamsValidPermissionUpdate = ajv.compile<PermissionsUpdateProps>(permissionUpdatePropsSchema);
|
||||
|
||||
export type PermissionsEndpoints = {
|
||||
'/v1/permissions.listAll': {
|
||||
GET: (params: PermissionsListAllProps) => {
|
||||
update: IPermission[];
|
||||
remove: IPermission[];
|
||||
};
|
||||
};
|
||||
'/v1/permissions.update': {
|
||||
POST: (params: PermissionsUpdateProps) => {
|
||||
permissions: IPermission[];
|
||||
};
|
||||
};
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user