feat: rename enum instead of string

This commit is contained in:
Mohamed Marrouchi
2025-01-16 10:14:50 +01:00
parent 3f9dd692bf
commit c27f37a6e6
18 changed files with 116 additions and 70 deletions

View File

@@ -39,6 +39,7 @@ import { attachment, attachmentFile } from '../mocks/attachment.mock';
import { AttachmentRepository } from '../repositories/attachment.repository';
import { Attachment, AttachmentModel } from '../schemas/attachment.schema';
import { AttachmentService } from '../services/attachment.service';
import { AttachmentResourceRef } from '../types';
import { AttachmentController } from './attachment.controller';
@@ -110,7 +111,7 @@ describe('AttachmentController', () => {
file: [],
},
{} as Request,
{ resourceRef: 'block_attachment' },
{ resourceRef: AttachmentResourceRef.BlockAttachment },
);
await expect(promiseResult).rejects.toThrow(
new BadRequestException('No file was selected'),
@@ -128,7 +129,7 @@ describe('AttachmentController', () => {
{
session: { passport: { user: { id: '9'.repeat(24) } } },
} as unknown as Request,
{ resourceRef: 'block_attachment' },
{ resourceRef: AttachmentResourceRef.BlockAttachment },
);
const [name] = attachmentFile.filename.split('.');
expect(attachmentService.create).toHaveBeenCalledWith({
@@ -136,7 +137,7 @@ describe('AttachmentController', () => {
type: attachmentFile.mimetype,
name: attachmentFile.originalname,
location: expect.stringMatching(new RegExp(`^/${name}`)),
resourceRef: 'block_attachment',
resourceRef: AttachmentResourceRef.BlockAttachment,
access: 'public',
createdByRef: 'User',
createdBy: '9'.repeat(24),
@@ -145,7 +146,7 @@ describe('AttachmentController', () => {
[
{
...attachment,
resourceRef: 'block_attachment',
resourceRef: AttachmentResourceRef.BlockAttachment,
createdByRef: 'User',
createdBy: '9'.repeat(24),
},

View File

@@ -18,6 +18,7 @@ import { Action } from '@/user/types/action.type';
import { attachment } from '../mocks/attachment.mock';
import { Attachment } from '../schemas/attachment.schema';
import { AttachmentService } from '../services/attachment.service';
import { AttachmentResourceRef } from '../types';
import { AttachmentGuard } from './attachment-ability.guard';
@@ -55,7 +56,7 @@ describe('AttachmentGuard', () => {
describe('canActivate', () => {
it('should allow GET requests with valid ref', async () => {
const mockUser = { roles: ['admin-id'] } as any;
const mockRef = ['user_avatar'];
const mockRef = [AttachmentResourceRef.UserAvatar];
jest.spyOn(modelService, 'findOne').mockImplementation((criteria) => {
return typeof criteria === 'string' ||
@@ -120,7 +121,7 @@ describe('AttachmentGuard', () => {
? Promise.reject('Invalid ID')
: Promise.resolve({
id: '9'.repeat(24),
resourceRef: `user_avatar`,
resourceRef: AttachmentResourceRef.UserAvatar,
} as Attachment);
});
@@ -191,7 +192,7 @@ describe('AttachmentGuard', () => {
const mockExecutionContext = {
switchToHttp: jest.fn().mockReturnValue({
getRequest: jest.fn().mockReturnValue({
query: { resourceRef: 'block_attachment' },
query: { resourceRef: AttachmentResourceRef.BlockAttachment },
method: 'POST',
user: mockUser,
}),

View File

@@ -26,7 +26,7 @@ import { Action } from '@/user/types/action.type';
import { TModel } from '@/user/types/model.type';
import { AttachmentService } from '../services/attachment.service';
import { TAttachmentResourceRef } from '../types';
import { AttachmentResourceRef, TAttachmentResourceRef } from '../types';
import {
isAttachmentResourceRef,
isAttachmentResourceRefArray,
@@ -46,46 +46,46 @@ export class AttachmentGuard implements CanActivate {
> = {
// Read attachments by ref
[Action.READ]: {
setting_attachment: [
[AttachmentResourceRef.SettingAttachment]: [
['setting', Action.READ],
['attachment', Action.READ],
],
user_avatar: [['user', Action.READ]],
block_attachment: [
[AttachmentResourceRef.UserAvatar]: [['user', Action.READ]],
[AttachmentResourceRef.BlockAttachment]: [
['block', Action.READ],
['attachment', Action.READ],
],
content_attachment: [
[AttachmentResourceRef.ContentAttachment]: [
['content', Action.READ],
['attachment', Action.READ],
],
subscriber_avatar: [['subscriber', Action.READ]],
message_attachment: [
[AttachmentResourceRef.SubscriberAvatar]: [['subscriber', Action.READ]],
[AttachmentResourceRef.MessageAttachment]: [
['message', Action.READ],
['attachment', Action.READ],
],
},
// Create attachments by ref
[Action.CREATE]: {
setting_attachment: [
[AttachmentResourceRef.SettingAttachment]: [
['setting', Action.UPDATE],
['attachment', Action.CREATE],
],
user_avatar: [
[AttachmentResourceRef.UserAvatar]: [
// Not authorized, done via /user/:id/edit endpoint
],
block_attachment: [
[AttachmentResourceRef.BlockAttachment]: [
['block', Action.UPDATE],
['attachment', Action.CREATE],
],
content_attachment: [
[AttachmentResourceRef.ContentAttachment]: [
['content', Action.UPDATE],
['attachment', Action.CREATE],
],
subscriber_avatar: [
[AttachmentResourceRef.SubscriberAvatar]: [
// Not authorized, done programmatically by the channel
],
message_attachment: [
[AttachmentResourceRef.MessageAttachment]: [
// Unless we're in case of a handover, done programmatically by the channel
['message', Action.CREATE],
['attachment', Action.CREATE],
@@ -93,36 +93,36 @@ export class AttachmentGuard implements CanActivate {
},
// Delete attachments by ref
[Action.DELETE]: {
setting_attachment: [
[AttachmentResourceRef.SettingAttachment]: [
['setting', Action.UPDATE],
['attachment', Action.DELETE],
],
user_avatar: [
[AttachmentResourceRef.UserAvatar]: [
// Not authorized
],
block_attachment: [
[AttachmentResourceRef.BlockAttachment]: [
['block', Action.UPDATE],
['attachment', Action.DELETE],
],
content_attachment: [
[AttachmentResourceRef.ContentAttachment]: [
['content', Action.UPDATE],
['attachment', Action.DELETE],
],
subscriber_avatar: [
[AttachmentResourceRef.SubscriberAvatar]: [
// Not authorized, done programmatically by the channel
],
message_attachment: [
[AttachmentResourceRef.MessageAttachment]: [
// Not authorized
],
},
// Update attachments is not possible
[Action.UPDATE]: {
setting_attachment: [],
user_avatar: [],
block_attachment: [],
content_attachment: [],
subscriber_avatar: [],
message_attachment: [],
[AttachmentResourceRef.SettingAttachment]: [],
[AttachmentResourceRef.UserAvatar]: [],
[AttachmentResourceRef.BlockAttachment]: [],
[AttachmentResourceRef.ContentAttachment]: [],
[AttachmentResourceRef.SubscriberAvatar]: [],
[AttachmentResourceRef.MessageAttachment]: [],
},
};
@@ -163,7 +163,7 @@ export class AttachmentGuard implements CanActivate {
*
* @param action - The action on the attachment.
* @param user - The current user.
* @param resourceRef - The resource ref of the attachment (e.g., user_avatar, setting_attachment).
* @param resourceRef - The resource ref of the attachment (e.g., [AttachmentResourceRef.UserAvatar], [AttachmentResourceRef.SettingAttachment]).
* @returns A promise that resolves to `true` if the user has the required upload permission, otherwise `false`.
*/
private async isAuthorized(

View File

@@ -9,6 +9,7 @@
import { Stream } from 'node:stream';
import { Attachment } from '../schemas/attachment.schema';
import { AttachmentResourceRef } from '../types';
export const attachment: Attachment = {
name: 'Screenshot from 2022-03-11 08-41-27-2a9799a8b6109c88fd9a7a690c1101934c.png',
@@ -16,7 +17,7 @@ export const attachment: Attachment = {
size: 343370,
location:
'/Screenshot from 2022-03-11 08-41-27-2a9799a8b6109c88fd9a7a690c1101934c.png',
resourceRef: 'block_attachment',
resourceRef: AttachmentResourceRef.BlockAttachment,
access: 'public',
id: '65940d115178607da65c82b6',
createdAt: new Date(),
@@ -47,7 +48,7 @@ export const attachments: Attachment[] = [
location:
'/app/src/attachment/uploads/Screenshot from 2022-03-11 08-41-27-2a9799a8b6109c88fd9a7a690c1101934c.png',
channel: { ['some-channel']: {} },
resourceRef: 'block_attachment',
resourceRef: AttachmentResourceRef.BlockAttachment,
access: 'public',
id: '65940d115178607da65c82b7',
createdAt: new Date(),
@@ -62,7 +63,7 @@ export const attachments: Attachment[] = [
location:
'/app/src/attachment/uploads/Screenshot from 2022-03-18 08-58-15-af61e7f71281f9fd3f1ad7ad10107741c.png',
channel: { ['some-channel']: {} },
resourceRef: 'block_attachment',
resourceRef: AttachmentResourceRef.BlockAttachment,
access: 'public',
id: '65940d115178607da65c82b8',
createdAt: new Date(),

View File

@@ -30,7 +30,7 @@ import { BaseService } from '@/utils/generics/base-service';
import { AttachmentMetadataDto } from '../dto/attachment.dto';
import { AttachmentRepository } from '../repositories/attachment.repository';
import { Attachment } from '../schemas/attachment.schema';
import { TAttachmentResourceRef } from '../types';
import { AttachmentResourceRef, TAttachmentResourceRef } from '../types';
import {
fileExists,
generateUniqueFilename,
@@ -164,7 +164,8 @@ export class AttachmentService extends BaseService<Attachment> {
* @returns The root directory path
*/
getRootDirByResourceRef(ref: TAttachmentResourceRef) {
return ref === 'subscriber_avatar' || ref === 'user_avatar'
return ref === AttachmentResourceRef.SubscriberAvatar ||
ref === AttachmentResourceRef.UserAvatar
? config.parameters.avatarDir
: config.parameters.uploadDir;
}

View File

@@ -24,12 +24,12 @@ export type TAttachmentCreatedByRef = `${AttachmentCreatedByRef}`;
* These resource references influence how the attachment is uploaded, stored, and accessed:
*/
export enum AttachmentResourceRef {
SettingAttachment = 'setting_attachment', // Attachments related to app settings, restricted to users with specific permissions.
UserAvatar = 'user_avatar', // Avatar files for users, only the current user can upload, accessible to those with appropriate permissions.
SubscriberAvatar = 'subscriber_avatar', // Avatar files for subscribers, uploaded programmatically, accessible to authorized users.
BlockAttachment = 'block_attachment', // Files sent by the bot, public or private based on the channel and user authentication.
ContentAttachment = 'content_attachment', // Files in the knowledge base, usually public but could vary based on specific needs.
MessageAttachment = 'message_attachment', // Files sent or received via messages, uploaded programmatically, accessible to users with inbox permissions.;
SettingAttachment = 'Setting', // Attachments related to app settings, restricted to users with specific permissions.
UserAvatar = 'User', // Avatar files for users, only the current user can upload, accessible to those with appropriate permissions.
SubscriberAvatar = 'Subscriber', // Avatar files for subscribers, uploaded programmatically, accessible to authorized users.
BlockAttachment = 'Block', // Files sent by the bot, public or private based on the channel and user authentication.
ContentAttachment = 'Content', // Files in the knowledge base, usually public but could vary based on specific needs.
MessageAttachment = 'Message', // Files sent or received via messages, uploaded programmatically, accessible to users with inbox permissions.;
}
export type TAttachmentResourceRef = `${AttachmentResourceRef}`;