From 3be1aaaaa480263a4c8a63f6584d5dd628abd721 Mon Sep 17 00:00:00 2001 From: Jason Rasmussen Date: Tue, 20 Aug 2024 08:50:14 -0400 Subject: [PATCH] refactor(server): controller cleanup (#11923) chore(server): controller cleanup --- mobile/lib/services/api.service.dart | 4 +- mobile/openapi/README.md | Bin 32053 -> 30931 bytes mobile/openapi/lib/api.dart | Bin 10937 -> 10904 bytes mobile/openapi/lib/api/deprecated_api.dart | Bin 15349 -> 2164 bytes mobile/openapi/lib/api/server_api.dart | Bin 4357 -> 16867 bytes mobile/openapi/lib/api/server_info_api.dart | Bin 13614 -> 0 bytes mobile/openapi/lib/model/permission.dart | Bin 14601 -> 14928 bytes open-api/immich-openapi-specs.json | 374 ++++++++---------- open-api/typescript-sdk/src/fetch-client.ts | 153 +++---- server/src/controllers/activity.controller.ts | 12 +- .../src/controllers/asset-media.controller.ts | 2 +- server/src/controllers/asset.controller.ts | 2 +- server/src/controllers/library.controller.ts | 12 +- .../controllers/notification.controller.ts | 4 +- server/src/controllers/oauth.controller.ts | 3 +- server/src/controllers/partner.controller.ts | 5 +- .../src/controllers/server-info.controller.ts | 7 +- server/src/controllers/server.controller.ts | 13 +- server/src/controllers/session.controller.ts | 7 +- server/src/controllers/stack.controller.ts | 2 +- server/src/controllers/timeline.controller.ts | 5 +- server/src/controllers/trash.controller.ts | 7 +- server/src/enum.ts | 5 +- server/src/services/trash.service.ts | 2 +- server/src/utils/access.ts | 4 - 25 files changed, 269 insertions(+), 354 deletions(-) delete mode 100644 mobile/openapi/lib/api/server_info_api.dart diff --git a/mobile/lib/services/api.service.dart b/mobile/lib/services/api.service.dart index 6ff62d4b3a..4a3cfb19a2 100644 --- a/mobile/lib/services/api.service.dart +++ b/mobile/lib/services/api.service.dart @@ -18,7 +18,7 @@ class ApiService implements Authentication { late AlbumsApi albumsApi; late AssetsApi assetsApi; late SearchApi searchApi; - late ServerInfoApi serverInfoApi; + late ServerApi serverInfoApi; late MapApi mapApi; late PartnersApi partnersApi; late PeopleApi peopleApi; @@ -50,7 +50,7 @@ class ApiService implements Authentication { oAuthApi = OAuthApi(_apiClient); albumsApi = AlbumsApi(_apiClient); assetsApi = AssetsApi(_apiClient); - serverInfoApi = ServerInfoApi(_apiClient); + serverInfoApi = ServerApi(_apiClient); searchApi = SearchApi(_apiClient); mapApi = MapApi(_apiClient); partnersApi = PartnersApi(_apiClient); diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index c49b5052d865b64bf072cde0f23aa84821414ff3..4e7dfb35fe61130883de22f07329147c28d77a5e 100644 GIT binary patch delta 302 zcmdn`i}CVD#tpralRfoBCv!`=ZoVQLAvU>JQfM-tDcj_AChU_pNXiT9Cnn{WmMGLH zaA^gn7L}zIO^%dOn!LhBve>N~yq=uuDsG>Zhe9mXsEy z7Ecy2sh;d9Ed!UWmzJHpz)WoNZfRw>*biwbVSS)Y#hLke$foMa$b!|x$jA!o7nkH0 zC8nn$%TJZj1k0b7(G=IuO-;#6)GetjNG(QIBW|Gx_L_^Vw4i=TMrtmK36-)C8x8eGkpHNI&SO>v3BLc^h< zl9ODi!6Jd@x^+X>WG z);9^soJG1Y4%0F#=vs;&SKv0@?E_W@hjTjZKAB6cija7rihqMuESA?eD~MN`@Pkc7 zH%hl}XkRuW%Icm7u4D%+=W?<_g6I3>VHYn1VMF#9J&F308P?&NSP@rv64-mZGy^P@ z*$XEDoKcs<0Je+mMHQ!G1o*p}iU9ss@_!3!WC|9tBpHGQDBI|!FGw872a<3}8~#N% n`9ab^&Qk1^o??pzKw>lohf_M|mL!|+_IRXjT37vtD+e3DF(CT* diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart index a6f860dda27e7417e12216704b39268cc731cf43..1179bff56d938159665025b414aa4875b8bcf2d1 100644 GIT binary patch delta 12 UcmdlPIwN$$Ue?X`SZ}KU04Vha0{{R3 delta 26 icmbOcx-)dcURKVcvecsZ%)GSx$&75`oAU@r9D_U zXA3=uW@e!9(~K+XF4&Y_Bc|xTL8WPMrOUeyrO<{6GvEPD$VVKN>#j>D3%Ni&2&EWP zGc#dg@MLo^oG_(pHJZ+V9D$5bu!y(m?`f@88-`44*uzNSkQofR5r;1|D3&x%srY5c zX$iYP9sS$0CTwR{@I3c^cNYR2u~}%+jx-s-hzk}%T9);2wH-2ff5J6HidL!20_IH9 zK*`#G3%J;7Z*BhC-lV~(xqpRs(vWjpSF-3t2B6T)l+a)%2(SD7BRD-q9g#8dtWBNv zXH<>PlCm8bqv@W@nK=+6`GK3sYhxn&zR?7x7h>paVyBEXu}y2l5n0(eXb>RTQ8B}5 z1{yxO(TJG|*+tbm8r21=4NgOLn4PHZ?zn73XCrdrkcED%!}GszNQRH3HZNqbhE+Jp+0)!oCddL*S;G^fxEQy<|KIs?nQu&jpMJHe8`#}C(5oR` z^cNAj6~qJD*{#PRc17muHWwH2Z|oi&G+aG^HB&2oUw_r>*OQCf%_T*N5t8fteI;et z@{^MMBHLW|rV)v27sMW3Si{@DFr8Z{ik6mB%IR_FsD$X zMt;GTPLDT#X~CS@PZ+sINJHUoCj@S6+`5sw#)Y-vQ?y;?iW`zLm2usIkCx!utz=TF`{4+`E9@}-ZZ%sC!ovF%gvwgV)4au)J`uxshm@FKb1 zIW4G{i?QCafP?Z%FD+*q@78!ZHf(Mj8e2bqE3`A-J2tu0xlOCf%721WkDoK(fei?s zaGSPO8S;-P`AX5%8jUVc-;Y9rIP=^B|09%9h@CGyxa?5ErTOa4t^jR?QOJha4Z}v= z*4JA!FGZ89Ursnxdbq#oVJQZ_LC9~oHqV@NbGc>5Czrgg8`o+1`b?AWUI+^t4^_VT zf%8pK6E@4IJCN&>i&sRt(TkJOSF%--3hnrmnaY)1cZtc?HDgi|D~GI1^o?8#BW;() zm^L-++#cCRw2j6Dr{A8&?&j>_^Dm|U5g!*K?hcM0v^Szzs`JOXoIkv((t}4{YAc^T z@|}wMtkS^`oDOdN_>pR{aPCM;y_g*Czi(3SBb~4*jTK|z_8%3E;(01suM4dcWnJNQ zQhY;VC*6uVt(aXgd-X>~iH1m#1#0KY?+v%@b5J@S@Zp`4+dk6tGga(f7j|29>D<#8 z|1ieyoipX#5aC(J3gXpsfBiq7`(Kr2f#g>!?+woXpy&7WfmJauZhsd}A0^poDv+-W z$YWhygYvlch8!=|YPA!ucH*n=#Fu4R!1!|YeE_+UijDEE5w86-6~fmA;V0hV%Lw=7 ztHZlYpB1(%Y_E>(WhoZ0yeW%5h_68Br0{zOazwvF@E<4LHInU26_MA4$VcSuWPeQ`T4pj^ djmug4qAV*iS7ctD%y|(O=$xg0jlsTX+l%0-wM8to9t5$$OTDb^B(9jj~&$IKs_xoM#TR#lrm)V%I!*ILx0IbL9 zAY{5HWB;OUSQ|-KkR07zI=d-x400A&oIfel;B;O?QD04n40occ7J|p&i1g6 z!I#PR=I7e#zZ4CI-oTNIHuzQ6M$>(=>x}W>xc)aSRBB69O+HG^Pom$&nyN2j!77Unrv<^@bD+(n;mg%b4se;I9~XYlgQ1emmzI zL{P6l#5ay4Sqd^o&y~%Ik@9=E>k>&N&Hz?XLEAC3y17Q3*~)>{ReECy&5C%)e$=*F z&{>`q>n|EIFgdN?sKL*4OKS(|xC$x@r_ov{tq;Lh@ei%ds&lB++!1;Nci$f2<0Rgo zC%IVHoy+4q&kBl$RU&m7-3f%DgD0USlt;8^{KYKmgi3ZFy?^Sa?Lr624zOvbH#tME8-D@R!y#Az delta 18 ZcmaFd%-E{5A%t~vhiC%p=1JCpYyd^o2BZK0 diff --git a/mobile/openapi/lib/api/server_info_api.dart b/mobile/openapi/lib/api/server_info_api.dart deleted file mode 100644 index dc58a94fd06b3aeeb87fb2751df907c4d1c21c46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13614 zcmeI2QBNB=5Xay1DW-jBKne*|m9C-%E``t{U4cT{>V!~gvXjJj8}HWklIAMD`;G10 zWH;INmI|bc;s?U6?HSuM|M{_5+-lWYEogu2o^8GDoOUkS-OdplpZw8jz|k3;o^|2< z+0n`IpHFC*8Tos_q~3ep+<93uw|pofiM>H2djlTgE+isR81yj2F$&$t?)f;5q%O5! z;e<_9FHUq%;@5;rG8b%2pD~m4TccFuT&i;Oek7D;Licz;6Y>E^Y0XvXWFZ%*dSN7n zG)#|}=)K(T^+!yqT8*aD5Dg%TQLvad>E~6gR_ljMDY!&=i}FMaqIS&Tdku;$8&}kP z7;;*|0g$1)yxxS}`5o-#t`80%zyV7_Ju{@q00vyJ5N2(23)|bGkatI1K`d#NQcq#R z6gi3|_L;^2xPaT8=FawS&24fn0f;C)ACvv$lO0qHf#6An1ud|!Kuup-HBcULfcw4w{VqS41V8@iQ0v%k9q3b& zF1phg?Fv$dW_FWtNK-LSb(4$R=x=PFpKREE028K0dR>3p>DIHG+~%^TEC|_seqUMJ zeEC^RevwVCI^&qcbpRp>L(*`e*Vdx5+cYt`GrPE_GE;fEsa zKE_7DWsVx@I*iiEuaV)KsYW#$yJ>@E!ew$!b@F+H0vKg~OvMRK|Fg0b5!{dqm{6(F zAh%#cr{~)*8Ze>pBSxtak*4xD69U(!Zms9Gwq>pP7>&t9a!pdEHm(}*#Sna#GD|vZRoV&MDpY0 zG@xEC#(Kj5E~WjVQk}GHY+PE?<(RVh)zWxiXuDle+y;F3*xV*j(JUU^>jG}4su{8K zQmYK@yirk~p4*<=)ww;>VgcB*)|DakG18+6{V6Qg!oxpf57K!&t=EOtnX(pmoi*Q+ z*qK>Tr=HoK+0~hyX^0eApmwf(Ww>p=Kysyd|Ix{9z6-jUJiFJ0-9}yNBK?BA0Pwl; z?uqcZp@+DCVWNKVg~_5c3nX9cTp65yqW?P3o4#UUJp5BQy@NB;c#y9P$WvYY0Oe`# zJvm;gRsSUJpTw&_i7(5tfbr$-RRFn;Bpc#mBV4&@Ji^xn;g>Gq%LsSv)!|*HPmgVn z?dsTGmSO?h%iXJh?Ibp5g)n%J0cZBq#A73z4jXZ{rOg2ikMVWE_*`DgBwv@TDp(K)!Uu3UIzVq9dZk(s=myD|EVXjGpQ1!gQ;t+3Rt8R~g(Tdi1FF zsIHFcOne18XN~`NAjfoo(;dZnY$ThRJdxLh$mf*p?D?9`bdooui Rb6$i6I_Eq7o6vW)e*qo#ho=Al diff --git a/mobile/openapi/lib/model/permission.dart b/mobile/openapi/lib/model/permission.dart index 3a9b61d81c1b61ecb99d7cb36b4ad7c027bc5caa..3f89c9826d6452c5f101beff7f9ece11a338152b 100644 GIT binary patch delta 274 zcmeAyx=^xV9_!{utPi-@Qj3c-^YbS2v&gU)L)nHb5^#1PmmHkk$SnnDPec;m$SXCO zS5RQ`2Whs+{{)36*9me>jx%E4{9E8J+hzfYi_A_Cg9B2FGV@b{QWH~jxD+w1Bo&K;aEhdA("/oauth/unlink", { ...opts, @@ -2458,102 +2458,27 @@ export function getSearchSuggestions({ country, includeNull, make, model, state, ...opts })); } -/** - * This property was deprecated in v1.107.0 - */ export function getAboutInfo(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: ServerAboutResponseDto; - }>("/server-info/about", { + }>("/server/about", { ...opts })); } -/** - * This property was deprecated in v1.107.0 - */ export function getServerConfig(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: ServerConfigDto; - }>("/server-info/config", { + }>("/server/config", { ...opts })); } -/** - * This property was deprecated in v1.107.0 - */ export function getServerFeatures(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: ServerFeaturesDto; - }>("/server-info/features", { - ...opts - })); -} -/** - * This property was deprecated in v1.107.0 - */ -export function getSupportedMediaTypes(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: ServerMediaTypesResponseDto; - }>("/server-info/media-types", { - ...opts - })); -} -/** - * This property was deprecated in v1.107.0 - */ -export function pingServer(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: ServerPingResponseRead; - }>("/server-info/ping", { - ...opts - })); -} -/** - * This property was deprecated in v1.107.0 - */ -export function getServerStatistics(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: ServerStatsResponseDto; - }>("/server-info/statistics", { - ...opts - })); -} -/** - * This property was deprecated in v1.107.0 - */ -export function getStorage(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: ServerStorageResponseDto; - }>("/server-info/storage", { - ...opts - })); -} -/** - * This property was deprecated in v1.107.0 - */ -export function getTheme(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: ServerThemeDto; - }>("/server-info/theme", { - ...opts - })); -} -/** - * This property was deprecated in v1.107.0 - */ -export function getServerVersion(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: ServerVersionResponseDto; - }>("/server-info/version", { + }>("/server/features", { ...opts })); } @@ -2585,6 +2510,54 @@ export function setServerLicense({ licenseKeyDto }: { body: licenseKeyDto }))); } +export function getSupportedMediaTypes(opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: ServerMediaTypesResponseDto; + }>("/server/media-types", { + ...opts + })); +} +export function pingServer(opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: ServerPingResponseRead; + }>("/server/ping", { + ...opts + })); +} +export function getServerStatistics(opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: ServerStatsResponseDto; + }>("/server/statistics", { + ...opts + })); +} +export function getStorage(opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: ServerStorageResponseDto; + }>("/server/storage", { + ...opts + })); +} +export function getTheme(opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: ServerThemeDto; + }>("/server/theme", { + ...opts + })); +} +export function getServerVersion(opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: ServerVersionResponseDto; + }>("/server/version", { + ...opts + })); +} export function deleteAllSessions(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/sessions", { ...opts, @@ -3205,7 +3178,6 @@ export enum Permission { AssetRead = "asset.read", AssetUpdate = "asset.update", AssetDelete = "asset.delete", - AssetRestore = "asset.restore", AssetShare = "asset.share", AssetView = "asset.view", AssetDownload = "asset.download", @@ -3247,6 +3219,9 @@ export enum Permission { PersonStatistics = "person.statistics", PersonMerge = "person.merge", PersonReassign = "person.reassign", + SessionRead = "session.read", + SessionUpdate = "session.update", + SessionDelete = "session.delete", SharedLinkCreate = "sharedLink.create", SharedLinkRead = "sharedLink.read", SharedLinkUpdate = "sharedLink.update", diff --git a/server/src/controllers/activity.controller.ts b/server/src/controllers/activity.controller.ts index 9b06f82f3a..b91f2902d5 100644 --- a/server/src/controllers/activity.controller.ts +++ b/server/src/controllers/activity.controller.ts @@ -25,12 +25,6 @@ export class ActivityController { return this.service.getAll(auth, dto); } - @Get('statistics') - @Authenticated({ permission: Permission.ACTIVITY_STATISTICS }) - getActivityStatistics(@Auth() auth: AuthDto, @Query() dto: ActivityDto): Promise { - return this.service.getStatistics(auth, dto); - } - @Post() @Authenticated({ permission: Permission.ACTIVITY_CREATE }) async createActivity( @@ -45,6 +39,12 @@ export class ActivityController { return value; } + @Get('statistics') + @Authenticated({ permission: Permission.ACTIVITY_STATISTICS }) + getActivityStatistics(@Auth() auth: AuthDto, @Query() dto: ActivityDto): Promise { + return this.service.getStatistics(auth, dto); + } + @Delete(':id') @HttpCode(HttpStatus.NO_CONTENT) @Authenticated({ permission: Permission.ACTIVITY_DELETE }) diff --git a/server/src/controllers/asset-media.controller.ts b/server/src/controllers/asset-media.controller.ts index 48fea8b8a6..fb5ec58f25 100644 --- a/server/src/controllers/asset-media.controller.ts +++ b/server/src/controllers/asset-media.controller.ts @@ -93,8 +93,8 @@ export class AssetMediaController { @Put(':id/original') @UseInterceptors(FileUploadInterceptor) @ApiConsumes('multipart/form-data') - @Authenticated({ sharedLink: true }) @EndpointLifecycle({ addedAt: 'v1.106.0' }) + @Authenticated({ sharedLink: true }) async replaceAsset( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, diff --git a/server/src/controllers/asset.controller.ts b/server/src/controllers/asset.controller.ts index f275aa7242..c6fdac1710 100644 --- a/server/src/controllers/asset.controller.ts +++ b/server/src/controllers/asset.controller.ts @@ -51,8 +51,8 @@ export class AssetController { } @Post('jobs') - @HttpCode(HttpStatus.NO_CONTENT) @Authenticated() + @HttpCode(HttpStatus.NO_CONTENT) runAssetJobs(@Auth() auth: AuthDto, @Body() dto: AssetJobsDto): Promise { return this.service.run(auth, dto); } diff --git a/server/src/controllers/library.controller.ts b/server/src/controllers/library.controller.ts index 18ba43c0a6..a45617fc2a 100644 --- a/server/src/controllers/library.controller.ts +++ b/server/src/controllers/library.controller.ts @@ -31,18 +31,18 @@ export class LibraryController { return this.service.create(dto); } - @Put(':id') - @Authenticated({ permission: Permission.LIBRARY_UPDATE, admin: true }) - updateLibrary(@Param() { id }: UUIDParamDto, @Body() dto: UpdateLibraryDto): Promise { - return this.service.update(id, dto); - } - @Get(':id') @Authenticated({ permission: Permission.LIBRARY_READ, admin: true }) getLibrary(@Param() { id }: UUIDParamDto): Promise { return this.service.get(id); } + @Put(':id') + @Authenticated({ permission: Permission.LIBRARY_UPDATE, admin: true }) + updateLibrary(@Param() { id }: UUIDParamDto, @Body() dto: UpdateLibraryDto): Promise { + return this.service.update(id, dto); + } + @Post(':id/validate') @HttpCode(200) @Authenticated({ admin: true }) diff --git a/server/src/controllers/notification.controller.ts b/server/src/controllers/notification.controller.ts index cc07022a93..2772e93b5d 100644 --- a/server/src/controllers/notification.controller.ts +++ b/server/src/controllers/notification.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, HttpCode, Post } from '@nestjs/common'; +import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { AuthDto } from 'src/dtos/auth.dto'; import { SystemConfigSmtpDto } from 'src/dtos/system-config.dto'; @@ -11,7 +11,7 @@ export class NotificationController { constructor(private service: NotificationService) {} @Post('test-email') - @HttpCode(200) + @HttpCode(HttpStatus.OK) @Authenticated({ admin: true }) sendTestEmail(@Auth() auth: AuthDto, @Body() dto: SystemConfigSmtpDto) { return this.service.sendTestEmail(auth.user.id, dto); diff --git a/server/src/controllers/oauth.controller.ts b/server/src/controllers/oauth.controller.ts index 764e67d676..b733dc612b 100644 --- a/server/src/controllers/oauth.controller.ts +++ b/server/src/controllers/oauth.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Get, HttpStatus, Post, Redirect, Req, Res } from '@nestjs/common'; +import { Body, Controller, Get, HttpCode, HttpStatus, Post, Redirect, Req, Res } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { Request, Response } from 'express'; import { AuthType } from 'src/constants'; @@ -58,6 +58,7 @@ export class OAuthController { } @Post('unlink') + @HttpCode(HttpStatus.OK) @Authenticated() unlinkOAuthAccount(@Auth() auth: AuthDto): Promise { return this.service.unlink(auth); diff --git a/server/src/controllers/partner.controller.ts b/server/src/controllers/partner.controller.ts index 0662243d61..6830fdd52f 100644 --- a/server/src/controllers/partner.controller.ts +++ b/server/src/controllers/partner.controller.ts @@ -1,9 +1,8 @@ import { Body, Controller, Delete, Get, Param, Post, Put, Query } from '@nestjs/common'; -import { ApiQuery, ApiTags } from '@nestjs/swagger'; +import { ApiTags } from '@nestjs/swagger'; import { AuthDto } from 'src/dtos/auth.dto'; import { PartnerResponseDto, PartnerSearchDto, UpdatePartnerDto } from 'src/dtos/partner.dto'; import { Permission } from 'src/enum'; -import { PartnerDirection } from 'src/interfaces/partner.interface'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { PartnerService } from 'src/services/partner.service'; import { UUIDParamDto } from 'src/validation'; @@ -14,9 +13,7 @@ export class PartnerController { constructor(private service: PartnerService) {} @Get() - @ApiQuery({ name: 'direction', type: 'string', enum: PartnerDirection, required: true }) @Authenticated({ permission: Permission.PARTNER_READ }) - // TODO: remove 'direction' and convert to full query dto getPartners(@Auth() auth: AuthDto, @Query() dto: PartnerSearchDto): Promise { return this.service.search(auth, dto); } diff --git a/server/src/controllers/server-info.controller.ts b/server/src/controllers/server-info.controller.ts index 812016f4eb..245bbbd347 100644 --- a/server/src/controllers/server-info.controller.ts +++ b/server/src/controllers/server-info.controller.ts @@ -1,5 +1,5 @@ import { Controller, Get } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiExcludeController, ApiTags } from '@nestjs/swagger'; import { EndpointLifecycle } from 'src/decorators'; import { ServerAboutResponseDto, @@ -16,6 +16,7 @@ import { Authenticated } from 'src/middleware/auth.guard'; import { ServerService } from 'src/services/server.service'; import { VersionService } from 'src/services/version.service'; +@ApiExcludeController() @ApiTags('Server Info') @Controller('server-info') export class ServerInfoController { @@ -68,9 +69,9 @@ export class ServerInfoController { return this.service.getConfig(); } - @Authenticated({ admin: true }) - @EndpointLifecycle({ deprecatedAt: 'v1.107.0' }) @Get('statistics') + @EndpointLifecycle({ deprecatedAt: 'v1.107.0' }) + @Authenticated({ admin: true }) getServerStatistics(): Promise { return this.service.getStatistics(); } diff --git a/server/src/controllers/server.controller.ts b/server/src/controllers/server.controller.ts index 0c615223e2..75becfe341 100644 --- a/server/src/controllers/server.controller.ts +++ b/server/src/controllers/server.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Delete, Get, Put } from '@nestjs/common'; -import { ApiExcludeEndpoint, ApiNotFoundResponse, ApiTags } from '@nestjs/swagger'; +import { ApiNotFoundResponse, ApiTags } from '@nestjs/swagger'; import { LicenseKeyDto, LicenseResponseDto } from 'src/dtos/license.dto'; import { ServerAboutResponseDto, @@ -26,57 +26,48 @@ export class ServerController { @Get('about') @Authenticated() - @ApiExcludeEndpoint() getAboutInfo(): Promise { return this.service.getAboutInfo(); } @Get('storage') @Authenticated() - @ApiExcludeEndpoint() getStorage(): Promise { return this.service.getStorage(); } @Get('ping') - @ApiExcludeEndpoint() pingServer(): ServerPingResponse { return this.service.ping(); } @Get('version') - @ApiExcludeEndpoint() getServerVersion(): ServerVersionResponseDto { return this.versionService.getVersion(); } @Get('features') - @ApiExcludeEndpoint() getServerFeatures(): Promise { return this.service.getFeatures(); } @Get('theme') - @ApiExcludeEndpoint() getTheme(): Promise { return this.service.getTheme(); } @Get('config') - @ApiExcludeEndpoint() getServerConfig(): Promise { return this.service.getConfig(); } - @Authenticated({ admin: true }) @Get('statistics') - @ApiExcludeEndpoint() + @Authenticated({ admin: true }) getServerStatistics(): Promise { return this.service.getStatistics(); } @Get('media-types') - @ApiExcludeEndpoint() getSupportedMediaTypes(): ServerMediaTypesResponseDto { return this.service.getSupportedMediaTypes(); } diff --git a/server/src/controllers/session.controller.ts b/server/src/controllers/session.controller.ts index a1fb4779a5..d526c2e599 100644 --- a/server/src/controllers/session.controller.ts +++ b/server/src/controllers/session.controller.ts @@ -2,6 +2,7 @@ import { Controller, Delete, Get, HttpCode, HttpStatus, Param } from '@nestjs/co import { ApiTags } from '@nestjs/swagger'; import { AuthDto } from 'src/dtos/auth.dto'; import { SessionResponseDto } from 'src/dtos/session.dto'; +import { Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { SessionService } from 'src/services/session.service'; import { UUIDParamDto } from 'src/validation'; @@ -12,21 +13,21 @@ export class SessionController { constructor(private service: SessionService) {} @Get() - @Authenticated() + @Authenticated({ permission: Permission.SESSION_READ }) getSessions(@Auth() auth: AuthDto): Promise { return this.service.getAll(auth); } @Delete() + @Authenticated({ permission: Permission.SESSION_DELETE }) @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() deleteAllSessions(@Auth() auth: AuthDto): Promise { return this.service.deleteAll(auth); } @Delete(':id') + @Authenticated({ permission: Permission.SESSION_DELETE }) @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() deleteSession(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.delete(auth, id); } diff --git a/server/src/controllers/stack.controller.ts b/server/src/controllers/stack.controller.ts index 184fa96b38..188952eba5 100644 --- a/server/src/controllers/stack.controller.ts +++ b/server/src/controllers/stack.controller.ts @@ -26,8 +26,8 @@ export class StackController { } @Delete() - @HttpCode(HttpStatus.NO_CONTENT) @Authenticated({ permission: Permission.STACK_DELETE }) + @HttpCode(HttpStatus.NO_CONTENT) deleteStacks(@Auth() auth: AuthDto, @Body() dto: BulkIdsDto): Promise { return this.service.deleteAll(auth, dto); } diff --git a/server/src/controllers/timeline.controller.ts b/server/src/controllers/timeline.controller.ts index 53c62f70ed..92de84d346 100644 --- a/server/src/controllers/timeline.controller.ts +++ b/server/src/controllers/timeline.controller.ts @@ -3,6 +3,7 @@ import { ApiTags } from '@nestjs/swagger'; import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { TimeBucketAssetDto, TimeBucketDto, TimeBucketResponseDto } from 'src/dtos/time-bucket.dto'; +import { Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { TimelineService } from 'src/services/timeline.service'; @@ -11,14 +12,14 @@ import { TimelineService } from 'src/services/timeline.service'; export class TimelineController { constructor(private service: TimelineService) {} - @Authenticated({ sharedLink: true }) @Get('buckets') + @Authenticated({ permission: Permission.ASSET_READ, sharedLink: true }) getTimeBuckets(@Auth() auth: AuthDto, @Query() dto: TimeBucketDto): Promise { return this.service.getTimeBuckets(auth, dto); } - @Authenticated({ sharedLink: true }) @Get('bucket') + @Authenticated({ permission: Permission.ASSET_READ, sharedLink: true }) getTimeBucket(@Auth() auth: AuthDto, @Query() dto: TimeBucketAssetDto): Promise { return this.service.getTimeBucket(auth, dto) as Promise; } diff --git a/server/src/controllers/trash.controller.ts b/server/src/controllers/trash.controller.ts index eae49d4ad1..20adbb11bb 100644 --- a/server/src/controllers/trash.controller.ts +++ b/server/src/controllers/trash.controller.ts @@ -2,6 +2,7 @@ import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { BulkIdsDto } from 'src/dtos/asset-ids.response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; +import { Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { TrashService } from 'src/services/trash.service'; @@ -12,21 +13,21 @@ export class TrashController { @Post('empty') @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() + @Authenticated({ permission: Permission.ASSET_DELETE }) emptyTrash(@Auth() auth: AuthDto): Promise { return this.service.empty(auth); } @Post('restore') @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() + @Authenticated({ permission: Permission.ASSET_DELETE }) restoreTrash(@Auth() auth: AuthDto): Promise { return this.service.restore(auth); } @Post('restore/assets') @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() + @Authenticated({ permission: Permission.ASSET_DELETE }) restoreAssets(@Auth() auth: AuthDto, @Body() dto: BulkIdsDto): Promise { return this.service.restoreAssets(auth, dto); } diff --git a/server/src/enum.ts b/server/src/enum.ts index 64cb1f118a..25ccbf961e 100644 --- a/server/src/enum.ts +++ b/server/src/enum.ts @@ -54,7 +54,6 @@ export enum Permission { ASSET_READ = 'asset.read', ASSET_UPDATE = 'asset.update', ASSET_DELETE = 'asset.delete', - ASSET_RESTORE = 'asset.restore', ASSET_SHARE = 'asset.share', ASSET_VIEW = 'asset.view', ASSET_DOWNLOAD = 'asset.download', @@ -107,6 +106,10 @@ export enum Permission { PERSON_MERGE = 'person.merge', PERSON_REASSIGN = 'person.reassign', + SESSION_READ = 'session.read', + SESSION_UPDATE = 'session.update', + SESSION_DELETE = 'session.delete', + SHARED_LINK_CREATE = 'sharedLink.create', SHARED_LINK_READ = 'sharedLink.read', SHARED_LINK_UPDATE = 'sharedLink.update', diff --git a/server/src/services/trash.service.ts b/server/src/services/trash.service.ts index f64aef0516..8376ba9221 100644 --- a/server/src/services/trash.service.ts +++ b/server/src/services/trash.service.ts @@ -20,7 +20,7 @@ export class TrashService { async restoreAssets(auth: AuthDto, dto: BulkIdsDto): Promise { const { ids } = dto; - await requireAccess(this.access, { auth, permission: Permission.ASSET_RESTORE, ids }); + await requireAccess(this.access, { auth, permission: Permission.ASSET_DELETE, ids }); await this.restoreAndSend(auth, ids); } diff --git a/server/src/utils/access.ts b/server/src/utils/access.ts index 9367b0987e..45badeec73 100644 --- a/server/src/utils/access.ts +++ b/server/src/utils/access.ts @@ -147,10 +147,6 @@ const checkOtherAccess = async (access: IAccessRepository, request: OtherAccessR return await access.asset.checkOwnerAccess(auth.user.id, ids); } - case Permission.ASSET_RESTORE: { - return await access.asset.checkOwnerAccess(auth.user.id, ids); - } - case Permission.ALBUM_READ: { const isOwner = await access.album.checkOwnerAccess(auth.user.id, ids); const isShared = await access.album.checkSharedAlbumAccess(