mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	refactor(server): auth decorator (#2588)
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| import { Controller, Get, Post, Body, Param, Delete, Put, Query, Response } from '@nestjs/common'; | ||||
| import { ParseMeUUIDPipe } from '../validation/parse-me-uuid-pipe'; | ||||
| import { AlbumService } from './album.service'; | ||||
| import { Authenticated } from '../../decorators/authenticated.decorator'; | ||||
| import { Authenticated, SharedLinkRoute } from '../../decorators/authenticated.decorator'; | ||||
| import { AuthUserDto, GetAuthUser } from '../../decorators/auth-user.decorator'; | ||||
| import { AddAssetsDto } from './dto/add-assets.dto'; | ||||
| import { AddUsersDto } from './dto/add-users.dto'; | ||||
| @@ -32,24 +32,23 @@ const handleDownload = (download: DownloadArchive, res: Res) => { | ||||
|  | ||||
| @ApiTags('Album') | ||||
| @Controller('album') | ||||
| @Authenticated() | ||||
| @UseValidation() | ||||
| export class AlbumController { | ||||
|   constructor(private readonly service: AlbumService) {} | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get('count-by-user-id') | ||||
|   getAlbumCountByUserId(@GetAuthUser() authUser: AuthUserDto): Promise<AlbumCountResponseDto> { | ||||
|     return this.service.getCountByUserId(authUser); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Put(':id/users') | ||||
|   addUsersToAlbum(@GetAuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto, @Body() dto: AddUsersDto) { | ||||
|     // TODO: Handle nonexistent sharedUserIds. | ||||
|     return this.service.addUsers(authUser, id, dto); | ||||
|   } | ||||
|  | ||||
|   @Authenticated({ isShared: true }) | ||||
|   @SharedLinkRoute() | ||||
|   @Put(':id/assets') | ||||
|   addAssetsToAlbum( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
| @@ -61,13 +60,12 @@ export class AlbumController { | ||||
|     return this.service.addAssets(authUser, id, dto); | ||||
|   } | ||||
|  | ||||
|   @Authenticated({ isShared: true }) | ||||
|   @SharedLinkRoute() | ||||
|   @Get(':id') | ||||
|   getAlbumInfo(@GetAuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto) { | ||||
|     return this.service.get(authUser, id); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Delete(':id/assets') | ||||
|   removeAssetFromAlbum( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
| @@ -77,7 +75,6 @@ export class AlbumController { | ||||
|     return this.service.removeAssets(authUser, id, dto); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Delete(':id/user/:userId') | ||||
|   removeUserFromAlbum( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
| @@ -87,7 +84,7 @@ export class AlbumController { | ||||
|     return this.service.removeUser(authUser, id, userId); | ||||
|   } | ||||
|  | ||||
|   @Authenticated({ isShared: true }) | ||||
|   @SharedLinkRoute() | ||||
|   @Get(':id/download') | ||||
|   @ApiOkResponse({ content: { 'application/zip': { schema: { type: 'string', format: 'binary' } } } }) | ||||
|   downloadArchive( | ||||
| @@ -100,7 +97,6 @@ export class AlbumController { | ||||
|     return this.service.downloadArchive(authUser, id, dto).then((download) => handleDownload(download, res)); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Post('create-shared-link') | ||||
|   createAlbumSharedLink(@GetAuthUser() authUser: AuthUserDto, @Body() dto: CreateAlbumSharedLinkDto) { | ||||
|     return this.service.createSharedLink(authUser, dto); | ||||
|   | ||||
| @@ -19,7 +19,7 @@ import { | ||||
|   StreamableFile, | ||||
|   ParseFilePipe, | ||||
| } from '@nestjs/common'; | ||||
| import { Authenticated } from '../../decorators/authenticated.decorator'; | ||||
| import { Authenticated, SharedLinkRoute } from '../../decorators/authenticated.decorator'; | ||||
| import { AssetService } from './asset.service'; | ||||
| import { FileFieldsInterceptor } from '@nestjs/platform-express'; | ||||
| import { AuthUserDto, GetAuthUser } from '../../decorators/auth-user.decorator'; | ||||
| @@ -68,10 +68,11 @@ function asStreamableFile({ stream, type, length }: ImmichReadStream) { | ||||
|  | ||||
| @ApiTags('Asset') | ||||
| @Controller('asset') | ||||
| @Authenticated() | ||||
| export class AssetController { | ||||
|   constructor(private assetService: AssetService) {} | ||||
|  | ||||
|   @Authenticated({ isShared: true }) | ||||
|   @SharedLinkRoute() | ||||
|   @Post('upload') | ||||
|   @UseInterceptors( | ||||
|     FileFieldsInterceptor( | ||||
| @@ -116,7 +117,7 @@ export class AssetController { | ||||
|     return responseDto; | ||||
|   } | ||||
|  | ||||
|   @Authenticated({ isShared: true }) | ||||
|   @SharedLinkRoute() | ||||
|   @Get('/download/:assetId') | ||||
|   @ApiOkResponse({ content: { 'application/octet-stream': { schema: { type: 'string', format: 'binary' } } } }) | ||||
|   async downloadFile( | ||||
| @@ -127,7 +128,7 @@ export class AssetController { | ||||
|     return this.assetService.downloadFile(authUser, assetId).then(asStreamableFile); | ||||
|   } | ||||
|  | ||||
|   @Authenticated({ isShared: true }) | ||||
|   @SharedLinkRoute() | ||||
|   @Post('/download-files') | ||||
|   @ApiOkResponse({ content: { 'application/octet-stream': { schema: { type: 'string', format: 'binary' } } } }) | ||||
|   async downloadFiles( | ||||
| @@ -148,7 +149,7 @@ export class AssetController { | ||||
|   /** | ||||
|    * Current this is not used in any UI element | ||||
|    */ | ||||
|   @Authenticated({ isShared: true }) | ||||
|   @SharedLinkRoute() | ||||
|   @Get('/download-library') | ||||
|   @ApiOkResponse({ content: { 'application/octet-stream': { schema: { type: 'string', format: 'binary' } } } }) | ||||
|   async downloadLibrary( | ||||
| @@ -165,7 +166,7 @@ export class AssetController { | ||||
|     return stream; | ||||
|   } | ||||
|  | ||||
|   @Authenticated({ isShared: true }) | ||||
|   @SharedLinkRoute() | ||||
|   @Get('/file/:assetId') | ||||
|   @Header('Cache-Control', 'max-age=31536000') | ||||
|   @ApiOkResponse({ content: { 'application/octet-stream': { schema: { type: 'string', format: 'binary' } } } }) | ||||
| @@ -180,7 +181,7 @@ export class AssetController { | ||||
|     return this.assetService.serveFile(authUser, assetId, query, res, headers); | ||||
|   } | ||||
|  | ||||
|   @Authenticated({ isShared: true }) | ||||
|   @SharedLinkRoute() | ||||
|   @Get('/thumbnail/:assetId') | ||||
|   @Header('Cache-Control', 'max-age=31536000') | ||||
|   @ApiOkResponse({ content: { 'application/octet-stream': { schema: { type: 'string', format: 'binary' } } } }) | ||||
| @@ -195,25 +196,21 @@ export class AssetController { | ||||
|     return this.assetService.getAssetThumbnail(assetId, query, res, headers); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get('/curated-objects') | ||||
|   async getCuratedObjects(@GetAuthUser() authUser: AuthUserDto): Promise<CuratedObjectsResponseDto[]> { | ||||
|     return this.assetService.getCuratedObject(authUser); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get('/curated-locations') | ||||
|   async getCuratedLocations(@GetAuthUser() authUser: AuthUserDto): Promise<CuratedLocationsResponseDto[]> { | ||||
|     return this.assetService.getCuratedLocation(authUser); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get('/search-terms') | ||||
|   async getAssetSearchTerms(@GetAuthUser() authUser: AuthUserDto): Promise<string[]> { | ||||
|     return this.assetService.getAssetSearchTerm(authUser); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Post('/search') | ||||
|   async searchAsset( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
| @@ -222,7 +219,6 @@ export class AssetController { | ||||
|     return this.assetService.searchAsset(authUser, searchAssetDto); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Post('/count-by-time-bucket') | ||||
|   async getAssetCountByTimeBucket( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
| @@ -231,13 +227,11 @@ export class AssetController { | ||||
|     return this.assetService.getAssetCountByTimeBucket(authUser, getAssetCountByTimeGroupDto); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get('/count-by-user-id') | ||||
|   async getAssetCountByUserId(@GetAuthUser() authUser: AuthUserDto): Promise<AssetCountByUserIdResponseDto> { | ||||
|     return this.assetService.getAssetCountByUserId(authUser); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get('/stat/archive') | ||||
|   async getArchivedAssetCountByUserId(@GetAuthUser() authUser: AuthUserDto): Promise<AssetCountByUserIdResponseDto> { | ||||
|     return this.assetService.getArchivedAssetCountByUserId(authUser); | ||||
| @@ -245,7 +239,6 @@ export class AssetController { | ||||
|   /** | ||||
|    * Get all AssetEntity belong to the user | ||||
|    */ | ||||
|   @Authenticated() | ||||
|   @Get('/') | ||||
|   @ApiHeader({ | ||||
|     name: 'if-none-match', | ||||
| @@ -260,7 +253,6 @@ export class AssetController { | ||||
|     return this.assetService.getAllAssets(authUser, dto); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Post('/time-bucket') | ||||
|   async getAssetByTimeBucket( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
| @@ -272,7 +264,6 @@ export class AssetController { | ||||
|   /** | ||||
|    * Get all asset of a device that are in the database, ID only. | ||||
|    */ | ||||
|   @Authenticated() | ||||
|   @Get('/:deviceId') | ||||
|   async getUserAssetsByDeviceId(@GetAuthUser() authUser: AuthUserDto, @Param() { deviceId }: DeviceIdDto) { | ||||
|     return await this.assetService.getUserAssetsByDeviceId(authUser, deviceId); | ||||
| @@ -281,7 +272,7 @@ export class AssetController { | ||||
|   /** | ||||
|    * Get a single asset's information | ||||
|    */ | ||||
|   @Authenticated({ isShared: true }) | ||||
|   @SharedLinkRoute() | ||||
|   @Get('/assetById/:assetId') | ||||
|   async getAssetById( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
| @@ -294,7 +285,6 @@ export class AssetController { | ||||
|   /** | ||||
|    * Update an asset | ||||
|    */ | ||||
|   @Authenticated() | ||||
|   @Put('/:assetId') | ||||
|   async updateAsset( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
| @@ -305,7 +295,6 @@ export class AssetController { | ||||
|     return await this.assetService.updateAsset(authUser, assetId, dto); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Delete('/') | ||||
|   async deleteAsset( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
| @@ -318,7 +307,7 @@ export class AssetController { | ||||
|   /** | ||||
|    * Check duplicated asset before uploading - for Web upload used | ||||
|    */ | ||||
|   @Authenticated({ isShared: true }) | ||||
|   @SharedLinkRoute() | ||||
|   @Post('/check') | ||||
|   @HttpCode(200) | ||||
|   async checkDuplicateAsset( | ||||
| @@ -331,7 +320,6 @@ export class AssetController { | ||||
|   /** | ||||
|    * Checks if multiple assets exist on the server and returns all existing - used by background backup | ||||
|    */ | ||||
|   @Authenticated() | ||||
|   @Post('/exist') | ||||
|   @HttpCode(200) | ||||
|   async checkExistingAssets( | ||||
| @@ -344,7 +332,6 @@ export class AssetController { | ||||
|   /** | ||||
|    * Checks if assets exist by checksums | ||||
|    */ | ||||
|   @Authenticated() | ||||
|   @Post('/bulk-upload-check') | ||||
|   @HttpCode(200) | ||||
|   bulkUploadCheck( | ||||
| @@ -354,7 +341,6 @@ export class AssetController { | ||||
|     return this.assetService.bulkUploadCheck(authUser, dto); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Post('/shared-link') | ||||
|   async createAssetsSharedLink( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
| @@ -363,7 +349,7 @@ export class AssetController { | ||||
|     return await this.assetService.createAssetsSharedLink(authUser, dto); | ||||
|   } | ||||
|  | ||||
|   @Authenticated({ isShared: true }) | ||||
|   @SharedLinkRoute() | ||||
|   @Patch('/shared-link/add') | ||||
|   async addAssetsToSharedLink( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
| @@ -372,7 +358,7 @@ export class AssetController { | ||||
|     return await this.assetService.addAssetsToSharedLink(authUser, dto); | ||||
|   } | ||||
|  | ||||
|   @Authenticated({ isShared: true }) | ||||
|   @SharedLinkRoute() | ||||
|   @Patch('/shared-link/remove') | ||||
|   async removeAssetsFromSharedLink( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
|   | ||||
| @@ -8,9 +8,9 @@ import { AuthUserDto, GetAuthUser } from '../../decorators/auth-user.decorator'; | ||||
| import { mapTag, TagResponseDto } from '@app/domain'; | ||||
| import { UUIDParamDto } from '../../controllers/dto/uuid-param.dto'; | ||||
|  | ||||
| @Authenticated() | ||||
| @ApiTags('Tag') | ||||
| @Controller('tag') | ||||
| @Authenticated() | ||||
| export class TagController { | ||||
|   constructor(private readonly tagService: TagService) {} | ||||
|  | ||||
|   | ||||
| @@ -19,16 +19,18 @@ import { Body, Controller, Delete, Get, Param, Post, Req, Res } from '@nestjs/co | ||||
| import { ApiBadRequestResponse, ApiTags } from '@nestjs/swagger'; | ||||
| import { Request, Response } from 'express'; | ||||
| import { GetAuthUser, GetLoginDetails } from '../decorators/auth-user.decorator'; | ||||
| import { Authenticated } from '../decorators/authenticated.decorator'; | ||||
| import { Authenticated, PublicRoute } from '../decorators/authenticated.decorator'; | ||||
| import { UseValidation } from '../decorators/use-validation.decorator'; | ||||
| import { UUIDParamDto } from './dto/uuid-param.dto'; | ||||
|  | ||||
| @ApiTags('Authentication') | ||||
| @Controller('auth') | ||||
| @Authenticated() | ||||
| @UseValidation() | ||||
| export class AuthController { | ||||
|   constructor(private readonly service: AuthService) {} | ||||
|  | ||||
|   @PublicRoute() | ||||
|   @Post('login') | ||||
|   async login( | ||||
|     @Body() loginCredential: LoginCredentialDto, | ||||
| @@ -40,43 +42,38 @@ export class AuthController { | ||||
|     return response; | ||||
|   } | ||||
|  | ||||
|   @PublicRoute() | ||||
|   @Post('admin-sign-up') | ||||
|   @ApiBadRequestResponse({ description: 'The server already has an admin' }) | ||||
|   adminSignUp(@Body() signUpCredential: SignUpDto): Promise<AdminSignupResponseDto> { | ||||
|     return this.service.adminSignUp(signUpCredential); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get('devices') | ||||
|   getAuthDevices(@GetAuthUser() authUser: AuthUserDto): Promise<AuthDeviceResponseDto[]> { | ||||
|     return this.service.getDevices(authUser); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Delete('devices') | ||||
|   logoutAuthDevices(@GetAuthUser() authUser: AuthUserDto): Promise<void> { | ||||
|     return this.service.logoutDevices(authUser); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Delete('devices/:id') | ||||
|   logoutAuthDevice(@GetAuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto): Promise<void> { | ||||
|     return this.service.logoutDevice(authUser, id); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Post('validateToken') | ||||
|   validateAccessToken(): ValidateAccessTokenResponseDto { | ||||
|     return { authStatus: true }; | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Post('change-password') | ||||
|   changePassword(@GetAuthUser() authUser: AuthUserDto, @Body() dto: ChangePasswordDto): Promise<UserResponseDto> { | ||||
|     return this.service.changePassword(authUser, dto); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Post('logout') | ||||
|   logout( | ||||
|     @Req() req: Request, | ||||
|   | ||||
| @@ -12,15 +12,17 @@ import { Body, Controller, Get, HttpStatus, Post, Redirect, Req, Res } from '@ne | ||||
| import { ApiTags } from '@nestjs/swagger'; | ||||
| import { Request, Response } from 'express'; | ||||
| import { GetAuthUser, GetLoginDetails } from '../decorators/auth-user.decorator'; | ||||
| import { Authenticated } from '../decorators/authenticated.decorator'; | ||||
| import { Authenticated, PublicRoute } from '../decorators/authenticated.decorator'; | ||||
| import { UseValidation } from '../decorators/use-validation.decorator'; | ||||
|  | ||||
| @ApiTags('OAuth') | ||||
| @Controller('oauth') | ||||
| @Authenticated() | ||||
| @UseValidation() | ||||
| export class OAuthController { | ||||
|   constructor(private service: OAuthService) {} | ||||
|  | ||||
|   @PublicRoute() | ||||
|   @Get('mobile-redirect') | ||||
|   @Redirect() | ||||
|   mobileRedirect(@Req() req: Request) { | ||||
| @@ -30,11 +32,13 @@ export class OAuthController { | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   @PublicRoute() | ||||
|   @Post('config') | ||||
|   generateConfig(@Body() dto: OAuthConfigDto): Promise<OAuthConfigResponseDto> { | ||||
|     return this.service.generateConfig(dto); | ||||
|   } | ||||
|  | ||||
|   @PublicRoute() | ||||
|   @Post('callback') | ||||
|   async callback( | ||||
|     @Res({ passthrough: true }) res: Response, | ||||
| @@ -46,13 +50,11 @@ export class OAuthController { | ||||
|     return response; | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Post('link') | ||||
|   link(@GetAuthUser() authUser: AuthUserDto, @Body() dto: OAuthCallbackDto): Promise<UserResponseDto> { | ||||
|     return this.service.link(authUser, dto); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Post('unlink') | ||||
|   unlink(@GetAuthUser() authUser: AuthUserDto): Promise<UserResponseDto> { | ||||
|     return this.service.unlink(authUser); | ||||
|   | ||||
| @@ -8,11 +8,11 @@ import { UUIDParamDto } from './dto/uuid-param.dto'; | ||||
|  | ||||
| @ApiTags('Partner') | ||||
| @Controller('partner') | ||||
| @Authenticated() | ||||
| @UseValidation() | ||||
| export class PartnerController { | ||||
|   constructor(private service: PartnerService) {} | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get() | ||||
|   @ApiQuery({ name: 'direction', type: 'string', enum: PartnerDirection, required: true }) | ||||
|   getPartners( | ||||
| @@ -22,13 +22,11 @@ export class PartnerController { | ||||
|     return this.service.getAll(authUser, direction); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Post(':id') | ||||
|   createPartner(@GetAuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto): Promise<UserResponseDto> { | ||||
|     return this.service.create(authUser, id); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Delete(':id') | ||||
|   removePartner(@GetAuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto): Promise<void> { | ||||
|     return this.service.remove(authUser, id); | ||||
|   | ||||
| @@ -7,32 +7,34 @@ import { | ||||
| } from '@app/domain'; | ||||
| import { Controller, Get } from '@nestjs/common'; | ||||
| import { ApiTags } from '@nestjs/swagger'; | ||||
| import { Authenticated } from '../decorators/authenticated.decorator'; | ||||
| import { AdminRoute, Authenticated, PublicRoute } from '../decorators/authenticated.decorator'; | ||||
| import { UseValidation } from '../decorators/use-validation.decorator'; | ||||
|  | ||||
| @ApiTags('Server Info') | ||||
| @Controller('server-info') | ||||
| @Authenticated() | ||||
| @UseValidation() | ||||
| export class ServerInfoController { | ||||
|   constructor(private service: ServerInfoService) {} | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get() | ||||
|   getServerInfo(): Promise<ServerInfoResponseDto> { | ||||
|     return this.service.getInfo(); | ||||
|   } | ||||
|  | ||||
|   @PublicRoute() | ||||
|   @Get('/ping') | ||||
|   pingServer(): ServerPingResponse { | ||||
|     return this.service.ping(); | ||||
|   } | ||||
|  | ||||
|   @PublicRoute() | ||||
|   @Get('/version') | ||||
|   getServerVersion(): ServerVersionReponseDto { | ||||
|     return this.service.getVersion(); | ||||
|   } | ||||
|  | ||||
|   @Authenticated({ admin: true }) | ||||
|   @AdminRoute() | ||||
|   @Get('/stats') | ||||
|   getStats(): Promise<ServerStatsResponseDto> { | ||||
|     return this.service.getStats(); | ||||
|   | ||||
| @@ -2,29 +2,28 @@ import { AuthUserDto, EditSharedLinkDto, SharedLinkResponseDto, ShareService } f | ||||
| import { Body, Controller, Delete, Get, Param, Patch } from '@nestjs/common'; | ||||
| import { ApiTags } from '@nestjs/swagger'; | ||||
| import { GetAuthUser } from '../decorators/auth-user.decorator'; | ||||
| import { Authenticated } from '../decorators/authenticated.decorator'; | ||||
| import { Authenticated, SharedLinkRoute } from '../decorators/authenticated.decorator'; | ||||
| import { UseValidation } from '../decorators/use-validation.decorator'; | ||||
| import { UUIDParamDto } from './dto/uuid-param.dto'; | ||||
|  | ||||
| @ApiTags('share') | ||||
| @Controller('share') | ||||
| @Authenticated() | ||||
| @UseValidation() | ||||
| export class SharedLinkController { | ||||
|   constructor(private readonly service: ShareService) {} | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get() | ||||
|   getAllSharedLinks(@GetAuthUser() authUser: AuthUserDto): Promise<SharedLinkResponseDto[]> { | ||||
|     return this.service.getAll(authUser); | ||||
|   } | ||||
|  | ||||
|   @Authenticated({ isShared: true }) | ||||
|   @SharedLinkRoute() | ||||
|   @Get('me') | ||||
|   getMySharedLink(@GetAuthUser() authUser: AuthUserDto): Promise<SharedLinkResponseDto> { | ||||
|     return this.service.getMine(authUser); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get(':id') | ||||
|   getSharedLinkById( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
| @@ -33,13 +32,11 @@ export class SharedLinkController { | ||||
|     return this.service.getById(authUser, id, true); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Delete(':id') | ||||
|   removeSharedLink(@GetAuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto): Promise<void> { | ||||
|     return this.service.remove(authUser, id); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Patch(':id') | ||||
|   editSharedLink( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
|   | ||||
| @@ -14,7 +14,7 @@ import { | ||||
|   Header, | ||||
| } from '@nestjs/common'; | ||||
| import { UserService } from '@app/domain'; | ||||
| import { Authenticated } from '../decorators/authenticated.decorator'; | ||||
| import { AdminRoute, Authenticated, PublicRoute } from '../decorators/authenticated.decorator'; | ||||
| import { AuthUserDto, GetAuthUser } from '../decorators/auth-user.decorator'; | ||||
| import { CreateUserDto } from '@app/domain'; | ||||
| import { UpdateUserDto } from '@app/domain'; | ||||
| @@ -32,58 +32,55 @@ import { UserIdDto } from '@app/domain/user/dto/user-id.dto'; | ||||
|  | ||||
| @ApiTags('User') | ||||
| @Controller('user') | ||||
| @Authenticated() | ||||
| @UseValidation() | ||||
| export class UserController { | ||||
|   constructor(private service: UserService) {} | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get() | ||||
|   getAllUsers(@GetAuthUser() authUser: AuthUserDto, @Query('isAll') isAll: boolean): Promise<UserResponseDto[]> { | ||||
|     return this.service.getAllUsers(authUser, isAll); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get('/info/:userId') | ||||
|   getUserById(@Param() { userId }: UserIdDto): Promise<UserResponseDto> { | ||||
|     return this.service.getUserById(userId); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get('me') | ||||
|   getMyUserInfo(@GetAuthUser() authUser: AuthUserDto): Promise<UserResponseDto> { | ||||
|     return this.service.getUserInfo(authUser); | ||||
|   } | ||||
|  | ||||
|   @Authenticated({ admin: true }) | ||||
|   @AdminRoute() | ||||
|   @Post() | ||||
|   createUser(@Body() createUserDto: CreateUserDto): Promise<UserResponseDto> { | ||||
|     return this.service.createUser(createUserDto); | ||||
|   } | ||||
|  | ||||
|   @PublicRoute() | ||||
|   @Get('/count') | ||||
|   getUserCount(@Query() dto: UserCountDto): Promise<UserCountResponseDto> { | ||||
|     return this.service.getUserCount(dto); | ||||
|   } | ||||
|  | ||||
|   @Authenticated({ admin: true }) | ||||
|   @AdminRoute() | ||||
|   @Delete('/:userId') | ||||
|   deleteUser(@GetAuthUser() authUser: AuthUserDto, @Param() { userId }: UserIdDto): Promise<UserResponseDto> { | ||||
|     return this.service.deleteUser(authUser, userId); | ||||
|   } | ||||
|  | ||||
|   @Authenticated({ admin: true }) | ||||
|   @AdminRoute() | ||||
|   @Post('/:userId/restore') | ||||
|   restoreUser(@GetAuthUser() authUser: AuthUserDto, @Param() { userId }: UserIdDto): Promise<UserResponseDto> { | ||||
|     return this.service.restoreUser(authUser, userId); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Put() | ||||
|   updateUser(@GetAuthUser() authUser: AuthUserDto, @Body() updateUserDto: UpdateUserDto): Promise<UserResponseDto> { | ||||
|     return this.service.updateUser(authUser, updateUserDto); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @UseInterceptors(FileInterceptor('file', profileImageUploadOption)) | ||||
|   @ApiConsumes('multipart/form-data') | ||||
|   @ApiBody({ | ||||
| @@ -98,7 +95,6 @@ export class UserController { | ||||
|     return this.service.createProfileImage(authUser, fileInfo); | ||||
|   } | ||||
|  | ||||
|   @Authenticated() | ||||
|   @Get('/profile-image/:userId') | ||||
|   @Header('Cache-Control', 'max-age=600') | ||||
|   async getProfileImage(@Param() { userId }: UserIdDto, @Response({ passthrough: true }) res: Res): Promise<any> { | ||||
|   | ||||
| @@ -11,8 +11,16 @@ export enum Metadata { | ||||
|   AUTH_ROUTE = 'auth_route', | ||||
|   ADMIN_ROUTE = 'admin_route', | ||||
|   SHARED_ROUTE = 'shared_route', | ||||
|   PUBLIC_SECURITY = 'public_security', | ||||
| } | ||||
|  | ||||
| const adminDecorator = SetMetadata(Metadata.ADMIN_ROUTE, true); | ||||
|  | ||||
| const sharedLinkDecorators = [ | ||||
|   SetMetadata(Metadata.SHARED_ROUTE, true), | ||||
|   ApiQuery({ name: 'key', type: String, required: false }), | ||||
| ]; | ||||
|  | ||||
| export const Authenticated = (options: AuthenticatedOptions = {}) => { | ||||
|   const decorators: MethodDecorator[] = [ | ||||
|     ApiBearerAuth(), | ||||
| @@ -22,13 +30,17 @@ export const Authenticated = (options: AuthenticatedOptions = {}) => { | ||||
|   ]; | ||||
|  | ||||
|   if (options.admin) { | ||||
|     decorators.push(SetMetadata(Metadata.ADMIN_ROUTE, true)); | ||||
|     decorators.push(adminDecorator); | ||||
|   } | ||||
|  | ||||
|   if (options.isShared) { | ||||
|     decorators.push(SetMetadata(Metadata.SHARED_ROUTE, true)); | ||||
|     decorators.push(ApiQuery({ name: 'key', type: String, required: false })); | ||||
|     decorators.push(...sharedLinkDecorators); | ||||
|   } | ||||
|  | ||||
|   return applyDecorators(...decorators); | ||||
| }; | ||||
|  | ||||
| export const PublicRoute = () => | ||||
|   applyDecorators(SetMetadata(Metadata.AUTH_ROUTE, false), ApiSecurity(Metadata.PUBLIC_SECURITY)); | ||||
| export const SharedLinkRoute = () => applyDecorators(...sharedLinkDecorators); | ||||
| export const AdminRoute = () => adminDecorator; | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { OpenAPIObject } from '@nestjs/swagger'; | ||||
| import { Metadata } from '../decorators/authenticated.decorator'; | ||||
|  | ||||
| export function patchOpenAPI(document: OpenAPIObject) { | ||||
|   for (const path of Object.values(document.paths)) { | ||||
| @@ -18,6 +19,10 @@ export function patchOpenAPI(document: OpenAPIObject) { | ||||
|         continue; | ||||
|       } | ||||
|  | ||||
|       if ((operation.security || []).find((item) => !!item[Metadata.PUBLIC_SECURITY])) { | ||||
|         delete operation.security; | ||||
|       } | ||||
|  | ||||
|       if (operation.summary === '') { | ||||
|         delete operation.summary; | ||||
|       } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user