chore!: make custom sounds page stop to use query param (#33499)

pull/33628/head
Marcos Spessatto Defendi 1 year ago committed by Guilherme Gazzo
parent 9662e1a227
commit 7da9ec6ee4
  1. 2
      apps/meteor/app/api/server/helpers/parseJsonQuery.ts
  2. 16
      apps/meteor/app/api/server/v1/custom-sounds.ts
  3. 3
      apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.tsx
  4. 130
      apps/meteor/tests/end-to-end/api/custom-sounds.ts
  5. 1
      packages/rest-typings/src/index.ts
  6. 9
      packages/rest-typings/src/v1/customSounds.ts
  7. 29
      packages/rest-typings/src/v1/voip.ts

@ -59,6 +59,7 @@ export async function parseJsonQuery(api: PartialThis): Promise<{
'/api/v1/channels.files',
'/api/v1/integrations.list',
'/api/v1/custom-user-status.list',
'/api/v1/custom-sounds.list',
].includes(route);
const isUnsafeQueryParamsAllowed = process.env.ALLOW_UNSAFE_QUERY_AND_FIELDS_API_PARAMS?.toUpperCase() === 'TRUE';
@ -70,7 +71,6 @@ export async function parseJsonQuery(api: PartialThis): Promise<{
try {
apiDeprecationLogger.parameter(route, 'fields', '8.0.0', response, messageGenerator);
fields = JSON.parse(params.fields) as Record<string, 0 | 1>;
Object.entries(fields).forEach(([key, value]) => {
if (value !== 1 && value !== 0) {
throw new Meteor.Error('error-invalid-sort-parameter', `Invalid fields parameter: ${key}`, {

@ -1,16 +1,26 @@
import { CustomSounds } from '@rocket.chat/models';
import { isCustomSoundsListProps } from '@rocket.chat/rest-typings';
import { escapeRegExp } from '@rocket.chat/string-helpers';
import { API } from '../api';
import { getPaginationItems } from '../helpers/getPaginationItems';
API.v1.addRoute(
'custom-sounds.list',
{ authRequired: true },
{ authRequired: true, validateParams: isCustomSoundsListProps },
{
async get() {
const { offset, count } = await getPaginationItems(this.queryParams);
const { offset, count } = await getPaginationItems(this.queryParams as Record<string, string | number | null | undefined>);
const { sort, query } = await this.parseJsonQuery();
const { cursor, totalCount } = CustomSounds.findPaginated(query, {
const { name } = this.queryParams;
const filter = {
...query,
...(name ? { name: { $regex: escapeRegExp(name as string), $options: 'i' } } : {}),
};
const { cursor, totalCount } = CustomSounds.findPaginated(filter, {
sort: sort || { name: 1 },
skip: offset,
limit: count,

@ -1,6 +1,5 @@
import { Pagination, States, StatesIcon, StatesActions, StatesAction, StatesTitle } from '@rocket.chat/fuselage';
import { useDebouncedValue } from '@rocket.chat/fuselage-hooks';
import { escapeRegExp } from '@rocket.chat/string-helpers';
import { useTranslation, useEndpoint } from '@rocket.chat/ui-contexts';
import { useQuery } from '@tanstack/react-query';
import type { MutableRefObject } from 'react';
@ -34,7 +33,7 @@ const CustomSoundsTable = ({ reload, onClick }: CustomSoundsTableProps) => {
const query = useDebouncedValue(
useMemo(
() => ({
query: JSON.stringify({ name: { $regex: escapeRegExp(text), $options: 'i' } }),
name: text,
sort: `{ "${sortBy}": ${sortDirection === 'asc' ? 1 : -1} }`,
...(itemsPerPage && { count: itemsPerPage }),
...(current && { offset: current }),

@ -7,9 +7,76 @@ import { before, describe, it, after } from 'mocha';
import { getCredentials, api, request, credentials } from '../../data/api-data';
async function insertOrUpdateSound(fileName: string, fileId?: string): Promise<string> {
fileId = fileId ?? '';
await request
.post(api('method.call/insertOrUpdateSound'))
.set(credentials)
.send({
message: JSON.stringify({
msg: 'method',
id: '1',
method: 'insertOrUpdateSound',
params: [{ name: fileName, extension: 'mp3', newFile: true }],
}),
})
.expect(200)
.expect((res) => {
fileId = JSON.parse(res.body.message).result;
});
return fileId;
}
async function uploadCustomSound(binary: string, fileName: string, fileId: string) {
await request
.post(api('method.call/uploadCustomSound'))
.set(credentials)
.send({
message: JSON.stringify({
msg: 'method',
id: '2',
method: 'uploadCustomSound',
params: [binary, 'audio/wav', { name: fileName, extension: 'wav', newFile: true, _id: fileId }],
}),
})
.expect(200);
}
describe('[CustomSounds]', () => {
const fileName = `test-file-${randomUUID()}`;
let fileId: string;
let fileId2: string;
let uploadDate: unknown;
before((done) => getCredentials(done));
before(async () => {
const data = readFileSync(path.resolve(__dirname, '../../mocks/files/audio_mock.wav'));
const binary = data.toString('binary');
fileId = await insertOrUpdateSound(fileName);
fileId2 = await insertOrUpdateSound(`${fileName}-2`);
await uploadCustomSound(binary, fileName, fileId);
await uploadCustomSound(binary, `${fileName}-2`, fileId2);
});
after(() =>
request
.post(api('method.call/deleteCustomSound'))
.set(credentials)
.send({
message: JSON.stringify({
msg: 'method',
id: '33',
method: 'deleteCustomSound',
params: [fileId],
}),
}),
);
describe('[/custom-sounds.list]', () => {
it('should return custom sounds', (done) => {
void request
@ -41,59 +108,28 @@ describe('[CustomSounds]', () => {
})
.end(done);
});
});
describe('Accessing custom sounds', () => {
let fileId: string;
const fileName = `test-file-${randomUUID()}`;
let uploadDate: unknown;
before(async () => {
const data = readFileSync(path.resolve(__dirname, '../../mocks/files/audio_mock.wav'));
const binary = data.toString('binary');
await request
.post(api('method.call/insertOrUpdateSound'))
it('should return custom sounds filtering it using the `name` parameter', (done) => {
void request
.get(api('custom-sounds.list'))
.set(credentials)
.send({
message: JSON.stringify({
msg: 'method',
id: '1',
method: 'insertOrUpdateSound',
params: [{ name: fileName, extension: 'mp3', newFile: true }],
}),
})
.expect(200)
.query({
name: `${fileName}-2`,
count: 5,
offset: 0,
})
.expect((res) => {
fileId = JSON.parse(res.body.message).result;
});
await request
.post(api('method.call/uploadCustomSound'))
.set(credentials)
.send({
message: JSON.stringify({
msg: 'method',
id: '2',
method: 'uploadCustomSound',
params: [binary, 'audio/wav', { name: fileName, extension: 'wav', newFile: true, _id: fileId }],
}),
expect(res.body).to.have.property('sounds').and.to.be.an('array');
expect(res.body).to.have.property('total').to.equal(1);
expect(res.body).to.have.property('offset').to.equal(0);
expect(res.body).to.have.property('count').to.equal(1);
expect(res.body.sounds[0]._id).to.be.equal(fileId2);
})
.expect(200);
.end(done);
});
});
after(() =>
request
.post(api('method.call/deleteCustomSound'))
.set(credentials)
.send({
message: JSON.stringify({
msg: 'method',
id: '33',
method: 'deleteCustomSound',
params: [fileId],
}),
}),
);
describe('Accessing custom sounds', () => {
it('should return forbidden if the there is no fileId on the url', (done) => {
void request
.get('/custom-sounds/')

@ -222,6 +222,7 @@ export * from './v1/videoConference';
export * from './v1/assets';
export * from './v1/channels';
export * from './v1/customUserStatus';
export * from './v1/customSounds';
export * from './v1/subscriptionsEndpoints';
export * from './v1/mailer';
export * from './v1/mailer/MailerParamsPOST';

@ -8,7 +8,7 @@ const ajv = new Ajv({
coerceTypes: true,
});
type CustomSoundsList = PaginatedRequest<{ query: string }>;
type CustomSoundsList = PaginatedRequest<{ name?: string }>;
const CustomSoundsListSchema = {
type: 'object',
@ -25,11 +25,16 @@ const CustomSoundsListSchema = {
type: 'string',
nullable: true,
},
name: {
type: 'string',
nullable: true,
},
query: {
type: 'string',
nullable: true,
},
},
required: ['query'],
required: [],
additionalProperties: false,
};

@ -21,35 +21,6 @@ const ajv = new Ajv({
coerceTypes: true,
});
/** *************************************************/
type CustomSoundsList = PaginatedRequest<{ query: string }>;
const CustomSoundsListSchema = {
type: 'object',
properties: {
count: {
type: 'number',
nullable: true,
},
offset: {
type: 'number',
nullable: true,
},
sort: {
type: 'string',
nullable: true,
},
query: {
type: 'string',
nullable: true,
},
},
required: [],
additionalProperties: false,
};
export const isCustomSoundsListProps = ajv.compile<CustomSoundsList>(CustomSoundsListSchema);
type ConnectorExtensionGetRegistrationInfoByUserId = { id: string };
const ConnectorExtensionGetRegistrationInfoByUserIdSchema: JSONSchemaType<ConnectorExtensionGetRegistrationInfoByUserId> = {

Loading…
Cancel
Save