From edde0f93aeedf29e70cee26047a3c594193e7fa5 Mon Sep 17 00:00:00 2001 From: Jason Rasmussen Date: Tue, 11 Nov 2025 17:01:14 -0500 Subject: [PATCH] feat: endpoint descriptions (#23813) --- .../repositories/folder_api.repository.dart | 2 +- mobile/lib/services/api.service.dart | 8 +- mobile/openapi/README.md | Bin 41496 -> 45954 bytes mobile/openapi/lib/api.dart | Bin 14791 -> 14774 bytes mobile/openapi/lib/api/activities_api.dart | Bin 8102 -> 8642 bytes mobile/openapi/lib/api/albums_api.dart | Bin 22643 -> 24171 bytes mobile/openapi/lib/api/api_keys_api.dart | Bin 9829 -> 10512 bytes mobile/openapi/lib/api/assets_api.dart | Bin 45079 -> 46487 bytes ...api.dart => authentication_admin_api.dart} | Bin 1533 -> 1595 bytes .../openapi/lib/api/authentication_api.dart | Bin 15631 -> 25471 bytes mobile/openapi/lib/api/deprecated_api.dart | Bin 8560 -> 14567 bytes mobile/openapi/lib/api/download_api.dart | Bin 4674 -> 5206 bytes mobile/openapi/lib/api/duplicates_api.dart | Bin 4453 -> 4661 bytes mobile/openapi/lib/api/faces_api.dart | Bin 6704 -> 7222 bytes mobile/openapi/lib/api/jobs_api.dart | Bin 5155 -> 5757 bytes mobile/openapi/lib/api/libraries_api.dart | Bin 13643 -> 13781 bytes mobile/openapi/lib/api/map_api.dart | Bin 5455 -> 5975 bytes mobile/openapi/lib/api/memories_api.dart | Bin 16683 -> 17405 bytes .../lib/api/notifications_admin_api.dart | Bin 5789 -> 6245 bytes mobile/openapi/lib/api/notifications_api.dart | Bin 10549 -> 10819 bytes mobile/openapi/lib/api/o_auth_api.dart | Bin 7747 -> 0 bytes mobile/openapi/lib/api/partners_api.dart | Bin 8919 -> 9159 bytes mobile/openapi/lib/api/people_api.dart | Bin 20147 -> 20481 bytes mobile/openapi/lib/api/search_api.dart | Bin 26924 -> 28136 bytes mobile/openapi/lib/api/server_api.dart | Bin 22379 -> 23646 bytes mobile/openapi/lib/api/sessions_api.dart | Bin 9031 -> 9345 bytes mobile/openapi/lib/api/shared_links_api.dart | Bin 15748 -> 16730 bytes mobile/openapi/lib/api/stacks_api.dart | Bin 11293 -> 11945 bytes mobile/openapi/lib/api/sync_api.dart | Bin 9258 -> 10405 bytes mobile/openapi/lib/api/system_config_api.dart | Bin 6999 -> 7049 bytes .../openapi/lib/api/system_metadata_api.dart | Bin 6790 -> 6792 bytes mobile/openapi/lib/api/tags_api.dart | Bin 15729 -> 16037 bytes mobile/openapi/lib/api/timeline_api.dart | Bin 12860 -> 12974 bytes mobile/openapi/lib/api/trash_api.dart | Bin 5071 -> 5131 bytes mobile/openapi/lib/api/users_admin_api.dart | Bin 20189 -> 19765 bytes mobile/openapi/lib/api/users_api.dart | Bin 23615 -> 24385 bytes .../lib/api/{view_api.dart => views_api.dart} | Bin 3630 -> 4015 bytes open-api/immich-openapi-specs.json | 1256 +++++++++++------ open-api/typescript-sdk/src/fetch-client.ts | 488 ++++--- server/src/constants.ts | 55 +- server/src/controllers/activity.controller.ts | 23 +- server/src/controllers/album.controller.ts | 56 +- server/src/controllers/api-key.controller.ts | 27 +- .../src/controllers/asset-media.controller.ts | 35 +- server/src/controllers/asset.controller.ts | 66 +- .../src/controllers/auth-admin.controller.ts | 10 +- server/src/controllers/auth.controller.ts | 51 +- server/src/controllers/download.controller.ts | 16 +- .../src/controllers/duplicate.controller.ts | 18 +- server/src/controllers/face.controller.ts | 23 +- server/src/controllers/job.controller.ts | 20 +- server/src/controllers/library.controller.ts | 39 +- server/src/controllers/map.controller.ts | 13 +- server/src/controllers/memory.controller.ts | 40 +- .../notification-admin.controller.ts | 17 +- .../controllers/notification.controller.ts | 30 +- server/src/controllers/oauth.controller.ts | 27 +- server/src/controllers/partner.controller.ts | 28 +- server/src/controllers/person.controller.ts | 23 +- server/src/controllers/search.controller.ts | 48 +- server/src/controllers/server.controller.ts | 45 +- server/src/controllers/session.controller.ts | 30 +- .../src/controllers/shared-link.controller.ts | 40 +- server/src/controllers/stack.controller.ts | 35 +- server/src/controllers/sync.controller.ts | 35 +- .../controllers/system-config.controller.ts | 19 +- .../controllers/system-metadata.controller.ts | 22 +- server/src/controllers/tag.controller.ts | 42 +- server/src/controllers/timeline.controller.ts | 11 +- server/src/controllers/trash.controller.ts | 18 +- .../src/controllers/user-admin.controller.ts | 46 +- server/src/controllers/user.controller.ts | 54 +- server/src/controllers/view.controller.ts | 13 +- server/src/decorators.ts | 4 +- server/src/enum.ts | 35 + server/src/utils/misc.ts | 33 +- 76 files changed, 2138 insertions(+), 763 deletions(-) rename mobile/openapi/lib/api/{auth_admin_api.dart => authentication_admin_api.dart} (77%) delete mode 100644 mobile/openapi/lib/api/o_auth_api.dart rename mobile/openapi/lib/api/{view_api.dart => views_api.dart} (83%) diff --git a/mobile/lib/repositories/folder_api.repository.dart b/mobile/lib/repositories/folder_api.repository.dart index dfda19e45..d20ca8e0a 100644 --- a/mobile/lib/repositories/folder_api.repository.dart +++ b/mobile/lib/repositories/folder_api.repository.dart @@ -8,7 +8,7 @@ import 'package:openapi/api.dart'; final folderApiRepositoryProvider = Provider((ref) => FolderApiRepository(ref.watch(apiServiceProvider).viewApi)); class FolderApiRepository extends ApiRepository { - final ViewApi _api; + final ViewsApi _api; final Logger _log = Logger("FolderApiRepository"); FolderApiRepository(this._api); diff --git a/mobile/lib/services/api.service.dart b/mobile/lib/services/api.service.dart index 698ac3a15..1a714b6f4 100644 --- a/mobile/lib/services/api.service.dart +++ b/mobile/lib/services/api.service.dart @@ -17,7 +17,7 @@ class ApiService implements Authentication { late UsersApi usersApi; late AuthenticationApi authenticationApi; - late OAuthApi oAuthApi; + late AuthenticationApi oAuthApi; late AlbumsApi albumsApi; late AssetsApi assetsApi; late SearchApi searchApi; @@ -32,7 +32,7 @@ class ApiService implements Authentication { late DownloadApi downloadApi; late TrashApi trashApi; late StacksApi stacksApi; - late ViewApi viewApi; + late ViewsApi viewApi; late MemoriesApi memoriesApi; late SessionsApi sessionsApi; @@ -56,7 +56,7 @@ class ApiService implements Authentication { } usersApi = UsersApi(_apiClient); authenticationApi = AuthenticationApi(_apiClient); - oAuthApi = OAuthApi(_apiClient); + oAuthApi = AuthenticationApi(_apiClient); albumsApi = AlbumsApi(_apiClient); assetsApi = AssetsApi(_apiClient); serverInfoApi = ServerApi(_apiClient); @@ -71,7 +71,7 @@ class ApiService implements Authentication { downloadApi = DownloadApi(_apiClient); trashApi = TrashApi(_apiClient); stacksApi = StacksApi(_apiClient); - viewApi = ViewApi(_apiClient); + viewApi = ViewsApi(_apiClient); memoriesApi = MemoriesApi(_apiClient); sessionsApi = SessionsApi(_apiClient); } diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index 33ccadba7ec4c5b423d9b41e7dfb3fbf3eba71d6..ff04a91defa0bdb14a6d3d3b88990008bb535ec7 100644 GIT binary patch delta 5933 zcmaJ_du&@*8P^6KZQ>+${C48>CVei+n)S85*0pZZrfJ+f?AVEuwDI-zv3+a%UiaSX zwAqBp9%z7gbo~HCvb02Xt zq)Ms3*ZCgj`+eWJ-}u#?kGy^7&5

QH_WO5ky5u%uEPXvIb9V@x!St)4nlMBdwgA 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 delta 1686 zcmb8vTTGK@90u^{GLfpFKo7LE6cOYgU;#l;C_PYwwvfHf;vsyHpVY$O@d;E+&^juIW@LOH6%3S27bq3&8wSI%Vk zYzAv;i?J*;E{P6HLwr^fkJ~eRdUa2`U(Y`k@$>xwye@K6q;!d4<|(m{*)7pA&q-`c zA|V<}wOA-k;z4PAXEw|$y$|0*IUC7_l}Ub98H~jF9c-DJ$twL}Z!$zTsf=VZ%18iH z(lOkUx+tr+IxlNy{jRJ7jb(N$mU-6EZO>%GsIO{AyvmFPg%o9S5A&4VP9|7CQ9i+} zQ|g${D-Fz}6&$9w%CLE>jhtq)f^7lj%C-K#U$+~GrYgAs=toVefMf@-G_=|(g2hsF_7g2|?b z>vDYCq#@_o-kqH`XjDPgzf@V#*6hHEW-m^(lt9%oN{+K$(K^I@skQH+OS?R5xwy-} zy4_}CF14BQTiZOP9=AIb_@cdqdMWC6kLN7J>2?L~>~3J|s~trc?6BtgBs87RQ53k} zxyZb*XNJzLg*_*ULha!F% z!o50Df?K^DbKKC&ypmJZXJG3$`gFM0mx9VD#LN5on0fvEqzrTY`CswjLd5T zbRdlM(2XK|V$?IYnI=gg&Y9HALbE+*9*&zw@WAZA=wJ|+EG775&`3(*u~^8}nQ_R# z_RbGknYC66nrvdMSR>5NVJ9iY#bJ(2v3}j=#uvvBkb=M?GsqT+3^)8$9ql@ zj&ZfrU1)XKaLh4}W+(kaoi6-C`Oa001y?^AVtsnFi+N+T53Oz+UUB;=6=)lClQLW| z=HdF-0Yt|mSTiZb`iV62^u#mFxMx2Jyff)Sf!7G$JB&}gCY1TCIOyYW(>D&i-+~pt z3DH0W!~s1S#`ggZI-bXQehlToB+iD!_&DeyWf%wzky-2sNAZ4m2;xW_%aK8f1jW$- z=8I7q{)$?0H6}qSHbBNO7@wk);@5Z=R7nv$o$KIC&~v2zdBRPGDRO+4OfbW#0P{gA ziiN5D)I|`)Hb6B!!1`;`&YS{zO&v^W1N{JU5q_4AU?Xm)J0307nFb^>z3*Phe5n2x D;6{Ws diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart index a4b58763c147c13eb3a6d7b8bfa27ff921f53a40..d0ac141bae24e7e3805e49946ba02cf3f3c1235d 100644 GIT binary patch delta 36 scmX?Jysdb{5$4HHm=z{JU>2Ax&nmT+J)XYM(Pzp70`Y8ftJ29f(NFOVrvh@qw?qNEp^{Rt2 z4DknLU5rG6iUgI?*21KSXnV{PEL3FbHb@K8em$vd|E9KkWcqd2TFqMpk**F`7A=*z*3nVujh^2XN~6u>M=i?Ibg3KoMvg@H)~nH8k7gjI=SY14!Z zP&VP7>j~I;A`H;Bm5)%CIh!GqJRZY{OQqA5b6xwVy_>c>PN(~~yG!y`a!l41EkJ3e z2?+N$L$Kb&^Js|Dg0O=|p2k7>hE)EDejT+|PS`v+PwBJkRR6q@b8_V7;G+5ojxKbo delta 558 zcmX@)yv%;XCPwp+jLc$%)V!2}{LH)(g`(8L(#)dNVug~7RE31ZLbMkwh|E5F*127a)kOKkY43RaHyQM@nALrL%A=8-ooQ9M6`Il_2 s7JbibO_WQDOA<>mi%T+-i?O)JZgPPf`{r&bHp&cxxXNsEfm{$X0M$~|X#fBK diff --git a/mobile/openapi/lib/api/albums_api.dart b/mobile/openapi/lib/api/albums_api.dart index a45083669c402b8f8f3aa2127e13677b13348369..1042a2850f606b7f7724ca22f3eb5ef26f84aae2 100644 GIT binary patch literal 24171 zcmeHPTXWks7Jm1yK=V+^J6fsR*@ups*z4FzqnT{%jpga=q#l(bAqxpbvLt0!>+yfz z?*Ie|h@|9LvMOI5;)o=000QUooeS9M>~uQp@VtNW_g}gnyPppG-DCEy_o3Tj$0zLL zNuT}uqF}erN1b-tZ#{Vgg6A+J+>h5kBB&idm1L0vnF%mqM z-IL0}d=cvEp-r3o4eJ4rSp+B5X zlEX-_n;lkMH9zClkuNax0YeA%^J16n6<6$y@%!L_d3@wd{WR~0K^Pl}!0}mrujnD4 zc4&`0k6|V}O;{Q-Ctwau30?6}{gq87AT1)Fn{8PVaTiPDsy=KuV*+G)$8D?o$1ueX z_QxV&SoU$~v6!dRIKY5o&ffR?r|k15og?a#nvJ0`CJUQN!eYdlSYh_v8x~A`e>YoF#*8_&X)mz~1LIz^ zf#qnRC;r3VU91bO@NG_%cIuu~sVm6Re+6AhSneys-xTVgKa03rFSQK&pBqjT`NEYO z-uaS*K?AEtqR%ohD`dVcf~)W=KRoR<<#R@lh$~vzW#ja`-_RGvd+S?zQ}wmEHTqt$ z1Nx3R^R`I3lPI0B1G)0hXVz1xk5xapwzu>mo6%B_L)Cl`N%~r853O~e+x8F2s%OpW zM#*fPscEu3*N#XRD?HM4h48l+$;_ToZN%n#lG$4n@*FX(Bo|X4I>qL zChxR|j`s=XoF{1^wdptxugS=D|8#jony-pbE1NQDNYEwa^mdl=ByU@Y9SINg>#t)D za|kh-z=E-a$5%YgZC4PoA?deksCYC|6DB+V;}8FAv1_y+JHF3?Fok8N0bv`-xJk-~ zskD8mm~iTH9g7sk4EIFRV!sm>+JjtRxb$}n05a+oVVz%{2mDW%-IRNb2Ojkn0YJ_x zP5K=)pp)h+!LI2g(s(B6hk7oc#HAc2(u}H!Svx>42Wf@zRs#F|_jq+>q|M!d3N>~o z2#=JSDmKSvoXjLB=BeKarB`ze*36hq1EIFZu^Yni#sByr*~EMgi9S?xjhHmZgfe=# zn`t~)JlCldsix5+4XID_5^UxS3673n?zpy!O8qNLBefdMzD{#Vyocunx;mq6beNA3 zXg8%j28K$2#c-e6%PRtBfNI=v!ES^x2(GCsYGdQ3hk;xY(j)+k3gbvnrJ#g)Z)4yp zvCvg{a%%Cc`EDFyW$0=p{8V1z7aUcO&R%d7Puh3IQJc|53!qh5YA-6pcFihfZcqbA zRp6+kIoBL&uVRYdrde#GSc|4?4Oi9!FOce4LaGdEECof&P!@pF9B&(<&}d1pRNp{h zG>M}YBcLrp_ZyvU!_z3Hi`(<^sJAIlB~B5})T$ zs5nG?N&xL5tR#oq1SnE|__8<@0Ma?VwZcrr#hhlV3Mk2bOX5iec|wVLD7l5}4;j%W zBo7%eGG1X@pbp$I;BzxrK|!nM6@=LqL0*6-9zq(W3N$pM0tu#Anz5Ftbz^^kKjLeU={$#ijIYH!% zGgngal&u#50$@l~Nz0-FA2N-y2?MUCEQMTJXEiZ>z05!xtu1M_sb+7hiLTu)H&zNT z81H};c#anLe2G=!hl5-U2q@~7m8sscNH131B zU##YnPBv_@)jUS+N}biz&*}>*7)A68$Cja%BD0zP4A~tg86zJ=2?O}P0TUC{xd<3( zJWO0Xn)-N*%q-GBm<1AKl$cAA&_Rhw!a~Y&4ITF@5*$;|_!15&x!{Hq6ntdEMseu! zB-w;PuEp>r?^wPKY882g` zNJ?$ zs(7o>$&1U}XrKdopogk`d-8hx(bTz7Sqx3~8pSj@f8Dc?&Z2>eI_tWq@d1M~isvqf z>aJkue(7$hLz(NZ%J5D8^#0oIJ|?FqhB4I8npISV2Wsjn!@8}mpK2_kIi95(DYRQt z9A|Owp3TfJrE^cabS{=<^19NpzWD8~d0r#fyJ`$LR}_v+>k@cF{hDy?v@Tl7I{)Hv z29@#*EvnqE9N|+{9l4zH{*-)J(1QQ!$%ycZPG`w&)N**1&)Skk8{Mv<&c1m472>o{ z-Zy*%CUZl)o-wSnSOt$7(u)janTMM;-!8F11znr>x6m_tsl{GbE%v$%O2I@1bDE~5 zvca7bjZ}1ve4(!ri6zsLdFe&vG>PXX3`zl4?*MjX1#r*Hylwa#Cjp|eY9}yRHD??d zRK+EZE?<%r-aUB?Qk|2-aRMA+WRX4*ha-?U@rQGV-X1A~x^)7eR<671U+=T~Qr*}U zhsAlc>@5&BmhQPC_5gnQ6EKkE$7aiQPY*Wh4c|5URd}uBw9)_>H{9<4o9ax5%_L71 z)SszOydgdFn3V-B(QBz83{6kR&Lj@WbVu`B^~EBLQl*cyJm3^G>Bk=2X2rrdN+wzP z#Up;&92MbsgrP^@)&xR6q>R1LblDL;kM-2T0TD=RYlqoa0;Uv=gqe<%ls0{SXV5=W|B=p zfimCMV}WwpHG=`Fn9iU8g%Yf^y;eW!)Rcu6+6?Cm2tD+U>CpLauO|GrR}_KwxkC^m z!_z80v10uFo5CfFb(Ah&pttVLfB2^c5#UARrGOyA28!;(RE>3rc;`k9al54UKzicy zpX1S8@%bzH{`vz1Wuzj7W6@`Mo_sdp5x@f4#LbHC${67;@}~;Nl(9ZHWzU2Gi{#DL z>~rSdqFA#2N-nm$zU(~mYLCxk&nOLQR$$O)LF)ZB^=UPHMI;JEfG{$&I?mT%DNqd@ zvZ)#_&$u%B2wn??eTf?j`LP@XQScEx7RLC@R*Uh}ZL{~`H7ek6g-`sT)R;bEqv_!Y z8k!=2ZTh0PK}(+~cFxDz9>bv)R{DhUkdImweO-NKK}Wjwvo(~h7uB`dgP6VK$pbj< zYd?#-#EfKW{vHMbVrQ?>#|<9?-B5?G|1wQtXDv zpX0UWAx3tuTDj2Hi&IPV zl8aIkOHvaQ3Q~)5GmDEe^YbPba;Hq5AE7qc)=71;ffMg!eOr#n3p7F$SWG!6 z;si8-eexmopGJg(0hn-8u%uhP%?mVtGLxeplt3YA-GA~K3E|C4^{k0V8hXVgi6xoE zC7H>^Xs)r}++*ZGM6$qP!e&cT9n7o3;1jm48aGCKigpJrR!D0$9Og7JtD5byzSXk_jS;Ghb DuVs8` diff --git a/mobile/openapi/lib/api/api_keys_api.dart b/mobile/openapi/lib/api/api_keys_api.dart index 3ac829c30c85cc485bcefb14ee298fafd89f6f7d..0bd26575c60621cb3004f00b34def437ee36fd0a 100644 GIT binary patch delta 1399 zcmc&!!Ab%_7-m;iFf59oFa!UvgI)9mx>QnV9>R()L9DyKG~~`MJF|%ddFcUyc>rIa zLoiPubnPJwqF3nH=&C7bP?TNf^8L*Bee-|cyq50Ej}Mx?=cCCHObR1P^_OFh*R;fO%+;Z#@-(yz#74?{QlZiS!Wk6uSvXOCtibmb1_47KoPcp~>r^=%k6w^uBUVPRMN<{6# zR2l5YmW}21)9c6txYb@pM|UdQ%TzD_(q&ntVL#x3kK1A+u`2IYGLgzqO1B;Z>PcN2 z8|)7#y(R}0HkH3#$4tvY#=-z1wLO`TK%>qoE%;agEyns`4^D@>TqO_-^=A@$9JXwG#W%2@5$;sFF1UG-? z3}7P06`00s-oWF+XiS9PfnHBR_BqV{&DZ#%naDC=0jKBY`+^V2(=5PbKY6*d$mS?f zX|fF1yhq%N*)|}xC@sGzw^$)DPr)N3BtSvk-8Do(9~j-b*{PMq`njp<3i-g;PAmb& zHBeCsFkO_C7UhAH#pW5(c1)Wc1^~`S3CREe diff --git a/mobile/openapi/lib/api/assets_api.dart b/mobile/openapi/lib/api/assets_api.dart index 7bae14bb58d3d3c813a1fcbc1483ad90b4c2a218..fdb171bedc1a999437dcacbac36f5e865a9d9a19 100644 GIT binary patch delta 4180 zcmc&%U1%It6lQ1gQ}ZL$(v+r)y(wA~Xg9lQOKO7TXG2q?wsG48tYC6?<|cd1{AGT2 zjilX5g{m!DdWBH1Ax|1)A1W86AcBY>D2U*L;7j@>f(Qj)d=k%{*`3X_3AQvp49vsa zbMHClyXX7PnT0#j!k^Nu&tk=NjwmxI>uEE{vosT{4G491b_Q=WL|kI))F7ykqe>28 z$04qRayU;A)@*{+Ig};DDDNdIa!uss2y%#>CpOAr2fmqx_(pAX=Hx&MDZ-=U=}rQi zFp`{P7Ynt_+F!%3O210m9?-FPf?buKXQSy_{!-n`^3DJu@+Ng$YD^={CYs-7hoy0T zq2U+lzEwWae6(gFZCY~ySP?j@pAj{tOk2k;1#mPvBjC&eCWnxVr{PUpC4r`FQwQ*1 zO~5Xo#fAw;+6*UEff`Rdc}?1MXQ_CCKef9jRvaQ4)I&KMow!)VE=JioG(+Yhc~%UO zV-bZ;Q3Zw8V0t)@HIE<*Lq$Mlrb4j`RZ^gCE~uSg6MXXX7G>gBBpd1bk}bs>*^Yg? z+2V5J^>>=t&#f(dwEwFZJG=MeZI7=fj@aFnSNLM<)3Lz{20mjdDTqXXR02i^>7M3N zODhBFAPiS5sDpKaT&k1GEdw{Y*{wnYUy2*jMx2|96Smm;1i!t%B{n`}77W3AWZHC^ z8dwWZk49X!ar^*7!zl{En^S9D8pQrR|FP|Wyjka`;vFoRrTmL$YUBeM;@Xr5O$zi0 zN>U|xsu1+TP>={aHQrv=l}N(FSK3cL~?V%uRpd!&JBZ>_%1_MMlL%H9&1`?At=6z zw@|GAPh385{C8=~y!m+0ES=NfpaSCNa=WPAw?WoQl23QYwG1Brs#UUg03 zX29Y>@(1DKLw%Fm9t1lYKj`byXu9LRU{0qqNXYp5B_J%?Pg^ckKpWCIY-0t60+b<& zIc-qUz&iXB9t;weKK>CO7(OB0do^1g$dUN7fJ(Jqnnp%sy~+*8h2{(`UvbukCXa1u zdJd}Ep@7(;e9AfmvI*RWTJyho@HPaDqT6{eA^8IT$MrV8>(swn?OLdUaLqE`%6mlC zHa1ikH-gAR(M%18vi5$>Nx* z0K_!B$*e~lSIo9dO@7BquLI?_I}qSMPi6~pt)B~f*RohP`5r$%tH;>Pd;`Cb`>lS} zT35Ush;b0s7itGH9yGXek3(;m*$9aKVzrOKvY7RuP@tZKcKY2|R5`y`xFK!CSz;D_ z?ydgV;Ftxf1w>n`{g&5OkJwQq4{*TA_j&jH57I`QCFlg0vF`b!{-49w#U^>O5@V$G zL;x&X0Bf+SuHS6esY*7`x4;%JKgMrf`b*k;Z$XYnghzJsQbIIYR_fiu?aMdh5JUgU z*U0gq#@!lTy0Toomq$1=74KrDD-d&Q9sm1-wph=Y|C1Y(<~?DGDHsMDWROCz9{rj1 z)%yJGKfH5kMewGHf5={Je3SzPpuvH?^<(3->NW@RYQW$a2{065(M;Tm38Fd%-C3_f XaPkxXM{#)hCwY@x2)(sRpUVFMTuhwx delta 2865 zcmc&$O=uHA6sEgsYig~nMk}H0ST)7gZfvYUEQ-b|wIGICd#NU_$=Gg_?8cop?j|CpQMzmdFMHUT?|a{S^WJvaz5<5~{4|M5AYtvPK!v`zSe?g^9^5^GTART3lvKRu%DA7?9HxYL>OaOGhQX z=dN=9T~IVAz#Nog&9ZAeRF$s=z2ZEKH*{mlF~gZZP_OVT@h+ZrSWOK6o-~BgGDfS@ zoE@wb+yWv0QixVJB04KeS{9F=OhhD|<|z=oBL>S3xLI2c9iydQB+n1dm|6m&(ki+y)-k8CBQwNSWeCI6g z$N8oYyoDapXnuYuc<1ck;J3UW4vh4!nH0gWtJ$|1(|E zjjLP^v%Cqo-VlL6cQ3s2R^yt^i6WScp20x(M;@LvZD?&4o11;&HY;9HaL}ftk)YF% zRDtb1BV4hBC!@IKFselu?zcwDy$-rjb?^MMwlSPuLWdsF%^V&t^DVL=>xJ`h~e5un;>Rf{ts zDWtutD?sW4M~-$8Pwu_o=~qv&dZHS}Z?v1L7`r0I3qen6O74Ns(@9xERTw=Xg5<1+ z*^7F{$h1|uC$nRFg09`TZe|MSj-=oeii`tTsgqoGfLBT zg;ZNMwW;ApMd}bz-|gwZP}*q^X diff --git a/mobile/openapi/lib/api/auth_admin_api.dart b/mobile/openapi/lib/api/authentication_admin_api.dart similarity index 77% rename from mobile/openapi/lib/api/auth_admin_api.dart rename to mobile/openapi/lib/api/authentication_admin_api.dart index d22b449aab0613b0c328b1f1ff281d083f85ab21..0a4b91ebc3342e5965778cc21adc10fe1cef7317 100644 GIT binary patch delta 314 zcmey%y_;u)4x?&nUP)$hVo7Fxo?}XGW}ag~rb0EBf`VgdNd`h{vMpnAeP~`zW?r^J zVor{NKS)|3F*!NEG_Rx>s9axPA3`cXR25@UrjS@%oS&STSdyBeP@W0YUs{}61UEz> zGfx3%r9yFKaY<^f9*UWM`6a1Vo28hlnCR{Zx6+c*qEwr*{LBh($ delta 215 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 delta 485 zcmaD}_`zwzCdSDX5{i>QFmjrOWMmdAq~@g*wA zr55QW7o{eaq$Vg7q!#6778hsc=S}wG%-P(>RLw-GIgW~&ll6@yC(mbMUwnv_8DyNb zp`M|knVx~30zS7T78j?M=m8y;g66K2$>&r=H`gmp2fK|T!yFauCjXF;+5BI{g?Vzj zhQVZi5j|j_u}rSgurnjdbp<(z$ru4QxsOS3vV#fl=1}8Y#?9-rp0HEPaA0U|);He4 F3IOQ$vEl## diff --git a/mobile/openapi/lib/api/download_api.dart b/mobile/openapi/lib/api/download_api.dart index 62c97bfc9c830fac814aab3a345f44be2877f47b..524562275347ae140bc713e101fe24db4b69cfa2 100644 GIT binary patch delta 795 zcmds!F;2rU6ov&s9Wt<0tiLJ-CUO8)2C`L%33YLjm&8))7wqR$Og%&vP60?c01}7b zFico2X{p2oVDa$u`?KHwy`O(vygnbTuX$w}Rt1!EBv3Z5bw@FfB+2%~K7#vnK1PtU z5v7eb6{IG(mU3Nc`X;$c+=c0e>ag@qP^*rR5gD|WI?diSj|nV2cybc%by{smi&;f7 zKAM`67c-D4TGmGTXF1KbZxt5J1Xp=X-AcxAbZymTCtx2r}xiUf8jvqV; X2R}90VH%&E{GWCDdHghdp58=XEGQf= delta 259 zcmcbnaY$vuI!3dQjLc$%)V!2}{LH)(g`(8L(#)dNVug~7RE31Z;^Nd2y_Ed&yqx^R zlmvx>)S}$X;^NHwyv;F8Y%JvJ6=2`bOs3w+F-$3w=L_U-&f;+)+YAAA&CT-#wlf0& D6SiUu diff --git a/mobile/openapi/lib/api/duplicates_api.dart b/mobile/openapi/lib/api/duplicates_api.dart index 9df6e46586debd85aa7d2d308f298b921e2ed6a7..7fa7b368b576e9137adcdb2635c8a710cb6d7320 100644 GIT binary patch delta 627 zcmaE=v{hxpCdMF_)ST3kRE0!^l+uEn%;dz9R4xSteSLihsQ{NQ&df{CNkynqNGvW+ zEm0^gNKMX6%S=sCNUBuGEGbs-blLoh@i7w(%$>ZQQ**N(t0H44)KPF37h`jBZfQpgPi&Kk$ezM;@ pgWHm+9&R9xK!eLuW}zN1CfrI(N{do$e1Pt@ae*eP&GLM1%m6&N*7N`X delta 390 zcmdn0@>FTVCPs^pjLc$%)V!2}{LH)(g`(8L(#)dNVug~7RE30;(t@1K2B`H`r1(XE4<>k#B-Mljr0rF44);S>KRt$mSbtKPYm7=4L-G cXGSyPf}toiF$FmgHvizRU?NxVb-p-e0LlZE(*OVf diff --git a/mobile/openapi/lib/api/faces_api.dart b/mobile/openapi/lib/api/faces_api.dart index 2f8e6be60dab85b08ae1692897b128628ddac528..1d2e7401e80350f28bb191602ef567b221d40ef3 100644 GIT binary patch delta 1017 zcmd5)u}T9$6eJ0W5F!deY@dyVVA6=#32GxKVz3e{_HN(ZEu6bycZ~*-wD$J}>Ff+F zSmX=*0;_z6rG;E;AeTUsBR8%;md-n9wZI-ppbi)>1eh^s=jt#6k>)8dz*NcD zCutSX5&2J)-BUKGu4G@$y8CQgm;ac4*f@3XYnPQl2X|?qh-vS%o?e6^gEe$f8zq0~ z|AG4m{H4&Q?5OP{f-uI_?K*6vuyaK*X7-kcCG`poDXm{4!Up`en)syTT9lg(xiHf17gPD#y4MYVad4O7Zy9S&9^Y{#P6 zP}Co2JLlwR4&%*|JVuO$1pN;5dJ3}7!S?^*ZDArqtD&gVW`4m4BAi}Ykb)NCAbTh4 ZaHwr=5M9GWIOMSyU?^I;*+7zw834nNw$uOs diff --git a/mobile/openapi/lib/api/jobs_api.dart b/mobile/openapi/lib/api/jobs_api.dart index 4c935828a0114edab20fc01b2440afdcf30e0f39..e783f93c7cfa15b31ff3aebd99c6c8314f48cdd5 100644 GIT binary patch delta 1155 zcmd^8F>Vw=5R?~T2_ythsL;W28#o0KfXE1NX0qPdUT*BUnPsNir;Gdp5+sEV-27-B%6;4Bbo%=E`N8E0OZI$mD-&GOD5hKNQG`UxzSujkEO-YsH8v;B znN7uw+Iy3~AKh}!??|VcLvH?A6Yo_t^Q-Cl$&EE(POiSXYp!kav6{D9(>zqzCR6RX z?{~<07%S2Y+y5>gE7?Ibpi+h)pw#5`=Hj!Cd)LB||1=H%EAulwCna4q8MfS0y( pJsd@YLW^yYk!OB+n{%(PYT&Em=4d*7_WOUoO54n)pD#W=`U{OzlNA5} delta 531 zcmeyXvsh!pGDg3UjLc$%)V!2}{LH)(1t2>yPa!cSH#1K+KQE_Jp(ww!Bvl6}n4(aW zT3DJ{lv=D%l98&Akd>dLmt2&ZSdyBcP>@=bn^|0(nV&b=p2L2!EWgI&em33B^33r} z)HYv|UuSban+>B6CGG|~I|bR*o9#IYn5b)_GWUO~`yCjzn`Qasn5iG8O`9u)S(pKD Cz`#=g diff --git a/mobile/openapi/lib/api/libraries_api.dart b/mobile/openapi/lib/api/libraries_api.dart index 9258f8e3eb9c6657d676fd336d577d7911cb0d35..ca59f823fe2fdcbd190e669320010eb5f4cf695d 100644 GIT binary patch delta 1499 zcmX?|bv1j#21YCAqSVBaRE0!^oXn)6#G*$# z{E^pw@@x^+$-S%=lOKq1ZC=5Y#YBmD0dks~ds)4h9bHm$QgONoCYgufAcdq#h0Ky- z1y2{K)BHDY=L}+^f^h+Io|6ky*(R^z`R)>wT2hpmT9yh8hRoDrlpupkgF>{pL?J&7 z-JL)kn?LfFFj2>(tpef9t|*pbMk7L+P@rv|Ei#*lO2!4q1x)^@#kcv1_(i6AxD%ks zOrf|Wu>=@CnaMbU4_mZsiTmYmz-0Yl9`vTkXM?Ulv)G| z^s>y9)cj(gTyA1|YO%16LSkMD(9--OAXlNZ7)U}BN#x|ca$K9&O8X8T9AUf+<{4gk}D{Y0Am(M>0>u}r5^9({aTO`s9k+J6U8QPF3?)R z92AzAlL>YqJi(@xfEyPa!cSH#1K+KQE_Jp(ww!Bvl6}n4(aW zT3DJ{lv=D%l98&Akdv8Ilvq@$mt2&ZSdyBcP>@=bn^|0(nV+}$6{7$%4a}W9QBQNS zACtvoe{s>xt62XsQEW#_YECMu+b6$bOqraZs<1hSGlnMSPtaYY5Qa%kLvmm+O2A46u`ogIQfrWuq97X5Ns8lcl3UH~hTTmhm57Cn-TVbB z3lXld)82rMU}5XOuyM)7AQBs!6g#jmU+??OOZm;Yze%0fQA>t>gvjffCr?o-8^Cql zB*G-YgAP*~L<>5eX1W(3csziP;O*q+3n2r>J&g)lLW1ck2jD4%8qSywO{#Ay1&6@X zo-^uS{T_25G;Tp7WC|kGp$I^t?n$mdhX}ik#vvTnQFR4Z*i33&s^!<{G25hKx=NLF zhVIe<)vY2u<;t{Tt0bIGY`d+*S&kfqkb66xIXFAWi0 z*n4zjSK?=T-7>_CuL_}!!WRa@58J1Mo7m2{!4f41HqdE1o8U7&Fj4flmV?p=TbuQf h|IK)R0(nefd?)__7}xTpnG0I{Ey$eJNjxlET3;?84k7>m delta 280 zcmcbvcV2755=PH})S|TfqTFJI#5@I$kdOccb$8bg1^wK_0w6BRPAw`{SI93&ElMoO z%+CWVN>M0EEh#O^D^@7UNL7dqN-ZwP&nr%i)tem8q%@hIi*52fCY#A?m_#Rcb9zix zU{0C5msw?U1DE~g=giKGlU3QSOx9xkz4<5GZN|xIOww3%*i8=R(uL`o{G8czvaX2u xWPNVw$y2xuCVO#vZ9c-S!Yqc};gc5%h^mp`;2vR*%`yV}nLuvY+#`IN832}$U^@T+ diff --git a/mobile/openapi/lib/api/memories_api.dart b/mobile/openapi/lib/api/memories_api.dart index 9916029e0bebbabd3483ad32971e986c876c6783..314595e84e3a8677671f944a5b3aec8bbe3f58fa 100644 GIT binary patch delta 1819 zcmdUw&ubGw6vxSKQXx=KL=ba%2(nm0<3U7%ty*)bAd!LxLD0$WOEa*$6J}-URVK5WzRQNvd@VLM!Sehj~Bpetkdt?s@6ki_*^fQu}5Q z08wiqAJ3WLrN`ce#dz~gO-idlqp2vGTw_ca%B9av1G zDDIQTewYLZJOmiUA9_o{n!=C*ST zIr9o@rh9hcj21;?y5OilX{JdE+*dz|WZ}4P2i6gZ&hL*R>!1?9NBSY5X%>Pnl2~U) zC+MamNZQkY(Nko{;;U84pH`ZW%(S*s`Rj$0y$k8Iwr4(`-*xYA5hU!|a&B~`h>CSM z_bU+9Ea<>yEj~=!+jaijUl2shWM$<3I?>{N?h|2t0;_PxLed@slL$&kjX{PIj5E5B zczjDIq6!2SQuGjDmnESl%7nTnlI`AAOA>NqF+C{(okb>s3{(CrmyiL2B`j)Jw5Z?jr%-pn+ei4t=Rl{F_H&E|iW(rB9R=?ZWjm(U$&fIRoSY!WK6#nQ zZ(|~Y0T>}EXz|gvxlqiDi7d^?4*1C{vN=lfER!V>t|%@^EXgb`$xJRrb4$wPdFBr$ z|25>={6Y2@3;9NEHdMaELUi)N611>nDx^7=_+*O39B49~EW#$Wd9F?>Gg-mxCsZSL0J--h0Gm+z1LCPI-S0hWv}z+kBsR)+%-p&^cS??@5W+***?0H8?LJjL`^ z`acd%dkKFXbgNP5&v&<*b@1A?hgW_xwfvS_n>B<(KGfKcs(oTEa+iI2Zvhf1GM-m7 Z{GKiF+x^bEyQ8Hy-`#%0jLAvje*yFf`lbK? delta 274 zcmaEAFjsfOA;zG9)S|TfqTFJI#5@I$kdOcc^#K3i5C#3jl-$fb{k;5=%(Tqp#FEVX zykd2Q{DRaXFdL{kMWHCQq_ilnSfL~%RUtYkwYUJNCN)-X@_g2m$?pWYHXmf_VA{Nl zwVqiVhb5CQbE&BjY3O|s<;{0Fg_$Qm6Oq}R%iDw7&<-I5;tfsM{7!H>)8=O)^~?Zo CNMoY_ diff --git a/mobile/openapi/lib/api/notifications_api.dart b/mobile/openapi/lib/api/notifications_api.dart index 1d276efaaff3bb23c69ca502dfafa2b4e8b9ab87..2de59a0a7612d6ca949ba3e5cc71f5217d2ab118 100644 GIT binary patch delta 1161 zcmdlQbU0+g4n|v-)ST3kRE0!^y!?{Pw9MqhlFa-(E(HaBeSHY209R35keUoqf>65o z1LGSe%8Zy?udcJ%fmNN+9cmAK-fR)$Z8_&{>Aw?YGRJ=A@;Lm2J>tl_Jt;Fyz>UtX*L^hi=^PPQ({HzgUV$iBfy z{(6Y4GC4#h5}X6>%dkzB*I=7`SlwWcvNdSK4o2&cjLc$%)V!2}{LH)(g`(8L(#)dNVug~7RE31R{F2PH%;dz9%=|pP zl+>KmlGFr+g4Cki%;I98(BzLod6ReYC``^{7n*!hk$3VwS+33NnT(h$$Tf7c9BVM8 zPD+_vAj~s)7CX=6a8*7a&AZv3eJ%M;nk>hvgJI%)t{6s3qCHuZnwWwfZku=Vlrou- zX9UnmKAVs8KW8G}37bC(onay0db7##!WElWOB`n=KK+yyq$FZZKm3!QEBH@7&%?EO zzU+DuA_~nwV5qomey-3!sguCzXObe@@U0B77)c>n+a diff --git a/mobile/openapi/lib/api/o_auth_api.dart b/mobile/openapi/lib/api/o_auth_api.dart deleted file mode 100644 index 9f16e37c702310299000d895cdb257eb1c247135..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7747 zcmeHL-)|Z@5Ps*cnD(K-X$!ro4;5{~(S)>-+Q215)hUXovunWZVsCA4C|Biwzp=f$ zu*;I;LQYL29`eIpdpw@`z8TLno0Vo0I_HDl^Y`78?rCSxJ%pp8M?j?Bd)fH?b;S(Xm zGFQVW)EMQlp zr;$+loe1VAu6X}MnDgBCn96zIm{Z}>w|{2C{fo;tOWI8+38-8wJkyf#u?Oz&{?D7` z#m3*aF13QKH2{BWMB!i_QL8~B@S;khC}h4xMDwc>yo&l5#6g0M1=JdhUyE`DWc7@_XS`h!#l_02F5)ds{;{G z*xv)guroW;xFW$RhEl3@Jz)`G2#{iCLQMCEPa_i{$^?0dUWQ&M*I@tMTvL^;ttX1y zSWqB2KTjye8bs4nXbOtTYbvw2!v$O!`phr_;3B86iLozVyz*d%>n9jvfD4Ur(Hsa& zo9JXo+R-*{X*Q*1%SGMENHF%05v z#xcP>O+_CewTR9v0W)(6E$3FgNOeI;)S^*YnmWaD9x#_f%$^ACVEgPDUVYU&PjcSj z;=r+W;T#vI6Wb&0Tq0=%6z$1K$o{4s6B26=^Mv&%ZWth4d^=^P2)38ux&Q^fUsrJthQ9A9=h z2n(ZK4!T1QDnoIShsr)}k&E7Uvl?hBuCM}qj^!hkkiOo$6j~`=QV}+j48$iZI7f~9 zE>ViQ-#uqMj=-?E!ibEDc$@DUp?^(fNuzjY|kY*Je%YMG}Xr8(Jy$zpO3kJ9EftRI-f;7&nt=j1!whMI6G zB3zlWIf1j8N~S4Dc`okZVGa#SEh)-OElY)kP%%mv!etW`ax#lc6!O#H>cBy#P@a*W z3kyq7uz~|OW%B`kIT{%~85p>mt%YYX+XtoQ<^$c0J@SJ~@(aL@$;?ZKxepZA2<5<7 zPnn#+skM2gcpwv{hHX}ma$`&hEl9zg9D@r|lQYvQfgzS!l95`3aEN*_%z?!j`K382 z3W)^;sfk4jnRyC8g$kv`sYO5~C7HRYIhlE>AZKrq`Nu>b%M_%XCQHh=0#mZ+<_q%d F%mBs9Ef@d* delta 673 zcmX@^e%*D$I!3dQjLc$%)V!2}{LH)(g`(8L(#)dNVug~7RE30s#G;bC)FQp)qSVBa z)C7fs)S}$X;^NHwyvd3J*_-2;mN1d4|Dw3&R4U0YBsCjv#&w`=L_tS3w9y8JPGC{uS{O{EV;_+3lXV*#KpoMD zJA7ZsYA5>y+sj?ziq)CULPN2=&b|A6SpTkYxlG@hLcF+z4VE$JR01R}4OL zW=lOL4&Tce%51`AV5f0KERfg+*&s%MtZ27vx%!;FsAbu9agt}w-BCvZ+09*MZV}jz z^M9*Lm;$mw^ns16VCoSp1WebFcJhO%pP7;W4h0buCfNOame1v%o+?K?q8X3)tA~Yj zAGDqTG1$SB#XcAEViVK+)l6Oee+0<^cpZMJ&G7vg-=~NQ`HAlL86+W+)&aGgKM1r>S0dXL8oOSVhtxQu1#EA+yW*EPtx(?vp%#I z-!5WxY@jh){`kso^}%iItq;9DSx9Xr%_z(-BO(z-ZdpVJvBT&97tyx(c&H4Tt6jhA8ey;xIsS-lAj?UB$GW6xX!0+O9rc(nVK{$U n_@K=uYz6``t_%&tEk>HxLcQ6a#spux@kSj9DBcYx&70ak+67lh delta 1408 zcmZo%z_@uX8uJ+_?CbP+JeMC0jWBo>yAt|Xjspu}4oXMjz zS>K3j^BT@D@(cmGWOF8uHBn)J#RU^4ui@m_oX_V*uI=8FjRk)j5)lEw@J~Sr{=CVH zC2nnABizSAhV}=##+w&QG?SzCqVmkmZ)NS7$gM$AS;_%}DTC>=GA)o*@hc#nx3 zy$^IuG*?LH7!EcTp0t}8&X!n=99 Hj~6ol(upRJ diff --git a/mobile/openapi/lib/api/search_api.dart b/mobile/openapi/lib/api/search_api.dart index 6c279a35037787eea001397607e2943ab7663416..375e9a1e8700029c0a1da0ff77493c18b3e1b30b 100644 GIT binary patch delta 2510 zcmd5;ziSjh6z1;y5dwyQ28)0^loZjJLj=JPv`~WR6(Ko{s6^*>-`$Sv?JP61r&p!1 zvyfx|0f}G{1chmAOf5DEHX_L%AR=gQraT$;n8e1dpjaEN(Um?c#o8yR$dgg30*X;u*7Y=zQr>H#7Jo^o2xlnPxlZ z&h8}CS*mk$g^uPTm;ec(X8X?hlOhv6?&CvpXjV$xNgp ziPIITyXkpk(utoPJ7G2luatV}Rd(GY3=OIri%0ED!FD^Su`Ed;lbSOhco0TkPah2~ACrRnB znuv7XU|rfW3LMEbO3r$PWUEXIO{beoJ0A7$5pYBl=(sY3=JM#r;z5b0Q#}_?jZT~8 zQ!}Nz{TwA?*hI~?6?kT4%ORJ|ypCE-auF%W&p}QN;dbNaV^i^ud&B0#X}`FacXg`c z=K0voQX`9$TDp--{FdI>jzoKm(o9m~P#1+0m-4&yghkDB$$h0;Gc=v1%AUxtpwKP#i=#q86b zlVpzV8bvzg{)i%8uN;rX=t=XvS}%5^`5Q-_>MgUjP%UA`g(U43&8$AR1k)WF3^F5y zemV&HMte8g$!M0MMYXUs;qmI?CG+E+F8-%0ZOT^{UzL{Tn;5B=TRhR8lENSmxQA^2nx*o7AHAY}6VaFHafX?G>j(_(>xb|96@@!Ze@^Q*Q@ Q3bxOIe6B6LoT!(616NXP*Z=?k delta 1274 zcmaEHn{mx0#to|&jY2XqixpDyQVQ}j^GXzoQVUBni&BdfN-|Ov5)zAxQ%m%UQWH}W z6be#{ax;sIGxPH%Ckoha-p^#oWJt2!&1YGIn8~zq@_r_f&38CenaI$;Ih!Y)9D6q> z3hZDb!@kMqWVJRQ6Odrs{7OQF#e#4+6_+HIWEPiXCKscHbn50GvZt8HH{qOY`sQ_t zZsd3#7|$t_Uu#%xexq7LPM`w=L38tK4KH%--lV%%l)SLl+@$NlGWjN}rW-Ujze!p~rv0g#3(^;nX|LAg Rf^_4_>lE2Gzsvf?1OV+U>?Z&K diff --git a/mobile/openapi/lib/api/server_api.dart b/mobile/openapi/lib/api/server_api.dart index 9fa8f2016d96ef1a663e25cd1be0a2d480f29203..f5b70a9ea45329c78e81daa3e2bb1f4075c3ccd1 100644 GIT binary patch literal 23646 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 GRAvD8^^P3? diff --git a/mobile/openapi/lib/api/sessions_api.dart b/mobile/openapi/lib/api/sessions_api.dart index 63528d17a781e606c3c2454164f81ec3348b820f..da508059bcb4b3be5446266cfa63ae5388b3862a 100644 GIT binary patch delta 1084 zcmX@^*66um9b>(7QEFmIszRbdacXgKW_})*f`Y!jK7>?2msChB2C7WX$jnJmD9KkS z$w*a5E-flb%`1Uv*HZ||$ShV!%}XiB&jbns*`>v)DGF)%MGDD@#U+_}>3YakOzstr z*zC!)ifOh@=-(n}FqCHk z4amzcQAmN9hZ^IL8G+?5V zd7J+V`!iekWSn9KTXh90@?1+#=cS2?gFb@JF f4Vcqlu~oadQ|2iX)eL;V?=-nn#&xr{f($bN>^f%z delta 780 zcmZqlJnpt(9iv%DMrN@>YFYH@L9ex6=(QEFmI zYJx&RYEf<`SZMM_-qgtlWZ5=%Gc92v(~QjvSzDQj(wmZ+lZs)#{pRzWmQ04kxF1FT z=3E{Q;=GNb4eagB8+q>&=Uq&_lNYjTO`atyG5Lcm`(#nUzb3@E92oE^XyI-@`8=oK z<`qKnOk|m`nOD@GnJAq(`N`R6cK2;ok_;lwUJTvH-v287lcQx#>H0W~Hm{{R30 diff --git a/mobile/openapi/lib/api/shared_links_api.dart b/mobile/openapi/lib/api/shared_links_api.dart index e32c566754f3db434a175bf31095207f4542cb36..79106e5db663281c16ae20a32b751fc3cac47b3c 100644 GIT binary patch delta 2000 zcmdT_&ubGw6sFl)#XzA-iuqxDjla^GHtHc@K&#k;LD8UA4+>??PLd&;owz$mj3NP1 zs25xE@ZP&1#qkeNJc)-Cys6;HQ!l-F>A~5gZc@#Ug8}t2J1pP4`QG>5`{wb3PmhLH zUk_E!X&R`OMYsi=feKbuHHii~HFCQFqS0t`h2L-mlA>vvYCiyXDnMnR#M}&A&r%DB zp%oZ4ILJLS^a_|nCnZ(>NHeo>(zkUNur%;WfdDl$TB2G})p27?$K_ZMSElcZcP^s* z%Ul;?S0vAjSQ~k(oH}n3m6IM~Isk)|+Xa*<6A^X4as5GvdUy(>?$csvbV^BFCETQ> zB)RB%`$g8a+O|-#?iROe@he_zj2#_dIIM?Hh^nWiRGqt1Mbjj*GrBdP1LRo(9l&-M zvlNxWYfz><3u;j!4Ng-kr_6vn;aR55Y)kwytL?ds&s+gq^iE(hxC@`VJUckc5d&4X z2RFS(hI6D6L9fq0Zt2BL1g=Rzjm)eZ772>LLtG8r#FxJJ_#rxvWxs}SJc%FuxA1e| z``=A2sp8l0M3?L?#t&jS=yS5$+aWug-5JL9;QpADAP%+;P>>>*nW@E{T?Fit@x~fy zsuFL0#F+z6T$h}(b+?vwNKaR>9icWE5{sc50}fmdCva(WpC}#v=DIK^O{(Ykwg7$U zzM8y0z<`pb*gU2T$;Qevd#anpoik+UU6!y-ed=D>&gF^ zcsE~Xy2d=&UE2i2nS7loee)mogUps88JWcjsd*^{`I&hoKr;$UGmBCoh9p32_5oU~ zmt2&ZSdyBc0JJeTv$z;&=j01gsgvvYZ6~j@;@Z53r;>>RqYQb{C+pZrY`)Ad#B5Ha zi+~PFL32;eI$aQ(p%$HV_pNq9D zfGJcchPf1yTah)OhCDpO1H&9rMnJQ-9wHJazhsOCCK7pM5ZwhISe=3Do$m#4J}B)RXW3@&U0RI9RZ~y=R delta 926 zcmZ1(J2zs(Dn^r#jLc$%)V!2}{LH)(g`(8L(#)dNVug~7RE31%lEma}z2u_Q#FEqm zg@V+g+|1(Q%>2B`He6|w&#)OyKETDb*_}C_i7Zn#FJy~nCPHUQYECMu{hMvLZWCiC zrq0O=*|aAY$gxcpkd~M{hxaF0)&sqtGC4p<2k3p#&E5RoWI9EWKXh}A5I>_4;V1yc zKnhv}^lgq5ac3e&FLDt4V-wzNBYu(?ACwlPU?zi{$z^iR;ACJVJ)cZdfbQ8`AeT#K wIOJ@uQ@Bh~IMgXfZoZ&gLrhY{8V0qKW3(N?VGyX%Lw*=QlcnJ17;Rr>0Ac)C)Bpeg diff --git a/mobile/openapi/lib/api/sync_api.dart b/mobile/openapi/lib/api/sync_api.dart index 9e594d6acee0eec85f82512fbc2c61c9199068cd..b1a3e61455c83041c129dcd7b465f6796a7f8ef3 100644 GIT binary patch delta 1727 zcmdT^!Dd0LqN`J!N;rdpxxX$Nwgs?_J;S%!bY&8`qOj3u4s|T1*Tc z4j(@PDHM`cLKJDopv|?i2s&-_WCOBO=z9>lcJ7rMZSdWCHDamti z8Zag25k!hCDHAK92-^uM8K%NzCz<@wM(00A@OiU{X7?6`d;)F7*@na$DNG8oCF1!M zw@a2>`*}qn*D4ieOyn}xc$z~BZ(0l)BLf^ED(c_`j$(pIW##_sjW_Xmsb|pL^51Um GL_Yx6>0q@0 delta 732 zcmZ1)xXNS0GDeG#jLc$%)V!2}{LH)(g`(8L(#)dNVug~7RE31%%DiOfjMU_8u%uo} zYEEiNYJx&RYEf?HWJ7V6$+mKule<_=Ci|#xZJy7R%|wZ5!ju0iD{by&4Po>PNG(ds zFUl=eNX%342nh*LP!I4A4pGntxkn%9ijqWK5K~WIjn$jnz^^{pm)jKVN@?>T)Y(_%B7NsVpK!bI&p?EP9xq3OJteEu(*{fGv0<H3b+6O diff --git a/mobile/openapi/lib/api/system_config_api.dart b/mobile/openapi/lib/api/system_config_api.dart index 2ab3879b8a54fe05b9283146a6d7bdc75469c23a..b04da7127316b417d8e4e0318e73beac8a1ecad6 100644 GIT binary patch delta 810 zcmca^)@i6>-YKcN|WpPPru0nEtURq{)X;ETHW_})*f`Y!jK7>>VN-ZhMOf5@Q zD9K1wNG>fZO3lNfYw}-wcgChSw&R~HlJs?!<3B6#R@5@X^Evd zCB?X%4ppI0mY7qTTC9+kUj+6MhW|JJWpAU4MU&67Xm0+;b(kpx?5mReqQrDyD5vHY zb%7 delta 739 zcmeA)zizf+8)HyNMrN@>YF$w*a5D6T9nNzHZ6&r8cp*DFd*Oi55ENG;0EEH2*6$W+Qi3v&;$+@XcJ zlNp&}Hpg&i(ZuY7ESi&JI5;*-aqp&y`HW0qn``(yXkzw37OBnpf{M%`R7oSH1u2Oo Ysqj<+40Wf?-$c$a(Zux48WM@j04079LjV8( diff --git a/mobile/openapi/lib/api/system_metadata_api.dart b/mobile/openapi/lib/api/system_metadata_api.dart index f6b9bad1d6a8c193f5fd6b89210d63a31de213b6..63fd7628ece43d66f05f6a5eb65ac0711cafc865 100644 GIT binary patch delta 793 zcmZoO?J(W2i!mrDwWKIBwJcR3F(o%MPa!`qDL=6&B{MIbOF=`baH^dg?T zSUUIDF7c6-4m-JS9@Em7$lht5?V)wF#eeZqqz4yNF9q%0Me))82-S2`g1WGXv z;CWv5g?m8&y+J5x6e38!D?svJKe7U#415rjbxlr;{Q(N8`d*+L6)|B#1N-)&jTXDHto>%xB)5!JZc(_yZWg7g8V;1;@($B<PE-H;NsE=Y&*3SmSJgOPvCaNetP%QsRH zon3l&A~2n}ht67ySq)FI=O*^J*NBU=ih}7b90wTS z8>1j=J=+HjkVzwKGcjY!Ox3#YJtziACGLhA*5~$XRb|(?ed{}U+=>LoGS%*cNJn>q d$1up6n7nnf4%@K)p-@bF)Q0t%zO?$>`3Y!E(d+;K delta 1128 zcmZ2l`>|@naz=xU%wmPqyp)3c%)AnXqSV6D%%ap{g_4X^g@lsCbiKsl;?$A^g@V+g z+|1(Q%>2B`ANW%y*Rfhm-p9$cc{WoH6X_-xFePr@#;U?>6hgrAe&;^@gbPf|vY^4P$ zn2Ef0^8xB4vj`#V4lHJXGMj>R GD>DGo9;oF2 diff --git a/mobile/openapi/lib/api/timeline_api.dart b/mobile/openapi/lib/api/timeline_api.dart index 70ac076c9dea13379fdc3fd5df2bf74b537a0da5..2afcea20ff18283c91ad6a57af08961f9e2ce687 100644 GIT binary patch delta 358 zcmdm!vMzPQI>u1<)Dne~%-mFkq|)T<)DkWQ1$}*e2&oX1T2hpmT9&Gis89@K<)tg+ zrzs@n z)S}$X;^NHwyvfqiIh*sDHt~|9cY%f>P_G>8=A)u~tYjFlSz6kb9E&$E(BR_&0BfLI Apa1{> diff --git a/mobile/openapi/lib/api/trash_api.dart b/mobile/openapi/lib/api/trash_api.dart index 480d19960aab67f0414aea4b7aae8d05497aeb44..f1dcbb88960fe21452f5ef94f4575f4bcc95bc4c 100644 GIT binary patch delta 441 zcmX@F-mS4=1*4;DZb3<Zw%}FguRY=Uq zQOGPw%`H~Q%u^`INQLOye21}!$%$fP^d<{%%Whu4a)8M(D7CmGzX)hwadB!%F^a2T zQpE+S$(d=H$xt;4X+`YF zLP2U#Zf0?DW`5q}2EKsJmP|@aQa`om0 NzA`fH)DyhR1OOJxi@yK> diff --git a/mobile/openapi/lib/api/users_admin_api.dart b/mobile/openapi/lib/api/users_admin_api.dart index 4a4301ff430278e2e9ad42b1c3fea523e3da1075..842a3ebc5b674ffca0f17034361f5111496227c3 100644 GIT binary patch delta 1515 zcmcaRmvQSX#toYowVjJn6H8JR5*12|Q;WD16!i7=A*2FaCNH%dEIaw3T*~AEcb3WX z?O7+UVl|$;R*-A+2Bs1wk_>TVO5J>yRf$>MB{e4%yUi#vlLhT3Z+^!4kcnswitfQ+ zCqCmeo_v>8eDhvjDQ3r@)RLmi)H19-h06hhp|~J5IWsLY8SG<)q)LU7jMU5`1y2{C z@276wC+NvU1)~g&6E^P@xycj=w;2@r3I#=}X{kl2dC958C@}$71#}CtB8B`kbQgnN zSt*e~3!@EoCCi9#`46*kub6KB`t zb7~xu*J#I2&X5qCtfj-h*+l(3P3%&1_XpXvd5!ibW|yGU;*$I#P;yQI=c5$N42)0$ zOju=^`K84 zZEj~OVWN#K0pgmQ{aNFfsbG3aYECMKAG&~k;M|nkM^%XX7mKIU#C(wZ&wI*F zUMw!Y`G(XJrcjFFAUGAA_VsW@!(K&?H_9EPqlX+)E2mFlzuv n>8WdXj~d~Q#Rg#Mxw+pllXmXkeBM=tMy5BoPTzdqGmRMlb*#=D diff --git a/mobile/openapi/lib/api/users_api.dart b/mobile/openapi/lib/api/users_api.dart index c8891ba0c22cd0bde396b4c22eb8cc173fc721f6..f398d9c8133f9e6df0b5508ad62e8d7409b0afad 100644 GIT binary patch literal 24385 zcmeHPZFAc;68^4Vf%Zcs-zZYAb00cxVxJq!sppc|b>!*XcswdBLKYf|WI-^lF5~~+ zT>vBjiIk{_a^)T~6Wb(!#oM#{;ANNneyiUnC)dM^7jFjd2UjP>=s(+l$c zVo2UyoSvWk_bbSTIsffZAzyvh`{(y9eB}2*DA;HciqVAo?2sfu5;Jead^Tf&?559r z7KK6MGl!yuM4kR$Fvg?z%9P{rfI z%6uNMc;tt{J!F$p8jQaGb~K(+5w}`Uoh0Fegb@p9#C!1nhgPdK_GuiG>lm7G5^?gm zMY4y^4ZL~nbEx>3Kz9A-?EyK=pU5lg@8e_Qu?bClnH7X82$}GJ`Xqaomr$vF80go6 zQOO7lt{{;Jaj*%W(R&7^Azl9@*O4DmkI=v)F_VOnfIYa`2}~7{Q%1YTQVvF8YR zA4-_W;grV&Mt>T5L@=3%AXepm8V)bX%@vCy77Ryfi^5Vm=-6hw8_h9;C)-mIJaG(qG3F#;_eD#V1iSHkn z*&|MEQY5A_LS|79)EruIBidN9eT&V3KlE!Y)@1Wp+@qeSYA_W(s{UZLS$Fa}(-{Ma zvq(#N)B~WEAXm*E4?cw-*~#U3M+qdDgaGQAN7HljWX*b-A+0NYwkJG&m(OeZ#-6<% zj|a0z&dISFI1xjVazuY8f<7XR!)JUAl@VLlOtTzr?7lpB7 zFx~Wla=FgtAj-NHaMSWV;2@dAuS1WKqgMoN)CcvZcSk*=3OUH+RD=&`?gxL2S%h{7 zETJ~2mY}X_651<}i+1G4xnyycH`O2wXs~v_Oj!U%U$7aNa9{xO3D_bv-a$z2Km>UJ z8w#0pgOTsP`}SX5@&Ng#)b~jcO5iB0kZ_6CT^YO+sf@qmGloST1eaio;2n><rYpbt?J{ObwOUNRS8YgcNfnKTO*K zl9)nztgN7J80v5~aM(G}2VgI)65o6SU0)hh0#?SFogjRzjbT1Hsh%r1fJ$pp?|BTy zlT)AnkDVaLbTnSdC#Or=D{`sIPih4gQj zO|KzvQfgikERngVT4?vvA@hd0XBHPbB(J6)v?~VdRKnay(kfdD-VC;DN$Pa)b}$^Y zQ+C-an%WJj4KzQ6+&cpEf{J6qvg1OrgeR8Exp3B+>lmoNnj*@Kg_n#a`N-w~pnNA` zh90egVD~(RT^JZ}uo`LZU2G&uj0Wz#-tsYn{f0ZpHLvz(tnce;{`O1#{||$aVznk@ z7Z?r;nw!`StC)-E=VCU(;4Y-XgEd;&*ycH`rRLKtGH`S+vIe>XT))Z4JK9){^1bkL zS!U$3xizp$%temOO)W-V(#7;X8;v(`3^|*d^EVcZ86J@3%Zw`q+d1}$sqKe8q*Ixm zWOZ@RVqrPDf=p_m>oFW_uwfZoRkuJ z7bf~NG6BUQGx|}VL^1+L@vvD{*ADKr)W$bjOB+$8P}p5plWOOPh8LbGFYE}z7Db$R zGaeL>1EO*RR#*mcLkG=mMwQzPM9v}zEh1PnsbV&3j8d<_W`^T$J%x8ZjL8iT#)nAy(6imm0_8RE>ncM zo!-E&PO(lyM`{E%zp~$dI;uq_wjdvb^3qlbUw#4YEU869H;o5aRS&QQAX?ic3!a-( zPGWXSg%{k}qHy`t41DW=ewH1;(bZNt4i4nypLYOnCkWosUA2LG0 zgSR}-6Z-YQ?jO~s%mJeIYnXoC%jQPr8Q#cbh*iXqPiFBZeIr;KX2_vfNDg`OM*NT$ zYbZjw1T_IC8wH%?__0uFSfVhkGEuz2a8iitL4_)D;iAL`KXHsD$ua_4sA+^k5F1qY zMj~cZjHgHpv8yii@h~-N}nx$7quoti(Sk2H|1zgN(P28)1k;W;j zu9!miQVSzFvw+j`078ujVgfjcx!qV1ktmGkAj*g6!?$3KmoVGL=q7?m2j={pklvUU z9SGG6WB^#PbeEyJwfp@nsrK6QcvC@ae@Jb)`*?3>-x zf7l#6FmHj=RN#?*TzAzEA6-BrVMI6z?ud1z)_(V2OCS><)am;(`Gx_FB51a973}{O zhk^Ql!53b%Twd>~C-UxeYQ?3CgWyVvVMsVLLdk&YwPMcjg3xJEQHpeu9^fPg`R zT6Y^CfhKIfTG;+FY_~sXyN=*%D(3q=VHTU_@Sw@E(P>1^XdC-D=S5fOe7|DWW)sh_j zh2)qgck(~i>B(w-%;h+07-qHz#5WY#P-HcV%+X}wx0ZuOqsJ>^MlGJSA}V+A4Vy{~ ziTgb(dQUeFbm>-YdW%xl@n)iy3gwZhWi^&oxC=hDMt(a&#iN0uQEIq#@3?gbI=O;W z%V55#VlBwA>=kTA3v{isP$1Ljs`^#J!v$42OkAc24JkLIT#b|$fNLS$Fmri^%J+a; z8_Gj=O*(F3?U2YUOqWe-4AZSl(7ILcSjNlNi>h>tgXbtLzOdya?(+^XoaOis-!PSwMr-;b|>i30tT-}8u1 zwikS3OUMcSc}e++MJbti>DXLRC)CD7nGs-zQ=T`Hz?Z6D5Xhu8`zlHYDT<>~^cm$}*9zb@Ocb7lcC(C9h!k9F$Y;Y3goHQ;wk2 zC}17|8l|u~Qtcrbo&n|A&G$6($>4XadiW3q$rZ8xzVSSnAZxbrBq7X#~cO?&N0?Mw6Gxi%6Zz20=2G? zD|SB!mf9wMvx3x`X#=?nnE%5gcmBXry>Cu>Gv7+v$6C!@l)fGsUiomtTmM^hHaZh0ylmGw# delta 197 zcmZ24zfNX@4kM3aL8d}Amx4lAW@`ClE5DL26NANoIZ?P*I9PQEEwPQC_h^Nk*zdbWmz>L4ICwYOLO7U#7!M rlS7znH}7LjXZ9j&u6}7=W?^ZnZb4#6Mll{sHgD$)W7=HKW5Emn;Kf8t diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index ed3d7a0ba..c6dc9061e 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -3,6 +3,7 @@ "paths": { "/activities": { "get": { + "description": "Returns a list of activities for the selected asset or album. The activities are returned in sorted order, with the oldest activities appearing first.", "operationId": "getActivities", "parameters": [ { @@ -75,13 +76,14 @@ "api_key": [] } ], + "summary": "List all activities", "tags": [ "Activities" ], - "x-immich-permission": "activity.read", - "description": "This endpoint requires the `activity.read` permission." + "x-immich-permission": "activity.read" }, "post": { + "description": "Create a like or a comment for an album, or an asset in an album.", "operationId": "createActivity", "parameters": [], "requestBody": { @@ -117,15 +119,16 @@ "api_key": [] } ], + "summary": "Create an activity", "tags": [ "Activities" ], - "x-immich-permission": "activity.create", - "description": "This endpoint requires the `activity.create` permission." + "x-immich-permission": "activity.create" } }, "/activities/statistics": { "get": { + "description": "Returns the number of likes and comments for a given album or asset in an album.", "operationId": "getActivityStatistics", "parameters": [ { @@ -170,15 +173,16 @@ "api_key": [] } ], + "summary": "Retrieve activity statistics", "tags": [ "Activities" ], - "x-immich-permission": "activity.statistics", - "description": "This endpoint requires the `activity.statistics` permission." + "x-immich-permission": "activity.statistics" } }, "/activities/{id}": { "delete": { + "description": "Removes a like or comment from a given album or asset in an album.", "operationId": "deleteActivity", "parameters": [ { @@ -207,15 +211,16 @@ "api_key": [] } ], + "summary": "Delete an activity", "tags": [ "Activities" ], - "x-immich-permission": "activity.delete", - "description": "This endpoint requires the `activity.delete` permission." + "x-immich-permission": "activity.delete" } }, "/admin/auth/unlink-all": { "post": { + "description": "Unlinks all OAuth accounts associated with user accounts in the system.", "operationId": "unlinkAllOAuthAccountsAdmin", "parameters": [], "responses": { @@ -234,16 +239,17 @@ "api_key": [] } ], + "summary": "Unlink all OAuth accounts", "tags": [ - "Auth (admin)" + "Authentication (admin)" ], "x-immich-admin-only": true, - "x-immich-permission": "adminAuth.unlinkAll", - "description": "This endpoint is an admin-only route, and requires the `adminAuth.unlinkAll` permission." + "x-immich-permission": "adminAuth.unlinkAll" } }, "/admin/notifications": { "post": { + "description": "Create a new notification for a specific user.", "operationId": "createNotification", "parameters": [], "requestBody": { @@ -279,14 +285,16 @@ "api_key": [] } ], + "summary": "Create a notification", "tags": [ - "Notifications (Admin)" + "Notifications (admin)" ], "x-immich-admin-only": true } }, "/admin/notifications/templates/{name}": { "post": { + "description": "Retrieve a preview of the provided email template.", "operationId": "getNotificationTemplateAdmin", "parameters": [ { @@ -331,14 +339,16 @@ "api_key": [] } ], + "summary": "Render email template", "tags": [ - "Notifications (Admin)" + "Notifications (admin)" ], "x-immich-admin-only": true } }, "/admin/notifications/test-email": { "post": { + "description": "Send a test email using the provided SMTP configuration.", "operationId": "sendTestEmailAdmin", "parameters": [], "requestBody": { @@ -374,14 +384,16 @@ "api_key": [] } ], + "summary": "Send test email", "tags": [ - "Notifications (Admin)" + "Notifications (admin)" ], "x-immich-admin-only": true } }, "/admin/users": { "get": { + "description": "Search for users.", "operationId": "searchUsersAdmin", "parameters": [ { @@ -428,14 +440,15 @@ "api_key": [] } ], + "summary": "Search users", "tags": [ "Users (admin)" ], "x-immich-admin-only": true, - "x-immich-permission": "adminUser.read", - "description": "This endpoint is an admin-only route, and requires the `adminUser.read` permission." + "x-immich-permission": "adminUser.read" }, "post": { + "description": "Create a new user.", "operationId": "createUserAdmin", "parameters": [], "requestBody": { @@ -471,16 +484,17 @@ "api_key": [] } ], + "summary": "Create a user", "tags": [ "Users (admin)" ], "x-immich-admin-only": true, - "x-immich-permission": "adminUser.create", - "description": "This endpoint is an admin-only route, and requires the `adminUser.create` permission." + "x-immich-permission": "adminUser.create" } }, "/admin/users/{id}": { "delete": { + "description": "Delete a user.", "operationId": "deleteUserAdmin", "parameters": [ { @@ -526,14 +540,15 @@ "api_key": [] } ], + "summary": "Delete a user", "tags": [ "Users (admin)" ], "x-immich-admin-only": true, - "x-immich-permission": "adminUser.delete", - "description": "This endpoint is an admin-only route, and requires the `adminUser.delete` permission." + "x-immich-permission": "adminUser.delete" }, "get": { + "description": "Retrieve a specific user by their ID.", "operationId": "getUserAdmin", "parameters": [ { @@ -569,14 +584,15 @@ "api_key": [] } ], + "summary": "Retrieve a user", "tags": [ "Users (admin)" ], "x-immich-admin-only": true, - "x-immich-permission": "adminUser.read", - "description": "This endpoint is an admin-only route, and requires the `adminUser.read` permission." + "x-immich-permission": "adminUser.read" }, "put": { + "description": "Update an existing user.", "operationId": "updateUserAdmin", "parameters": [ { @@ -622,16 +638,17 @@ "api_key": [] } ], + "summary": "Update a user", "tags": [ "Users (admin)" ], "x-immich-admin-only": true, - "x-immich-permission": "adminUser.update", - "description": "This endpoint is an admin-only route, and requires the `adminUser.update` permission." + "x-immich-permission": "adminUser.update" } }, "/admin/users/{id}/preferences": { "get": { + "description": "Retrieve the preferences of a specific user.", "operationId": "getUserPreferencesAdmin", "parameters": [ { @@ -667,14 +684,15 @@ "api_key": [] } ], + "summary": "Retrieve user preferences", "tags": [ "Users (admin)" ], "x-immich-admin-only": true, - "x-immich-permission": "adminUser.read", - "description": "This endpoint is an admin-only route, and requires the `adminUser.read` permission." + "x-immich-permission": "adminUser.read" }, "put": { + "description": "Update the preferences of a specific user.", "operationId": "updateUserPreferencesAdmin", "parameters": [ { @@ -720,16 +738,17 @@ "api_key": [] } ], + "summary": "Update user preferences", "tags": [ "Users (admin)" ], "x-immich-admin-only": true, - "x-immich-permission": "adminUser.update", - "description": "This endpoint is an admin-only route, and requires the `adminUser.update` permission." + "x-immich-permission": "adminUser.update" } }, "/admin/users/{id}/restore": { "post": { + "description": "Restore a previously deleted user.", "operationId": "restoreUserAdmin", "parameters": [ { @@ -765,16 +784,17 @@ "api_key": [] } ], + "summary": "Restore a deleted user", "tags": [ "Users (admin)" ], "x-immich-admin-only": true, - "x-immich-permission": "adminUser.delete", - "description": "This endpoint is an admin-only route, and requires the `adminUser.delete` permission." + "x-immich-permission": "adminUser.delete" } }, "/admin/users/{id}/sessions": { "get": { + "description": "Retrieve all sessions for a specific user.", "operationId": "getUserSessionsAdmin", "parameters": [ { @@ -813,16 +833,17 @@ "api_key": [] } ], + "summary": "Retrieve user sessions", "tags": [ "Users (admin)" ], "x-immich-admin-only": true, - "x-immich-permission": "adminSession.read", - "description": "This endpoint is an admin-only route, and requires the `adminSession.read` permission." + "x-immich-permission": "adminSession.read" } }, "/admin/users/{id}/statistics": { "get": { + "description": "Retrieve asset statistics for a specific user.", "operationId": "getUserStatisticsAdmin", "parameters": [ { @@ -882,16 +903,17 @@ "api_key": [] } ], + "summary": "Retrieve user statistics", "tags": [ "Users (admin)" ], "x-immich-admin-only": true, - "x-immich-permission": "adminUser.read", - "description": "This endpoint is an admin-only route, and requires the `adminUser.read` permission." + "x-immich-permission": "adminUser.read" } }, "/albums": { "get": { + "description": "Retrieve a list of albums available to the authenticated user.", "operationId": "getAllAlbums", "parameters": [ { @@ -939,13 +961,14 @@ "api_key": [] } ], + "summary": "List all albums", "tags": [ "Albums" ], - "x-immich-permission": "album.read", - "description": "This endpoint requires the `album.read` permission." + "x-immich-permission": "album.read" }, "post": { + "description": "Create a new album. The album can also be created with initial users and assets.", "operationId": "createAlbum", "parameters": [], "requestBody": { @@ -981,15 +1004,16 @@ "api_key": [] } ], + "summary": "Create an album", "tags": [ "Albums" ], - "x-immich-permission": "album.create", - "description": "This endpoint requires the `album.create` permission." + "x-immich-permission": "album.create" } }, "/albums/assets": { "put": { + "description": "Send a list of asset IDs and album IDs to add each asset to each album.", "operationId": "addAssetsToAlbums", "parameters": [ { @@ -1042,15 +1066,16 @@ "api_key": [] } ], + "summary": "Add assets to albums", "tags": [ "Albums" ], - "x-immich-permission": "albumAsset.create", - "description": "This endpoint requires the `albumAsset.create` permission." + "x-immich-permission": "albumAsset.create" } }, "/albums/statistics": { "get": { + "description": "Returns statistics about the albums available to the authenticated user.", "operationId": "getAlbumStatistics", "parameters": [], "responses": { @@ -1076,15 +1101,16 @@ "api_key": [] } ], + "summary": "Retrieve album statistics", "tags": [ "Albums" ], - "x-immich-permission": "album.statistics", - "description": "This endpoint requires the `album.statistics` permission." + "x-immich-permission": "album.statistics" } }, "/albums/{id}": { "delete": { + "description": "Delete a specific album by its ID. Note the album is initially trashed and then immediately scheduled for deletion, but relies on a background job to complete the process.", "operationId": "deleteAlbum", "parameters": [ { @@ -1113,13 +1139,14 @@ "api_key": [] } ], + "summary": "Delete an album", "tags": [ "Albums" ], - "x-immich-permission": "album.delete", - "description": "This endpoint requires the `album.delete` permission." + "x-immich-permission": "album.delete" }, "get": { + "description": "Retrieve information about a specific album by its ID.", "operationId": "getAlbumInfo", "parameters": [ { @@ -1179,13 +1206,14 @@ "api_key": [] } ], + "summary": "Retrieve an album", "tags": [ "Albums" ], - "x-immich-permission": "album.read", - "description": "This endpoint requires the `album.read` permission." + "x-immich-permission": "album.read" }, "patch": { + "description": "Update the information of a specific album by its ID. This endpoint can be used to update the album name, description, sort order, etc. However, it is not used to add or remove assets or users from the album.", "operationId": "updateAlbumInfo", "parameters": [ { @@ -1231,15 +1259,16 @@ "api_key": [] } ], + "summary": "Update an album", "tags": [ "Albums" ], - "x-immich-permission": "album.update", - "description": "This endpoint requires the `album.update` permission." + "x-immich-permission": "album.update" } }, "/albums/{id}/assets": { "delete": { + "description": "Remove multiple assets from a specific album by its ID.", "operationId": "removeAssetFromAlbum", "parameters": [ { @@ -1288,13 +1317,14 @@ "api_key": [] } ], + "summary": "Remove assets from an album", "tags": [ "Albums" ], - "x-immich-permission": "albumAsset.delete", - "description": "This endpoint requires the `albumAsset.delete` permission." + "x-immich-permission": "albumAsset.delete" }, "put": { + "description": "Add multiple assets to a specific album by its ID.", "operationId": "addAssetsToAlbum", "parameters": [ { @@ -1359,15 +1389,16 @@ "api_key": [] } ], + "summary": "Add assets to an album", "tags": [ "Albums" ], - "x-immich-permission": "albumAsset.create", - "description": "This endpoint requires the `albumAsset.create` permission." + "x-immich-permission": "albumAsset.create" } }, "/albums/{id}/user/{userId}": { "delete": { + "description": "Remove a user from an album. Use an ID of \"me\" to leave a shared album.", "operationId": "removeUserFromAlbum", "parameters": [ { @@ -1404,13 +1435,14 @@ "api_key": [] } ], + "summary": "Remove user from album", "tags": [ "Albums" ], - "x-immich-permission": "albumUser.delete", - "description": "This endpoint requires the `albumUser.delete` permission." + "x-immich-permission": "albumUser.delete" }, "put": { + "description": "Change the role for a specific user in a specific album.", "operationId": "updateAlbumUser", "parameters": [ { @@ -1457,15 +1489,16 @@ "api_key": [] } ], + "summary": "Update user role", "tags": [ "Albums" ], - "x-immich-permission": "albumUser.update", - "description": "This endpoint requires the `albumUser.update` permission." + "x-immich-permission": "albumUser.update" } }, "/albums/{id}/users": { "put": { + "description": "Share an album with multiple users. Each user can be given a specific role in the album.", "operationId": "addUsersToAlbum", "parameters": [ { @@ -1511,15 +1544,16 @@ "api_key": [] } ], + "summary": "Share album with users", "tags": [ "Albums" ], - "x-immich-permission": "albumUser.create", - "description": "This endpoint requires the `albumUser.create` permission." + "x-immich-permission": "albumUser.create" } }, "/api-keys": { "get": { + "description": "Retrieve all API keys of the current user.", "operationId": "getApiKeys", "parameters": [], "responses": { @@ -1548,13 +1582,14 @@ "api_key": [] } ], + "summary": "List all API keys", "tags": [ - "API Keys" + "API keys" ], - "x-immich-permission": "apiKey.read", - "description": "This endpoint requires the `apiKey.read` permission." + "x-immich-permission": "apiKey.read" }, "post": { + "description": "Creates a new API key. It will be limited to the permissions specified.", "operationId": "createApiKey", "parameters": [], "requestBody": { @@ -1590,15 +1625,16 @@ "api_key": [] } ], + "summary": "Create an API key", "tags": [ - "API Keys" + "API keys" ], - "x-immich-permission": "apiKey.create", - "description": "This endpoint requires the `apiKey.create` permission." + "x-immich-permission": "apiKey.create" } }, "/api-keys/me": { "get": { + "description": "Retrieve the API key that is used to access this endpoint.", "operationId": "getMyApiKey", "parameters": [], "responses": { @@ -1624,13 +1660,15 @@ "api_key": [] } ], + "summary": "Retrieve the current API key", "tags": [ - "API Keys" + "API keys" ] } }, "/api-keys/{id}": { "delete": { + "description": "Deletes an API key identified by its ID. The current user must own this API key.", "operationId": "deleteApiKey", "parameters": [ { @@ -1659,13 +1697,14 @@ "api_key": [] } ], + "summary": "Delete an API key", "tags": [ - "API Keys" + "API keys" ], - "x-immich-permission": "apiKey.delete", - "description": "This endpoint requires the `apiKey.delete` permission." + "x-immich-permission": "apiKey.delete" }, "get": { + "description": "Retrieve an API key by its ID. The current user must own this API key.", "operationId": "getApiKey", "parameters": [ { @@ -1701,13 +1740,14 @@ "api_key": [] } ], + "summary": "Retrieve an API key", "tags": [ - "API Keys" + "API keys" ], - "x-immich-permission": "apiKey.read", - "description": "This endpoint requires the `apiKey.read` permission." + "x-immich-permission": "apiKey.read" }, "put": { + "description": "Updates the name and permissions of an API key by its ID. The current user must own this API key.", "operationId": "updateApiKey", "parameters": [ { @@ -1753,15 +1793,16 @@ "api_key": [] } ], + "summary": "Update an API key", "tags": [ - "API Keys" + "API keys" ], - "x-immich-permission": "apiKey.update", - "description": "This endpoint requires the `apiKey.update` permission." + "x-immich-permission": "apiKey.update" } }, "/assets": { "delete": { + "description": "Deletes multiple assets at the same time.", "operationId": "deleteAssets", "parameters": [], "requestBody": { @@ -1790,13 +1831,14 @@ "api_key": [] } ], + "summary": "Delete assets", "tags": [ "Assets" ], - "x-immich-permission": "asset.delete", - "description": "This endpoint requires the `asset.delete` permission." + "x-immich-permission": "asset.delete" }, "post": { + "description": "Uploads a new asset to the server.", "operationId": "uploadAsset", "parameters": [ { @@ -1859,13 +1901,14 @@ "api_key": [] } ], + "summary": "Upload asset", "tags": [ "Assets" ], - "x-immich-permission": "asset.upload", - "description": "This endpoint requires the `asset.upload` permission." + "x-immich-permission": "asset.upload" }, "put": { + "description": "Updates multiple assets at the same time.", "operationId": "updateAssets", "parameters": [], "requestBody": { @@ -1894,16 +1937,16 @@ "api_key": [] } ], + "summary": "Update assets", "tags": [ "Assets" ], - "x-immich-permission": "asset.update", - "description": "This endpoint requires the `asset.update` permission." + "x-immich-permission": "asset.update" } }, "/assets/bulk-upload-check": { "post": { - "description": "Checks if assets exist by checksums. This endpoint requires the `asset.upload` permission.", + "description": "Determine which assets have already been uploaded to the server based on their SHA1 checksums.", "operationId": "checkBulkUpload", "parameters": [], "requestBody": { @@ -1939,7 +1982,7 @@ "api_key": [] } ], - "summary": "checkBulkUpload", + "summary": "Check bulk upload", "tags": [ "Assets" ], @@ -1948,6 +1991,7 @@ }, "/assets/copy": { "put": { + "description": "Copy asset information like albums, tags, etc. from one asset to another.", "operationId": "copyAsset", "parameters": [], "requestBody": { @@ -1976,16 +2020,17 @@ "api_key": [] } ], + "summary": "Copy asset", "tags": [ "Assets" ], - "x-immich-permission": "asset.copy", - "description": "This endpoint requires the `asset.copy` permission." + "x-immich-permission": "asset.copy" } }, "/assets/device/{deviceId}": { "get": { - "description": "Get all asset of a device that are in the database, ID only.", + "deprecated": true, + "description": "This property was deprecated in v2.0.0. Get all asset of a device that are in the database, ID only.", "operationId": "getAllUserAssetsByDeviceId", "parameters": [ { @@ -2023,10 +2068,14 @@ "api_key": [] } ], - "summary": "getAllUserAssetsByDeviceId", + "summary": "Retrieve assets by device ID", "tags": [ - "Assets" - ] + "Assets", + "Deprecated" + ], + "x-immich-lifecycle": { + "deprecatedAt": "v2.0.0" + } } }, "/assets/exist": { @@ -2067,7 +2116,7 @@ "api_key": [] } ], - "summary": "checkExistingAssets", + "summary": "Check existing assets", "tags": [ "Assets" ] @@ -2075,6 +2124,7 @@ }, "/assets/jobs": { "post": { + "description": "Run a specific job on a set of assets.", "operationId": "runAssetJobs", "parameters": [], "requestBody": { @@ -2103,6 +2153,7 @@ "api_key": [] } ], + "summary": "Run an asset job", "tags": [ "Assets" ] @@ -2111,7 +2162,7 @@ "/assets/random": { "get": { "deprecated": true, - "description": "This property was deprecated in v1.116.0. This endpoint requires the `asset.read` permission.", + "description": "This property was deprecated in v1.116.0. Retrieve a specified number of random assets for the authenticated user.", "operationId": "getRandom", "parameters": [ { @@ -2150,6 +2201,7 @@ "api_key": [] } ], + "summary": "Get random assets", "tags": [ "Assets", "Deprecated" @@ -2162,6 +2214,7 @@ }, "/assets/statistics": { "get": { + "description": "Retrieve various statistics about the assets owned by the authenticated user.", "operationId": "getAssetStatistics", "parameters": [ { @@ -2212,15 +2265,16 @@ "api_key": [] } ], + "summary": "Get asset statistics", "tags": [ "Assets" ], - "x-immich-permission": "asset.statistics", - "description": "This endpoint requires the `asset.statistics` permission." + "x-immich-permission": "asset.statistics" } }, "/assets/{id}": { "get": { + "description": "Retrieve detailed information about a specific asset.", "operationId": "getAssetInfo", "parameters": [ { @@ -2272,13 +2326,14 @@ "api_key": [] } ], + "summary": "Retrieve an asset", "tags": [ "Assets" ], - "x-immich-permission": "asset.read", - "description": "This endpoint requires the `asset.read` permission." + "x-immich-permission": "asset.read" }, "put": { + "description": "Update information of a specific asset.", "operationId": "updateAsset", "parameters": [ { @@ -2324,15 +2379,16 @@ "api_key": [] } ], + "summary": "Update an asset", "tags": [ "Assets" ], - "x-immich-permission": "asset.update", - "description": "This endpoint requires the `asset.update` permission." + "x-immich-permission": "asset.update" } }, "/assets/{id}/metadata": { "get": { + "description": "Retrieve all metadata key-value pairs associated with the specified asset.", "operationId": "getAssetMetadata", "parameters": [ { @@ -2371,13 +2427,14 @@ "api_key": [] } ], + "summary": "Get asset metadata", "tags": [ "Assets" ], - "x-immich-permission": "asset.read", - "description": "This endpoint requires the `asset.read` permission." + "x-immich-permission": "asset.read" }, "put": { + "description": "Update or add metadata key-value pairs for the specified asset.", "operationId": "updateAssetMetadata", "parameters": [ { @@ -2426,15 +2483,16 @@ "api_key": [] } ], + "summary": "Update asset metadata", "tags": [ "Assets" ], - "x-immich-permission": "asset.update", - "description": "This endpoint requires the `asset.update` permission." + "x-immich-permission": "asset.update" } }, "/assets/{id}/metadata/{key}": { "delete": { + "description": "Delete a specific metadata key-value pair associated with the specified asset.", "operationId": "deleteAssetMetadata", "parameters": [ { @@ -2471,13 +2529,14 @@ "api_key": [] } ], + "summary": "Delete asset metadata by key", "tags": [ "Assets" ], - "x-immich-permission": "asset.update", - "description": "This endpoint requires the `asset.update` permission." + "x-immich-permission": "asset.update" }, "get": { + "description": "Retrieve the value of a specific metadata key associated with the specified asset.", "operationId": "getAssetMetadataByKey", "parameters": [ { @@ -2521,15 +2580,16 @@ "api_key": [] } ], + "summary": "Retrieve asset metadata by key", "tags": [ "Assets" ], - "x-immich-permission": "asset.read", - "description": "This endpoint requires the `asset.read` permission." + "x-immich-permission": "asset.read" } }, "/assets/{id}/ocr": { "get": { + "description": "Retrieve all OCR (Optical Character Recognition) data associated with the specified asset.", "operationId": "getAssetOcr", "parameters": [ { @@ -2568,15 +2628,16 @@ "api_key": [] } ], + "summary": "Retrieve asset OCR data", "tags": [ "Assets" ], - "x-immich-permission": "asset.read", - "description": "This endpoint requires the `asset.read` permission." + "x-immich-permission": "asset.read" } }, "/assets/{id}/original": { "get": { + "description": "Downloads the original file of the specified asset.", "operationId": "downloadAsset", "parameters": [ { @@ -2629,15 +2690,15 @@ "api_key": [] } ], + "summary": "Download original asset", "tags": [ "Assets" ], - "x-immich-permission": "asset.download", - "description": "This endpoint requires the `asset.download` permission." + "x-immich-permission": "asset.download" }, "put": { "deprecated": true, - "description": "This property was deprecated in v1.142.0. Replace the asset with new file, without changing its id. This endpoint requires the `asset.replace` permission.", + "description": "This property was deprecated in v1.142.0. Replace the asset with new file, without changing its id.", "operationId": "replaceAsset", "parameters": [ { @@ -2699,7 +2760,7 @@ "api_key": [] } ], - "summary": "Replace the asset with new file, without changing its id", + "summary": "Replace asset", "tags": [ "Assets", "Deprecated" @@ -2713,6 +2774,7 @@ }, "/assets/{id}/thumbnail": { "get": { + "description": "Retrieve the thumbnail image for the specified asset.", "operationId": "viewAsset", "parameters": [ { @@ -2773,15 +2835,16 @@ "api_key": [] } ], + "summary": "View asset thumbnail", "tags": [ "Assets" ], - "x-immich-permission": "asset.view", - "description": "This endpoint requires the `asset.view` permission." + "x-immich-permission": "asset.view" } }, "/assets/{id}/video/playback": { "get": { + "description": "Streams the video file for the specified asset. This endpoint also supports byte range requests.", "operationId": "playAssetVideo", "parameters": [ { @@ -2834,15 +2897,16 @@ "api_key": [] } ], + "summary": "Play asset video", "tags": [ "Assets" ], - "x-immich-permission": "asset.view", - "description": "This endpoint requires the `asset.view` permission." + "x-immich-permission": "asset.view" } }, "/auth/admin-sign-up": { "post": { + "description": "Create the first admin user in the system.", "operationId": "signUpAdmin", "parameters": [], "requestBody": { @@ -2867,6 +2931,7 @@ "description": "" } }, + "summary": "Register admin", "tags": [ "Authentication" ] @@ -2874,6 +2939,7 @@ }, "/auth/change-password": { "post": { + "description": "Change the password of the current user.", "operationId": "changePassword", "parameters": [], "requestBody": { @@ -2909,15 +2975,16 @@ "api_key": [] } ], + "summary": "Change password", "tags": [ "Authentication" ], - "x-immich-permission": "auth.changePassword", - "description": "This endpoint requires the `auth.changePassword` permission." + "x-immich-permission": "auth.changePassword" } }, "/auth/login": { "post": { + "description": "Login with username and password and receive a session token.", "operationId": "login", "parameters": [], "requestBody": { @@ -2942,6 +3009,7 @@ "description": "" } }, + "summary": "Login", "tags": [ "Authentication" ] @@ -2949,6 +3017,7 @@ }, "/auth/logout": { "post": { + "description": "Logout the current user and invalidate the session token.", "operationId": "logout", "parameters": [], "responses": { @@ -2974,6 +3043,7 @@ "api_key": [] } ], + "summary": "Logout", "tags": [ "Authentication" ] @@ -2981,6 +3051,7 @@ }, "/auth/pin-code": { "delete": { + "description": "Reset the pin code for the current user by providing the account password", "operationId": "resetPinCode", "parameters": [], "requestBody": { @@ -3009,13 +3080,14 @@ "api_key": [] } ], + "summary": "Reset pin code", "tags": [ "Authentication" ], - "x-immich-permission": "pinCode.delete", - "description": "This endpoint requires the `pinCode.delete` permission." + "x-immich-permission": "pinCode.delete" }, "post": { + "description": "Setup a new pin code for the current user.", "operationId": "setupPinCode", "parameters": [], "requestBody": { @@ -3044,13 +3116,14 @@ "api_key": [] } ], + "summary": "Setup pin code", "tags": [ "Authentication" ], - "x-immich-permission": "pinCode.create", - "description": "This endpoint requires the `pinCode.create` permission." + "x-immich-permission": "pinCode.create" }, "put": { + "description": "Change the pin code for the current user.", "operationId": "changePinCode", "parameters": [], "requestBody": { @@ -3079,15 +3152,16 @@ "api_key": [] } ], + "summary": "Change pin code", "tags": [ "Authentication" ], - "x-immich-permission": "pinCode.update", - "description": "This endpoint requires the `pinCode.update` permission." + "x-immich-permission": "pinCode.update" } }, "/auth/session/lock": { "post": { + "description": "Remove elevated access to locked assets from the current session.", "operationId": "lockAuthSession", "parameters": [], "responses": { @@ -3106,6 +3180,7 @@ "api_key": [] } ], + "summary": "Lock auth session", "tags": [ "Authentication" ] @@ -3113,6 +3188,7 @@ }, "/auth/session/unlock": { "post": { + "description": "Temporarily grant the session elevated access to locked assets by providing the correct PIN code.", "operationId": "unlockAuthSession", "parameters": [], "requestBody": { @@ -3141,6 +3217,7 @@ "api_key": [] } ], + "summary": "Unlock auth session", "tags": [ "Authentication" ] @@ -3148,6 +3225,7 @@ }, "/auth/status": { "get": { + "description": "Get information about the current session, including whether the user has a password, and if the session can access locked assets.", "operationId": "getAuthStatus", "parameters": [], "responses": { @@ -3173,6 +3251,7 @@ "api_key": [] } ], + "summary": "Retrieve auth status", "tags": [ "Authentication" ] @@ -3180,6 +3259,7 @@ }, "/auth/validateToken": { "post": { + "description": "Validate the current authorization method is still valid.", "operationId": "validateAccessToken", "parameters": [], "responses": { @@ -3205,6 +3285,7 @@ "api_key": [] } ], + "summary": "Validate access token", "tags": [ "Authentication" ] @@ -3212,6 +3293,7 @@ }, "/download/archive": { "post": { + "description": "Download a ZIP archive containing the specified assets. The assets must have been previously requested via the \"getDownloadInfo\" endpoint.", "operationId": "downloadArchive", "parameters": [ { @@ -3265,15 +3347,16 @@ "api_key": [] } ], + "summary": "Download asset archive", "tags": [ "Download" ], - "x-immich-permission": "asset.download", - "description": "This endpoint requires the `asset.download` permission." + "x-immich-permission": "asset.download" } }, "/download/info": { "post": { + "description": "Retrieve information about how to request a download for the specified assets or album. The response includes groups of assets that can be downloaded together.", "operationId": "getDownloadInfo", "parameters": [ { @@ -3326,15 +3409,16 @@ "api_key": [] } ], + "summary": "Retrieve download information", "tags": [ "Download" ], - "x-immich-permission": "asset.download", - "description": "This endpoint requires the `asset.download` permission." + "x-immich-permission": "asset.download" } }, "/duplicates": { "delete": { + "description": "Delete multiple duplicate assets specified by their IDs.", "operationId": "deleteDuplicates", "parameters": [], "requestBody": { @@ -3363,13 +3447,14 @@ "api_key": [] } ], + "summary": "Delete duplicates", "tags": [ "Duplicates" ], - "x-immich-permission": "duplicate.delete", - "description": "This endpoint requires the `duplicate.delete` permission." + "x-immich-permission": "duplicate.delete" }, "get": { + "description": "Retrieve a list of duplicate assets available to the authenticated user.", "operationId": "getAssetDuplicates", "parameters": [], "responses": { @@ -3398,15 +3483,16 @@ "api_key": [] } ], + "summary": "Retrieve duplicates", "tags": [ "Duplicates" ], - "x-immich-permission": "duplicate.read", - "description": "This endpoint requires the `duplicate.read` permission." + "x-immich-permission": "duplicate.read" } }, "/duplicates/{id}": { "delete": { + "description": "Delete a single duplicate asset specified by its ID.", "operationId": "deleteDuplicate", "parameters": [ { @@ -3435,15 +3521,16 @@ "api_key": [] } ], + "summary": "Delete a duplicate", "tags": [ "Duplicates" ], - "x-immich-permission": "duplicate.delete", - "description": "This endpoint requires the `duplicate.delete` permission." + "x-immich-permission": "duplicate.delete" } }, "/faces": { "get": { + "description": "Retrieve all faces belonging to an asset.", "operationId": "getFaces", "parameters": [ { @@ -3482,13 +3569,14 @@ "api_key": [] } ], + "summary": "Retrieve faces for asset", "tags": [ "Faces" ], - "x-immich-permission": "face.read", - "description": "This endpoint requires the `face.read` permission." + "x-immich-permission": "face.read" }, "post": { + "description": "Create a new face that has not been discovered by facial recognition. The content of the bounding box is considered a face.", "operationId": "createFace", "parameters": [], "requestBody": { @@ -3517,15 +3605,16 @@ "api_key": [] } ], + "summary": "Create a face", "tags": [ "Faces" ], - "x-immich-permission": "face.create", - "description": "This endpoint requires the `face.create` permission." + "x-immich-permission": "face.create" } }, "/faces/{id}": { "delete": { + "description": "Delete a face identified by the id. Optionally can be force deleted.", "operationId": "deleteFace", "parameters": [ { @@ -3564,13 +3653,14 @@ "api_key": [] } ], + "summary": "Delete a face", "tags": [ "Faces" ], - "x-immich-permission": "face.delete", - "description": "This endpoint requires the `face.delete` permission." + "x-immich-permission": "face.delete" }, "put": { + "description": "Re-assign the face provided in the body to the person identified by the id in the path parameter.", "operationId": "reassignFacesById", "parameters": [ { @@ -3616,15 +3706,16 @@ "api_key": [] } ], + "summary": "Re-assign a face to another person", "tags": [ "Faces" ], - "x-immich-permission": "face.update", - "description": "This endpoint requires the `face.update` permission." + "x-immich-permission": "face.update" } }, "/jobs": { "get": { + "description": "Retrieve the counts of the current queue, as well as the current status.", "operationId": "getAllJobsStatus", "parameters": [], "responses": { @@ -3650,14 +3741,15 @@ "api_key": [] } ], + "summary": "Retrieve queue counts and status", "tags": [ "Jobs" ], "x-immich-admin-only": true, - "x-immich-permission": "job.read", - "description": "This endpoint is an admin-only route, and requires the `job.read` permission." + "x-immich-permission": "job.read" }, "post": { + "description": "Run a specific job. Most jobs are queued automatically, but this endpoint allows for manual creation of a handful of jobs, including various cleanup tasks, as well as creating a new database backup.", "operationId": "createJob", "parameters": [], "requestBody": { @@ -3686,16 +3778,17 @@ "api_key": [] } ], + "summary": "Create a manual job", "tags": [ "Jobs" ], "x-immich-admin-only": true, - "x-immich-permission": "job.create", - "description": "This endpoint is an admin-only route, and requires the `job.create` permission." + "x-immich-permission": "job.create" } }, "/jobs/{id}": { "put": { + "description": "Queue all assets for a specific job type. Defaults to only queueing assets that have not yet been processed, but the force command can be used to re-process all assets.", "operationId": "sendJobCommand", "parameters": [ { @@ -3740,16 +3833,17 @@ "api_key": [] } ], + "summary": "Run jobs", "tags": [ "Jobs" ], "x-immich-admin-only": true, - "x-immich-permission": "job.create", - "description": "This endpoint is an admin-only route, and requires the `job.create` permission." + "x-immich-permission": "job.create" } }, "/libraries": { "get": { + "description": "Retrieve a list of external libraries.", "operationId": "getAllLibraries", "parameters": [], "responses": { @@ -3778,14 +3872,15 @@ "api_key": [] } ], + "summary": "Retrieve libraries", "tags": [ "Libraries" ], "x-immich-admin-only": true, - "x-immich-permission": "library.read", - "description": "This endpoint is an admin-only route, and requires the `library.read` permission." + "x-immich-permission": "library.read" }, "post": { + "description": "Create a new external library.", "operationId": "createLibrary", "parameters": [], "requestBody": { @@ -3821,16 +3916,17 @@ "api_key": [] } ], + "summary": "Create a library", "tags": [ "Libraries" ], "x-immich-admin-only": true, - "x-immich-permission": "library.create", - "description": "This endpoint is an admin-only route, and requires the `library.create` permission." + "x-immich-permission": "library.create" } }, "/libraries/{id}": { "delete": { + "description": "Delete an external library by its ID.", "operationId": "deleteLibrary", "parameters": [ { @@ -3859,14 +3955,15 @@ "api_key": [] } ], + "summary": "Delete a library", "tags": [ "Libraries" ], "x-immich-admin-only": true, - "x-immich-permission": "library.delete", - "description": "This endpoint is an admin-only route, and requires the `library.delete` permission." + "x-immich-permission": "library.delete" }, "get": { + "description": "Retrieve an external library by its ID.", "operationId": "getLibrary", "parameters": [ { @@ -3902,14 +3999,15 @@ "api_key": [] } ], + "summary": "Retrieve a library", "tags": [ "Libraries" ], "x-immich-admin-only": true, - "x-immich-permission": "library.read", - "description": "This endpoint is an admin-only route, and requires the `library.read` permission." + "x-immich-permission": "library.read" }, "put": { + "description": "Update an existing external library.", "operationId": "updateLibrary", "parameters": [ { @@ -3955,16 +4053,17 @@ "api_key": [] } ], + "summary": "Update a library", "tags": [ "Libraries" ], "x-immich-admin-only": true, - "x-immich-permission": "library.update", - "description": "This endpoint is an admin-only route, and requires the `library.update` permission." + "x-immich-permission": "library.update" } }, "/libraries/{id}/scan": { "post": { + "description": "Queue a scan for the external library to find and import new assets.", "operationId": "scanLibrary", "parameters": [ { @@ -3993,16 +4092,17 @@ "api_key": [] } ], + "summary": "Scan a library", "tags": [ "Libraries" ], "x-immich-admin-only": true, - "x-immich-permission": "library.update", - "description": "This endpoint is an admin-only route, and requires the `library.update` permission." + "x-immich-permission": "library.update" } }, "/libraries/{id}/statistics": { "get": { + "description": "Retrieve statistics for a specific external library, including number of videos, images, and storage usage.", "operationId": "getLibraryStatistics", "parameters": [ { @@ -4038,16 +4138,17 @@ "api_key": [] } ], + "summary": "Retrieve library statistics", "tags": [ "Libraries" ], "x-immich-admin-only": true, - "x-immich-permission": "library.statistics", - "description": "This endpoint is an admin-only route, and requires the `library.statistics` permission." + "x-immich-permission": "library.statistics" } }, "/libraries/{id}/validate": { "post": { + "description": "Validate the settings of an external library.", "operationId": "validate", "parameters": [ { @@ -4093,6 +4194,7 @@ "api_key": [] } ], + "summary": "Validate library settings", "tags": [ "Libraries" ], @@ -4101,24 +4203,9 @@ }, "/map/markers": { "get": { + "description": "Retrieve a list of latitude and longitude coordinates for every asset with location data.", "operationId": "getMapMarkers", "parameters": [ - { - "name": "isArchived", - "required": false, - "in": "query", - "schema": { - "type": "boolean" - } - }, - { - "name": "isFavorite", - "required": false, - "in": "query", - "schema": { - "type": "boolean" - } - }, { "name": "fileCreatedAfter", "required": false, @@ -4137,6 +4224,22 @@ "type": "string" } }, + { + "name": "isArchived", + "required": false, + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "isFavorite", + "required": false, + "in": "query", + "schema": { + "type": "boolean" + } + }, { "name": "withPartners", "required": false, @@ -4180,6 +4283,7 @@ "api_key": [] } ], + "summary": "Retrieve map markers", "tags": [ "Map" ] @@ -4187,6 +4291,7 @@ }, "/map/reverse-geocode": { "get": { + "description": "Retrieve location information (e.g., city, country) for given latitude and longitude coordinates.", "operationId": "reverseGeocode", "parameters": [ { @@ -4234,6 +4339,7 @@ "api_key": [] } ], + "summary": "Reverse geocode coordinates", "tags": [ "Map" ] @@ -4241,6 +4347,7 @@ }, "/memories": { "get": { + "description": "Retrieve a list of memories. Memories are sorted descending by creation date by default, although they can also be sorted in ascending order, or randomly.", "operationId": "searchMemories", "parameters": [ { @@ -4321,13 +4428,14 @@ "api_key": [] } ], + "summary": "Retrieve memories", "tags": [ "Memories" ], - "x-immich-permission": "memory.read", - "description": "This endpoint requires the `memory.read` permission." + "x-immich-permission": "memory.read" }, "post": { + "description": "Create a new memory by providing a name, description, and a list of asset IDs to include in the memory.", "operationId": "createMemory", "parameters": [], "requestBody": { @@ -4363,15 +4471,16 @@ "api_key": [] } ], + "summary": "Create a memory", "tags": [ "Memories" ], - "x-immich-permission": "memory.create", - "description": "This endpoint requires the `memory.create` permission." + "x-immich-permission": "memory.create" } }, "/memories/statistics": { "get": { + "description": "Retrieve statistics about memories, such as total count and other relevant metrics.", "operationId": "memoriesStatistics", "parameters": [ { @@ -4449,15 +4558,16 @@ "api_key": [] } ], + "summary": "Retrieve memories statistics", "tags": [ "Memories" ], - "x-immich-permission": "memory.statistics", - "description": "This endpoint requires the `memory.statistics` permission." + "x-immich-permission": "memory.statistics" } }, "/memories/{id}": { "delete": { + "description": "Delete a specific memory by its ID.", "operationId": "deleteMemory", "parameters": [ { @@ -4486,13 +4596,14 @@ "api_key": [] } ], + "summary": "Delete a memory", "tags": [ "Memories" ], - "x-immich-permission": "memory.delete", - "description": "This endpoint requires the `memory.delete` permission." + "x-immich-permission": "memory.delete" }, "get": { + "description": "Retrieve a specific memory by its ID.", "operationId": "getMemory", "parameters": [ { @@ -4528,13 +4639,14 @@ "api_key": [] } ], + "summary": "Retrieve a memory", "tags": [ "Memories" ], - "x-immich-permission": "memory.read", - "description": "This endpoint requires the `memory.read` permission." + "x-immich-permission": "memory.read" }, "put": { + "description": "Update an existing memory by its ID.", "operationId": "updateMemory", "parameters": [ { @@ -4580,15 +4692,16 @@ "api_key": [] } ], + "summary": "Update a memory", "tags": [ "Memories" ], - "x-immich-permission": "memory.update", - "description": "This endpoint requires the `memory.update` permission." + "x-immich-permission": "memory.update" } }, "/memories/{id}/assets": { "delete": { + "description": "Remove a list of asset IDs from a specific memory.", "operationId": "removeMemoryAssets", "parameters": [ { @@ -4637,13 +4750,14 @@ "api_key": [] } ], + "summary": "Remove assets from a memory", "tags": [ "Memories" ], - "x-immich-permission": "memoryAsset.delete", - "description": "This endpoint requires the `memoryAsset.delete` permission." + "x-immich-permission": "memoryAsset.delete" }, "put": { + "description": "Add a list of asset IDs to a specific memory.", "operationId": "addMemoryAssets", "parameters": [ { @@ -4692,15 +4806,16 @@ "api_key": [] } ], + "summary": "Add assets to a memory", "tags": [ "Memories" ], - "x-immich-permission": "memoryAsset.create", - "description": "This endpoint requires the `memoryAsset.create` permission." + "x-immich-permission": "memoryAsset.create" } }, "/notifications": { "delete": { + "description": "Delete a list of notifications at once.", "operationId": "deleteNotifications", "parameters": [], "requestBody": { @@ -4729,13 +4844,14 @@ "api_key": [] } ], + "summary": "Delete notifications", "tags": [ "Notifications" ], - "x-immich-permission": "notification.delete", - "description": "This endpoint requires the `notification.delete` permission." + "x-immich-permission": "notification.delete" }, "get": { + "description": "Retrieve a list of notifications.", "operationId": "getNotifications", "parameters": [ { @@ -4798,13 +4914,14 @@ "api_key": [] } ], + "summary": "Retrieve notifications", "tags": [ "Notifications" ], - "x-immich-permission": "notification.read", - "description": "This endpoint requires the `notification.read` permission." + "x-immich-permission": "notification.read" }, "put": { + "description": "Update a list of notifications. Allows to bulk-set the read status of notifications.", "operationId": "updateNotifications", "parameters": [], "requestBody": { @@ -4833,15 +4950,16 @@ "api_key": [] } ], + "summary": "Update notifications", "tags": [ "Notifications" ], - "x-immich-permission": "notification.update", - "description": "This endpoint requires the `notification.update` permission." + "x-immich-permission": "notification.update" } }, "/notifications/{id}": { "delete": { + "description": "Delete a specific notification.", "operationId": "deleteNotification", "parameters": [ { @@ -4870,13 +4988,14 @@ "api_key": [] } ], + "summary": "Delete a notification", "tags": [ "Notifications" ], - "x-immich-permission": "notification.delete", - "description": "This endpoint requires the `notification.delete` permission." + "x-immich-permission": "notification.delete" }, "get": { + "description": "Retrieve a specific notification identified by id.", "operationId": "getNotification", "parameters": [ { @@ -4912,13 +5031,14 @@ "api_key": [] } ], + "summary": "Get a notification", "tags": [ "Notifications" ], - "x-immich-permission": "notification.read", - "description": "This endpoint requires the `notification.read` permission." + "x-immich-permission": "notification.read" }, "put": { + "description": "Update a specific notification to set its read status.", "operationId": "updateNotification", "parameters": [ { @@ -4964,15 +5084,16 @@ "api_key": [] } ], + "summary": "Update a notification", "tags": [ "Notifications" ], - "x-immich-permission": "notification.update", - "description": "This endpoint requires the `notification.update` permission." + "x-immich-permission": "notification.update" } }, "/oauth/authorize": { "post": { + "description": "Initiate the OAuth authorization process.", "operationId": "startOAuth", "parameters": [], "requestBody": { @@ -4997,13 +5118,15 @@ "description": "" } }, + "summary": "Start OAuth", "tags": [ - "OAuth" + "Authentication" ] } }, "/oauth/callback": { "post": { + "description": "Complete the OAuth authorization process by exchanging the authorization code for a session token.", "operationId": "finishOAuth", "parameters": [], "requestBody": { @@ -5028,13 +5151,15 @@ "description": "" } }, + "summary": "Finish OAuth", "tags": [ - "OAuth" + "Authentication" ] } }, "/oauth/link": { "post": { + "description": "Link an OAuth account to the authenticated user.", "operationId": "linkOAuthAccount", "parameters": [], "requestBody": { @@ -5070,13 +5195,15 @@ "api_key": [] } ], + "summary": "Link OAuth account", "tags": [ - "OAuth" + "Authentication" ] } }, "/oauth/mobile-redirect": { "get": { + "description": "Requests to this URL are automatically forwarded to the mobile app, and is used in some cases for OAuth redirecting.", "operationId": "redirectOAuthToMobile", "parameters": [], "responses": { @@ -5084,13 +5211,15 @@ "description": "" } }, + "summary": "Redirect OAuth to mobile", "tags": [ - "OAuth" + "Authentication" ] } }, "/oauth/unlink": { "post": { + "description": "Unlink the OAuth account from the authenticated user.", "operationId": "unlinkOAuthAccount", "parameters": [], "responses": { @@ -5116,13 +5245,15 @@ "api_key": [] } ], + "summary": "Unlink OAuth account", "tags": [ - "OAuth" + "Authentication" ] } }, "/partners": { "get": { + "description": "Retrieve a list of partners with whom assets are shared.", "operationId": "getPartners", "parameters": [ { @@ -5160,13 +5291,14 @@ "api_key": [] } ], + "summary": "Retrieve partners", "tags": [ "Partners" ], - "x-immich-permission": "partner.read", - "description": "This endpoint requires the `partner.read` permission." + "x-immich-permission": "partner.read" }, "post": { + "description": "Create a new partner to share assets with.", "operationId": "createPartner", "parameters": [], "requestBody": { @@ -5202,15 +5334,16 @@ "api_key": [] } ], + "summary": "Create a partner", "tags": [ "Partners" ], - "x-immich-permission": "partner.create", - "description": "This endpoint requires the `partner.create` permission." + "x-immich-permission": "partner.create" } }, "/partners/{id}": { "delete": { + "description": "Stop sharing assets with a partner.", "operationId": "removePartner", "parameters": [ { @@ -5239,15 +5372,15 @@ "api_key": [] } ], + "summary": "Remove a partner", "tags": [ "Partners" ], - "x-immich-permission": "partner.delete", - "description": "This endpoint requires the `partner.delete` permission." + "x-immich-permission": "partner.delete" }, "post": { "deprecated": true, - "description": "This property was deprecated in v1.141.0. This endpoint requires the `partner.create` permission.", + "description": "This property was deprecated in v1.141.0. Create a new partner to share assets with.", "operationId": "createPartnerDeprecated", "parameters": [ { @@ -5283,6 +5416,7 @@ "api_key": [] } ], + "summary": "Create a partner", "tags": [ "Partners", "Deprecated" @@ -5293,6 +5427,7 @@ "x-immich-permission": "partner.create" }, "put": { + "description": "Specify whether a partner's assets should appear in the user's timeline.", "operationId": "updatePartner", "parameters": [ { @@ -5338,15 +5473,16 @@ "api_key": [] } ], + "summary": "Update a partner", "tags": [ "Partners" ], - "x-immich-permission": "partner.update", - "description": "This endpoint requires the `partner.update` permission." + "x-immich-permission": "partner.update" } }, "/people": { "delete": { + "description": "Bulk delete a list of people at once.", "operationId": "deletePeople", "parameters": [], "requestBody": { @@ -5375,13 +5511,14 @@ "api_key": [] } ], + "summary": "Delete people", "tags": [ "People" ], - "x-immich-permission": "person.delete", - "description": "This endpoint requires the `person.delete` permission." + "x-immich-permission": "person.delete" }, "get": { + "description": "Retrieve a list of all people.", "operationId": "getAllPeople", "parameters": [ { @@ -5457,13 +5594,14 @@ "api_key": [] } ], + "summary": "Get all people", "tags": [ "People" ], - "x-immich-permission": "person.read", - "description": "This endpoint requires the `person.read` permission." + "x-immich-permission": "person.read" }, "post": { + "description": "Create a new person that can have multiple faces assigned to them.", "operationId": "createPerson", "parameters": [], "requestBody": { @@ -5499,13 +5637,14 @@ "api_key": [] } ], + "summary": "Create a person", "tags": [ "People" ], - "x-immich-permission": "person.create", - "description": "This endpoint requires the `person.create` permission." + "x-immich-permission": "person.create" }, "put": { + "description": "Bulk update multiple people at once.", "operationId": "updatePeople", "parameters": [], "requestBody": { @@ -5544,15 +5683,16 @@ "api_key": [] } ], + "summary": "Update people", "tags": [ "People" ], - "x-immich-permission": "person.update", - "description": "This endpoint requires the `person.update` permission." + "x-immich-permission": "person.update" } }, "/people/{id}": { "delete": { + "description": "Delete an individual person.", "operationId": "deletePerson", "parameters": [ { @@ -5581,13 +5721,14 @@ "api_key": [] } ], + "summary": "Delete person", "tags": [ "People" ], - "x-immich-permission": "person.delete", - "description": "This endpoint requires the `person.delete` permission." + "x-immich-permission": "person.delete" }, "get": { + "description": "Retrieve a person by id.", "operationId": "getPerson", "parameters": [ { @@ -5623,13 +5764,14 @@ "api_key": [] } ], + "summary": "Get a person", "tags": [ "People" ], - "x-immich-permission": "person.read", - "description": "This endpoint requires the `person.read` permission." + "x-immich-permission": "person.read" }, "put": { + "description": "Update an individual person.", "operationId": "updatePerson", "parameters": [ { @@ -5675,15 +5817,16 @@ "api_key": [] } ], + "summary": "Update person", "tags": [ "People" ], - "x-immich-permission": "person.update", - "description": "This endpoint requires the `person.update` permission." + "x-immich-permission": "person.update" } }, "/people/{id}/merge": { "post": { + "description": "Merge a list of people into the person specified in the path parameter.", "operationId": "mergePerson", "parameters": [ { @@ -5732,15 +5875,16 @@ "api_key": [] } ], + "summary": "Merge people", "tags": [ "People" ], - "x-immich-permission": "person.merge", - "description": "This endpoint requires the `person.merge` permission." + "x-immich-permission": "person.merge" } }, "/people/{id}/reassign": { "put": { + "description": "Bulk reassign a list of faces to a different person.", "operationId": "reassignFaces", "parameters": [ { @@ -5789,15 +5933,16 @@ "api_key": [] } ], + "summary": "Reassign faces", "tags": [ "People" ], - "x-immich-permission": "person.reassign", - "description": "This endpoint requires the `person.reassign` permission." + "x-immich-permission": "person.reassign" } }, "/people/{id}/statistics": { "get": { + "description": "Retrieve statistics about a specific person.", "operationId": "getPersonStatistics", "parameters": [ { @@ -5833,15 +5978,16 @@ "api_key": [] } ], + "summary": "Get person statistics", "tags": [ "People" ], - "x-immich-permission": "person.statistics", - "description": "This endpoint requires the `person.statistics` permission." + "x-immich-permission": "person.statistics" } }, "/people/{id}/thumbnail": { "get": { + "description": "Retrieve the thumbnail file for a person.", "operationId": "getPersonThumbnail", "parameters": [ { @@ -5878,15 +6024,16 @@ "api_key": [] } ], + "summary": "Get person thumbnail", "tags": [ "People" ], - "x-immich-permission": "person.read", - "description": "This endpoint requires the `person.read` permission." + "x-immich-permission": "person.read" } }, "/search/cities": { "get": { + "description": "Retrieve a list of assets with each asset belonging to a different city. This endpoint is used on the places pages to show a single thumbnail for each city the user has assets in.", "operationId": "getAssetsByCity", "parameters": [], "responses": { @@ -5915,15 +6062,16 @@ "api_key": [] } ], + "summary": "Retrieve assets by city", "tags": [ "Search" ], - "x-immich-permission": "asset.read", - "description": "This endpoint requires the `asset.read` permission." + "x-immich-permission": "asset.read" } }, "/search/explore": { "get": { + "description": "Retrieve data for the explore section, such as popular people and places.", "operationId": "getExploreData", "parameters": [], "responses": { @@ -5952,15 +6100,16 @@ "api_key": [] } ], + "summary": "Retrieve explore data", "tags": [ "Search" ], - "x-immich-permission": "asset.read", - "description": "This endpoint requires the `asset.read` permission." + "x-immich-permission": "asset.read" } }, "/search/large-assets": { "post": { + "description": "Search for assets that are considered large based on specified criteria.", "operationId": "searchLargeAssets", "parameters": [ { @@ -6279,15 +6428,16 @@ "api_key": [] } ], + "summary": "Search large assets", "tags": [ "Search" ], - "x-immich-permission": "asset.read", - "description": "This endpoint requires the `asset.read` permission." + "x-immich-permission": "asset.read" } }, "/search/metadata": { "post": { + "description": "Search for assets based on various metadata criteria.", "operationId": "searchAssets", "parameters": [], "requestBody": { @@ -6323,15 +6473,16 @@ "api_key": [] } ], + "summary": "Search assets by metadata", "tags": [ "Search" ], - "x-immich-permission": "asset.read", - "description": "This endpoint requires the `asset.read` permission." + "x-immich-permission": "asset.read" } }, "/search/person": { "get": { + "description": "Search for people by name.", "operationId": "searchPerson", "parameters": [ { @@ -6377,15 +6528,16 @@ "api_key": [] } ], + "summary": "Search people", "tags": [ "Search" ], - "x-immich-permission": "person.read", - "description": "This endpoint requires the `person.read` permission." + "x-immich-permission": "person.read" } }, "/search/places": { "get": { + "description": "Search for places by name.", "operationId": "searchPlaces", "parameters": [ { @@ -6423,15 +6575,16 @@ "api_key": [] } ], + "summary": "Search places", "tags": [ "Search" ], - "x-immich-permission": "asset.read", - "description": "This endpoint requires the `asset.read` permission." + "x-immich-permission": "asset.read" } }, "/search/random": { "post": { + "description": "Retrieve a random selection of assets based on the provided criteria.", "operationId": "searchRandom", "parameters": [], "requestBody": { @@ -6470,15 +6623,16 @@ "api_key": [] } ], + "summary": "Search random assets", "tags": [ "Search" ], - "x-immich-permission": "asset.read", - "description": "This endpoint requires the `asset.read` permission." + "x-immich-permission": "asset.read" } }, "/search/smart": { "post": { + "description": "Perform a smart search for assets by using machine learning vectors to determine relevance.", "operationId": "searchSmart", "parameters": [], "requestBody": { @@ -6514,15 +6668,16 @@ "api_key": [] } ], + "summary": "Smart asset search", "tags": [ "Search" ], - "x-immich-permission": "asset.read", - "description": "This endpoint requires the `asset.read` permission." + "x-immich-permission": "asset.read" } }, "/search/statistics": { "post": { + "description": "Retrieve statistical data about assets based on search criteria, such as the total matching count.", "operationId": "searchAssetStatistics", "parameters": [], "requestBody": { @@ -6558,15 +6713,16 @@ "api_key": [] } ], + "summary": "Search asset statistics", "tags": [ "Search" ], - "x-immich-permission": "asset.statistics", - "description": "This endpoint requires the `asset.statistics` permission." + "x-immich-permission": "asset.statistics" } }, "/search/suggestions": { "get": { + "description": "Retrieve search suggestions based on partial input. This endpoint is used for typeahead search features.", "operationId": "getSearchSuggestions", "parameters": [ { @@ -6653,15 +6809,16 @@ "api_key": [] } ], + "summary": "Retrieve search suggestions", "tags": [ "Search" ], - "x-immich-permission": "asset.read", - "description": "This endpoint requires the `asset.read` permission." + "x-immich-permission": "asset.read" } }, "/server/about": { "get": { + "description": "Retrieve a list of information about the server.", "operationId": "getAboutInfo", "parameters": [], "responses": { @@ -6687,15 +6844,16 @@ "api_key": [] } ], + "summary": "Get server information", "tags": [ "Server" ], - "x-immich-permission": "server.about", - "description": "This endpoint requires the `server.about` permission." + "x-immich-permission": "server.about" } }, "/server/apk-links": { "get": { + "description": "Retrieve links to the APKs for the current server version.", "operationId": "getApkLinks", "parameters": [], "responses": { @@ -6721,15 +6879,16 @@ "api_key": [] } ], + "summary": "Get APK links", "tags": [ "Server" ], - "x-immich-permission": "server.apkLinks", - "description": "This endpoint requires the `server.apkLinks` permission." + "x-immich-permission": "server.apkLinks" } }, "/server/config": { "get": { + "description": "Retrieve the current server configuration.", "operationId": "getServerConfig", "parameters": [], "responses": { @@ -6744,6 +6903,7 @@ "description": "" } }, + "summary": "Get config", "tags": [ "Server" ] @@ -6751,6 +6911,7 @@ }, "/server/features": { "get": { + "description": "Retrieve available features supported by this server.", "operationId": "getServerFeatures", "parameters": [], "responses": { @@ -6765,6 +6926,7 @@ "description": "" } }, + "summary": "Get features", "tags": [ "Server" ] @@ -6772,6 +6934,7 @@ }, "/server/license": { "delete": { + "description": "Delete the currently set server product key.", "operationId": "deleteServerLicense", "parameters": [], "responses": { @@ -6790,14 +6953,15 @@ "api_key": [] } ], + "summary": "Delete server product key", "tags": [ "Server" ], "x-immich-admin-only": true, - "x-immich-permission": "serverLicense.delete", - "description": "This endpoint is an admin-only route, and requires the `serverLicense.delete` permission." + "x-immich-permission": "serverLicense.delete" }, "get": { + "description": "Retrieve information about whether the server currently has a product key registered.", "operationId": "getServerLicense", "parameters": [], "responses": { @@ -6826,14 +6990,15 @@ "api_key": [] } ], + "summary": "Get product key", "tags": [ "Server" ], "x-immich-admin-only": true, - "x-immich-permission": "serverLicense.read", - "description": "This endpoint is an admin-only route, and requires the `serverLicense.read` permission." + "x-immich-permission": "serverLicense.read" }, "put": { + "description": "Validate and set the server product key if successful.", "operationId": "setServerLicense", "parameters": [], "requestBody": { @@ -6869,16 +7034,17 @@ "api_key": [] } ], + "summary": "Set server product key", "tags": [ "Server" ], "x-immich-admin-only": true, - "x-immich-permission": "serverLicense.update", - "description": "This endpoint is an admin-only route, and requires the `serverLicense.update` permission." + "x-immich-permission": "serverLicense.update" } }, "/server/media-types": { "get": { + "description": "Retrieve all media types supported by the server.", "operationId": "getSupportedMediaTypes", "parameters": [], "responses": { @@ -6893,6 +7059,7 @@ "description": "" } }, + "summary": "Get supported media types", "tags": [ "Server" ] @@ -6900,6 +7067,7 @@ }, "/server/ping": { "get": { + "description": "Pong", "operationId": "pingServer", "parameters": [], "responses": { @@ -6914,6 +7082,7 @@ "description": "" } }, + "summary": "Ping", "tags": [ "Server" ] @@ -6921,6 +7090,7 @@ }, "/server/statistics": { "get": { + "description": "Retrieve statistics about the entire Immich instance such as asset counts.", "operationId": "getServerStatistics", "parameters": [], "responses": { @@ -6946,16 +7116,17 @@ "api_key": [] } ], + "summary": "Get statistics", "tags": [ "Server" ], "x-immich-admin-only": true, - "x-immich-permission": "server.statistics", - "description": "This endpoint is an admin-only route, and requires the `server.statistics` permission." + "x-immich-permission": "server.statistics" } }, "/server/storage": { "get": { + "description": "Retrieve the current storage utilization information of the server.", "operationId": "getStorage", "parameters": [], "responses": { @@ -6981,15 +7152,16 @@ "api_key": [] } ], + "summary": "Get storage", "tags": [ "Server" ], - "x-immich-permission": "server.storage", - "description": "This endpoint requires the `server.storage` permission." + "x-immich-permission": "server.storage" } }, "/server/theme": { "get": { + "description": "Retrieve the custom CSS, if existent.", "operationId": "getTheme", "parameters": [], "responses": { @@ -7004,6 +7176,7 @@ "description": "" } }, + "summary": "Get theme", "tags": [ "Server" ] @@ -7011,6 +7184,7 @@ }, "/server/version": { "get": { + "description": "Retrieve the current server version in semantic versioning (semver) format.", "operationId": "getServerVersion", "parameters": [], "responses": { @@ -7025,6 +7199,7 @@ "description": "" } }, + "summary": "Get server version", "tags": [ "Server" ] @@ -7032,6 +7207,7 @@ }, "/server/version-check": { "get": { + "description": "Retrieve information about the last time the version check ran.", "operationId": "getVersionCheck", "parameters": [], "responses": { @@ -7057,15 +7233,16 @@ "api_key": [] } ], + "summary": "Get version check status", "tags": [ "Server" ], - "x-immich-permission": "server.versionCheck", - "description": "This endpoint requires the `server.versionCheck` permission." + "x-immich-permission": "server.versionCheck" } }, "/server/version-history": { "get": { + "description": "Retrieve a list of past versions the server has been on.", "operationId": "getVersionHistory", "parameters": [], "responses": { @@ -7083,6 +7260,7 @@ "description": "" } }, + "summary": "Get version history", "tags": [ "Server" ] @@ -7090,6 +7268,7 @@ }, "/sessions": { "delete": { + "description": "Delete all sessions for the user. This will not delete the current session.", "operationId": "deleteAllSessions", "parameters": [], "responses": { @@ -7108,13 +7287,14 @@ "api_key": [] } ], + "summary": "Delete all sessions", "tags": [ "Sessions" ], - "x-immich-permission": "session.delete", - "description": "This endpoint requires the `session.delete` permission." + "x-immich-permission": "session.delete" }, "get": { + "description": "Retrieve a list of sessions for the user.", "operationId": "getSessions", "parameters": [], "responses": { @@ -7143,13 +7323,14 @@ "api_key": [] } ], + "summary": "Retrieve sessions", "tags": [ "Sessions" ], - "x-immich-permission": "session.read", - "description": "This endpoint requires the `session.read` permission." + "x-immich-permission": "session.read" }, "post": { + "description": "Create a session as a child to the current session. This endpoint is used for casting.", "operationId": "createSession", "parameters": [], "requestBody": { @@ -7185,15 +7366,16 @@ "api_key": [] } ], + "summary": "Create a session", "tags": [ "Sessions" ], - "x-immich-permission": "session.create", - "description": "This endpoint requires the `session.create` permission." + "x-immich-permission": "session.create" } }, "/sessions/{id}": { "delete": { + "description": "Delete a specific session by id.", "operationId": "deleteSession", "parameters": [ { @@ -7222,13 +7404,14 @@ "api_key": [] } ], + "summary": "Delete a session", "tags": [ "Sessions" ], - "x-immich-permission": "session.delete", - "description": "This endpoint requires the `session.delete` permission." + "x-immich-permission": "session.delete" }, "put": { + "description": "Update a specific session identified by id.", "operationId": "updateSession", "parameters": [ { @@ -7274,15 +7457,16 @@ "api_key": [] } ], + "summary": "Update a session", "tags": [ "Sessions" ], - "x-immich-permission": "session.update", - "description": "This endpoint requires the `session.update` permission." + "x-immich-permission": "session.update" } }, "/sessions/{id}/lock": { "post": { + "description": "Lock a specific session by id.", "operationId": "lockSession", "parameters": [ { @@ -7311,15 +7495,16 @@ "api_key": [] } ], + "summary": "Lock a session", "tags": [ "Sessions" ], - "x-immich-permission": "session.lock", - "description": "This endpoint requires the `session.lock` permission." + "x-immich-permission": "session.lock" } }, "/shared-links": { "get": { + "description": "Retrieve a list of all shared links.", "operationId": "getAllSharedLinks", "parameters": [ { @@ -7358,13 +7543,14 @@ "api_key": [] } ], + "summary": "Retrieve all shared links", "tags": [ - "Shared Links" + "Shared links" ], - "x-immich-permission": "sharedLink.read", - "description": "This endpoint requires the `sharedLink.read` permission." + "x-immich-permission": "sharedLink.read" }, "post": { + "description": "Create a new shared link.", "operationId": "createSharedLink", "parameters": [], "requestBody": { @@ -7400,17 +7586,26 @@ "api_key": [] } ], + "summary": "Create a shared link", "tags": [ - "Shared Links" + "Shared links" ], - "x-immich-permission": "sharedLink.create", - "description": "This endpoint requires the `sharedLink.create` permission." + "x-immich-permission": "sharedLink.create" } }, "/shared-links/me": { "get": { + "description": "Retrieve the current shared link associated with authentication method.", "operationId": "getMySharedLink", "parameters": [ + { + "name": "key", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, { "name": "password", "required": false, @@ -7420,22 +7615,6 @@ "type": "string" } }, - { - "name": "token", - "required": false, - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "key", - "required": false, - "in": "query", - "schema": { - "type": "string" - } - }, { "name": "slug", "required": false, @@ -7443,6 +7622,14 @@ "schema": { "type": "string" } + }, + { + "name": "token", + "required": false, + "in": "query", + "schema": { + "type": "string" + } } ], "responses": { @@ -7468,13 +7655,15 @@ "api_key": [] } ], + "summary": "Retrieve current shared link", "tags": [ - "Shared Links" + "Shared links" ] } }, "/shared-links/{id}": { "delete": { + "description": "Delete a specific shared link by its ID.", "operationId": "removeSharedLink", "parameters": [ { @@ -7503,13 +7692,14 @@ "api_key": [] } ], + "summary": "Delete a shared link", "tags": [ - "Shared Links" + "Shared links" ], - "x-immich-permission": "sharedLink.delete", - "description": "This endpoint requires the `sharedLink.delete` permission." + "x-immich-permission": "sharedLink.delete" }, "get": { + "description": "Retrieve a specific shared link by its ID.", "operationId": "getSharedLinkById", "parameters": [ { @@ -7545,13 +7735,14 @@ "api_key": [] } ], + "summary": "Retrieve a shared link", "tags": [ - "Shared Links" + "Shared links" ], - "x-immich-permission": "sharedLink.read", - "description": "This endpoint requires the `sharedLink.read` permission." + "x-immich-permission": "sharedLink.read" }, "patch": { + "description": "Update an existing shared link by its ID.", "operationId": "updateSharedLink", "parameters": [ { @@ -7597,15 +7788,16 @@ "api_key": [] } ], + "summary": "Update a shared link", "tags": [ - "Shared Links" + "Shared links" ], - "x-immich-permission": "sharedLink.update", - "description": "This endpoint requires the `sharedLink.update` permission." + "x-immich-permission": "sharedLink.update" } }, "/shared-links/{id}/assets": { "delete": { + "description": "Remove assets from a specific shared link by its ID. This endpoint is only relevant for shared link of type individual.", "operationId": "removeSharedLinkAssets", "parameters": [ { @@ -7670,11 +7862,13 @@ "api_key": [] } ], + "summary": "Remove assets from a shared link", "tags": [ - "Shared Links" + "Shared links" ] }, "put": { + "description": "Add assets to a specific shared link by its ID. This endpoint is only relevant for shared link of type individual.", "operationId": "addSharedLinkAssets", "parameters": [ { @@ -7739,13 +7933,15 @@ "api_key": [] } ], + "summary": "Add assets to a shared link", "tags": [ - "Shared Links" + "Shared links" ] } }, "/stacks": { "delete": { + "description": "Delete multiple stacks by providing a list of stack IDs.", "operationId": "deleteStacks", "parameters": [], "requestBody": { @@ -7774,13 +7970,14 @@ "api_key": [] } ], + "summary": "Delete stacks", "tags": [ "Stacks" ], - "x-immich-permission": "stack.delete", - "description": "This endpoint requires the `stack.delete` permission." + "x-immich-permission": "stack.delete" }, "get": { + "description": "Retrieve a list of stacks.", "operationId": "searchStacks", "parameters": [ { @@ -7819,13 +8016,14 @@ "api_key": [] } ], + "summary": "Retrieve stacks", "tags": [ "Stacks" ], - "x-immich-permission": "stack.read", - "description": "This endpoint requires the `stack.read` permission." + "x-immich-permission": "stack.read" }, "post": { + "description": "Create a new stack by providing a name and a list of asset IDs to include in the stack. If any of the provided asset IDs are primary assets of an existing stack, the existing stack will be merged into the newly created stack.", "operationId": "createStack", "parameters": [], "requestBody": { @@ -7861,15 +8059,16 @@ "api_key": [] } ], + "summary": "Create a stack", "tags": [ "Stacks" ], - "x-immich-permission": "stack.create", - "description": "This endpoint requires the `stack.create` permission." + "x-immich-permission": "stack.create" } }, "/stacks/{id}": { "delete": { + "description": "Delete a specific stack by its ID.", "operationId": "deleteStack", "parameters": [ { @@ -7898,13 +8097,14 @@ "api_key": [] } ], + "summary": "Delete a stack", "tags": [ "Stacks" ], - "x-immich-permission": "stack.delete", - "description": "This endpoint requires the `stack.delete` permission." + "x-immich-permission": "stack.delete" }, "get": { + "description": "Retrieve a specific stack by its ID.", "operationId": "getStack", "parameters": [ { @@ -7940,13 +8140,14 @@ "api_key": [] } ], + "summary": "Retrieve a stack", "tags": [ "Stacks" ], - "x-immich-permission": "stack.read", - "description": "This endpoint requires the `stack.read` permission." + "x-immich-permission": "stack.read" }, "put": { + "description": "Update an existing stack by its ID.", "operationId": "updateStack", "parameters": [ { @@ -7992,15 +8193,16 @@ "api_key": [] } ], + "summary": "Update a stack", "tags": [ "Stacks" ], - "x-immich-permission": "stack.update", - "description": "This endpoint requires the `stack.update` permission." + "x-immich-permission": "stack.update" } }, "/stacks/{id}/assets/{assetId}": { "delete": { + "description": "Remove a specific asset from a stack by providing the stack ID and asset ID.", "operationId": "removeAssetFromStack", "parameters": [ { @@ -8038,15 +8240,16 @@ "api_key": [] } ], + "summary": "Remove an asset from a stack", "tags": [ "Stacks" ], - "x-immich-permission": "stack.update", - "description": "This endpoint requires the `stack.update` permission." + "x-immich-permission": "stack.update" } }, "/sync/ack": { "delete": { + "description": "Delete specific synchronization acknowledgments.", "operationId": "deleteSyncAck", "parameters": [], "requestBody": { @@ -8075,13 +8278,14 @@ "api_key": [] } ], + "summary": "Delete acknowledgements", "tags": [ "Sync" ], - "x-immich-permission": "syncCheckpoint.delete", - "description": "This endpoint requires the `syncCheckpoint.delete` permission." + "x-immich-permission": "syncCheckpoint.delete" }, "get": { + "description": "Retrieve the synchronization acknowledgments for the current session.", "operationId": "getSyncAck", "parameters": [], "responses": { @@ -8110,13 +8314,14 @@ "api_key": [] } ], + "summary": "Retrieve acknowledgements", "tags": [ "Sync" ], - "x-immich-permission": "syncCheckpoint.read", - "description": "This endpoint requires the `syncCheckpoint.read` permission." + "x-immich-permission": "syncCheckpoint.read" }, "post": { + "description": "Send a list of synchronization acknowledgements to confirm that the latest changes have been received.", "operationId": "sendSyncAck", "parameters": [], "requestBody": { @@ -8145,15 +8350,17 @@ "api_key": [] } ], + "summary": "Acknowledge changes", "tags": [ "Sync" ], - "x-immich-permission": "syncCheckpoint.update", - "description": "This endpoint requires the `syncCheckpoint.update` permission." + "x-immich-permission": "syncCheckpoint.update" } }, "/sync/delta-sync": { "post": { + "deprecated": true, + "description": "This property was deprecated in v2.0.0. Retrieve changed assets since the last sync for the authenticated user.", "operationId": "getDeltaSync", "parameters": [], "requestBody": { @@ -8189,13 +8396,20 @@ "api_key": [] } ], + "summary": "Get delta sync for user", "tags": [ - "Sync" - ] + "Sync", + "Deprecated" + ], + "x-immich-lifecycle": { + "deprecatedAt": "v2.0.0" + } } }, "/sync/full-sync": { "post": { + "deprecated": true, + "description": "This property was deprecated in v2.0.0. Retrieve all assets for a full synchronization for the authenticated user.", "operationId": "getFullSyncForUser", "parameters": [], "requestBody": { @@ -8234,13 +8448,19 @@ "api_key": [] } ], + "summary": "Get full sync for user", "tags": [ - "Sync" - ] + "Sync", + "Deprecated" + ], + "x-immich-lifecycle": { + "deprecatedAt": "v2.0.0" + } } }, "/sync/stream": { "post": { + "description": "Retrieve a JSON lines streamed response of changes for synchronization. This endpoint is used by the mobile app to efficiently stay up to date with changes.", "operationId": "getSyncStream", "parameters": [], "requestBody": { @@ -8269,15 +8489,16 @@ "api_key": [] } ], + "summary": "Stream sync changes", "tags": [ "Sync" ], - "x-immich-permission": "sync.stream", - "description": "This endpoint requires the `sync.stream` permission." + "x-immich-permission": "sync.stream" } }, "/system-config": { "get": { + "description": "Retrieve the current system configuration.", "operationId": "getConfig", "parameters": [], "responses": { @@ -8303,14 +8524,15 @@ "api_key": [] } ], + "summary": "Get system configuration", "tags": [ - "System Config" + "System config" ], "x-immich-admin-only": true, - "x-immich-permission": "systemConfig.read", - "description": "This endpoint is an admin-only route, and requires the `systemConfig.read` permission." + "x-immich-permission": "systemConfig.read" }, "put": { + "description": "Update the system configuration with a new system configuration.", "operationId": "updateConfig", "parameters": [], "requestBody": { @@ -8346,16 +8568,17 @@ "api_key": [] } ], + "summary": "Update system configuration", "tags": [ - "System Config" + "System config" ], "x-immich-admin-only": true, - "x-immich-permission": "systemConfig.update", - "description": "This endpoint is an admin-only route, and requires the `systemConfig.update` permission." + "x-immich-permission": "systemConfig.update" } }, "/system-config/defaults": { "get": { + "description": "Retrieve the default values for the system configuration.", "operationId": "getConfigDefaults", "parameters": [], "responses": { @@ -8381,16 +8604,17 @@ "api_key": [] } ], + "summary": "Get system configuration defaults", "tags": [ - "System Config" + "System config" ], "x-immich-admin-only": true, - "x-immich-permission": "systemConfig.read", - "description": "This endpoint is an admin-only route, and requires the `systemConfig.read` permission." + "x-immich-permission": "systemConfig.read" } }, "/system-config/storage-template-options": { "get": { + "description": "Retrieve exemplary storage template options.", "operationId": "getStorageTemplateOptions", "parameters": [], "responses": { @@ -8416,16 +8640,17 @@ "api_key": [] } ], + "summary": "Get storage template options", "tags": [ - "System Config" + "System config" ], "x-immich-admin-only": true, - "x-immich-permission": "systemConfig.read", - "description": "This endpoint is an admin-only route, and requires the `systemConfig.read` permission." + "x-immich-permission": "systemConfig.read" } }, "/system-metadata/admin-onboarding": { "get": { + "description": "Retrieve the current admin onboarding status.", "operationId": "getAdminOnboarding", "parameters": [], "responses": { @@ -8451,14 +8676,15 @@ "api_key": [] } ], + "summary": "Retrieve admin onboarding", "tags": [ - "System Metadata" + "System metadata" ], "x-immich-admin-only": true, - "x-immich-permission": "systemMetadata.read", - "description": "This endpoint is an admin-only route, and requires the `systemMetadata.read` permission." + "x-immich-permission": "systemMetadata.read" }, "post": { + "description": "Update the admin onboarding status.", "operationId": "updateAdminOnboarding", "parameters": [], "requestBody": { @@ -8487,16 +8713,17 @@ "api_key": [] } ], + "summary": "Update admin onboarding", "tags": [ - "System Metadata" + "System metadata" ], "x-immich-admin-only": true, - "x-immich-permission": "systemMetadata.update", - "description": "This endpoint is an admin-only route, and requires the `systemMetadata.update` permission." + "x-immich-permission": "systemMetadata.update" } }, "/system-metadata/reverse-geocoding-state": { "get": { + "description": "Retrieve the current state of the reverse geocoding import.", "operationId": "getReverseGeocodingState", "parameters": [], "responses": { @@ -8522,16 +8749,17 @@ "api_key": [] } ], + "summary": "Retrieve reverse geocoding state", "tags": [ - "System Metadata" + "System metadata" ], "x-immich-admin-only": true, - "x-immich-permission": "systemMetadata.read", - "description": "This endpoint is an admin-only route, and requires the `systemMetadata.read` permission." + "x-immich-permission": "systemMetadata.read" } }, "/system-metadata/version-check-state": { "get": { + "description": "Retrieve the current state of the version check process.", "operationId": "getVersionCheckState", "parameters": [], "responses": { @@ -8557,16 +8785,17 @@ "api_key": [] } ], + "summary": "Retrieve version check state", "tags": [ - "System Metadata" + "System metadata" ], "x-immich-admin-only": true, - "x-immich-permission": "systemMetadata.read", - "description": "This endpoint is an admin-only route, and requires the `systemMetadata.read` permission." + "x-immich-permission": "systemMetadata.read" } }, "/tags": { "get": { + "description": "Retrieve a list of all tags.", "operationId": "getAllTags", "parameters": [], "responses": { @@ -8595,13 +8824,14 @@ "api_key": [] } ], + "summary": "Retrieve tags", "tags": [ "Tags" ], - "x-immich-permission": "tag.read", - "description": "This endpoint requires the `tag.read` permission." + "x-immich-permission": "tag.read" }, "post": { + "description": "Create a new tag by providing a name and optional color.", "operationId": "createTag", "parameters": [], "requestBody": { @@ -8637,13 +8867,14 @@ "api_key": [] } ], + "summary": "Create a tag", "tags": [ "Tags" ], - "x-immich-permission": "tag.create", - "description": "This endpoint requires the `tag.create` permission." + "x-immich-permission": "tag.create" }, "put": { + "description": "Create or update multiple tags in a single request.", "operationId": "upsertTags", "parameters": [], "requestBody": { @@ -8682,15 +8913,16 @@ "api_key": [] } ], + "summary": "Upsert tags", "tags": [ "Tags" ], - "x-immich-permission": "tag.create", - "description": "This endpoint requires the `tag.create` permission." + "x-immich-permission": "tag.create" } }, "/tags/assets": { "put": { + "description": "Add multiple tags to multiple assets in a single request.", "operationId": "bulkTagAssets", "parameters": [], "requestBody": { @@ -8726,15 +8958,16 @@ "api_key": [] } ], + "summary": "Tag assets", "tags": [ "Tags" ], - "x-immich-permission": "tag.asset", - "description": "This endpoint requires the `tag.asset` permission." + "x-immich-permission": "tag.asset" } }, "/tags/{id}": { "delete": { + "description": "Delete a specific tag by its ID.", "operationId": "deleteTag", "parameters": [ { @@ -8763,13 +8996,14 @@ "api_key": [] } ], + "summary": "Delete a tag", "tags": [ "Tags" ], - "x-immich-permission": "tag.delete", - "description": "This endpoint requires the `tag.delete` permission." + "x-immich-permission": "tag.delete" }, "get": { + "description": "Retrieve a specific tag by its ID.", "operationId": "getTagById", "parameters": [ { @@ -8805,13 +9039,14 @@ "api_key": [] } ], + "summary": "Retrieve a tag", "tags": [ "Tags" ], - "x-immich-permission": "tag.read", - "description": "This endpoint requires the `tag.read` permission." + "x-immich-permission": "tag.read" }, "put": { + "description": "Update an existing tag identified by its ID.", "operationId": "updateTag", "parameters": [ { @@ -8857,15 +9092,16 @@ "api_key": [] } ], + "summary": "Update a tag", "tags": [ "Tags" ], - "x-immich-permission": "tag.update", - "description": "This endpoint requires the `tag.update` permission." + "x-immich-permission": "tag.update" } }, "/tags/{id}/assets": { "delete": { + "description": "Remove a tag from all the specified assets.", "operationId": "untagAssets", "parameters": [ { @@ -8914,13 +9150,14 @@ "api_key": [] } ], + "summary": "Untag assets", "tags": [ "Tags" ], - "x-immich-permission": "tag.asset", - "description": "This endpoint requires the `tag.asset` permission." + "x-immich-permission": "tag.asset" }, "put": { + "description": "Add a tag to all the specified assets.", "operationId": "tagAssets", "parameters": [ { @@ -8969,15 +9206,16 @@ "api_key": [] } ], + "summary": "Tag assets", "tags": [ "Tags" ], - "x-immich-permission": "tag.asset", - "description": "This endpoint requires the `tag.asset` permission." + "x-immich-permission": "tag.asset" } }, "/timeline/bucket": { "get": { + "description": "Retrieve a string of all asset ids in a given time bucket.", "operationId": "getTimeBucket", "parameters": [ { @@ -9133,15 +9371,16 @@ "api_key": [] } ], + "summary": "Get time bucket", "tags": [ "Timeline" ], - "x-immich-permission": "asset.read", - "description": "This endpoint requires the `asset.read` permission." + "x-immich-permission": "asset.read" } }, "/timeline/buckets": { "get": { + "description": "Retrieve a list of all minimal time buckets.", "operationId": "getTimeBuckets", "parameters": [ { @@ -9290,15 +9529,16 @@ "api_key": [] } ], + "summary": "Get time buckets", "tags": [ "Timeline" ], - "x-immich-permission": "asset.read", - "description": "This endpoint requires the `asset.read` permission." + "x-immich-permission": "asset.read" } }, "/trash/empty": { "post": { + "description": "Permanently delete all items in the trash.", "operationId": "emptyTrash", "parameters": [], "responses": { @@ -9324,15 +9564,16 @@ "api_key": [] } ], + "summary": "Empty trash", "tags": [ "Trash" ], - "x-immich-permission": "asset.delete", - "description": "This endpoint requires the `asset.delete` permission." + "x-immich-permission": "asset.delete" } }, "/trash/restore": { "post": { + "description": "Restore all items in the trash.", "operationId": "restoreTrash", "parameters": [], "responses": { @@ -9358,15 +9599,16 @@ "api_key": [] } ], + "summary": "Restore trash", "tags": [ "Trash" ], - "x-immich-permission": "asset.delete", - "description": "This endpoint requires the `asset.delete` permission." + "x-immich-permission": "asset.delete" } }, "/trash/restore/assets": { "post": { + "description": "Restore specific assets from the trash.", "operationId": "restoreAssets", "parameters": [], "requestBody": { @@ -9402,15 +9644,16 @@ "api_key": [] } ], + "summary": "Restore assets", "tags": [ "Trash" ], - "x-immich-permission": "asset.delete", - "description": "This endpoint requires the `asset.delete` permission." + "x-immich-permission": "asset.delete" } }, "/users": { "get": { + "description": "Retrieve a list of all users on the server.", "operationId": "searchUsers", "parameters": [], "responses": { @@ -9439,15 +9682,16 @@ "api_key": [] } ], + "summary": "Get all users", "tags": [ "Users" ], - "x-immich-permission": "user.read", - "description": "This endpoint requires the `user.read` permission." + "x-immich-permission": "user.read" } }, "/users/me": { "get": { + "description": "Retrieve information about the user making the API request.", "operationId": "getMyUser", "parameters": [], "responses": { @@ -9473,13 +9717,14 @@ "api_key": [] } ], + "summary": "Get current user", "tags": [ "Users" ], - "x-immich-permission": "user.read", - "description": "This endpoint requires the `user.read` permission." + "x-immich-permission": "user.read" }, "put": { + "description": "Update the current user making teh API request.", "operationId": "updateMyUser", "parameters": [], "requestBody": { @@ -9515,15 +9760,16 @@ "api_key": [] } ], + "summary": "Update current user", "tags": [ "Users" ], - "x-immich-permission": "user.update", - "description": "This endpoint requires the `user.update` permission." + "x-immich-permission": "user.update" } }, "/users/me/license": { "delete": { + "description": "Delete the registered product key for the current user.", "operationId": "deleteUserLicense", "parameters": [], "responses": { @@ -9542,13 +9788,14 @@ "api_key": [] } ], + "summary": "Delete user product key", "tags": [ "Users" ], - "x-immich-permission": "userLicense.delete", - "description": "This endpoint requires the `userLicense.delete` permission." + "x-immich-permission": "userLicense.delete" }, "get": { + "description": "Retrieve information about whether the current user has a registered product key.", "operationId": "getUserLicense", "parameters": [], "responses": { @@ -9574,13 +9821,14 @@ "api_key": [] } ], + "summary": "Retrieve user product key", "tags": [ "Users" ], - "x-immich-permission": "userLicense.read", - "description": "This endpoint requires the `userLicense.read` permission." + "x-immich-permission": "userLicense.read" }, "put": { + "description": "Register a product key for the current user.", "operationId": "setUserLicense", "parameters": [], "requestBody": { @@ -9616,15 +9864,16 @@ "api_key": [] } ], + "summary": "Set user product key", "tags": [ "Users" ], - "x-immich-permission": "userLicense.update", - "description": "This endpoint requires the `userLicense.update` permission." + "x-immich-permission": "userLicense.update" } }, "/users/me/onboarding": { "delete": { + "description": "Delete the onboarding status of the current user.", "operationId": "deleteUserOnboarding", "parameters": [], "responses": { @@ -9643,13 +9892,14 @@ "api_key": [] } ], + "summary": "Delete user onboarding", "tags": [ "Users" ], - "x-immich-permission": "userOnboarding.delete", - "description": "This endpoint requires the `userOnboarding.delete` permission." + "x-immich-permission": "userOnboarding.delete" }, "get": { + "description": "Retrieve the onboarding status of the current user.", "operationId": "getUserOnboarding", "parameters": [], "responses": { @@ -9675,13 +9925,14 @@ "api_key": [] } ], + "summary": "Retrieve user onboarding", "tags": [ "Users" ], - "x-immich-permission": "userOnboarding.read", - "description": "This endpoint requires the `userOnboarding.read` permission." + "x-immich-permission": "userOnboarding.read" }, "put": { + "description": "Update the onboarding status of the current user.", "operationId": "setUserOnboarding", "parameters": [], "requestBody": { @@ -9717,15 +9968,16 @@ "api_key": [] } ], + "summary": "Update user onboarding", "tags": [ "Users" ], - "x-immich-permission": "userOnboarding.update", - "description": "This endpoint requires the `userOnboarding.update` permission." + "x-immich-permission": "userOnboarding.update" } }, "/users/me/preferences": { "get": { + "description": "Retrieve the preferences for the current user.", "operationId": "getMyPreferences", "parameters": [], "responses": { @@ -9751,13 +10003,14 @@ "api_key": [] } ], + "summary": "Get my preferences", "tags": [ "Users" ], - "x-immich-permission": "userPreference.read", - "description": "This endpoint requires the `userPreference.read` permission." + "x-immich-permission": "userPreference.read" }, "put": { + "description": "Update the preferences of the current user.", "operationId": "updateMyPreferences", "parameters": [], "requestBody": { @@ -9793,15 +10046,16 @@ "api_key": [] } ], + "summary": "Update my preferences", "tags": [ "Users" ], - "x-immich-permission": "userPreference.update", - "description": "This endpoint requires the `userPreference.update` permission." + "x-immich-permission": "userPreference.update" } }, "/users/profile-image": { "delete": { + "description": "Delete the profile image of the current user.", "operationId": "deleteProfileImage", "parameters": [], "responses": { @@ -9820,13 +10074,14 @@ "api_key": [] } ], + "summary": "Delete user profile image", "tags": [ "Users" ], - "x-immich-permission": "userProfileImage.delete", - "description": "This endpoint requires the `userProfileImage.delete` permission." + "x-immich-permission": "userProfileImage.delete" }, "post": { + "description": "Upload and set a new profile image for the current user.", "operationId": "createProfileImage", "parameters": [], "requestBody": { @@ -9863,15 +10118,16 @@ "api_key": [] } ], + "summary": "Create user profile image", "tags": [ "Users" ], - "x-immich-permission": "userProfileImage.update", - "description": "This endpoint requires the `userProfileImage.update` permission." + "x-immich-permission": "userProfileImage.update" } }, "/users/{id}": { "get": { + "description": "Retrieve a specific user by their ID.", "operationId": "getUser", "parameters": [ { @@ -9907,15 +10163,16 @@ "api_key": [] } ], + "summary": "Retrieve a user", "tags": [ "Users" ], - "x-immich-permission": "user.read", - "description": "This endpoint requires the `user.read` permission." + "x-immich-permission": "user.read" } }, "/users/{id}/profile-image": { "get": { + "description": "Retrieve the profile image file for a user.", "operationId": "getProfileImage", "parameters": [ { @@ -9952,15 +10209,16 @@ "api_key": [] } ], + "summary": "Retrieve user profile image", "tags": [ "Users" ], - "x-immich-permission": "userProfileImage.read", - "description": "This endpoint requires the `userProfileImage.read` permission." + "x-immich-permission": "userProfileImage.read" } }, "/view/folder": { "get": { + "description": "Retrieve assets that are children of a specific folder.", "operationId": "getAssetsByOriginalPath", "parameters": [ { @@ -9998,13 +10256,15 @@ "api_key": [] } ], + "summary": "Retrieve assets by original path", "tags": [ - "View" + "Views" ] } }, "/view/folder/unique-paths": { "get": { + "description": "Retrieve a list of unique folder paths from asset original paths.", "operationId": "getUniqueOriginalPaths", "parameters": [], "responses": { @@ -10033,8 +10293,9 @@ "api_key": [] } ], + "summary": "Retrieve unique paths", "tags": [ - "View" + "Views" ] } } @@ -10045,7 +10306,136 @@ "version": "2.2.3", "contact": {} }, - "tags": [], + "tags": [ + { + "name": "Activities", + "description": "An activity is a like or a comment made by a user on an asset or album." + }, + { + "name": "Albums", + "description": "An album is a collection of assets that can be shared with other users or via shared links." + }, + { + "name": "API keys", + "description": "An api key can be used to programmatically access the Immich API." + }, + { + "name": "Assets", + "description": "An asset is an image or video that has been uploaded to Immich." + }, + { + "name": "Authentication", + "description": "Endpoints related to user authentication, including OAuth." + }, + { + "name": "Authentication (admin)", + "description": "Administrative endpoints related to authentication." + }, + { + "name": "Deprecated", + "description": "Deprecated endpoints that are planned for removal in the next major release." + }, + { + "name": "Download", + "description": "Endpoints for downloading assets or collections of assets." + }, + { + "name": "Duplicates", + "description": "Endpoints for managing and identifying duplicate assets." + }, + { + "name": "Faces", + "description": "A face is a detected human face within an asset, which can be associated with a person. Faces are normally detected via machine learning, but can also be created via manually." + }, + { + "name": "Jobs", + "description": "Queues and background jobs are used for processing tasks asynchronously. Queues can be paused and resumed as needed." + }, + { + "name": "Libraries", + "description": "An external library is made up of input file paths or expressions that are scanned for asset files. Discovered files are automatically imported. Assets much be unique within a library, but can be duplicated across libraries. Each user has a default upload library, and can have one or more external libraries." + }, + { + "name": "Map", + "description": "Map endpoints include supplemental functionality related to geolocation, such as reverse geocoding and retrieving map markers for assets with geolocation data." + }, + { + "name": "Memories", + "description": "A memory is a specialized collection of assets with dedicated viewing implementations in the web and mobile clients. A memory includes fields related to visibility and are automatically generated per user via a background job." + }, + { + "name": "Notifications", + "description": "A notification is a specialized message sent to users to inform them of important events. Currently, these notifications are only shown in the Immich web application." + }, + { + "name": "Notifications (admin)", + "description": "Notification administrative endpoints." + }, + { + "name": "Partners", + "description": "A partner is a link with another user that allows sharing of assets between two users." + }, + { + "name": "People", + "description": "A person is a collection of faces, which can be favorited and named. A person can also be merged into another person. People are automatically created via the face recognition job." + }, + { + "name": "Search", + "description": "Endpoints related to searching assets via text, smart search, optical character recognition (OCR), and other filters like person, album, and other metadata. Search endpoints usually support pagination and sorting." + }, + { + "name": "Server", + "description": "Information about the current server deployment, including version and build information, available features, supported media types, and more." + }, + { + "name": "Sessions", + "description": "A session represents an authenticated login session for a user. Sessions also appear in the web application as \"Authorized devices\"." + }, + { + "name": "Shared links", + "description": "A shared link is a public url that provides access to a specific album, asset, or collection of assets. A shared link can be protected with a password, include a specific slug, allow or disallow downloads, and optionally include an expiration date." + }, + { + "name": "Stacks", + "description": "A stack is a group of related assets. One asset is the \"primary\" asset, and the rest are \"child\" assets. On the main timeline, stack parents are included by default, while child assets are hidden." + }, + { + "name": "Sync", + "description": "A collection of endpoints for the new mobile synchronization implementation." + }, + { + "name": "System config", + "description": "Endpoints to view, modify, and validate the system configuration settings." + }, + { + "name": "System metadata", + "description": "Endpoints to view, modify, and validate the system metadata, which includes information about things like admin onboarding status." + }, + { + "name": "Tags", + "description": "A tag is a user-defined label that can be applied to assets for organizational purposes. Tags can also be hierarchical, allowing for parent-child relationships between tags." + }, + { + "name": "Timeline", + "description": "Specialized endpoints related to the timeline implementation used in the web application. External applications or tools should not use or rely on these endpoints, as they are subject to change without notice." + }, + { + "name": "Trash", + "description": "Endpoints for managing the trash can, which includes assets that have been discarded. Items in the trash are automatically deleted after a configured amount of time." + }, + { + "name": "Users (admin)", + "description": "Administrative endpoints for managing users, including creating, updating, deleting, and restoring users. Also includes endpoints for resetting passwords and PIN codes." + }, + { + "name": "Users", + "description": "Endpoints for viewing and updating the current users, including product key information, profile picture data, onboarding progress, and more." + }, + { + "name": "Views", + "description": "Endpoints for specialized views, such as the folder view." + } + ], "servers": [ { "url": "/api" diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index a0f43c620..eed7b2708 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -1677,7 +1677,7 @@ export type CreateProfileImageResponseDto = { userId: string; }; /** - * This endpoint requires the `activity.read` permission. + * List all activities */ export function getActivities({ albumId, assetId, level, $type, userId }: { albumId: string; @@ -1700,7 +1700,7 @@ export function getActivities({ albumId, assetId, level, $type, userId }: { })); } /** - * This endpoint requires the `activity.create` permission. + * Create an activity */ export function createActivity({ activityCreateDto }: { activityCreateDto: ActivityCreateDto; @@ -1715,7 +1715,7 @@ export function createActivity({ activityCreateDto }: { }))); } /** - * This endpoint requires the `activity.statistics` permission. + * Retrieve activity statistics */ export function getActivityStatistics({ albumId, assetId }: { albumId: string; @@ -1732,7 +1732,7 @@ export function getActivityStatistics({ albumId, assetId }: { })); } /** - * This endpoint requires the `activity.delete` permission. + * Delete an activity */ export function deleteActivity({ id }: { id: string; @@ -1743,7 +1743,7 @@ export function deleteActivity({ id }: { })); } /** - * This endpoint is an admin-only route, and requires the `adminAuth.unlinkAll` permission. + * Unlink all OAuth accounts */ export function unlinkAllOAuthAccountsAdmin(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/admin/auth/unlink-all", { @@ -1751,6 +1751,9 @@ export function unlinkAllOAuthAccountsAdmin(opts?: Oazapfts.RequestOpts) { method: "POST" })); } +/** + * Create a notification + */ export function createNotification({ notificationCreateDto }: { notificationCreateDto: NotificationCreateDto; }, opts?: Oazapfts.RequestOpts) { @@ -1763,6 +1766,9 @@ export function createNotification({ notificationCreateDto }: { body: notificationCreateDto }))); } +/** + * Render email template + */ export function getNotificationTemplateAdmin({ name, templateDto }: { name: string; templateDto: TemplateDto; @@ -1776,6 +1782,9 @@ export function getNotificationTemplateAdmin({ name, templateDto }: { body: templateDto }))); } +/** + * Send test email + */ export function sendTestEmailAdmin({ systemConfigSmtpDto }: { systemConfigSmtpDto: SystemConfigSmtpDto; }, opts?: Oazapfts.RequestOpts) { @@ -1789,7 +1798,7 @@ export function sendTestEmailAdmin({ systemConfigSmtpDto }: { }))); } /** - * This endpoint is an admin-only route, and requires the `adminUser.read` permission. + * Search users */ export function searchUsersAdmin({ id, withDeleted }: { id?: string; @@ -1806,7 +1815,7 @@ export function searchUsersAdmin({ id, withDeleted }: { })); } /** - * This endpoint is an admin-only route, and requires the `adminUser.create` permission. + * Create a user */ export function createUserAdmin({ userAdminCreateDto }: { userAdminCreateDto: UserAdminCreateDto; @@ -1821,7 +1830,7 @@ export function createUserAdmin({ userAdminCreateDto }: { }))); } /** - * This endpoint is an admin-only route, and requires the `adminUser.delete` permission. + * Delete a user */ export function deleteUserAdmin({ id, userAdminDeleteDto }: { id: string; @@ -1837,7 +1846,7 @@ export function deleteUserAdmin({ id, userAdminDeleteDto }: { }))); } /** - * This endpoint is an admin-only route, and requires the `adminUser.read` permission. + * Retrieve a user */ export function getUserAdmin({ id }: { id: string; @@ -1850,7 +1859,7 @@ export function getUserAdmin({ id }: { })); } /** - * This endpoint is an admin-only route, and requires the `adminUser.update` permission. + * Update a user */ export function updateUserAdmin({ id, userAdminUpdateDto }: { id: string; @@ -1866,7 +1875,7 @@ export function updateUserAdmin({ id, userAdminUpdateDto }: { }))); } /** - * This endpoint is an admin-only route, and requires the `adminUser.read` permission. + * Retrieve user preferences */ export function getUserPreferencesAdmin({ id }: { id: string; @@ -1879,7 +1888,7 @@ export function getUserPreferencesAdmin({ id }: { })); } /** - * This endpoint is an admin-only route, and requires the `adminUser.update` permission. + * Update user preferences */ export function updateUserPreferencesAdmin({ id, userPreferencesUpdateDto }: { id: string; @@ -1895,7 +1904,7 @@ export function updateUserPreferencesAdmin({ id, userPreferencesUpdateDto }: { }))); } /** - * This endpoint is an admin-only route, and requires the `adminUser.delete` permission. + * Restore a deleted user */ export function restoreUserAdmin({ id }: { id: string; @@ -1909,7 +1918,7 @@ export function restoreUserAdmin({ id }: { })); } /** - * This endpoint is an admin-only route, and requires the `adminSession.read` permission. + * Retrieve user sessions */ export function getUserSessionsAdmin({ id }: { id: string; @@ -1922,7 +1931,7 @@ export function getUserSessionsAdmin({ id }: { })); } /** - * This endpoint is an admin-only route, and requires the `adminUser.read` permission. + * Retrieve user statistics */ export function getUserStatisticsAdmin({ id, isFavorite, isTrashed, visibility }: { id: string; @@ -1942,7 +1951,7 @@ export function getUserStatisticsAdmin({ id, isFavorite, isTrashed, visibility } })); } /** - * This endpoint requires the `album.read` permission. + * List all albums */ export function getAllAlbums({ assetId, shared }: { assetId?: string; @@ -1959,7 +1968,7 @@ export function getAllAlbums({ assetId, shared }: { })); } /** - * This endpoint requires the `album.create` permission. + * Create an album */ export function createAlbum({ createAlbumDto }: { createAlbumDto: CreateAlbumDto; @@ -1974,7 +1983,7 @@ export function createAlbum({ createAlbumDto }: { }))); } /** - * This endpoint requires the `albumAsset.create` permission. + * Add assets to albums */ export function addAssetsToAlbums({ key, slug, albumsAddAssetsDto }: { key?: string; @@ -1994,7 +2003,7 @@ export function addAssetsToAlbums({ key, slug, albumsAddAssetsDto }: { }))); } /** - * This endpoint requires the `album.statistics` permission. + * Retrieve album statistics */ export function getAlbumStatistics(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -2005,7 +2014,7 @@ export function getAlbumStatistics(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `album.delete` permission. + * Delete an album */ export function deleteAlbum({ id }: { id: string; @@ -2016,7 +2025,7 @@ export function deleteAlbum({ id }: { })); } /** - * This endpoint requires the `album.read` permission. + * Retrieve an album */ export function getAlbumInfo({ id, key, slug, withoutAssets }: { id: string; @@ -2036,7 +2045,7 @@ export function getAlbumInfo({ id, key, slug, withoutAssets }: { })); } /** - * This endpoint requires the `album.update` permission. + * Update an album */ export function updateAlbumInfo({ id, updateAlbumDto }: { id: string; @@ -2052,7 +2061,7 @@ export function updateAlbumInfo({ id, updateAlbumDto }: { }))); } /** - * This endpoint requires the `albumAsset.delete` permission. + * Remove assets from an album */ export function removeAssetFromAlbum({ id, bulkIdsDto }: { id: string; @@ -2068,7 +2077,7 @@ export function removeAssetFromAlbum({ id, bulkIdsDto }: { }))); } /** - * This endpoint requires the `albumAsset.create` permission. + * Add assets to an album */ export function addAssetsToAlbum({ id, key, slug, bulkIdsDto }: { id: string; @@ -2089,7 +2098,7 @@ export function addAssetsToAlbum({ id, key, slug, bulkIdsDto }: { }))); } /** - * This endpoint requires the `albumUser.delete` permission. + * Remove user from album */ export function removeUserFromAlbum({ id, userId }: { id: string; @@ -2101,7 +2110,7 @@ export function removeUserFromAlbum({ id, userId }: { })); } /** - * This endpoint requires the `albumUser.update` permission. + * Update user role */ export function updateAlbumUser({ id, userId, updateAlbumUserDto }: { id: string; @@ -2115,7 +2124,7 @@ export function updateAlbumUser({ id, userId, updateAlbumUserDto }: { }))); } /** - * This endpoint requires the `albumUser.create` permission. + * Share album with users */ export function addUsersToAlbum({ id, addUsersDto }: { id: string; @@ -2131,7 +2140,7 @@ export function addUsersToAlbum({ id, addUsersDto }: { }))); } /** - * This endpoint requires the `apiKey.read` permission. + * List all API keys */ export function getApiKeys(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -2142,7 +2151,7 @@ export function getApiKeys(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `apiKey.create` permission. + * Create an API key */ export function createApiKey({ apiKeyCreateDto }: { apiKeyCreateDto: ApiKeyCreateDto; @@ -2156,6 +2165,9 @@ export function createApiKey({ apiKeyCreateDto }: { body: apiKeyCreateDto }))); } +/** + * Retrieve the current API key + */ export function getMyApiKey(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -2165,7 +2177,7 @@ export function getMyApiKey(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `apiKey.delete` permission. + * Delete an API key */ export function deleteApiKey({ id }: { id: string; @@ -2176,7 +2188,7 @@ export function deleteApiKey({ id }: { })); } /** - * This endpoint requires the `apiKey.read` permission. + * Retrieve an API key */ export function getApiKey({ id }: { id: string; @@ -2189,7 +2201,7 @@ export function getApiKey({ id }: { })); } /** - * This endpoint requires the `apiKey.update` permission. + * Update an API key */ export function updateApiKey({ id, apiKeyUpdateDto }: { id: string; @@ -2205,7 +2217,7 @@ export function updateApiKey({ id, apiKeyUpdateDto }: { }))); } /** - * This endpoint requires the `asset.delete` permission. + * Delete assets */ export function deleteAssets({ assetBulkDeleteDto }: { assetBulkDeleteDto: AssetBulkDeleteDto; @@ -2217,7 +2229,7 @@ export function deleteAssets({ assetBulkDeleteDto }: { }))); } /** - * This endpoint requires the `asset.upload` permission. + * Upload asset */ export function uploadAsset({ key, slug, xImmichChecksum, assetMediaCreateDto }: { key?: string; @@ -2241,7 +2253,7 @@ export function uploadAsset({ key, slug, xImmichChecksum, assetMediaCreateDto }: }))); } /** - * This endpoint requires the `asset.update` permission. + * Update assets */ export function updateAssets({ assetBulkUpdateDto }: { assetBulkUpdateDto: AssetBulkUpdateDto; @@ -2253,7 +2265,7 @@ export function updateAssets({ assetBulkUpdateDto }: { }))); } /** - * checkBulkUpload + * Check bulk upload */ export function checkBulkUpload({ assetBulkUploadCheckDto }: { assetBulkUploadCheckDto: AssetBulkUploadCheckDto; @@ -2268,7 +2280,7 @@ export function checkBulkUpload({ assetBulkUploadCheckDto }: { }))); } /** - * This endpoint requires the `asset.copy` permission. + * Copy asset */ export function copyAsset({ assetCopyDto }: { assetCopyDto: AssetCopyDto; @@ -2280,7 +2292,7 @@ export function copyAsset({ assetCopyDto }: { }))); } /** - * getAllUserAssetsByDeviceId + * Retrieve assets by device ID */ export function getAllUserAssetsByDeviceId({ deviceId }: { deviceId: string; @@ -2293,7 +2305,7 @@ export function getAllUserAssetsByDeviceId({ deviceId }: { })); } /** - * checkExistingAssets + * Check existing assets */ export function checkExistingAssets({ checkExistingAssetsDto }: { checkExistingAssetsDto: CheckExistingAssetsDto; @@ -2307,6 +2319,9 @@ export function checkExistingAssets({ checkExistingAssetsDto }: { body: checkExistingAssetsDto }))); } +/** + * Run an asset job + */ export function runAssetJobs({ assetJobsDto }: { assetJobsDto: AssetJobsDto; }, opts?: Oazapfts.RequestOpts) { @@ -2317,7 +2332,7 @@ export function runAssetJobs({ assetJobsDto }: { }))); } /** - * This property was deprecated in v1.116.0. This endpoint requires the `asset.read` permission. + * Get random assets */ export function getRandom({ count }: { count?: number; @@ -2332,7 +2347,7 @@ export function getRandom({ count }: { })); } /** - * This endpoint requires the `asset.statistics` permission. + * Get asset statistics */ export function getAssetStatistics({ isFavorite, isTrashed, visibility }: { isFavorite?: boolean; @@ -2351,7 +2366,7 @@ export function getAssetStatistics({ isFavorite, isTrashed, visibility }: { })); } /** - * This endpoint requires the `asset.read` permission. + * Retrieve an asset */ export function getAssetInfo({ id, key, slug }: { id: string; @@ -2369,7 +2384,7 @@ export function getAssetInfo({ id, key, slug }: { })); } /** - * This endpoint requires the `asset.update` permission. + * Update an asset */ export function updateAsset({ id, updateAssetDto }: { id: string; @@ -2385,7 +2400,7 @@ export function updateAsset({ id, updateAssetDto }: { }))); } /** - * This endpoint requires the `asset.read` permission. + * Get asset metadata */ export function getAssetMetadata({ id }: { id: string; @@ -2398,7 +2413,7 @@ export function getAssetMetadata({ id }: { })); } /** - * This endpoint requires the `asset.update` permission. + * Update asset metadata */ export function updateAssetMetadata({ id, assetMetadataUpsertDto }: { id: string; @@ -2414,7 +2429,7 @@ export function updateAssetMetadata({ id, assetMetadataUpsertDto }: { }))); } /** - * This endpoint requires the `asset.update` permission. + * Delete asset metadata by key */ export function deleteAssetMetadata({ id, key }: { id: string; @@ -2426,7 +2441,7 @@ export function deleteAssetMetadata({ id, key }: { })); } /** - * This endpoint requires the `asset.read` permission. + * Retrieve asset metadata by key */ export function getAssetMetadataByKey({ id, key }: { id: string; @@ -2440,7 +2455,7 @@ export function getAssetMetadataByKey({ id, key }: { })); } /** - * This endpoint requires the `asset.read` permission. + * Retrieve asset OCR data */ export function getAssetOcr({ id }: { id: string; @@ -2453,7 +2468,7 @@ export function getAssetOcr({ id }: { })); } /** - * This endpoint requires the `asset.download` permission. + * Download original asset */ export function downloadAsset({ id, key, slug }: { id: string; @@ -2471,7 +2486,7 @@ export function downloadAsset({ id, key, slug }: { })); } /** - * Replace the asset with new file, without changing its id + * Replace asset */ export function replaceAsset({ id, key, slug, assetMediaReplaceDto }: { id: string; @@ -2492,7 +2507,7 @@ export function replaceAsset({ id, key, slug, assetMediaReplaceDto }: { }))); } /** - * This endpoint requires the `asset.view` permission. + * View asset thumbnail */ export function viewAsset({ id, key, size, slug }: { id: string; @@ -2512,7 +2527,7 @@ export function viewAsset({ id, key, size, slug }: { })); } /** - * This endpoint requires the `asset.view` permission. + * Play asset video */ export function playAssetVideo({ id, key, slug }: { id: string; @@ -2529,6 +2544,9 @@ export function playAssetVideo({ id, key, slug }: { ...opts })); } +/** + * Register admin + */ export function signUpAdmin({ signUpDto }: { signUpDto: SignUpDto; }, opts?: Oazapfts.RequestOpts) { @@ -2542,7 +2560,7 @@ export function signUpAdmin({ signUpDto }: { }))); } /** - * This endpoint requires the `auth.changePassword` permission. + * Change password */ export function changePassword({ changePasswordDto }: { changePasswordDto: ChangePasswordDto; @@ -2556,6 +2574,9 @@ export function changePassword({ changePasswordDto }: { body: changePasswordDto }))); } +/** + * Login + */ export function login({ loginCredentialDto }: { loginCredentialDto: LoginCredentialDto; }, opts?: Oazapfts.RequestOpts) { @@ -2568,6 +2589,9 @@ export function login({ loginCredentialDto }: { body: loginCredentialDto }))); } +/** + * Logout + */ export function logout(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -2578,7 +2602,7 @@ export function logout(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `pinCode.delete` permission. + * Reset pin code */ export function resetPinCode({ pinCodeResetDto }: { pinCodeResetDto: PinCodeResetDto; @@ -2590,7 +2614,7 @@ export function resetPinCode({ pinCodeResetDto }: { }))); } /** - * This endpoint requires the `pinCode.create` permission. + * Setup pin code */ export function setupPinCode({ pinCodeSetupDto }: { pinCodeSetupDto: PinCodeSetupDto; @@ -2602,7 +2626,7 @@ export function setupPinCode({ pinCodeSetupDto }: { }))); } /** - * This endpoint requires the `pinCode.update` permission. + * Change pin code */ export function changePinCode({ pinCodeChangeDto }: { pinCodeChangeDto: PinCodeChangeDto; @@ -2613,12 +2637,18 @@ export function changePinCode({ pinCodeChangeDto }: { body: pinCodeChangeDto }))); } +/** + * Lock auth session + */ export function lockAuthSession(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/auth/session/lock", { ...opts, method: "POST" })); } +/** + * Unlock auth session + */ export function unlockAuthSession({ sessionUnlockDto }: { sessionUnlockDto: SessionUnlockDto; }, opts?: Oazapfts.RequestOpts) { @@ -2628,6 +2658,9 @@ export function unlockAuthSession({ sessionUnlockDto }: { body: sessionUnlockDto }))); } +/** + * Retrieve auth status + */ export function getAuthStatus(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -2636,6 +2669,9 @@ export function getAuthStatus(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * Validate access token + */ export function validateAccessToken(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -2646,7 +2682,7 @@ export function validateAccessToken(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `asset.download` permission. + * Download asset archive */ export function downloadArchive({ key, slug, assetIdsDto }: { key?: string; @@ -2666,7 +2702,7 @@ export function downloadArchive({ key, slug, assetIdsDto }: { }))); } /** - * This endpoint requires the `asset.download` permission. + * Retrieve download information */ export function getDownloadInfo({ key, slug, downloadInfoDto }: { key?: string; @@ -2686,7 +2722,7 @@ export function getDownloadInfo({ key, slug, downloadInfoDto }: { }))); } /** - * This endpoint requires the `duplicate.delete` permission. + * Delete duplicates */ export function deleteDuplicates({ bulkIdsDto }: { bulkIdsDto: BulkIdsDto; @@ -2698,7 +2734,7 @@ export function deleteDuplicates({ bulkIdsDto }: { }))); } /** - * This endpoint requires the `duplicate.read` permission. + * Retrieve duplicates */ export function getAssetDuplicates(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -2709,7 +2745,7 @@ export function getAssetDuplicates(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `duplicate.delete` permission. + * Delete a duplicate */ export function deleteDuplicate({ id }: { id: string; @@ -2720,7 +2756,7 @@ export function deleteDuplicate({ id }: { })); } /** - * This endpoint requires the `face.read` permission. + * Retrieve faces for asset */ export function getFaces({ id }: { id: string; @@ -2735,7 +2771,7 @@ export function getFaces({ id }: { })); } /** - * This endpoint requires the `face.create` permission. + * Create a face */ export function createFace({ assetFaceCreateDto }: { assetFaceCreateDto: AssetFaceCreateDto; @@ -2747,7 +2783,7 @@ export function createFace({ assetFaceCreateDto }: { }))); } /** - * This endpoint requires the `face.delete` permission. + * Delete a face */ export function deleteFace({ id, assetFaceDeleteDto }: { id: string; @@ -2760,7 +2796,7 @@ export function deleteFace({ id, assetFaceDeleteDto }: { }))); } /** - * This endpoint requires the `face.update` permission. + * Re-assign a face to another person */ export function reassignFacesById({ id, faceDto }: { id: string; @@ -2776,7 +2812,7 @@ export function reassignFacesById({ id, faceDto }: { }))); } /** - * This endpoint is an admin-only route, and requires the `job.read` permission. + * Retrieve queue counts and status */ export function getAllJobsStatus(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -2787,7 +2823,7 @@ export function getAllJobsStatus(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint is an admin-only route, and requires the `job.create` permission. + * Create a manual job */ export function createJob({ jobCreateDto }: { jobCreateDto: JobCreateDto; @@ -2799,7 +2835,7 @@ export function createJob({ jobCreateDto }: { }))); } /** - * This endpoint is an admin-only route, and requires the `job.create` permission. + * Run jobs */ export function sendJobCommand({ id, jobCommandDto }: { id: JobName; @@ -2815,7 +2851,7 @@ export function sendJobCommand({ id, jobCommandDto }: { }))); } /** - * This endpoint is an admin-only route, and requires the `library.read` permission. + * Retrieve libraries */ export function getAllLibraries(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -2826,7 +2862,7 @@ export function getAllLibraries(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint is an admin-only route, and requires the `library.create` permission. + * Create a library */ export function createLibrary({ createLibraryDto }: { createLibraryDto: CreateLibraryDto; @@ -2841,7 +2877,7 @@ export function createLibrary({ createLibraryDto }: { }))); } /** - * This endpoint is an admin-only route, and requires the `library.delete` permission. + * Delete a library */ export function deleteLibrary({ id }: { id: string; @@ -2852,7 +2888,7 @@ export function deleteLibrary({ id }: { })); } /** - * This endpoint is an admin-only route, and requires the `library.read` permission. + * Retrieve a library */ export function getLibrary({ id }: { id: string; @@ -2865,7 +2901,7 @@ export function getLibrary({ id }: { })); } /** - * This endpoint is an admin-only route, and requires the `library.update` permission. + * Update a library */ export function updateLibrary({ id, updateLibraryDto }: { id: string; @@ -2881,7 +2917,7 @@ export function updateLibrary({ id, updateLibraryDto }: { }))); } /** - * This endpoint is an admin-only route, and requires the `library.update` permission. + * Scan a library */ export function scanLibrary({ id }: { id: string; @@ -2892,7 +2928,7 @@ export function scanLibrary({ id }: { })); } /** - * This endpoint is an admin-only route, and requires the `library.statistics` permission. + * Retrieve library statistics */ export function getLibraryStatistics({ id }: { id: string; @@ -2904,6 +2940,9 @@ export function getLibraryStatistics({ id }: { ...opts })); } +/** + * Validate library settings + */ export function validate({ id, validateLibraryDto }: { id: string; validateLibraryDto: ValidateLibraryDto; @@ -2917,11 +2956,14 @@ export function validate({ id, validateLibraryDto }: { body: validateLibraryDto }))); } -export function getMapMarkers({ isArchived, isFavorite, fileCreatedAfter, fileCreatedBefore, withPartners, withSharedAlbums }: { - isArchived?: boolean; - isFavorite?: boolean; +/** + * Retrieve map markers + */ +export function getMapMarkers({ fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners, withSharedAlbums }: { fileCreatedAfter?: string; fileCreatedBefore?: string; + isArchived?: boolean; + isFavorite?: boolean; withPartners?: boolean; withSharedAlbums?: boolean; }, opts?: Oazapfts.RequestOpts) { @@ -2929,16 +2971,19 @@ export function getMapMarkers({ isArchived, isFavorite, fileCreatedAfter, fileCr status: 200; data: MapMarkerResponseDto[]; }>(`/map/markers${QS.query(QS.explode({ - isArchived, - isFavorite, fileCreatedAfter, fileCreatedBefore, + isArchived, + isFavorite, withPartners, withSharedAlbums }))}`, { ...opts })); } +/** + * Reverse geocode coordinates + */ export function reverseGeocode({ lat, lon }: { lat: number; lon: number; @@ -2954,7 +2999,7 @@ export function reverseGeocode({ lat, lon }: { })); } /** - * This endpoint requires the `memory.read` permission. + * Retrieve memories */ export function searchMemories({ $for, isSaved, isTrashed, order, size, $type }: { $for?: string; @@ -2979,7 +3024,7 @@ export function searchMemories({ $for, isSaved, isTrashed, order, size, $type }: })); } /** - * This endpoint requires the `memory.create` permission. + * Create a memory */ export function createMemory({ memoryCreateDto }: { memoryCreateDto: MemoryCreateDto; @@ -2994,7 +3039,7 @@ export function createMemory({ memoryCreateDto }: { }))); } /** - * This endpoint requires the `memory.statistics` permission. + * Retrieve memories statistics */ export function memoriesStatistics({ $for, isSaved, isTrashed, order, size, $type }: { $for?: string; @@ -3019,7 +3064,7 @@ export function memoriesStatistics({ $for, isSaved, isTrashed, order, size, $typ })); } /** - * This endpoint requires the `memory.delete` permission. + * Delete a memory */ export function deleteMemory({ id }: { id: string; @@ -3030,7 +3075,7 @@ export function deleteMemory({ id }: { })); } /** - * This endpoint requires the `memory.read` permission. + * Retrieve a memory */ export function getMemory({ id }: { id: string; @@ -3043,7 +3088,7 @@ export function getMemory({ id }: { })); } /** - * This endpoint requires the `memory.update` permission. + * Update a memory */ export function updateMemory({ id, memoryUpdateDto }: { id: string; @@ -3059,7 +3104,7 @@ export function updateMemory({ id, memoryUpdateDto }: { }))); } /** - * This endpoint requires the `memoryAsset.delete` permission. + * Remove assets from a memory */ export function removeMemoryAssets({ id, bulkIdsDto }: { id: string; @@ -3075,7 +3120,7 @@ export function removeMemoryAssets({ id, bulkIdsDto }: { }))); } /** - * This endpoint requires the `memoryAsset.create` permission. + * Add assets to a memory */ export function addMemoryAssets({ id, bulkIdsDto }: { id: string; @@ -3091,7 +3136,7 @@ export function addMemoryAssets({ id, bulkIdsDto }: { }))); } /** - * This endpoint requires the `notification.delete` permission. + * Delete notifications */ export function deleteNotifications({ notificationDeleteAllDto }: { notificationDeleteAllDto: NotificationDeleteAllDto; @@ -3103,7 +3148,7 @@ export function deleteNotifications({ notificationDeleteAllDto }: { }))); } /** - * This endpoint requires the `notification.read` permission. + * Retrieve notifications */ export function getNotifications({ id, level, $type, unread }: { id?: string; @@ -3124,7 +3169,7 @@ export function getNotifications({ id, level, $type, unread }: { })); } /** - * This endpoint requires the `notification.update` permission. + * Update notifications */ export function updateNotifications({ notificationUpdateAllDto }: { notificationUpdateAllDto: NotificationUpdateAllDto; @@ -3136,7 +3181,7 @@ export function updateNotifications({ notificationUpdateAllDto }: { }))); } /** - * This endpoint requires the `notification.delete` permission. + * Delete a notification */ export function deleteNotification({ id }: { id: string; @@ -3147,7 +3192,7 @@ export function deleteNotification({ id }: { })); } /** - * This endpoint requires the `notification.read` permission. + * Get a notification */ export function getNotification({ id }: { id: string; @@ -3160,7 +3205,7 @@ export function getNotification({ id }: { })); } /** - * This endpoint requires the `notification.update` permission. + * Update a notification */ export function updateNotification({ id, notificationUpdateDto }: { id: string; @@ -3175,6 +3220,9 @@ export function updateNotification({ id, notificationUpdateDto }: { body: notificationUpdateDto }))); } +/** + * Start OAuth + */ export function startOAuth({ oAuthConfigDto }: { oAuthConfigDto: OAuthConfigDto; }, opts?: Oazapfts.RequestOpts) { @@ -3187,6 +3235,9 @@ export function startOAuth({ oAuthConfigDto }: { body: oAuthConfigDto }))); } +/** + * Finish OAuth + */ export function finishOAuth({ oAuthCallbackDto }: { oAuthCallbackDto: OAuthCallbackDto; }, opts?: Oazapfts.RequestOpts) { @@ -3199,6 +3250,9 @@ export function finishOAuth({ oAuthCallbackDto }: { body: oAuthCallbackDto }))); } +/** + * Link OAuth account + */ export function linkOAuthAccount({ oAuthCallbackDto }: { oAuthCallbackDto: OAuthCallbackDto; }, opts?: Oazapfts.RequestOpts) { @@ -3211,11 +3265,17 @@ export function linkOAuthAccount({ oAuthCallbackDto }: { body: oAuthCallbackDto }))); } +/** + * Redirect OAuth to mobile + */ export function redirectOAuthToMobile(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/oauth/mobile-redirect", { ...opts })); } +/** + * Unlink OAuth account + */ export function unlinkOAuthAccount(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3226,7 +3286,7 @@ export function unlinkOAuthAccount(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `partner.read` permission. + * Retrieve partners */ export function getPartners({ direction }: { direction: PartnerDirection; @@ -3241,7 +3301,7 @@ export function getPartners({ direction }: { })); } /** - * This endpoint requires the `partner.create` permission. + * Create a partner */ export function createPartner({ partnerCreateDto }: { partnerCreateDto: PartnerCreateDto; @@ -3256,7 +3316,7 @@ export function createPartner({ partnerCreateDto }: { }))); } /** - * This endpoint requires the `partner.delete` permission. + * Remove a partner */ export function removePartner({ id }: { id: string; @@ -3267,7 +3327,7 @@ export function removePartner({ id }: { })); } /** - * This property was deprecated in v1.141.0. This endpoint requires the `partner.create` permission. + * Create a partner */ export function createPartnerDeprecated({ id }: { id: string; @@ -3281,7 +3341,7 @@ export function createPartnerDeprecated({ id }: { })); } /** - * This endpoint requires the `partner.update` permission. + * Update a partner */ export function updatePartner({ id, partnerUpdateDto }: { id: string; @@ -3297,7 +3357,7 @@ export function updatePartner({ id, partnerUpdateDto }: { }))); } /** - * This endpoint requires the `person.delete` permission. + * Delete people */ export function deletePeople({ bulkIdsDto }: { bulkIdsDto: BulkIdsDto; @@ -3309,7 +3369,7 @@ export function deletePeople({ bulkIdsDto }: { }))); } /** - * This endpoint requires the `person.read` permission. + * Get all people */ export function getAllPeople({ closestAssetId, closestPersonId, page, size, withHidden }: { closestAssetId?: string; @@ -3332,7 +3392,7 @@ export function getAllPeople({ closestAssetId, closestPersonId, page, size, with })); } /** - * This endpoint requires the `person.create` permission. + * Create a person */ export function createPerson({ personCreateDto }: { personCreateDto: PersonCreateDto; @@ -3347,7 +3407,7 @@ export function createPerson({ personCreateDto }: { }))); } /** - * This endpoint requires the `person.update` permission. + * Update people */ export function updatePeople({ peopleUpdateDto }: { peopleUpdateDto: PeopleUpdateDto; @@ -3362,7 +3422,7 @@ export function updatePeople({ peopleUpdateDto }: { }))); } /** - * This endpoint requires the `person.delete` permission. + * Delete person */ export function deletePerson({ id }: { id: string; @@ -3373,7 +3433,7 @@ export function deletePerson({ id }: { })); } /** - * This endpoint requires the `person.read` permission. + * Get a person */ export function getPerson({ id }: { id: string; @@ -3386,7 +3446,7 @@ export function getPerson({ id }: { })); } /** - * This endpoint requires the `person.update` permission. + * Update person */ export function updatePerson({ id, personUpdateDto }: { id: string; @@ -3402,7 +3462,7 @@ export function updatePerson({ id, personUpdateDto }: { }))); } /** - * This endpoint requires the `person.merge` permission. + * Merge people */ export function mergePerson({ id, mergePersonDto }: { id: string; @@ -3418,7 +3478,7 @@ export function mergePerson({ id, mergePersonDto }: { }))); } /** - * This endpoint requires the `person.reassign` permission. + * Reassign faces */ export function reassignFaces({ id, assetFaceUpdateDto }: { id: string; @@ -3434,7 +3494,7 @@ export function reassignFaces({ id, assetFaceUpdateDto }: { }))); } /** - * This endpoint requires the `person.statistics` permission. + * Get person statistics */ export function getPersonStatistics({ id }: { id: string; @@ -3447,7 +3507,7 @@ export function getPersonStatistics({ id }: { })); } /** - * This endpoint requires the `person.read` permission. + * Get person thumbnail */ export function getPersonThumbnail({ id }: { id: string; @@ -3460,7 +3520,7 @@ export function getPersonThumbnail({ id }: { })); } /** - * This endpoint requires the `asset.read` permission. + * Retrieve assets by city */ export function getAssetsByCity(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -3471,7 +3531,7 @@ export function getAssetsByCity(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `asset.read` permission. + * Retrieve explore data */ export function getExploreData(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -3482,7 +3542,7 @@ export function getExploreData(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `asset.read` permission. + * Search large assets */ export function searchLargeAssets({ albumIds, city, country, createdAfter, createdBefore, deviceId, isEncoded, isFavorite, isMotion, isNotInAlbum, isOffline, lensModel, libraryId, make, minFileSize, model, ocr, personIds, rating, size, state, tagIds, takenAfter, takenBefore, trashedAfter, trashedBefore, $type, updatedAfter, updatedBefore, visibility, withDeleted, withExif }: { albumIds?: string[]; @@ -3560,7 +3620,7 @@ export function searchLargeAssets({ albumIds, city, country, createdAfter, creat })); } /** - * This endpoint requires the `asset.read` permission. + * Search assets by metadata */ export function searchAssets({ metadataSearchDto }: { metadataSearchDto: MetadataSearchDto; @@ -3575,7 +3635,7 @@ export function searchAssets({ metadataSearchDto }: { }))); } /** - * This endpoint requires the `person.read` permission. + * Search people */ export function searchPerson({ name, withHidden }: { name: string; @@ -3592,7 +3652,7 @@ export function searchPerson({ name, withHidden }: { })); } /** - * This endpoint requires the `asset.read` permission. + * Search places */ export function searchPlaces({ name }: { name: string; @@ -3607,7 +3667,7 @@ export function searchPlaces({ name }: { })); } /** - * This endpoint requires the `asset.read` permission. + * Search random assets */ export function searchRandom({ randomSearchDto }: { randomSearchDto: RandomSearchDto; @@ -3622,7 +3682,7 @@ export function searchRandom({ randomSearchDto }: { }))); } /** - * This endpoint requires the `asset.read` permission. + * Smart asset search */ export function searchSmart({ smartSearchDto }: { smartSearchDto: SmartSearchDto; @@ -3637,7 +3697,7 @@ export function searchSmart({ smartSearchDto }: { }))); } /** - * This endpoint requires the `asset.statistics` permission. + * Search asset statistics */ export function searchAssetStatistics({ statisticsSearchDto }: { statisticsSearchDto: StatisticsSearchDto; @@ -3652,7 +3712,7 @@ export function searchAssetStatistics({ statisticsSearchDto }: { }))); } /** - * This endpoint requires the `asset.read` permission. + * Retrieve search suggestions */ export function getSearchSuggestions({ country, includeNull, lensModel, make, model, state, $type }: { country?: string; @@ -3679,7 +3739,7 @@ export function getSearchSuggestions({ country, includeNull, lensModel, make, mo })); } /** - * This endpoint requires the `server.about` permission. + * Get server information */ export function getAboutInfo(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -3690,7 +3750,7 @@ export function getAboutInfo(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `server.apkLinks` permission. + * Get APK links */ export function getApkLinks(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -3700,6 +3760,9 @@ export function getApkLinks(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * Get config + */ export function getServerConfig(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3708,6 +3771,9 @@ export function getServerConfig(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * Get features + */ export function getServerFeatures(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3717,7 +3783,7 @@ export function getServerFeatures(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint is an admin-only route, and requires the `serverLicense.delete` permission. + * Delete server product key */ export function deleteServerLicense(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/server/license", { @@ -3726,7 +3792,7 @@ export function deleteServerLicense(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint is an admin-only route, and requires the `serverLicense.read` permission. + * Get product key */ export function getServerLicense(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -3739,7 +3805,7 @@ export function getServerLicense(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint is an admin-only route, and requires the `serverLicense.update` permission. + * Set server product key */ export function setServerLicense({ licenseKeyDto }: { licenseKeyDto: LicenseKeyDto; @@ -3753,6 +3819,9 @@ export function setServerLicense({ licenseKeyDto }: { body: licenseKeyDto }))); } +/** + * Get supported media types + */ export function getSupportedMediaTypes(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3761,6 +3830,9 @@ export function getSupportedMediaTypes(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * Ping + */ export function pingServer(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3770,7 +3842,7 @@ export function pingServer(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint is an admin-only route, and requires the `server.statistics` permission. + * Get statistics */ export function getServerStatistics(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -3781,7 +3853,7 @@ export function getServerStatistics(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `server.storage` permission. + * Get storage */ export function getStorage(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -3791,6 +3863,9 @@ export function getStorage(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * Get theme + */ export function getTheme(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3799,6 +3874,9 @@ export function getTheme(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * Get server version + */ export function getServerVersion(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3808,7 +3886,7 @@ export function getServerVersion(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `server.versionCheck` permission. + * Get version check status */ export function getVersionCheck(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -3818,6 +3896,9 @@ export function getVersionCheck(opts?: Oazapfts.RequestOpts) { ...opts })); } +/** + * Get version history + */ export function getVersionHistory(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -3827,7 +3908,7 @@ export function getVersionHistory(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `session.delete` permission. + * Delete all sessions */ export function deleteAllSessions(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/sessions", { @@ -3836,7 +3917,7 @@ export function deleteAllSessions(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `session.read` permission. + * Retrieve sessions */ export function getSessions(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -3847,7 +3928,7 @@ export function getSessions(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `session.create` permission. + * Create a session */ export function createSession({ sessionCreateDto }: { sessionCreateDto: SessionCreateDto; @@ -3862,7 +3943,7 @@ export function createSession({ sessionCreateDto }: { }))); } /** - * This endpoint requires the `session.delete` permission. + * Delete a session */ export function deleteSession({ id }: { id: string; @@ -3873,7 +3954,7 @@ export function deleteSession({ id }: { })); } /** - * This endpoint requires the `session.update` permission. + * Update a session */ export function updateSession({ id, sessionUpdateDto }: { id: string; @@ -3889,7 +3970,7 @@ export function updateSession({ id, sessionUpdateDto }: { }))); } /** - * This endpoint requires the `session.lock` permission. + * Lock a session */ export function lockSession({ id }: { id: string; @@ -3900,7 +3981,7 @@ export function lockSession({ id }: { })); } /** - * This endpoint requires the `sharedLink.read` permission. + * Retrieve all shared links */ export function getAllSharedLinks({ albumId }: { albumId?: string; @@ -3915,7 +3996,7 @@ export function getAllSharedLinks({ albumId }: { })); } /** - * This endpoint requires the `sharedLink.create` permission. + * Create a shared link */ export function createSharedLink({ sharedLinkCreateDto }: { sharedLinkCreateDto: SharedLinkCreateDto; @@ -3929,26 +4010,29 @@ export function createSharedLink({ sharedLinkCreateDto }: { body: sharedLinkCreateDto }))); } -export function getMySharedLink({ password, token, key, slug }: { - password?: string; - token?: string; +/** + * Retrieve current shared link + */ +export function getMySharedLink({ key, password, slug, token }: { key?: string; + password?: string; slug?: string; + token?: string; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: SharedLinkResponseDto; }>(`/shared-links/me${QS.query(QS.explode({ - password, - token, key, - slug + password, + slug, + token }))}`, { ...opts })); } /** - * This endpoint requires the `sharedLink.delete` permission. + * Delete a shared link */ export function removeSharedLink({ id }: { id: string; @@ -3959,7 +4043,7 @@ export function removeSharedLink({ id }: { })); } /** - * This endpoint requires the `sharedLink.read` permission. + * Retrieve a shared link */ export function getSharedLinkById({ id }: { id: string; @@ -3972,7 +4056,7 @@ export function getSharedLinkById({ id }: { })); } /** - * This endpoint requires the `sharedLink.update` permission. + * Update a shared link */ export function updateSharedLink({ id, sharedLinkEditDto }: { id: string; @@ -3987,6 +4071,9 @@ export function updateSharedLink({ id, sharedLinkEditDto }: { body: sharedLinkEditDto }))); } +/** + * Remove assets from a shared link + */ export function removeSharedLinkAssets({ id, key, slug, assetIdsDto }: { id: string; key?: string; @@ -4005,6 +4092,9 @@ export function removeSharedLinkAssets({ id, key, slug, assetIdsDto }: { body: assetIdsDto }))); } +/** + * Add assets to a shared link + */ export function addSharedLinkAssets({ id, key, slug, assetIdsDto }: { id: string; key?: string; @@ -4024,7 +4114,7 @@ export function addSharedLinkAssets({ id, key, slug, assetIdsDto }: { }))); } /** - * This endpoint requires the `stack.delete` permission. + * Delete stacks */ export function deleteStacks({ bulkIdsDto }: { bulkIdsDto: BulkIdsDto; @@ -4036,7 +4126,7 @@ export function deleteStacks({ bulkIdsDto }: { }))); } /** - * This endpoint requires the `stack.read` permission. + * Retrieve stacks */ export function searchStacks({ primaryAssetId }: { primaryAssetId?: string; @@ -4051,7 +4141,7 @@ export function searchStacks({ primaryAssetId }: { })); } /** - * This endpoint requires the `stack.create` permission. + * Create a stack */ export function createStack({ stackCreateDto }: { stackCreateDto: StackCreateDto; @@ -4066,7 +4156,7 @@ export function createStack({ stackCreateDto }: { }))); } /** - * This endpoint requires the `stack.delete` permission. + * Delete a stack */ export function deleteStack({ id }: { id: string; @@ -4077,7 +4167,7 @@ export function deleteStack({ id }: { })); } /** - * This endpoint requires the `stack.read` permission. + * Retrieve a stack */ export function getStack({ id }: { id: string; @@ -4090,7 +4180,7 @@ export function getStack({ id }: { })); } /** - * This endpoint requires the `stack.update` permission. + * Update a stack */ export function updateStack({ id, stackUpdateDto }: { id: string; @@ -4106,7 +4196,7 @@ export function updateStack({ id, stackUpdateDto }: { }))); } /** - * This endpoint requires the `stack.update` permission. + * Remove an asset from a stack */ export function removeAssetFromStack({ assetId, id }: { assetId: string; @@ -4118,7 +4208,7 @@ export function removeAssetFromStack({ assetId, id }: { })); } /** - * This endpoint requires the `syncCheckpoint.delete` permission. + * Delete acknowledgements */ export function deleteSyncAck({ syncAckDeleteDto }: { syncAckDeleteDto: SyncAckDeleteDto; @@ -4130,7 +4220,7 @@ export function deleteSyncAck({ syncAckDeleteDto }: { }))); } /** - * This endpoint requires the `syncCheckpoint.read` permission. + * Retrieve acknowledgements */ export function getSyncAck(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4141,7 +4231,7 @@ export function getSyncAck(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `syncCheckpoint.update` permission. + * Acknowledge changes */ export function sendSyncAck({ syncAckSetDto }: { syncAckSetDto: SyncAckSetDto; @@ -4152,6 +4242,9 @@ export function sendSyncAck({ syncAckSetDto }: { body: syncAckSetDto }))); } +/** + * Get delta sync for user + */ export function getDeltaSync({ assetDeltaSyncDto }: { assetDeltaSyncDto: AssetDeltaSyncDto; }, opts?: Oazapfts.RequestOpts) { @@ -4164,6 +4257,9 @@ export function getDeltaSync({ assetDeltaSyncDto }: { body: assetDeltaSyncDto }))); } +/** + * Get full sync for user + */ export function getFullSyncForUser({ assetFullSyncDto }: { assetFullSyncDto: AssetFullSyncDto; }, opts?: Oazapfts.RequestOpts) { @@ -4177,7 +4273,7 @@ export function getFullSyncForUser({ assetFullSyncDto }: { }))); } /** - * This endpoint requires the `sync.stream` permission. + * Stream sync changes */ export function getSyncStream({ syncStreamDto }: { syncStreamDto: SyncStreamDto; @@ -4189,7 +4285,7 @@ export function getSyncStream({ syncStreamDto }: { }))); } /** - * This endpoint is an admin-only route, and requires the `systemConfig.read` permission. + * Get system configuration */ export function getConfig(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4200,7 +4296,7 @@ export function getConfig(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint is an admin-only route, and requires the `systemConfig.update` permission. + * Update system configuration */ export function updateConfig({ systemConfigDto }: { systemConfigDto: SystemConfigDto; @@ -4215,7 +4311,7 @@ export function updateConfig({ systemConfigDto }: { }))); } /** - * This endpoint is an admin-only route, and requires the `systemConfig.read` permission. + * Get system configuration defaults */ export function getConfigDefaults(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4226,7 +4322,7 @@ export function getConfigDefaults(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint is an admin-only route, and requires the `systemConfig.read` permission. + * Get storage template options */ export function getStorageTemplateOptions(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4237,7 +4333,7 @@ export function getStorageTemplateOptions(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint is an admin-only route, and requires the `systemMetadata.read` permission. + * Retrieve admin onboarding */ export function getAdminOnboarding(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4248,7 +4344,7 @@ export function getAdminOnboarding(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint is an admin-only route, and requires the `systemMetadata.update` permission. + * Update admin onboarding */ export function updateAdminOnboarding({ adminOnboardingUpdateDto }: { adminOnboardingUpdateDto: AdminOnboardingUpdateDto; @@ -4260,7 +4356,7 @@ export function updateAdminOnboarding({ adminOnboardingUpdateDto }: { }))); } /** - * This endpoint is an admin-only route, and requires the `systemMetadata.read` permission. + * Retrieve reverse geocoding state */ export function getReverseGeocodingState(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4271,7 +4367,7 @@ export function getReverseGeocodingState(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint is an admin-only route, and requires the `systemMetadata.read` permission. + * Retrieve version check state */ export function getVersionCheckState(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4282,7 +4378,7 @@ export function getVersionCheckState(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `tag.read` permission. + * Retrieve tags */ export function getAllTags(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4293,7 +4389,7 @@ export function getAllTags(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `tag.create` permission. + * Create a tag */ export function createTag({ tagCreateDto }: { tagCreateDto: TagCreateDto; @@ -4308,7 +4404,7 @@ export function createTag({ tagCreateDto }: { }))); } /** - * This endpoint requires the `tag.create` permission. + * Upsert tags */ export function upsertTags({ tagUpsertDto }: { tagUpsertDto: TagUpsertDto; @@ -4323,7 +4419,7 @@ export function upsertTags({ tagUpsertDto }: { }))); } /** - * This endpoint requires the `tag.asset` permission. + * Tag assets */ export function bulkTagAssets({ tagBulkAssetsDto }: { tagBulkAssetsDto: TagBulkAssetsDto; @@ -4338,7 +4434,7 @@ export function bulkTagAssets({ tagBulkAssetsDto }: { }))); } /** - * This endpoint requires the `tag.delete` permission. + * Delete a tag */ export function deleteTag({ id }: { id: string; @@ -4349,7 +4445,7 @@ export function deleteTag({ id }: { })); } /** - * This endpoint requires the `tag.read` permission. + * Retrieve a tag */ export function getTagById({ id }: { id: string; @@ -4362,7 +4458,7 @@ export function getTagById({ id }: { })); } /** - * This endpoint requires the `tag.update` permission. + * Update a tag */ export function updateTag({ id, tagUpdateDto }: { id: string; @@ -4378,7 +4474,7 @@ export function updateTag({ id, tagUpdateDto }: { }))); } /** - * This endpoint requires the `tag.asset` permission. + * Untag assets */ export function untagAssets({ id, bulkIdsDto }: { id: string; @@ -4394,7 +4490,7 @@ export function untagAssets({ id, bulkIdsDto }: { }))); } /** - * This endpoint requires the `tag.asset` permission. + * Tag assets */ export function tagAssets({ id, bulkIdsDto }: { id: string; @@ -4410,7 +4506,7 @@ export function tagAssets({ id, bulkIdsDto }: { }))); } /** - * This endpoint requires the `asset.read` permission. + * Get time bucket */ export function getTimeBucket({ albumId, isFavorite, isTrashed, key, order, personId, slug, tagId, timeBucket, userId, visibility, withCoordinates, withPartners, withStacked }: { albumId?: string; @@ -4451,7 +4547,7 @@ export function getTimeBucket({ albumId, isFavorite, isTrashed, key, order, pers })); } /** - * This endpoint requires the `asset.read` permission. + * Get time buckets */ export function getTimeBuckets({ albumId, isFavorite, isTrashed, key, order, personId, slug, tagId, userId, visibility, withCoordinates, withPartners, withStacked }: { albumId?: string; @@ -4490,7 +4586,7 @@ export function getTimeBuckets({ albumId, isFavorite, isTrashed, key, order, per })); } /** - * This endpoint requires the `asset.delete` permission. + * Empty trash */ export function emptyTrash(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4502,7 +4598,7 @@ export function emptyTrash(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `asset.delete` permission. + * Restore trash */ export function restoreTrash(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4514,7 +4610,7 @@ export function restoreTrash(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `asset.delete` permission. + * Restore assets */ export function restoreAssets({ bulkIdsDto }: { bulkIdsDto: BulkIdsDto; @@ -4529,7 +4625,7 @@ export function restoreAssets({ bulkIdsDto }: { }))); } /** - * This endpoint requires the `user.read` permission. + * Get all users */ export function searchUsers(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4540,7 +4636,7 @@ export function searchUsers(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `user.read` permission. + * Get current user */ export function getMyUser(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4551,7 +4647,7 @@ export function getMyUser(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `user.update` permission. + * Update current user */ export function updateMyUser({ userUpdateMeDto }: { userUpdateMeDto: UserUpdateMeDto; @@ -4566,7 +4662,7 @@ export function updateMyUser({ userUpdateMeDto }: { }))); } /** - * This endpoint requires the `userLicense.delete` permission. + * Delete user product key */ export function deleteUserLicense(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/users/me/license", { @@ -4575,7 +4671,7 @@ export function deleteUserLicense(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `userLicense.read` permission. + * Retrieve user product key */ export function getUserLicense(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4586,7 +4682,7 @@ export function getUserLicense(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `userLicense.update` permission. + * Set user product key */ export function setUserLicense({ licenseKeyDto }: { licenseKeyDto: LicenseKeyDto; @@ -4601,7 +4697,7 @@ export function setUserLicense({ licenseKeyDto }: { }))); } /** - * This endpoint requires the `userOnboarding.delete` permission. + * Delete user onboarding */ export function deleteUserOnboarding(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/users/me/onboarding", { @@ -4610,7 +4706,7 @@ export function deleteUserOnboarding(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `userOnboarding.read` permission. + * Retrieve user onboarding */ export function getUserOnboarding(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4621,7 +4717,7 @@ export function getUserOnboarding(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `userOnboarding.update` permission. + * Update user onboarding */ export function setUserOnboarding({ onboardingDto }: { onboardingDto: OnboardingDto; @@ -4636,7 +4732,7 @@ export function setUserOnboarding({ onboardingDto }: { }))); } /** - * This endpoint requires the `userPreference.read` permission. + * Get my preferences */ export function getMyPreferences(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ @@ -4647,7 +4743,7 @@ export function getMyPreferences(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `userPreference.update` permission. + * Update my preferences */ export function updateMyPreferences({ userPreferencesUpdateDto }: { userPreferencesUpdateDto: UserPreferencesUpdateDto; @@ -4662,7 +4758,7 @@ export function updateMyPreferences({ userPreferencesUpdateDto }: { }))); } /** - * This endpoint requires the `userProfileImage.delete` permission. + * Delete user profile image */ export function deleteProfileImage(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/users/profile-image", { @@ -4671,7 +4767,7 @@ export function deleteProfileImage(opts?: Oazapfts.RequestOpts) { })); } /** - * This endpoint requires the `userProfileImage.update` permission. + * Create user profile image */ export function createProfileImage({ createProfileImageDto }: { createProfileImageDto: CreateProfileImageDto; @@ -4686,7 +4782,7 @@ export function createProfileImage({ createProfileImageDto }: { }))); } /** - * This endpoint requires the `user.read` permission. + * Retrieve a user */ export function getUser({ id }: { id: string; @@ -4699,7 +4795,7 @@ export function getUser({ id }: { })); } /** - * This endpoint requires the `userProfileImage.read` permission. + * Retrieve user profile image */ export function getProfileImage({ id }: { id: string; @@ -4711,6 +4807,9 @@ export function getProfileImage({ id }: { ...opts })); } +/** + * Retrieve assets by original path + */ export function getAssetsByOriginalPath({ path }: { path: string; }, opts?: Oazapfts.RequestOpts) { @@ -4723,6 +4822,9 @@ export function getAssetsByOriginalPath({ path }: { ...opts })); } +/** + * Retrieve unique paths + */ export function getUniqueOriginalPaths(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; diff --git a/server/src/constants.ts b/server/src/constants.ts index 3b75ca9f7..1a14bdbcc 100644 --- a/server/src/constants.ts +++ b/server/src/constants.ts @@ -2,7 +2,7 @@ import { Duration } from 'luxon'; import { readFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { SemVer } from 'semver'; -import { DatabaseExtension, ExifOrientation, VectorIndex } from 'src/enum'; +import { ApiTag, DatabaseExtension, ExifOrientation, VectorIndex } from 'src/enum'; export const POSTGRES_VERSION_RANGE = '>=14.0.0'; export const VECTORCHORD_VERSION_RANGE = '>=0.3 <0.6'; @@ -138,3 +138,56 @@ export const ORIENTATION_TO_SHARP_ROTATION: Record = { + [ApiTag.Activities]: 'An activity is a like or a comment made by a user on an asset or album.', + [ApiTag.Albums]: 'An album is a collection of assets that can be shared with other users or via shared links.', + [ApiTag.ApiKeys]: 'An api key can be used to programmatically access the Immich API.', + [ApiTag.Assets]: 'An asset is an image or video that has been uploaded to Immich.', + [ApiTag.Authentication]: 'Endpoints related to user authentication, including OAuth.', + [ApiTag.AuthenticationAdmin]: 'Administrative endpoints related to authentication.', + [ApiTag.Deprecated]: 'Deprecated endpoints that are planned for removal in the next major release.', + [ApiTag.Download]: 'Endpoints for downloading assets or collections of assets.', + [ApiTag.Duplicates]: 'Endpoints for managing and identifying duplicate assets.', + [ApiTag.Faces]: + 'A face is a detected human face within an asset, which can be associated with a person. Faces are normally detected via machine learning, but can also be created via manually.', + [ApiTag.Jobs]: + 'Queues and background jobs are used for processing tasks asynchronously. Queues can be paused and resumed as needed.', + [ApiTag.Libraries]: + 'An external library is made up of input file paths or expressions that are scanned for asset files. Discovered files are automatically imported. Assets much be unique within a library, but can be duplicated across libraries. Each user has a default upload library, and can have one or more external libraries.', + [ApiTag.Map]: + 'Map endpoints include supplemental functionality related to geolocation, such as reverse geocoding and retrieving map markers for assets with geolocation data.', + [ApiTag.Memories]: + 'A memory is a specialized collection of assets with dedicated viewing implementations in the web and mobile clients. A memory includes fields related to visibility and are automatically generated per user via a background job.', + [ApiTag.Notifications]: + 'A notification is a specialized message sent to users to inform them of important events. Currently, these notifications are only shown in the Immich web application.', + [ApiTag.NotificationsAdmin]: 'Notification administrative endpoints.', + [ApiTag.Partners]: 'A partner is a link with another user that allows sharing of assets between two users.', + [ApiTag.People]: + 'A person is a collection of faces, which can be favorited and named. A person can also be merged into another person. People are automatically created via the face recognition job.', + [ApiTag.Search]: + 'Endpoints related to searching assets via text, smart search, optical character recognition (OCR), and other filters like person, album, and other metadata. Search endpoints usually support pagination and sorting.', + [ApiTag.Server]: + 'Information about the current server deployment, including version and build information, available features, supported media types, and more.', + [ApiTag.Sessions]: + 'A session represents an authenticated login session for a user. Sessions also appear in the web application as "Authorized devices".', + [ApiTag.SharedLinks]: + 'A shared link is a public url that provides access to a specific album, asset, or collection of assets. A shared link can be protected with a password, include a specific slug, allow or disallow downloads, and optionally include an expiration date.', + [ApiTag.Stacks]: + 'A stack is a group of related assets. One asset is the "primary" asset, and the rest are "child" assets. On the main timeline, stack parents are included by default, while child assets are hidden.', + [ApiTag.Sync]: 'A collection of endpoints for the new mobile synchronization implementation.', + [ApiTag.SystemConfig]: 'Endpoints to view, modify, and validate the system configuration settings.', + [ApiTag.SystemMetadata]: + 'Endpoints to view, modify, and validate the system metadata, which includes information about things like admin onboarding status.', + [ApiTag.Tags]: + 'A tag is a user-defined label that can be applied to assets for organizational purposes. Tags can also be hierarchical, allowing for parent-child relationships between tags.', + [ApiTag.Timeline]: + 'Specialized endpoints related to the timeline implementation used in the web application. External applications or tools should not use or rely on these endpoints, as they are subject to change without notice.', + [ApiTag.Trash]: + 'Endpoints for managing the trash can, which includes assets that have been discarded. Items in the trash are automatically deleted after a configured amount of time.', + [ApiTag.UsersAdmin]: + 'Administrative endpoints for managing users, including creating, updating, deleting, and restoring users. Also includes endpoints for resetting passwords and PIN codes.', + [ApiTag.Users]: + 'Endpoints for viewing and updating the current users, including product key information, profile picture data, onboarding progress, and more.', + [ApiTag.Views]: 'Endpoints for specialized views, such as the folder view.', +}; diff --git a/server/src/controllers/activity.controller.ts b/server/src/controllers/activity.controller.ts index 75b2e2f8a..e0c71a00e 100644 --- a/server/src/controllers/activity.controller.ts +++ b/server/src/controllers/activity.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Query, Res } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { Response } from 'express'; import { ActivityCreateDto, @@ -9,24 +9,33 @@ import { ActivityStatisticsResponseDto, } from 'src/dtos/activity.dto'; import { AuthDto } from 'src/dtos/auth.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { ActivityService } from 'src/services/activity.service'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('Activities') +@ApiTags(ApiTag.Activities) @Controller('activities') export class ActivityController { constructor(private service: ActivityService) {} @Get() @Authenticated({ permission: Permission.ActivityRead }) + @ApiOperation({ + summary: 'List all activities', + description: + 'Returns a list of activities for the selected asset or album. The activities are returned in sorted order, with the oldest activities appearing first.', + }) getActivities(@Auth() auth: AuthDto, @Query() dto: ActivitySearchDto): Promise { return this.service.getAll(auth, dto); } @Post() @Authenticated({ permission: Permission.ActivityCreate }) + @ApiOperation({ + summary: 'Create an activity', + description: 'Create a like or a comment for an album, or an asset in an album.', + }) async createActivity( @Auth() auth: AuthDto, @Body() dto: ActivityCreateDto, @@ -41,6 +50,10 @@ export class ActivityController { @Get('statistics') @Authenticated({ permission: Permission.ActivityStatistics }) + @ApiOperation({ + summary: 'Retrieve activity statistics', + description: 'Returns the number of likes and comments for a given album or asset in an album.', + }) getActivityStatistics(@Auth() auth: AuthDto, @Query() dto: ActivityDto): Promise { return this.service.getStatistics(auth, dto); } @@ -48,6 +61,10 @@ export class ActivityController { @Delete(':id') @Authenticated({ permission: Permission.ActivityDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete an activity', + description: 'Removes a like or comment from a given album or asset in an album.', + }) deleteActivity(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.delete(auth, id); } diff --git a/server/src/controllers/album.controller.ts b/server/src/controllers/album.controller.ts index 47f8b5603..671aa5500 100644 --- a/server/src/controllers/album.controller.ts +++ b/server/src/controllers/album.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Patch, Post, Put, Query } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { AddUsersDto, AlbumInfoDto, @@ -14,36 +14,52 @@ import { } from 'src/dtos/album.dto'; import { BulkIdResponseDto, BulkIdsDto } from 'src/dtos/asset-ids.response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { AlbumService } from 'src/services/album.service'; import { ParseMeUUIDPipe, UUIDParamDto } from 'src/validation'; -@ApiTags('Albums') +@ApiTags(ApiTag.Albums) @Controller('albums') export class AlbumController { constructor(private service: AlbumService) {} @Get() @Authenticated({ permission: Permission.AlbumRead }) + @ApiOperation({ + summary: 'List all albums', + description: 'Retrieve a list of albums available to the authenticated user.', + }) getAllAlbums(@Auth() auth: AuthDto, @Query() query: GetAlbumsDto): Promise { return this.service.getAll(auth, query); } @Post() @Authenticated({ permission: Permission.AlbumCreate }) + @ApiOperation({ + summary: 'Create an album', + description: 'Create a new album. The album can also be created with initial users and assets.', + }) createAlbum(@Auth() auth: AuthDto, @Body() dto: CreateAlbumDto): Promise { return this.service.create(auth, dto); } @Get('statistics') @Authenticated({ permission: Permission.AlbumStatistics }) + @ApiOperation({ + summary: 'Retrieve album statistics', + description: 'Returns statistics about the albums available to the authenticated user.', + }) getAlbumStatistics(@Auth() auth: AuthDto): Promise { return this.service.getStatistics(auth); } @Authenticated({ permission: Permission.AlbumRead, sharedLink: true }) @Get(':id') + @ApiOperation({ + summary: 'Retrieve an album', + description: 'Retrieve information about a specific album by its ID.', + }) getAlbumInfo( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -54,6 +70,11 @@ export class AlbumController { @Patch(':id') @Authenticated({ permission: Permission.AlbumUpdate }) + @ApiOperation({ + summary: 'Update an album', + description: + 'Update the information of a specific album by its ID. This endpoint can be used to update the album name, description, sort order, etc. However, it is not used to add or remove assets or users from the album.', + }) updateAlbumInfo( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -65,12 +86,21 @@ export class AlbumController { @Delete(':id') @Authenticated({ permission: Permission.AlbumDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete an album', + description: + 'Delete a specific album by its ID. Note the album is initially trashed and then immediately scheduled for deletion, but relies on a background job to complete the process.', + }) deleteAlbum(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto) { return this.service.delete(auth, id); } @Put(':id/assets') @Authenticated({ permission: Permission.AlbumAssetCreate, sharedLink: true }) + @ApiOperation({ + summary: 'Add assets to an album', + description: 'Add multiple assets to a specific album by its ID.', + }) addAssetsToAlbum( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -81,12 +111,20 @@ export class AlbumController { @Put('assets') @Authenticated({ permission: Permission.AlbumAssetCreate, sharedLink: true }) + @ApiOperation({ + summary: 'Add assets to albums', + description: 'Send a list of asset IDs and album IDs to add each asset to each album.', + }) addAssetsToAlbums(@Auth() auth: AuthDto, @Body() dto: AlbumsAddAssetsDto): Promise { return this.service.addAssetsToAlbums(auth, dto); } @Delete(':id/assets') @Authenticated({ permission: Permission.AlbumAssetDelete }) + @ApiOperation({ + summary: 'Remove assets from an album', + description: 'Remove multiple assets from a specific album by its ID.', + }) removeAssetFromAlbum( @Auth() auth: AuthDto, @Body() dto: BulkIdsDto, @@ -97,6 +135,10 @@ export class AlbumController { @Put(':id/users') @Authenticated({ permission: Permission.AlbumUserCreate }) + @ApiOperation({ + summary: 'Share album with users', + description: 'Share an album with multiple users. Each user can be given a specific role in the album.', + }) addUsersToAlbum( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -108,6 +150,10 @@ export class AlbumController { @Put(':id/user/:userId') @Authenticated({ permission: Permission.AlbumUserUpdate }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Update user role', + description: 'Change the role for a specific user in a specific album.', + }) updateAlbumUser( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -120,6 +166,10 @@ export class AlbumController { @Delete(':id/user/:userId') @Authenticated({ permission: Permission.AlbumUserDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Remove user from album', + description: 'Remove a user from an album. Use an ID of "me" to leave a shared album.', + }) removeUserFromAlbum( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, diff --git a/server/src/controllers/api-key.controller.ts b/server/src/controllers/api-key.controller.ts index 59b690812..8a4e01e36 100644 --- a/server/src/controllers/api-key.controller.ts +++ b/server/src/controllers/api-key.controller.ts @@ -1,43 +1,60 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { APIKeyCreateDto, APIKeyCreateResponseDto, APIKeyResponseDto, APIKeyUpdateDto } from 'src/dtos/api-key.dto'; import { AuthDto } from 'src/dtos/auth.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { ApiKeyService } from 'src/services/api-key.service'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('API Keys') +@ApiTags(ApiTag.ApiKeys) @Controller('api-keys') export class ApiKeyController { constructor(private service: ApiKeyService) {} @Post() @Authenticated({ permission: Permission.ApiKeyCreate }) + @ApiOperation({ + summary: 'Create an API key', + description: 'Creates a new API key. It will be limited to the permissions specified.', + }) createApiKey(@Auth() auth: AuthDto, @Body() dto: APIKeyCreateDto): Promise { return this.service.create(auth, dto); } @Get() @Authenticated({ permission: Permission.ApiKeyRead }) + @ApiOperation({ summary: 'List all API keys', description: 'Retrieve all API keys of the current user.' }) getApiKeys(@Auth() auth: AuthDto): Promise { return this.service.getAll(auth); } @Get('me') @Authenticated({ permission: false }) + @ApiOperation({ + summary: 'Retrieve the current API key', + description: 'Retrieve the API key that is used to access this endpoint.', + }) async getMyApiKey(@Auth() auth: AuthDto): Promise { return this.service.getMine(auth); } @Get(':id') @Authenticated({ permission: Permission.ApiKeyRead }) + @ApiOperation({ + summary: 'Retrieve an API key', + description: 'Retrieve an API key by its ID. The current user must own this API key.', + }) getApiKey(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.getById(auth, id); } @Put(':id') @Authenticated({ permission: Permission.ApiKeyUpdate }) + @ApiOperation({ + summary: 'Update an API key', + description: 'Updates the name and permissions of an API key by its ID. The current user must own this API key.', + }) updateApiKey( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -49,6 +66,10 @@ export class ApiKeyController { @Delete(':id') @Authenticated({ permission: Permission.ApiKeyDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete an API key', + description: 'Deletes an API key identified by its ID. The current user must own this API key.', + }) deleteApiKey(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.delete(auth, id); } diff --git a/server/src/controllers/asset-media.controller.ts b/server/src/controllers/asset-media.controller.ts index 688e513b6..6f110b33b 100644 --- a/server/src/controllers/asset-media.controller.ts +++ b/server/src/controllers/asset-media.controller.ts @@ -34,7 +34,7 @@ import { UploadFieldName, } from 'src/dtos/asset-media.dto'; import { AuthDto } from 'src/dtos/auth.dto'; -import { ImmichHeader, Permission, RouteKey } from 'src/enum'; +import { ApiTag, ImmichHeader, Permission, RouteKey } from 'src/enum'; import { AssetUploadInterceptor } from 'src/middleware/asset-upload.interceptor'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; import { FileUploadInterceptor, getFiles } from 'src/middleware/file-upload.interceptor'; @@ -44,7 +44,7 @@ import { UploadFiles } from 'src/types'; import { ImmichFileResponse, sendFile } from 'src/utils/file'; import { FileNotEmptyValidator, UUIDParamDto } from 'src/validation'; -@ApiTags('Assets') +@ApiTags(ApiTag.Assets) @Controller(RouteKey.Asset) export class AssetMediaController { constructor( @@ -53,6 +53,7 @@ export class AssetMediaController { ) {} @Post() + @Authenticated({ permission: Permission.AssetUpload, sharedLink: true }) @UseInterceptors(AssetUploadInterceptor, FileUploadInterceptor) @ApiConsumes('multipart/form-data') @ApiHeader({ @@ -61,7 +62,10 @@ export class AssetMediaController { required: false, }) @ApiBody({ description: 'Asset Upload Information', type: AssetMediaCreateDto }) - @Authenticated({ permission: Permission.AssetUpload, sharedLink: true }) + @ApiOperation({ + summary: 'Upload asset', + description: 'Uploads a new asset to the server.', + }) async uploadAsset( @Auth() auth: AuthDto, @UploadedFiles(new ParseFilePipe({ validators: [new FileNotEmptyValidator(['assetData'])] })) files: UploadFiles, @@ -81,6 +85,10 @@ export class AssetMediaController { @Get(':id/original') @FileResponse() @Authenticated({ permission: Permission.AssetDownload, sharedLink: true }) + @ApiOperation({ + summary: 'Download original asset', + description: 'Downloads the original file of the specified asset.', + }) async downloadAsset( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -90,17 +98,14 @@ export class AssetMediaController { await sendFile(res, next, () => this.service.downloadOriginal(auth, id), this.logger); } - /** - * Replace the asset with new file, without changing its id - */ @Put(':id/original') @UseInterceptors(FileUploadInterceptor) @ApiConsumes('multipart/form-data') @EndpointLifecycle({ addedAt: 'v1.106.0', deprecatedAt: 'v1.142.0', - summary: 'replaceAsset', - description: 'Replace the asset with new file, without changing its id', + summary: 'Replace asset', + description: 'Replace the asset with new file, without changing its id.', }) @Authenticated({ permission: Permission.AssetReplace, sharedLink: true }) async replaceAsset( @@ -122,6 +127,10 @@ export class AssetMediaController { @Get(':id/thumbnail') @FileResponse() @Authenticated({ permission: Permission.AssetView, sharedLink: true }) + @ApiOperation({ + summary: 'View asset thumbnail', + description: 'Retrieve the thumbnail image for the specified asset.', + }) async viewAsset( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -159,6 +168,10 @@ export class AssetMediaController { @Get(':id/video/playback') @FileResponse() @Authenticated({ permission: Permission.AssetView, sharedLink: true }) + @ApiOperation({ + summary: 'Play asset video', + description: 'Streams the video file for the specified asset. This endpoint also supports byte range requests.', + }) async playAssetVideo( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -174,7 +187,7 @@ export class AssetMediaController { @Post('exist') @Authenticated() @ApiOperation({ - summary: 'checkExistingAssets', + summary: 'Check existing assets', description: 'Checks if multiple assets exist on the server and returns all existing - used by background backup', }) @HttpCode(HttpStatus.OK) @@ -191,8 +204,8 @@ export class AssetMediaController { @Post('bulk-upload-check') @Authenticated({ permission: Permission.AssetUpload }) @ApiOperation({ - summary: 'checkBulkUpload', - description: 'Checks if assets exist by checksums', + summary: 'Check bulk upload', + description: 'Determine which assets have already been uploaded to the server based on their SHA1 checksums.', }) @HttpCode(HttpStatus.OK) checkBulkUpload( diff --git a/server/src/controllers/asset.controller.ts b/server/src/controllers/asset.controller.ts index a6f8c7921..6a7309b6d 100644 --- a/server/src/controllers/asset.controller.ts +++ b/server/src/controllers/asset.controller.ts @@ -18,29 +18,31 @@ import { } from 'src/dtos/asset.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { AssetOcrResponseDto } from 'src/dtos/ocr.dto'; -import { Permission, RouteKey } from 'src/enum'; +import { ApiTag, Permission, RouteKey } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { AssetService } from 'src/services/asset.service'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('Assets') +@ApiTags(ApiTag.Assets) @Controller(RouteKey.Asset) export class AssetController { constructor(private service: AssetService) {} @Get('random') @Authenticated({ permission: Permission.AssetRead }) - @EndpointLifecycle({ deprecatedAt: 'v1.116.0' }) + @EndpointLifecycle({ + deprecatedAt: 'v1.116.0', + summary: 'Get random assets', + description: 'Retrieve a specified number of random assets for the authenticated user.', + }) getRandom(@Auth() auth: AuthDto, @Query() dto: RandomAssetsDto): Promise { return this.service.getRandom(auth, dto.count ?? 1); } - /** - * Get all asset of a device that are in the database, ID only. - */ @Get('/device/:deviceId') - @ApiOperation({ - summary: 'getAllUserAssetsByDeviceId', + @EndpointLifecycle({ + deprecatedAt: 'v2.0.0', + summary: 'Retrieve assets by device ID', description: 'Get all asset of a device that are in the database, ID only.', }) @Authenticated() @@ -50,6 +52,10 @@ export class AssetController { @Get('statistics') @Authenticated({ permission: Permission.AssetStatistics }) + @ApiOperation({ + summary: 'Get asset statistics', + description: 'Retrieve various statistics about the assets owned by the authenticated user.', + }) getAssetStatistics(@Auth() auth: AuthDto, @Query() dto: AssetStatsDto): Promise { return this.service.getStatistics(auth, dto); } @@ -57,6 +63,10 @@ export class AssetController { @Post('jobs') @Authenticated() @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Run an asset job', + description: 'Run a specific job on a set of assets.', + }) runAssetJobs(@Auth() auth: AuthDto, @Body() dto: AssetJobsDto): Promise { return this.service.run(auth, dto); } @@ -64,6 +74,10 @@ export class AssetController { @Put() @Authenticated({ permission: Permission.AssetUpdate }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Update assets', + description: 'Updates multiple assets at the same time.', + }) updateAssets(@Auth() auth: AuthDto, @Body() dto: AssetBulkUpdateDto): Promise { return this.service.updateAll(auth, dto); } @@ -71,12 +85,20 @@ export class AssetController { @Delete() @Authenticated({ permission: Permission.AssetDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete assets', + description: 'Deletes multiple assets at the same time.', + }) deleteAssets(@Auth() auth: AuthDto, @Body() dto: AssetBulkDeleteDto): Promise { return this.service.deleteAll(auth, dto); } @Get(':id') @Authenticated({ permission: Permission.AssetRead, sharedLink: true }) + @ApiOperation({ + summary: 'Retrieve an asset', + description: 'Retrieve detailed information about a specific asset.', + }) getAssetInfo(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.get(auth, id) as Promise; } @@ -84,12 +106,20 @@ export class AssetController { @Put('copy') @Authenticated({ permission: Permission.AssetCopy }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Copy asset', + description: 'Copy asset information like albums, tags, etc. from one asset to another.', + }) copyAsset(@Auth() auth: AuthDto, @Body() dto: AssetCopyDto): Promise { return this.service.copy(auth, dto); } @Put(':id') @Authenticated({ permission: Permission.AssetUpdate }) + @ApiOperation({ + summary: 'Update an asset', + description: 'Update information of a specific asset.', + }) updateAsset( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -100,18 +130,30 @@ export class AssetController { @Get(':id/metadata') @Authenticated({ permission: Permission.AssetRead }) + @ApiOperation({ + summary: 'Get asset metadata', + description: 'Retrieve all metadata key-value pairs associated with the specified asset.', + }) getAssetMetadata(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.getMetadata(auth, id); } @Get(':id/ocr') @Authenticated({ permission: Permission.AssetRead }) + @ApiOperation({ + summary: 'Retrieve asset OCR data', + description: 'Retrieve all OCR (Optical Character Recognition) data associated with the specified asset.', + }) getAssetOcr(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.getOcr(auth, id); } @Put(':id/metadata') @Authenticated({ permission: Permission.AssetUpdate }) + @ApiOperation({ + summary: 'Update asset metadata', + description: 'Update or add metadata key-value pairs for the specified asset.', + }) updateAssetMetadata( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -122,6 +164,10 @@ export class AssetController { @Get(':id/metadata/:key') @Authenticated({ permission: Permission.AssetRead }) + @ApiOperation({ + summary: 'Retrieve asset metadata by key', + description: 'Retrieve the value of a specific metadata key associated with the specified asset.', + }) getAssetMetadataByKey( @Auth() auth: AuthDto, @Param() { id, key }: AssetMetadataRouteParams, @@ -132,6 +178,10 @@ export class AssetController { @Delete(':id/metadata/:key') @Authenticated({ permission: Permission.AssetUpdate }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete asset metadata by key', + description: 'Delete a specific metadata key-value pair associated with the specified asset.', + }) deleteAssetMetadata(@Auth() auth: AuthDto, @Param() { id, key }: AssetMetadataRouteParams): Promise { return this.service.deleteMetadataByKey(auth, id, key); } diff --git a/server/src/controllers/auth-admin.controller.ts b/server/src/controllers/auth-admin.controller.ts index dba352783..8cbdf5d6d 100644 --- a/server/src/controllers/auth-admin.controller.ts +++ b/server/src/controllers/auth-admin.controller.ts @@ -1,17 +1,21 @@ import { Controller, HttpCode, HttpStatus, Post } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { AuthDto } from 'src/dtos/auth.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { AuthAdminService } from 'src/services/auth-admin.service'; -@ApiTags('Auth (admin)') +@ApiTags(ApiTag.AuthenticationAdmin) @Controller('admin/auth') export class AuthAdminController { constructor(private service: AuthAdminService) {} @Post('unlink-all') @Authenticated({ permission: Permission.AdminAuthUnlinkAll, admin: true }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Unlink all OAuth accounts', + description: 'Unlinks all OAuth accounts associated with user accounts in the system.', + }) unlinkAllOAuthAccountsAdmin(@Auth() auth: AuthDto): Promise { return this.service.unlinkAll(auth); } diff --git a/server/src/controllers/auth.controller.ts b/server/src/controllers/auth.controller.ts index 636e3a304..7f76ff195 100644 --- a/server/src/controllers/auth.controller.ts +++ b/server/src/controllers/auth.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Post, Put, Req, Res } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { Request, Response } from 'express'; import { AuthDto, @@ -16,17 +16,21 @@ import { ValidateAccessTokenResponseDto, } from 'src/dtos/auth.dto'; import { UserAdminResponseDto } from 'src/dtos/user.dto'; -import { AuthType, ImmichCookie, Permission } from 'src/enum'; +import { ApiTag, AuthType, ImmichCookie, Permission } from 'src/enum'; import { Auth, Authenticated, GetLoginDetails } from 'src/middleware/auth.guard'; import { AuthService, LoginDetails } from 'src/services/auth.service'; import { respondWithCookie, respondWithoutCookie } from 'src/utils/response'; -@ApiTags('Authentication') +@ApiTags(ApiTag.Authentication) @Controller('auth') export class AuthController { constructor(private service: AuthService) {} @Post('login') + @ApiOperation({ + summary: 'Login', + description: 'Login with username and password and receive a session token.', + }) async login( @Res({ passthrough: true }) res: Response, @Body() loginCredential: LoginCredentialDto, @@ -44,11 +48,19 @@ export class AuthController { } @Post('admin-sign-up') + @ApiOperation({ + summary: 'Register admin', + description: 'Create the first admin user in the system.', + }) signUpAdmin(@Body() dto: SignUpDto): Promise { return this.service.adminSignUp(dto); } @Post('validateToken') + @ApiOperation({ + summary: 'Validate access token', + description: 'Validate the current authorization method is still valid.', + }) @Authenticated({ permission: false }) @HttpCode(HttpStatus.OK) validateAccessToken(): ValidateAccessTokenResponseDto { @@ -58,6 +70,10 @@ export class AuthController { @Post('change-password') @Authenticated({ permission: Permission.AuthChangePassword }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Change password', + description: 'Change the password of the current user.', + }) changePassword(@Auth() auth: AuthDto, @Body() dto: ChangePasswordDto): Promise { return this.service.changePassword(auth, dto); } @@ -65,6 +81,10 @@ export class AuthController { @Post('logout') @Authenticated() @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Logout', + description: 'Logout the current user and invalidate the session token.', + }) async logout( @Req() request: Request, @Res({ passthrough: true }) res: Response, @@ -82,6 +102,11 @@ export class AuthController { @Get('status') @Authenticated() + @ApiOperation({ + summary: 'Retrieve auth status', + description: + 'Get information about the current session, including whether the user has a password, and if the session can access locked assets.', + }) getAuthStatus(@Auth() auth: AuthDto): Promise { return this.service.getAuthStatus(auth); } @@ -89,6 +114,10 @@ export class AuthController { @Post('pin-code') @Authenticated({ permission: Permission.PinCodeCreate }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Setup pin code', + description: 'Setup a new pin code for the current user.', + }) setupPinCode(@Auth() auth: AuthDto, @Body() dto: PinCodeSetupDto): Promise { return this.service.setupPinCode(auth, dto); } @@ -96,6 +125,10 @@ export class AuthController { @Put('pin-code') @Authenticated({ permission: Permission.PinCodeUpdate }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Change pin code', + description: 'Change the pin code for the current user.', + }) async changePinCode(@Auth() auth: AuthDto, @Body() dto: PinCodeChangeDto): Promise { return this.service.changePinCode(auth, dto); } @@ -103,6 +136,10 @@ export class AuthController { @Delete('pin-code') @Authenticated({ permission: Permission.PinCodeDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Reset pin code', + description: 'Reset the pin code for the current user by providing the account password', + }) async resetPinCode(@Auth() auth: AuthDto, @Body() dto: PinCodeResetDto): Promise { return this.service.resetPinCode(auth, dto); } @@ -110,12 +147,20 @@ export class AuthController { @Post('session/unlock') @Authenticated() @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Unlock auth session', + description: 'Temporarily grant the session elevated access to locked assets by providing the correct PIN code.', + }) async unlockAuthSession(@Auth() auth: AuthDto, @Body() dto: SessionUnlockDto): Promise { return this.service.unlockSession(auth, dto); } @Post('session/lock') @Authenticated() + @ApiOperation({ + summary: 'Lock auth session', + description: 'Remove elevated access to locked assets from the current session.', + }) @HttpCode(HttpStatus.NO_CONTENT) async lockAuthSession(@Auth() auth: AuthDto): Promise { return this.service.lockSession(auth); diff --git a/server/src/controllers/download.controller.ts b/server/src/controllers/download.controller.ts index a7c2af78e..26288412d 100644 --- a/server/src/controllers/download.controller.ts +++ b/server/src/controllers/download.controller.ts @@ -1,20 +1,25 @@ import { Body, Controller, HttpCode, HttpStatus, Post, StreamableFile } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { AssetIdsDto } from 'src/dtos/asset.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { DownloadInfoDto, DownloadResponseDto } from 'src/dtos/download.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; import { DownloadService } from 'src/services/download.service'; import { asStreamableFile } from 'src/utils/file'; -@ApiTags('Download') +@ApiTags(ApiTag.Download) @Controller('download') export class DownloadController { constructor(private service: DownloadService) {} @Post('info') @Authenticated({ permission: Permission.AssetDownload, sharedLink: true }) + @ApiOperation({ + summary: 'Retrieve download information', + description: + 'Retrieve information about how to request a download for the specified assets or album. The response includes groups of assets that can be downloaded together.', + }) getDownloadInfo(@Auth() auth: AuthDto, @Body() dto: DownloadInfoDto): Promise { return this.service.getDownloadInfo(auth, dto); } @@ -23,6 +28,11 @@ export class DownloadController { @Authenticated({ permission: Permission.AssetDownload, sharedLink: true }) @FileResponse() @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Download asset archive', + description: + 'Download a ZIP archive containing the specified assets. The assets must have been previously requested via the "getDownloadInfo" endpoint.', + }) downloadArchive(@Auth() auth: AuthDto, @Body() dto: AssetIdsDto): Promise { return this.service.downloadArchive(auth, dto).then(asStreamableFile); } diff --git a/server/src/controllers/duplicate.controller.ts b/server/src/controllers/duplicate.controller.ts index 9cf5ae97a..5fddef9dd 100644 --- a/server/src/controllers/duplicate.controller.ts +++ b/server/src/controllers/duplicate.controller.ts @@ -1,20 +1,24 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { BulkIdsDto } from 'src/dtos/asset-ids.response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { DuplicateResponseDto } from 'src/dtos/duplicate.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { DuplicateService } from 'src/services/duplicate.service'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('Duplicates') +@ApiTags(ApiTag.Duplicates) @Controller('duplicates') export class DuplicateController { constructor(private service: DuplicateService) {} @Get() @Authenticated({ permission: Permission.DuplicateRead }) + @ApiOperation({ + summary: 'Retrieve duplicates', + description: 'Retrieve a list of duplicate assets available to the authenticated user.', + }) getAssetDuplicates(@Auth() auth: AuthDto): Promise { return this.service.getDuplicates(auth); } @@ -22,6 +26,10 @@ export class DuplicateController { @Delete() @Authenticated({ permission: Permission.DuplicateDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete duplicates', + description: 'Delete multiple duplicate assets specified by their IDs.', + }) deleteDuplicates(@Auth() auth: AuthDto, @Body() dto: BulkIdsDto): Promise { return this.service.deleteAll(auth, dto); } @@ -29,6 +37,10 @@ export class DuplicateController { @Delete(':id') @Authenticated({ permission: Permission.DuplicateDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete a duplicate', + description: 'Delete a single duplicate asset specified by its ID.', + }) deleteDuplicate(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.delete(auth, id); } diff --git a/server/src/controllers/face.controller.ts b/server/src/controllers/face.controller.ts index 564b217c1..cc7f23929 100644 --- a/server/src/controllers/face.controller.ts +++ b/server/src/controllers/face.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put, Query } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { AuthDto } from 'src/dtos/auth.dto'; import { AssetFaceCreateDto, @@ -8,30 +8,43 @@ import { FaceDto, PersonResponseDto, } from 'src/dtos/person.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { PersonService } from 'src/services/person.service'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('Faces') +@ApiTags(ApiTag.Faces) @Controller('faces') export class FaceController { constructor(private service: PersonService) {} @Post() @Authenticated({ permission: Permission.FaceCreate }) + @ApiOperation({ + summary: 'Create a face', + description: + 'Create a new face that has not been discovered by facial recognition. The content of the bounding box is considered a face.', + }) createFace(@Auth() auth: AuthDto, @Body() dto: AssetFaceCreateDto) { return this.service.createFace(auth, dto); } @Get() @Authenticated({ permission: Permission.FaceRead }) + @ApiOperation({ + summary: 'Retrieve faces for asset', + description: 'Retrieve all faces belonging to an asset.', + }) getFaces(@Auth() auth: AuthDto, @Query() dto: FaceDto): Promise { return this.service.getFacesById(auth, dto); } @Put(':id') @Authenticated({ permission: Permission.FaceUpdate }) + @ApiOperation({ + summary: 'Re-assign a face to another person', + description: 'Re-assign the face provided in the body to the person identified by the id in the path parameter.', + }) reassignFacesById( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -43,6 +56,10 @@ export class FaceController { @Delete(':id') @Authenticated({ permission: Permission.FaceDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete a face', + description: 'Delete a face identified by the id. Optionally can be force deleted.', + }) deleteFace(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @Body() dto: AssetFaceDeleteDto): Promise { return this.service.deleteFace(auth, id, dto); } diff --git a/server/src/controllers/job.controller.ts b/server/src/controllers/job.controller.ts index 9c4e81964..b34f5ffec 100644 --- a/server/src/controllers/job.controller.ts +++ b/server/src/controllers/job.controller.ts @@ -1,17 +1,21 @@ import { Body, Controller, Get, HttpCode, HttpStatus, Param, Post, Put } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { AllJobStatusResponseDto, JobCommandDto, JobCreateDto, JobIdParamDto, JobStatusDto } from 'src/dtos/job.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Authenticated } from 'src/middleware/auth.guard'; import { JobService } from 'src/services/job.service'; -@ApiTags('Jobs') +@ApiTags(ApiTag.Jobs) @Controller('jobs') export class JobController { constructor(private service: JobService) {} @Get() @Authenticated({ permission: Permission.JobRead, admin: true }) + @ApiOperation({ + summary: 'Retrieve queue counts and status', + description: 'Retrieve the counts of the current queue, as well as the current status.', + }) getAllJobsStatus(): Promise { return this.service.getAllJobsStatus(); } @@ -19,12 +23,22 @@ export class JobController { @Post() @Authenticated({ permission: Permission.JobCreate, admin: true }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Create a manual job', + description: + 'Run a specific job. Most jobs are queued automatically, but this endpoint allows for manual creation of a handful of jobs, including various cleanup tasks, as well as creating a new database backup.', + }) createJob(@Body() dto: JobCreateDto): Promise { return this.service.create(dto); } @Put(':id') @Authenticated({ permission: Permission.JobCreate, admin: true }) + @ApiOperation({ + summary: 'Run jobs', + description: + 'Queue all assets for a specific job type. Defaults to only queueing assets that have not yet been processed, but the force command can be used to re-process all assets.', + }) sendJobCommand(@Param() { id }: JobIdParamDto, @Body() dto: JobCommandDto): Promise { return this.service.handleCommand(id, dto); } diff --git a/server/src/controllers/library.controller.ts b/server/src/controllers/library.controller.ts index b37bc40ce..8b527eb4b 100644 --- a/server/src/controllers/library.controller.ts +++ b/server/src/controllers/library.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { CreateLibraryDto, LibraryResponseDto, @@ -8,36 +8,52 @@ import { ValidateLibraryDto, ValidateLibraryResponseDto, } from 'src/dtos/library.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Authenticated } from 'src/middleware/auth.guard'; import { LibraryService } from 'src/services/library.service'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('Libraries') +@ApiTags(ApiTag.Libraries) @Controller('libraries') export class LibraryController { constructor(private service: LibraryService) {} @Get() @Authenticated({ permission: Permission.LibraryRead, admin: true }) + @ApiOperation({ + summary: 'Retrieve libraries', + description: 'Retrieve a list of external libraries.', + }) getAllLibraries(): Promise { return this.service.getAll(); } @Post() @Authenticated({ permission: Permission.LibraryCreate, admin: true }) + @ApiOperation({ + summary: 'Create a library', + description: 'Create a new external library.', + }) createLibrary(@Body() dto: CreateLibraryDto): Promise { return this.service.create(dto); } @Get(':id') @Authenticated({ permission: Permission.LibraryRead, admin: true }) + @ApiOperation({ + summary: 'Retrieve a library', + description: 'Retrieve an external library by its ID.', + }) getLibrary(@Param() { id }: UUIDParamDto): Promise { return this.service.get(id); } @Put(':id') @Authenticated({ permission: Permission.LibraryUpdate, admin: true }) + @ApiOperation({ + summary: 'Update a library', + description: 'Update an existing external library.', + }) updateLibrary(@Param() { id }: UUIDParamDto, @Body() dto: UpdateLibraryDto): Promise { return this.service.update(id, dto); } @@ -45,6 +61,10 @@ export class LibraryController { @Delete(':id') @Authenticated({ permission: Permission.LibraryDelete, admin: true }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete a library', + description: 'Delete an external library by its ID.', + }) deleteLibrary(@Param() { id }: UUIDParamDto): Promise { return this.service.delete(id); } @@ -52,6 +72,10 @@ export class LibraryController { @Post(':id/validate') @Authenticated({ admin: true }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Validate library settings', + description: 'Validate the settings of an external library.', + }) // TODO: change endpoint to validate current settings instead validate(@Param() { id }: UUIDParamDto, @Body() dto: ValidateLibraryDto): Promise { return this.service.validate(id, dto); @@ -59,6 +83,11 @@ export class LibraryController { @Get(':id/statistics') @Authenticated({ permission: Permission.LibraryStatistics, admin: true }) + @ApiOperation({ + summary: 'Retrieve library statistics', + description: + 'Retrieve statistics for a specific external library, including number of videos, images, and storage usage.', + }) getLibraryStatistics(@Param() { id }: UUIDParamDto): Promise { return this.service.getStatistics(id); } @@ -66,6 +95,10 @@ export class LibraryController { @Post(':id/scan') @Authenticated({ permission: Permission.LibraryUpdate, admin: true }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Scan a library', + description: 'Queue a scan for the external library to find and import new assets.', + }) scanLibrary(@Param() { id }: UUIDParamDto): Promise { return this.service.queueScan(id); } diff --git a/server/src/controllers/map.controller.ts b/server/src/controllers/map.controller.ts index 88104e6b5..41acfbd5b 100644 --- a/server/src/controllers/map.controller.ts +++ b/server/src/controllers/map.controller.ts @@ -1,5 +1,5 @@ import { Controller, Get, HttpCode, HttpStatus, Query } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { AuthDto } from 'src/dtos/auth.dto'; import { MapMarkerDto, @@ -7,16 +7,21 @@ import { MapReverseGeocodeDto, MapReverseGeocodeResponseDto, } from 'src/dtos/map.dto'; +import { ApiTag } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { MapService } from 'src/services/map.service'; -@ApiTags('Map') +@ApiTags(ApiTag.Map) @Controller('map') export class MapController { constructor(private service: MapService) {} @Get('markers') @Authenticated() + @ApiOperation({ + summary: 'Retrieve map markers', + description: 'Retrieve a list of latitude and longitude coordinates for every asset with location data.', + }) getMapMarkers(@Auth() auth: AuthDto, @Query() options: MapMarkerDto): Promise { return this.service.getMapMarkers(auth, options); } @@ -24,6 +29,10 @@ export class MapController { @Authenticated() @Get('reverse-geocode') @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Reverse geocode coordinates', + description: 'Retrieve location information (e.g., city, country) for given latitude and longitude coordinates.', + }) reverseGeocode(@Query() dto: MapReverseGeocodeDto): Promise { return this.service.reverseGeocode(dto); } diff --git a/server/src/controllers/memory.controller.ts b/server/src/controllers/memory.controller.ts index 3b5ad2bb4..d433ae88e 100644 --- a/server/src/controllers/memory.controller.ts +++ b/server/src/controllers/memory.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put, Query } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { BulkIdResponseDto, BulkIdsDto } from 'src/dtos/asset-ids.response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { @@ -9,42 +9,64 @@ import { MemoryStatisticsResponseDto, MemoryUpdateDto, } from 'src/dtos/memory.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { MemoryService } from 'src/services/memory.service'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('Memories') +@ApiTags(ApiTag.Memories) @Controller('memories') export class MemoryController { constructor(private service: MemoryService) {} @Get() @Authenticated({ permission: Permission.MemoryRead }) + @ApiOperation({ + summary: 'Retrieve memories', + description: + 'Retrieve a list of memories. Memories are sorted descending by creation date by default, although they can also be sorted in ascending order, or randomly.', + }) searchMemories(@Auth() auth: AuthDto, @Query() dto: MemorySearchDto): Promise { return this.service.search(auth, dto); } @Post() @Authenticated({ permission: Permission.MemoryCreate }) + @ApiOperation({ + summary: 'Create a memory', + description: + 'Create a new memory by providing a name, description, and a list of asset IDs to include in the memory.', + }) createMemory(@Auth() auth: AuthDto, @Body() dto: MemoryCreateDto): Promise { return this.service.create(auth, dto); } @Get('statistics') @Authenticated({ permission: Permission.MemoryStatistics }) + @ApiOperation({ + summary: 'Retrieve memories statistics', + description: 'Retrieve statistics about memories, such as total count and other relevant metrics.', + }) memoriesStatistics(@Auth() auth: AuthDto, @Query() dto: MemorySearchDto): Promise { return this.service.statistics(auth, dto); } @Get(':id') @Authenticated({ permission: Permission.MemoryRead }) + @ApiOperation({ + summary: 'Retrieve a memory', + description: 'Retrieve a specific memory by its ID.', + }) getMemory(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.get(auth, id); } @Put(':id') @Authenticated({ permission: Permission.MemoryUpdate }) + @ApiOperation({ + summary: 'Update a memory', + description: 'Update an existing memory by its ID.', + }) updateMemory( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -56,12 +78,20 @@ export class MemoryController { @Delete(':id') @Authenticated({ permission: Permission.MemoryDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete a memory', + description: 'Delete a specific memory by its ID.', + }) deleteMemory(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.remove(auth, id); } @Put(':id/assets') @Authenticated({ permission: Permission.MemoryAssetCreate }) + @ApiOperation({ + summary: 'Add assets to a memory', + description: 'Add a list of asset IDs to a specific memory.', + }) addMemoryAssets( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -73,6 +103,10 @@ export class MemoryController { @Delete(':id/assets') @Authenticated({ permission: Permission.MemoryAssetDelete }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Remove assets from a memory', + description: 'Remove a list of asset IDs from a specific memory.', + }) removeMemoryAssets( @Auth() auth: AuthDto, @Body() dto: BulkIdsDto, diff --git a/server/src/controllers/notification-admin.controller.ts b/server/src/controllers/notification-admin.controller.ts index 28ca7bfd3..fe7d9d1e4 100644 --- a/server/src/controllers/notification-admin.controller.ts +++ b/server/src/controllers/notification-admin.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, HttpCode, HttpStatus, Param, Post } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { AuthDto } from 'src/dtos/auth.dto'; import { NotificationCreateDto, @@ -9,17 +9,22 @@ import { TestEmailResponseDto, } from 'src/dtos/notification.dto'; import { SystemConfigSmtpDto } from 'src/dtos/system-config.dto'; +import { ApiTag } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { EmailTemplate } from 'src/repositories/email.repository'; import { NotificationAdminService } from 'src/services/notification-admin.service'; -@ApiTags('Notifications (Admin)') +@ApiTags(ApiTag.NotificationsAdmin) @Controller('admin/notifications') export class NotificationAdminController { constructor(private service: NotificationAdminService) {} @Post() @Authenticated({ admin: true }) + @ApiOperation({ + summary: 'Create a notification', + description: 'Create a new notification for a specific user.', + }) createNotification(@Auth() auth: AuthDto, @Body() dto: NotificationCreateDto): Promise { return this.service.create(auth, dto); } @@ -27,6 +32,10 @@ export class NotificationAdminController { @Post('test-email') @Authenticated({ admin: true }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Send test email', + description: 'Send a test email using the provided SMTP configuration.', + }) sendTestEmailAdmin(@Auth() auth: AuthDto, @Body() dto: SystemConfigSmtpDto): Promise { return this.service.sendTestEmail(auth.user.id, dto); } @@ -34,6 +43,10 @@ export class NotificationAdminController { @Post('templates/:name') @Authenticated({ admin: true }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Render email template', + description: 'Retrieve a preview of the provided email template.', + }) getNotificationTemplateAdmin( @Auth() auth: AuthDto, @Param('name') name: EmailTemplate, diff --git a/server/src/controllers/notification.controller.ts b/server/src/controllers/notification.controller.ts index 8ce183c5d..7d4840dd0 100644 --- a/server/src/controllers/notification.controller.ts +++ b/server/src/controllers/notification.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Put, Query } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { AuthDto } from 'src/dtos/auth.dto'; import { NotificationDeleteAllDto, @@ -8,18 +8,22 @@ import { NotificationUpdateAllDto, NotificationUpdateDto, } from 'src/dtos/notification.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { NotificationService } from 'src/services/notification.service'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('Notifications') +@ApiTags(ApiTag.Notifications) @Controller('notifications') export class NotificationController { constructor(private service: NotificationService) {} @Get() @Authenticated({ permission: Permission.NotificationRead }) + @ApiOperation({ + summary: 'Retrieve notifications', + description: 'Retrieve a list of notifications.', + }) getNotifications(@Auth() auth: AuthDto, @Query() dto: NotificationSearchDto): Promise { return this.service.search(auth, dto); } @@ -27,6 +31,10 @@ export class NotificationController { @Put() @Authenticated({ permission: Permission.NotificationUpdate }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Update notifications', + description: 'Update a list of notifications. Allows to bulk-set the read status of notifications.', + }) updateNotifications(@Auth() auth: AuthDto, @Body() dto: NotificationUpdateAllDto): Promise { return this.service.updateAll(auth, dto); } @@ -34,18 +42,30 @@ export class NotificationController { @Delete() @Authenticated({ permission: Permission.NotificationDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete notifications', + description: 'Delete a list of notifications at once.', + }) deleteNotifications(@Auth() auth: AuthDto, @Body() dto: NotificationDeleteAllDto): Promise { return this.service.deleteAll(auth, dto); } @Get(':id') @Authenticated({ permission: Permission.NotificationRead }) + @ApiOperation({ + summary: 'Get a notification', + description: 'Retrieve a specific notification identified by id.', + }) getNotification(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.get(auth, id); } @Put(':id') @Authenticated({ permission: Permission.NotificationUpdate }) + @ApiOperation({ + summary: 'Update a notification', + description: 'Update a specific notification to set its read status.', + }) updateNotification( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -57,6 +77,10 @@ export class NotificationController { @Delete(':id') @Authenticated({ permission: Permission.NotificationDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete a notification', + description: 'Delete a specific notification.', + }) deleteNotification(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.delete(auth, id); } diff --git a/server/src/controllers/oauth.controller.ts b/server/src/controllers/oauth.controller.ts index f81a18455..cd15486d5 100644 --- a/server/src/controllers/oauth.controller.ts +++ b/server/src/controllers/oauth.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Get, HttpCode, HttpStatus, Post, Redirect, Req, Res } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { Request, Response } from 'express'; import { AuthDto, @@ -9,18 +9,23 @@ import { OAuthConfigDto, } from 'src/dtos/auth.dto'; import { UserAdminResponseDto } from 'src/dtos/user.dto'; -import { AuthType, ImmichCookie } from 'src/enum'; +import { ApiTag, AuthType, ImmichCookie } from 'src/enum'; import { Auth, Authenticated, GetLoginDetails } from 'src/middleware/auth.guard'; import { AuthService, LoginDetails } from 'src/services/auth.service'; import { respondWithCookie } from 'src/utils/response'; -@ApiTags('OAuth') +@ApiTags(ApiTag.Authentication) @Controller('oauth') export class OAuthController { constructor(private service: AuthService) {} @Get('mobile-redirect') @Redirect() + @ApiOperation({ + summary: 'Redirect OAuth to mobile', + description: + 'Requests to this URL are automatically forwarded to the mobile app, and is used in some cases for OAuth redirecting.', + }) redirectOAuthToMobile(@Req() request: Request) { return { url: this.service.getMobileRedirect(request.url), @@ -29,6 +34,10 @@ export class OAuthController { } @Post('authorize') + @ApiOperation({ + summary: 'Start OAuth', + description: 'Initiate the OAuth authorization process.', + }) async startOAuth( @Body() dto: OAuthConfigDto, @Res({ passthrough: true }) res: Response, @@ -49,6 +58,10 @@ export class OAuthController { } @Post('callback') + @ApiOperation({ + summary: 'Finish OAuth', + description: 'Complete the OAuth authorization process by exchanging the authorization code for a session token.', + }) async finishOAuth( @Req() request: Request, @Res({ passthrough: true }) res: Response, @@ -71,6 +84,10 @@ export class OAuthController { @Post('link') @Authenticated() @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Link OAuth account', + description: 'Link an OAuth account to the authenticated user.', + }) linkOAuthAccount( @Req() request: Request, @Auth() auth: AuthDto, @@ -82,6 +99,10 @@ export class OAuthController { @Post('unlink') @Authenticated() @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Unlink OAuth account', + description: 'Unlink the OAuth account from the authenticated user.', + }) 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 7cb5c1c27..63ad84002 100644 --- a/server/src/controllers/partner.controller.ts +++ b/server/src/controllers/partner.controller.ts @@ -1,32 +1,44 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put, Query } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { EndpointLifecycle } from 'src/decorators'; import { AuthDto } from 'src/dtos/auth.dto'; import { PartnerCreateDto, PartnerResponseDto, PartnerSearchDto, PartnerUpdateDto } from 'src/dtos/partner.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { PartnerService } from 'src/services/partner.service'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('Partners') +@ApiTags(ApiTag.Partners) @Controller('partners') export class PartnerController { constructor(private service: PartnerService) {} @Get() @Authenticated({ permission: Permission.PartnerRead }) + @ApiOperation({ + summary: 'Retrieve partners', + description: 'Retrieve a list of partners with whom assets are shared.', + }) getPartners(@Auth() auth: AuthDto, @Query() dto: PartnerSearchDto): Promise { return this.service.search(auth, dto); } @Post() @Authenticated({ permission: Permission.PartnerCreate }) + @ApiOperation({ + summary: 'Create a partner', + description: 'Create a new partner to share assets with.', + }) createPartner(@Auth() auth: AuthDto, @Body() dto: PartnerCreateDto): Promise { return this.service.create(auth, dto); } @Post(':id') - @EndpointLifecycle({ deprecatedAt: 'v1.141.0' }) + @EndpointLifecycle({ + deprecatedAt: 'v1.141.0', + summary: 'Create a partner', + description: 'Create a new partner to share assets with.', + }) @Authenticated({ permission: Permission.PartnerCreate }) createPartnerDeprecated(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.create(auth, { sharedWithId: id }); @@ -34,6 +46,10 @@ export class PartnerController { @Put(':id') @Authenticated({ permission: Permission.PartnerUpdate }) + @ApiOperation({ + summary: 'Update a partner', + description: "Specify whether a partner's assets should appear in the user's timeline.", + }) updatePartner( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -45,6 +61,10 @@ export class PartnerController { @Delete(':id') @Authenticated({ permission: Permission.PartnerDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Remove a partner', + description: 'Stop sharing assets with a partner.', + }) removePartner(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.remove(auth, id); } diff --git a/server/src/controllers/person.controller.ts b/server/src/controllers/person.controller.ts index 84bb864cd..6acb95844 100644 --- a/server/src/controllers/person.controller.ts +++ b/server/src/controllers/person.controller.ts @@ -12,7 +12,7 @@ import { Query, Res, } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { NextFunction, Response } from 'express'; import { BulkIdResponseDto, BulkIdsDto } from 'src/dtos/asset-ids.response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; @@ -27,14 +27,14 @@ import { PersonStatisticsResponseDto, PersonUpdateDto, } from 'src/dtos/person.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; import { LoggingRepository } from 'src/repositories/logging.repository'; import { PersonService } from 'src/services/person.service'; import { sendFile } from 'src/utils/file'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('People') +@ApiTags(ApiTag.People) @Controller('people') export class PersonController { constructor( @@ -46,18 +46,24 @@ export class PersonController { @Get() @Authenticated({ permission: Permission.PersonRead }) + @ApiOperation({ summary: 'Get all people', description: 'Retrieve a list of all people.' }) getAllPeople(@Auth() auth: AuthDto, @Query() options: PersonSearchDto): Promise { return this.service.getAll(auth, options); } @Post() @Authenticated({ permission: Permission.PersonCreate }) + @ApiOperation({ + summary: 'Create a person', + description: 'Create a new person that can have multiple faces assigned to them.', + }) createPerson(@Auth() auth: AuthDto, @Body() dto: PersonCreateDto): Promise { return this.service.create(auth, dto); } @Put() @Authenticated({ permission: Permission.PersonUpdate }) + @ApiOperation({ summary: 'Update people', description: 'Bulk update multiple people at once.' }) updatePeople(@Auth() auth: AuthDto, @Body() dto: PeopleUpdateDto): Promise { return this.service.updateAll(auth, dto); } @@ -65,18 +71,21 @@ export class PersonController { @Delete() @Authenticated({ permission: Permission.PersonDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ summary: 'Delete people', description: 'Bulk delete a list of people at once.' }) deletePeople(@Auth() auth: AuthDto, @Body() dto: BulkIdsDto): Promise { return this.service.deleteAll(auth, dto); } @Get(':id') @Authenticated({ permission: Permission.PersonRead }) + @ApiOperation({ summary: 'Get a person', description: 'Retrieve a person by id.' }) getPerson(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.getById(auth, id); } @Put(':id') @Authenticated({ permission: Permission.PersonUpdate }) + @ApiOperation({ summary: 'Update person', description: 'Update an individual person.' }) updatePerson( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -88,12 +97,14 @@ export class PersonController { @Delete(':id') @Authenticated({ permission: Permission.PersonDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ summary: 'Delete person', description: 'Delete an individual person.' }) deletePerson(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.delete(auth, id); } @Get(':id/statistics') @Authenticated({ permission: Permission.PersonStatistics }) + @ApiOperation({ summary: 'Get person statistics', description: 'Retrieve statistics about a specific person.' }) getPersonStatistics(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.getStatistics(auth, id); } @@ -101,6 +112,7 @@ export class PersonController { @Get(':id/thumbnail') @FileResponse() @Authenticated({ permission: Permission.PersonRead }) + @ApiOperation({ summary: 'Get person thumbnail', description: 'Retrieve the thumbnail file for a person.' }) async getPersonThumbnail( @Res() res: Response, @Next() next: NextFunction, @@ -112,6 +124,7 @@ export class PersonController { @Put(':id/reassign') @Authenticated({ permission: Permission.PersonReassign }) + @ApiOperation({ summary: 'Reassign faces', description: 'Bulk reassign a list of faces to a different person.' }) reassignFaces( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -123,6 +136,10 @@ export class PersonController { @Post(':id/merge') @Authenticated({ permission: Permission.PersonMerge }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Merge people', + description: 'Merge a list of people into the person specified in the path parameter.', + }) mergePerson( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, diff --git a/server/src/controllers/search.controller.ts b/server/src/controllers/search.controller.ts index f9aa6bce8..e04fbaa3f 100644 --- a/server/src/controllers/search.controller.ts +++ b/server/src/controllers/search.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Get, HttpCode, HttpStatus, Post, Query } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { PersonResponseDto } from 'src/dtos/person.dto'; @@ -17,11 +17,11 @@ import { SmartSearchDto, StatisticsSearchDto, } from 'src/dtos/search.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { SearchService } from 'src/services/search.service'; -@ApiTags('Search') +@ApiTags(ApiTag.Search) @Controller('search') export class SearchController { constructor(private service: SearchService) {} @@ -29,6 +29,10 @@ export class SearchController { @Post('metadata') @Authenticated({ permission: Permission.AssetRead }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Search assets by metadata', + description: 'Search for assets based on various metadata criteria.', + }) searchAssets(@Auth() auth: AuthDto, @Body() dto: MetadataSearchDto): Promise { return this.service.searchMetadata(auth, dto); } @@ -36,6 +40,10 @@ export class SearchController { @Post('statistics') @Authenticated({ permission: Permission.AssetStatistics }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Search asset statistics', + description: 'Retrieve statistical data about assets based on search criteria, such as the total matching count.', + }) searchAssetStatistics(@Auth() auth: AuthDto, @Body() dto: StatisticsSearchDto): Promise { return this.service.searchStatistics(auth, dto); } @@ -43,6 +51,10 @@ export class SearchController { @Post('random') @Authenticated({ permission: Permission.AssetRead }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Search random assets', + description: 'Retrieve a random selection of assets based on the provided criteria.', + }) searchRandom(@Auth() auth: AuthDto, @Body() dto: RandomSearchDto): Promise { return this.service.searchRandom(auth, dto); } @@ -50,6 +62,10 @@ export class SearchController { @Post('large-assets') @Authenticated({ permission: Permission.AssetRead }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Search large assets', + description: 'Search for assets that are considered large based on specified criteria.', + }) searchLargeAssets(@Auth() auth: AuthDto, @Query() dto: LargeAssetSearchDto): Promise { return this.service.searchLargeAssets(auth, dto); } @@ -57,36 +73,62 @@ export class SearchController { @Post('smart') @Authenticated({ permission: Permission.AssetRead }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Smart asset search', + description: 'Perform a smart search for assets by using machine learning vectors to determine relevance.', + }) searchSmart(@Auth() auth: AuthDto, @Body() dto: SmartSearchDto): Promise { return this.service.searchSmart(auth, dto); } @Get('explore') @Authenticated({ permission: Permission.AssetRead }) + @ApiOperation({ + summary: 'Retrieve explore data', + description: 'Retrieve data for the explore section, such as popular people and places.', + }) getExploreData(@Auth() auth: AuthDto): Promise { return this.service.getExploreData(auth); } @Get('person') @Authenticated({ permission: Permission.PersonRead }) + @ApiOperation({ + summary: 'Search people', + description: 'Search for people by name.', + }) searchPerson(@Auth() auth: AuthDto, @Query() dto: SearchPeopleDto): Promise { return this.service.searchPerson(auth, dto); } @Get('places') @Authenticated({ permission: Permission.AssetRead }) + @ApiOperation({ + summary: 'Search places', + description: 'Search for places by name.', + }) searchPlaces(@Query() dto: SearchPlacesDto): Promise { return this.service.searchPlaces(dto); } @Get('cities') @Authenticated({ permission: Permission.AssetRead }) + @ApiOperation({ + summary: 'Retrieve assets by city', + description: + 'Retrieve a list of assets with each asset belonging to a different city. This endpoint is used on the places pages to show a single thumbnail for each city the user has assets in.', + }) getAssetsByCity(@Auth() auth: AuthDto): Promise { return this.service.getAssetsByCity(auth); } @Get('suggestions') @Authenticated({ permission: Permission.AssetRead }) + @ApiOperation({ + summary: 'Retrieve search suggestions', + description: + 'Retrieve search suggestions based on partial input. This endpoint is used for typeahead search features.', + }) getSearchSuggestions(@Auth() auth: AuthDto, @Query() dto: SearchSuggestionRequestDto): Promise { // TODO fix open api generation to indicate that results can be nullable return this.service.getSearchSuggestions(auth, dto) as Promise; diff --git a/server/src/controllers/server.controller.ts b/server/src/controllers/server.controller.ts index f9a340eb3..c9c8539bb 100644 --- a/server/src/controllers/server.controller.ts +++ b/server/src/controllers/server.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Put } from '@nestjs/common'; -import { ApiNotFoundResponse, ApiTags } from '@nestjs/swagger'; +import { ApiNotFoundResponse, ApiOperation, ApiTags } from '@nestjs/swagger'; import { LicenseKeyDto, LicenseResponseDto } from 'src/dtos/license.dto'; import { ServerAboutResponseDto, @@ -15,13 +15,13 @@ import { ServerVersionResponseDto, } from 'src/dtos/server.dto'; import { VersionCheckStateResponseDto } from 'src/dtos/system-metadata.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Authenticated } from 'src/middleware/auth.guard'; import { ServerService } from 'src/services/server.service'; import { SystemMetadataService } from 'src/services/system-metadata.service'; import { VersionService } from 'src/services/version.service'; -@ApiTags('Server') +@ApiTags(ApiTag.Server) @Controller('server') export class ServerController { constructor( @@ -32,59 +32,85 @@ export class ServerController { @Get('about') @Authenticated({ permission: Permission.ServerAbout }) + @ApiOperation({ summary: 'Get server information', description: 'Retrieve a list of information about the server.' }) getAboutInfo(): Promise { return this.service.getAboutInfo(); } @Get('apk-links') @Authenticated({ permission: Permission.ServerApkLinks }) + @ApiOperation({ summary: 'Get APK links', description: 'Retrieve links to the APKs for the current server version.' }) getApkLinks(): ServerApkLinksDto { return this.service.getApkLinks(); } @Get('storage') @Authenticated({ permission: Permission.ServerStorage }) + @ApiOperation({ + summary: 'Get storage', + description: 'Retrieve the current storage utilization information of the server.', + }) getStorage(): Promise { return this.service.getStorage(); } @Get('ping') + @ApiOperation({ summary: 'Ping', description: 'Pong' }) pingServer(): ServerPingResponse { return this.service.ping(); } @Get('version') + @ApiOperation({ + summary: 'Get server version', + description: 'Retrieve the current server version in semantic versioning (semver) format.', + }) getServerVersion(): ServerVersionResponseDto { return this.versionService.getVersion(); } @Get('version-history') + @ApiOperation({ + summary: 'Get version history', + description: 'Retrieve a list of past versions the server has been on.', + }) getVersionHistory(): Promise { return this.versionService.getVersionHistory(); } @Get('features') + @ApiOperation({ summary: 'Get features', description: 'Retrieve available features supported by this server.' }) getServerFeatures(): Promise { return this.service.getFeatures(); } @Get('theme') + @ApiOperation({ summary: 'Get theme', description: 'Retrieve the custom CSS, if existent.' }) getTheme(): Promise { return this.service.getTheme(); } @Get('config') + @ApiOperation({ summary: 'Get config', description: 'Retrieve the current server configuration.' }) getServerConfig(): Promise { return this.service.getSystemConfig(); } @Get('statistics') @Authenticated({ permission: Permission.ServerStatistics, admin: true }) + @ApiOperation({ + summary: 'Get statistics', + description: 'Retrieve statistics about the entire Immich instance such as asset counts.', + }) getServerStatistics(): Promise { return this.service.getStatistics(); } @Get('media-types') + @ApiOperation({ + summary: 'Get supported media types', + description: 'Retrieve all media types supported by the server.', + }) getSupportedMediaTypes(): ServerMediaTypesResponseDto { return this.service.getSupportedMediaTypes(); } @@ -92,12 +118,20 @@ export class ServerController { @Get('license') @Authenticated({ permission: Permission.ServerLicenseRead, admin: true }) @ApiNotFoundResponse() + @ApiOperation({ + summary: 'Get product key', + description: 'Retrieve information about whether the server currently has a product key registered.', + }) getServerLicense(): Promise { return this.service.getLicense(); } @Put('license') @Authenticated({ permission: Permission.ServerLicenseUpdate, admin: true }) + @ApiOperation({ + summary: 'Set server product key', + description: 'Validate and set the server product key if successful.', + }) setServerLicense(@Body() license: LicenseKeyDto): Promise { return this.service.setLicense(license); } @@ -105,12 +139,17 @@ export class ServerController { @Delete('license') @Authenticated({ permission: Permission.ServerLicenseDelete, admin: true }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ summary: 'Delete server product key', description: 'Delete the currently set server product key.' }) deleteServerLicense(): Promise { return this.service.deleteLicense(); } @Get('version-check') @Authenticated({ permission: Permission.ServerVersionCheck }) + @ApiOperation({ + summary: 'Get version check status', + description: 'Retrieve information about the last time the version check ran.', + }) getVersionCheck(): Promise { return this.systemMetadataService.getVersionCheckState(); } diff --git a/server/src/controllers/session.controller.ts b/server/src/controllers/session.controller.ts index cbe8158fe..47cd7a6f1 100644 --- a/server/src/controllers/session.controller.ts +++ b/server/src/controllers/session.controller.ts @@ -1,25 +1,33 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { AuthDto } from 'src/dtos/auth.dto'; import { SessionCreateDto, SessionCreateResponseDto, SessionResponseDto, SessionUpdateDto } from 'src/dtos/session.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { SessionService } from 'src/services/session.service'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('Sessions') +@ApiTags(ApiTag.Sessions) @Controller('sessions') export class SessionController { constructor(private service: SessionService) {} @Post() @Authenticated({ permission: Permission.SessionCreate }) + @ApiOperation({ + summary: 'Create a session', + description: 'Create a session as a child to the current session. This endpoint is used for casting.', + }) createSession(@Auth() auth: AuthDto, @Body() dto: SessionCreateDto): Promise { return this.service.create(auth, dto); } @Get() @Authenticated({ permission: Permission.SessionRead }) + @ApiOperation({ + summary: 'Retrieve sessions', + description: 'Retrieve a list of sessions for the user.', + }) getSessions(@Auth() auth: AuthDto): Promise { return this.service.getAll(auth); } @@ -27,12 +35,20 @@ export class SessionController { @Delete() @Authenticated({ permission: Permission.SessionDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete all sessions', + description: 'Delete all sessions for the user. This will not delete the current session.', + }) deleteAllSessions(@Auth() auth: AuthDto): Promise { return this.service.deleteAll(auth); } @Put(':id') @Authenticated({ permission: Permission.SessionUpdate }) + @ApiOperation({ + summary: 'Update a session', + description: 'Update a specific session identified by id.', + }) updateSession( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -44,6 +60,10 @@ export class SessionController { @Delete(':id') @Authenticated({ permission: Permission.SessionDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete a session', + description: 'Delete a specific session by id.', + }) deleteSession(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.delete(auth, id); } @@ -51,6 +71,10 @@ export class SessionController { @Post(':id/lock') @Authenticated({ permission: Permission.SessionLock }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Lock a session', + description: 'Lock a specific session by id.', + }) lockSession(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.lock(auth, id); } diff --git a/server/src/controllers/shared-link.controller.ts b/server/src/controllers/shared-link.controller.ts index ef0a93e01..e3e55f294 100644 --- a/server/src/controllers/shared-link.controller.ts +++ b/server/src/controllers/shared-link.controller.ts @@ -13,7 +13,7 @@ import { Req, Res, } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { Request, Response } from 'express'; import { AssetIdsResponseDto } from 'src/dtos/asset-ids.response.dto'; import { AssetIdsDto } from 'src/dtos/asset.dto'; @@ -25,26 +25,34 @@ import { SharedLinkResponseDto, SharedLinkSearchDto, } from 'src/dtos/shared-link.dto'; -import { ImmichCookie, Permission } from 'src/enum'; +import { ApiTag, ImmichCookie, Permission } from 'src/enum'; import { Auth, Authenticated, GetLoginDetails } from 'src/middleware/auth.guard'; import { LoginDetails } from 'src/services/auth.service'; import { SharedLinkService } from 'src/services/shared-link.service'; import { respondWithCookie } from 'src/utils/response'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('Shared Links') +@ApiTags(ApiTag.SharedLinks) @Controller('shared-links') export class SharedLinkController { constructor(private service: SharedLinkService) {} @Get() @Authenticated({ permission: Permission.SharedLinkRead }) + @ApiOperation({ + summary: 'Retrieve all shared links', + description: 'Retrieve a list of all shared links.', + }) getAllSharedLinks(@Auth() auth: AuthDto, @Query() dto: SharedLinkSearchDto): Promise { return this.service.getAll(auth, dto); } @Get('me') @Authenticated({ sharedLink: true }) + @ApiOperation({ + summary: 'Retrieve current shared link', + description: 'Retrieve the current shared link associated with authentication method.', + }) async getMySharedLink( @Auth() auth: AuthDto, @Query() dto: SharedLinkPasswordDto, @@ -65,18 +73,30 @@ export class SharedLinkController { @Get(':id') @Authenticated({ permission: Permission.SharedLinkRead }) + @ApiOperation({ + summary: 'Retrieve a shared link', + description: 'Retrieve a specific shared link by its ID.', + }) getSharedLinkById(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.get(auth, id); } @Post() @Authenticated({ permission: Permission.SharedLinkCreate }) + @ApiOperation({ + summary: 'Create a shared link', + description: 'Create a new shared link.', + }) createSharedLink(@Auth() auth: AuthDto, @Body() dto: SharedLinkCreateDto) { return this.service.create(auth, dto); } @Patch(':id') @Authenticated({ permission: Permission.SharedLinkUpdate }) + @ApiOperation({ + summary: 'Update a shared link', + description: 'Update an existing shared link by its ID.', + }) updateSharedLink( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -88,12 +108,21 @@ export class SharedLinkController { @Delete(':id') @Authenticated({ permission: Permission.SharedLinkDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete a shared link', + description: 'Delete a specific shared link by its ID.', + }) removeSharedLink(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.remove(auth, id); } @Put(':id/assets') @Authenticated({ sharedLink: true }) + @ApiOperation({ + summary: 'Add assets to a shared link', + description: + 'Add assets to a specific shared link by its ID. This endpoint is only relevant for shared link of type individual.', + }) addSharedLinkAssets( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -104,6 +133,11 @@ export class SharedLinkController { @Delete(':id/assets') @Authenticated({ sharedLink: true }) + @ApiOperation({ + summary: 'Remove assets from a shared link', + description: + 'Remove assets from a specific shared link by its ID. This endpoint is only relevant for shared link of type individual.', + }) removeSharedLinkAssets( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, diff --git a/server/src/controllers/stack.controller.ts b/server/src/controllers/stack.controller.ts index 6acd4abc2..def3900c7 100644 --- a/server/src/controllers/stack.controller.ts +++ b/server/src/controllers/stack.controller.ts @@ -1,26 +1,35 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put, Query } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { BulkIdsDto } from 'src/dtos/asset-ids.response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { StackCreateDto, StackResponseDto, StackSearchDto, StackUpdateDto } from 'src/dtos/stack.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { StackService } from 'src/services/stack.service'; import { UUIDAssetIDParamDto, UUIDParamDto } from 'src/validation'; -@ApiTags('Stacks') +@ApiTags(ApiTag.Stacks) @Controller('stacks') export class StackController { constructor(private service: StackService) {} @Get() @Authenticated({ permission: Permission.StackRead }) + @ApiOperation({ + summary: 'Retrieve stacks', + description: 'Retrieve a list of stacks.', + }) searchStacks(@Auth() auth: AuthDto, @Query() query: StackSearchDto): Promise { return this.service.search(auth, query); } @Post() @Authenticated({ permission: Permission.StackCreate }) + @ApiOperation({ + summary: 'Create a stack', + description: + 'Create a new stack by providing a name and a list of asset IDs to include in the stack. If any of the provided asset IDs are primary assets of an existing stack, the existing stack will be merged into the newly created stack.', + }) createStack(@Auth() auth: AuthDto, @Body() dto: StackCreateDto): Promise { return this.service.create(auth, dto); } @@ -28,18 +37,30 @@ export class StackController { @Delete() @Authenticated({ permission: Permission.StackDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete stacks', + description: 'Delete multiple stacks by providing a list of stack IDs.', + }) deleteStacks(@Auth() auth: AuthDto, @Body() dto: BulkIdsDto): Promise { return this.service.deleteAll(auth, dto); } @Get(':id') @Authenticated({ permission: Permission.StackRead }) + @ApiOperation({ + summary: 'Retrieve a stack', + description: 'Retrieve a specific stack by its ID.', + }) getStack(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.get(auth, id); } @Put(':id') @Authenticated({ permission: Permission.StackUpdate }) + @ApiOperation({ + summary: 'Update a stack', + description: 'Update an existing stack by its ID.', + }) updateStack( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -51,6 +72,10 @@ export class StackController { @Delete(':id') @Authenticated({ permission: Permission.StackDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete a stack', + description: 'Delete a specific stack by its ID.', + }) deleteStack(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.delete(auth, id); } @@ -58,6 +83,10 @@ export class StackController { @Delete(':id/assets/:assetId') @Authenticated({ permission: Permission.StackUpdate }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Remove an asset from a stack', + description: 'Remove a specific asset from a stack by providing the stack ID and asset ID.', + }) removeAssetFromStack(@Auth() auth: AuthDto, @Param() dto: UUIDAssetIDParamDto): Promise { return this.service.removeAsset(auth, dto); } diff --git a/server/src/controllers/sync.controller.ts b/server/src/controllers/sync.controller.ts index 61432e43e..1f105e6b2 100644 --- a/server/src/controllers/sync.controller.ts +++ b/server/src/controllers/sync.controller.ts @@ -1,6 +1,7 @@ import { Body, Controller, Delete, Get, Header, HttpCode, HttpStatus, Post, Res } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { Response } from 'express'; +import { EndpointLifecycle } from 'src/decorators'; import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { @@ -12,12 +13,12 @@ import { SyncAckSetDto, SyncStreamDto, } from 'src/dtos/sync.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { GlobalExceptionFilter } from 'src/middleware/global-exception.filter'; import { SyncService } from 'src/services/sync.service'; -@ApiTags('Sync') +@ApiTags(ApiTag.Sync) @Controller('sync') export class SyncController { constructor( @@ -28,6 +29,11 @@ export class SyncController { @Post('full-sync') @Authenticated() @HttpCode(HttpStatus.OK) + @EndpointLifecycle({ + deprecatedAt: 'v2.0.0', + summary: 'Get full sync for user', + description: 'Retrieve all assets for a full synchronization for the authenticated user.', + }) getFullSyncForUser(@Auth() auth: AuthDto, @Body() dto: AssetFullSyncDto): Promise { return this.service.getFullSync(auth, dto); } @@ -35,6 +41,11 @@ export class SyncController { @Post('delta-sync') @Authenticated() @HttpCode(HttpStatus.OK) + @EndpointLifecycle({ + deprecatedAt: 'v2.0.0', + summary: 'Get delta sync for user', + description: 'Retrieve changed assets since the last sync for the authenticated user.', + }) getDeltaSync(@Auth() auth: AuthDto, @Body() dto: AssetDeltaSyncDto): Promise { return this.service.getDeltaSync(auth, dto); } @@ -43,6 +54,11 @@ export class SyncController { @Authenticated({ permission: Permission.SyncStream }) @Header('Content-Type', 'application/jsonlines+json') @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Stream sync changes', + description: + 'Retrieve a JSON lines streamed response of changes for synchronization. This endpoint is used by the mobile app to efficiently stay up to date with changes.', + }) async getSyncStream(@Auth() auth: AuthDto, @Res() res: Response, @Body() dto: SyncStreamDto) { try { await this.service.stream(auth, res, dto); @@ -54,6 +70,10 @@ export class SyncController { @Get('ack') @Authenticated({ permission: Permission.SyncCheckpointRead }) + @ApiOperation({ + summary: 'Retrieve acknowledgements', + description: 'Retrieve the synchronization acknowledgments for the current session.', + }) getSyncAck(@Auth() auth: AuthDto): Promise { return this.service.getAcks(auth); } @@ -61,6 +81,11 @@ export class SyncController { @Post('ack') @Authenticated({ permission: Permission.SyncCheckpointUpdate }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Acknowledge changes', + description: + 'Send a list of synchronization acknowledgements to confirm that the latest changes have been received.', + }) sendSyncAck(@Auth() auth: AuthDto, @Body() dto: SyncAckSetDto) { return this.service.setAcks(auth, dto); } @@ -68,6 +93,10 @@ export class SyncController { @Delete('ack') @Authenticated({ permission: Permission.SyncCheckpointDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete acknowledgements', + description: 'Delete specific synchronization acknowledgments.', + }) deleteSyncAck(@Auth() auth: AuthDto, @Body() dto: SyncAckDeleteDto): Promise { return this.service.deleteAcks(auth, dto); } diff --git a/server/src/controllers/system-config.controller.ts b/server/src/controllers/system-config.controller.ts index 69117f4d4..66d62135b 100644 --- a/server/src/controllers/system-config.controller.ts +++ b/server/src/controllers/system-config.controller.ts @@ -1,12 +1,12 @@ import { Body, Controller, Get, Put } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { SystemConfigDto, SystemConfigTemplateStorageOptionDto } from 'src/dtos/system-config.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Authenticated } from 'src/middleware/auth.guard'; import { StorageTemplateService } from 'src/services/storage-template.service'; import { SystemConfigService } from 'src/services/system-config.service'; -@ApiTags('System Config') +@ApiTags(ApiTag.SystemConfig) @Controller('system-config') export class SystemConfigController { constructor( @@ -16,24 +16,37 @@ export class SystemConfigController { @Get() @Authenticated({ permission: Permission.SystemConfigRead, admin: true }) + @ApiOperation({ summary: 'Get system configuration', description: 'Retrieve the current system configuration.' }) getConfig(): Promise { return this.service.getSystemConfig(); } @Get('defaults') @Authenticated({ permission: Permission.SystemConfigRead, admin: true }) + @ApiOperation({ + summary: 'Get system configuration defaults', + description: 'Retrieve the default values for the system configuration.', + }) getConfigDefaults(): SystemConfigDto { return this.service.getDefaults(); } @Put() @Authenticated({ permission: Permission.SystemConfigUpdate, admin: true }) + @ApiOperation({ + summary: 'Update system configuration', + description: 'Update the system configuration with a new system configuration.', + }) updateConfig(@Body() dto: SystemConfigDto): Promise { return this.service.updateSystemConfig(dto); } @Get('storage-template-options') @Authenticated({ permission: Permission.SystemConfigRead, admin: true }) + @ApiOperation({ + summary: 'Get storage template options', + description: 'Retrieve exemplary storage template options.', + }) getStorageTemplateOptions(): SystemConfigTemplateStorageOptionDto { return this.storageTemplateService.getStorageTemplateOptions(); } diff --git a/server/src/controllers/system-metadata.controller.ts b/server/src/controllers/system-metadata.controller.ts index d6634e944..f97eb3877 100644 --- a/server/src/controllers/system-metadata.controller.ts +++ b/server/src/controllers/system-metadata.controller.ts @@ -1,21 +1,25 @@ import { Body, Controller, Get, HttpCode, HttpStatus, Post } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { AdminOnboardingUpdateDto, ReverseGeocodingStateResponseDto, VersionCheckStateResponseDto, } from 'src/dtos/system-metadata.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Authenticated } from 'src/middleware/auth.guard'; import { SystemMetadataService } from 'src/services/system-metadata.service'; -@ApiTags('System Metadata') +@ApiTags(ApiTag.SystemMetadata) @Controller('system-metadata') export class SystemMetadataController { constructor(private service: SystemMetadataService) {} @Get('admin-onboarding') @Authenticated({ permission: Permission.SystemMetadataRead, admin: true }) + @ApiOperation({ + summary: 'Retrieve admin onboarding', + description: 'Retrieve the current admin onboarding status.', + }) getAdminOnboarding(): Promise { return this.service.getAdminOnboarding(); } @@ -23,18 +27,30 @@ export class SystemMetadataController { @Post('admin-onboarding') @Authenticated({ permission: Permission.SystemMetadataUpdate, admin: true }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Update admin onboarding', + description: 'Update the admin onboarding status.', + }) updateAdminOnboarding(@Body() dto: AdminOnboardingUpdateDto): Promise { return this.service.updateAdminOnboarding(dto); } @Get('reverse-geocoding-state') @Authenticated({ permission: Permission.SystemMetadataRead, admin: true }) + @ApiOperation({ + summary: 'Retrieve reverse geocoding state', + description: 'Retrieve the current state of the reverse geocoding import.', + }) getReverseGeocodingState(): Promise { return this.service.getReverseGeocodingState(); } @Get('version-check-state') @Authenticated({ permission: Permission.SystemMetadataRead, admin: true }) + @ApiOperation({ + summary: 'Retrieve version check state', + description: 'Retrieve the current state of the version check process.', + }) getVersionCheckState(): Promise { return this.service.getVersionCheckState(); } diff --git a/server/src/controllers/tag.controller.ts b/server/src/controllers/tag.controller.ts index 59915ef2a..514718f10 100644 --- a/server/src/controllers/tag.controller.ts +++ b/server/src/controllers/tag.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { BulkIdResponseDto, BulkIdsDto } from 'src/dtos/asset-ids.response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { @@ -10,48 +10,72 @@ import { TagUpdateDto, TagUpsertDto, } from 'src/dtos/tag.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { TagService } from 'src/services/tag.service'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('Tags') +@ApiTags(ApiTag.Tags) @Controller('tags') export class TagController { constructor(private service: TagService) {} @Post() @Authenticated({ permission: Permission.TagCreate }) + @ApiOperation({ + summary: 'Create a tag', + description: 'Create a new tag by providing a name and optional color.', + }) createTag(@Auth() auth: AuthDto, @Body() dto: TagCreateDto): Promise { return this.service.create(auth, dto); } @Get() @Authenticated({ permission: Permission.TagRead }) + @ApiOperation({ + summary: 'Retrieve tags', + description: 'Retrieve a list of all tags.', + }) getAllTags(@Auth() auth: AuthDto): Promise { return this.service.getAll(auth); } @Put() @Authenticated({ permission: Permission.TagCreate }) + @ApiOperation({ + summary: 'Upsert tags', + description: 'Create or update multiple tags in a single request.', + }) upsertTags(@Auth() auth: AuthDto, @Body() dto: TagUpsertDto): Promise { return this.service.upsert(auth, dto); } @Put('assets') @Authenticated({ permission: Permission.TagAsset }) + @ApiOperation({ + summary: 'Tag assets', + description: 'Add multiple tags to multiple assets in a single request.', + }) bulkTagAssets(@Auth() auth: AuthDto, @Body() dto: TagBulkAssetsDto): Promise { return this.service.bulkTagAssets(auth, dto); } @Get(':id') @Authenticated({ permission: Permission.TagRead }) + @ApiOperation({ + summary: 'Retrieve a tag', + description: 'Retrieve a specific tag by its ID.', + }) getTagById(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.get(auth, id); } @Put(':id') @Authenticated({ permission: Permission.TagUpdate }) + @ApiOperation({ + summary: 'Update a tag', + description: 'Update an existing tag identified by its ID.', + }) updateTag(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @Body() dto: TagUpdateDto): Promise { return this.service.update(auth, id, dto); } @@ -59,12 +83,20 @@ export class TagController { @Delete(':id') @Authenticated({ permission: Permission.TagDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete a tag', + description: 'Delete a specific tag by its ID.', + }) deleteTag(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.remove(auth, id); } @Put(':id/assets') @Authenticated({ permission: Permission.TagAsset }) + @ApiOperation({ + summary: 'Tag assets', + description: 'Add a tag to all the specified assets.', + }) tagAssets( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -75,6 +107,10 @@ export class TagController { @Delete(':id/assets') @Authenticated({ permission: Permission.TagAsset }) + @ApiOperation({ + summary: 'Untag assets', + description: 'Remove a tag from all the specified assets.', + }) untagAssets( @Auth() auth: AuthDto, @Body() dto: BulkIdsDto, diff --git a/server/src/controllers/timeline.controller.ts b/server/src/controllers/timeline.controller.ts index 8cab840ec..c2d3284fd 100644 --- a/server/src/controllers/timeline.controller.ts +++ b/server/src/controllers/timeline.controller.ts @@ -1,18 +1,19 @@ import { Controller, Get, Header, Query } from '@nestjs/common'; -import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; +import { ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger'; import { AuthDto } from 'src/dtos/auth.dto'; import { TimeBucketAssetDto, TimeBucketAssetResponseDto, TimeBucketDto } from 'src/dtos/time-bucket.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { TimelineService } from 'src/services/timeline.service'; -@ApiTags('Timeline') +@ApiTags(ApiTag.Timeline) @Controller('timeline') export class TimelineController { constructor(private service: TimelineService) {} @Get('buckets') @Authenticated({ permission: Permission.AssetRead, sharedLink: true }) + @ApiOperation({ summary: 'Get time buckets', description: 'Retrieve a list of all minimal time buckets.' }) getTimeBuckets(@Auth() auth: AuthDto, @Query() dto: TimeBucketDto) { return this.service.getTimeBuckets(auth, dto); } @@ -21,6 +22,10 @@ export class TimelineController { @Authenticated({ permission: Permission.AssetRead, sharedLink: true }) @ApiOkResponse({ type: TimeBucketAssetResponseDto }) @Header('Content-Type', 'application/json') + @ApiOperation({ + summary: 'Get time bucket', + description: 'Retrieve a string of all asset ids in a given time bucket.', + }) getTimeBucket(@Auth() auth: AuthDto, @Query() dto: TimeBucketAssetDto) { return this.service.getTimeBucket(auth, dto); } diff --git a/server/src/controllers/trash.controller.ts b/server/src/controllers/trash.controller.ts index eaf489f10..1b7ab6a39 100644 --- a/server/src/controllers/trash.controller.ts +++ b/server/src/controllers/trash.controller.ts @@ -1,13 +1,13 @@ import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { BulkIdsDto } from 'src/dtos/asset-ids.response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { TrashResponseDto } from 'src/dtos/trash.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { TrashService } from 'src/services/trash.service'; -@ApiTags('Trash') +@ApiTags(ApiTag.Trash) @Controller('trash') export class TrashController { constructor(private service: TrashService) {} @@ -15,6 +15,10 @@ export class TrashController { @Post('empty') @Authenticated({ permission: Permission.AssetDelete }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Empty trash', + description: 'Permanently delete all items in the trash.', + }) emptyTrash(@Auth() auth: AuthDto): Promise { return this.service.empty(auth); } @@ -22,6 +26,10 @@ export class TrashController { @Post('restore') @Authenticated({ permission: Permission.AssetDelete }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Restore trash', + description: 'Restore all items in the trash.', + }) restoreTrash(@Auth() auth: AuthDto): Promise { return this.service.restore(auth); } @@ -29,6 +37,10 @@ export class TrashController { @Post('restore/assets') @Authenticated({ permission: Permission.AssetDelete }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Restore assets', + description: 'Restore specific assets from the trash.', + }) restoreAssets(@Auth() auth: AuthDto, @Body() dto: BulkIdsDto): Promise { return this.service.restoreAssets(auth, dto); } diff --git a/server/src/controllers/user-admin.controller.ts b/server/src/controllers/user-admin.controller.ts index 25a4691b7..466cbb6f1 100644 --- a/server/src/controllers/user-admin.controller.ts +++ b/server/src/controllers/user-admin.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put, Query } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { AssetStatsDto, AssetStatsResponseDto } from 'src/dtos/asset.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { SessionResponseDto } from 'src/dtos/session.dto'; @@ -11,36 +11,52 @@ import { UserAdminSearchDto, UserAdminUpdateDto, } from 'src/dtos/user.dto'; -import { Permission } from 'src/enum'; +import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { UserAdminService } from 'src/services/user-admin.service'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('Users (admin)') +@ApiTags(ApiTag.UsersAdmin) @Controller('admin/users') export class UserAdminController { constructor(private service: UserAdminService) {} @Get() @Authenticated({ permission: Permission.AdminUserRead, admin: true }) + @ApiOperation({ + summary: 'Search users', + description: 'Search for users.', + }) searchUsersAdmin(@Auth() auth: AuthDto, @Query() dto: UserAdminSearchDto): Promise { return this.service.search(auth, dto); } @Post() @Authenticated({ permission: Permission.AdminUserCreate, admin: true }) + @ApiOperation({ + summary: 'Create a user', + description: 'Create a new user.', + }) createUserAdmin(@Body() createUserDto: UserAdminCreateDto): Promise { return this.service.create(createUserDto); } @Get(':id') @Authenticated({ permission: Permission.AdminUserRead, admin: true }) + @ApiOperation({ + summary: 'Retrieve a user', + description: 'Retrieve a specific user by their ID.', + }) getUserAdmin(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.get(auth, id); } @Put(':id') @Authenticated({ permission: Permission.AdminUserUpdate, admin: true }) + @ApiOperation({ + summary: 'Update a user', + description: 'Update an existing user.', + }) updateUserAdmin( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -51,6 +67,10 @@ export class UserAdminController { @Delete(':id') @Authenticated({ permission: Permission.AdminUserDelete, admin: true }) + @ApiOperation({ + summary: 'Delete a user', + description: 'Delete a user.', + }) deleteUserAdmin( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -61,12 +81,20 @@ export class UserAdminController { @Get(':id/sessions') @Authenticated({ permission: Permission.AdminSessionRead, admin: true }) + @ApiOperation({ + summary: 'Retrieve user sessions', + description: 'Retrieve all sessions for a specific user.', + }) getUserSessionsAdmin(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.getSessions(auth, id); } @Get(':id/statistics') @Authenticated({ permission: Permission.AdminUserRead, admin: true }) + @ApiOperation({ + summary: 'Retrieve user statistics', + description: 'Retrieve asset statistics for a specific user.', + }) getUserStatisticsAdmin( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -77,12 +105,20 @@ export class UserAdminController { @Get(':id/preferences') @Authenticated({ permission: Permission.AdminUserRead, admin: true }) + @ApiOperation({ + summary: 'Retrieve user preferences', + description: 'Retrieve the preferences of a specific user.', + }) getUserPreferencesAdmin(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.getPreferences(auth, id); } @Put(':id/preferences') @Authenticated({ permission: Permission.AdminUserUpdate, admin: true }) + @ApiOperation({ + summary: 'Update user preferences', + description: 'Update the preferences of a specific user.', + }) updateUserPreferencesAdmin( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @@ -94,6 +130,10 @@ export class UserAdminController { @Post(':id/restore') @Authenticated({ permission: Permission.AdminUserDelete, admin: true }) @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Restore a deleted user', + description: 'Restore a previously deleted user.', + }) restoreUserAdmin(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.restore(auth, id); } diff --git a/server/src/controllers/user.controller.ts b/server/src/controllers/user.controller.ts index d72b088c5..d76daaa0d 100644 --- a/server/src/controllers/user.controller.ts +++ b/server/src/controllers/user.controller.ts @@ -13,7 +13,7 @@ import { UploadedFile, UseInterceptors, } from '@nestjs/common'; -import { ApiBody, ApiConsumes, ApiTags } from '@nestjs/swagger'; +import { ApiBody, ApiConsumes, ApiOperation, ApiTags } from '@nestjs/swagger'; import { NextFunction, Response } from 'express'; import { AuthDto } from 'src/dtos/auth.dto'; import { LicenseKeyDto, LicenseResponseDto } from 'src/dtos/license.dto'; @@ -21,7 +21,7 @@ import { OnboardingDto, OnboardingResponseDto } from 'src/dtos/onboarding.dto'; import { UserPreferencesResponseDto, UserPreferencesUpdateDto } from 'src/dtos/user-preferences.dto'; import { CreateProfileImageDto, CreateProfileImageResponseDto } from 'src/dtos/user-profile.dto'; import { UserAdminResponseDto, UserResponseDto, UserUpdateMeDto } from 'src/dtos/user.dto'; -import { Permission, RouteKey } from 'src/enum'; +import { ApiTag, Permission, RouteKey } from 'src/enum'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; import { FileUploadInterceptor } from 'src/middleware/file-upload.interceptor'; import { LoggingRepository } from 'src/repositories/logging.repository'; @@ -29,7 +29,7 @@ import { UserService } from 'src/services/user.service'; import { sendFile } from 'src/utils/file'; import { UUIDParamDto } from 'src/validation'; -@ApiTags('Users') +@ApiTags(ApiTag.Users) @Controller(RouteKey.User) export class UserController { constructor( @@ -39,30 +39,38 @@ export class UserController { @Get() @Authenticated({ permission: Permission.UserRead }) + @ApiOperation({ summary: 'Get all users', description: 'Retrieve a list of all users on the server.' }) searchUsers(@Auth() auth: AuthDto): Promise { return this.service.search(auth); } @Get('me') @Authenticated({ permission: Permission.UserRead }) + @ApiOperation({ + summary: 'Get current user', + description: 'Retrieve information about the user making the API request.', + }) getMyUser(@Auth() auth: AuthDto): Promise { return this.service.getMe(auth); } @Put('me') @Authenticated({ permission: Permission.UserUpdate }) + @ApiOperation({ summary: 'Update current user', description: 'Update the current user making teh API request.' }) updateMyUser(@Auth() auth: AuthDto, @Body() dto: UserUpdateMeDto): Promise { return this.service.updateMe(auth, dto); } @Get('me/preferences') @Authenticated({ permission: Permission.UserPreferenceRead }) + @ApiOperation({ summary: 'Get my preferences', description: 'Retrieve the preferences for the current user.' }) getMyPreferences(@Auth() auth: AuthDto): Promise { return this.service.getMyPreferences(auth); } @Put('me/preferences') @Authenticated({ permission: Permission.UserPreferenceUpdate }) + @ApiOperation({ summary: 'Update my preferences', description: 'Update the preferences of the current user.' }) updateMyPreferences( @Auth() auth: AuthDto, @Body() dto: UserPreferencesUpdateDto, @@ -72,12 +80,20 @@ export class UserController { @Get('me/license') @Authenticated({ permission: Permission.UserLicenseRead }) + @ApiOperation({ + summary: 'Retrieve user product key', + description: 'Retrieve information about whether the current user has a registered product key.', + }) getUserLicense(@Auth() auth: AuthDto): Promise { return this.service.getLicense(auth); } @Put('me/license') @Authenticated({ permission: Permission.UserLicenseUpdate }) + @ApiOperation({ + summary: 'Set user product key', + description: 'Register a product key for the current user.', + }) async setUserLicense(@Auth() auth: AuthDto, @Body() license: LicenseKeyDto): Promise { return this.service.setLicense(auth, license); } @@ -85,18 +101,30 @@ export class UserController { @Delete('me/license') @Authenticated({ permission: Permission.UserLicenseDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete user product key', + description: 'Delete the registered product key for the current user.', + }) async deleteUserLicense(@Auth() auth: AuthDto): Promise { await this.service.deleteLicense(auth); } @Get('me/onboarding') @Authenticated({ permission: Permission.UserOnboardingRead }) + @ApiOperation({ + summary: 'Retrieve user onboarding', + description: 'Retrieve the onboarding status of the current user.', + }) getUserOnboarding(@Auth() auth: AuthDto): Promise { return this.service.getOnboarding(auth); } @Put('me/onboarding') @Authenticated({ permission: Permission.UserOnboardingUpdate }) + @ApiOperation({ + summary: 'Update user onboarding', + description: 'Update the onboarding status of the current user.', + }) async setUserOnboarding(@Auth() auth: AuthDto, @Body() Onboarding: OnboardingDto): Promise { return this.service.setOnboarding(auth, Onboarding); } @@ -104,12 +132,20 @@ export class UserController { @Delete('me/onboarding') @Authenticated({ permission: Permission.UserOnboardingDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete user onboarding', + description: 'Delete the onboarding status of the current user.', + }) async deleteUserOnboarding(@Auth() auth: AuthDto): Promise { await this.service.deleteOnboarding(auth); } @Get(':id') @Authenticated({ permission: Permission.UserRead }) + @ApiOperation({ + summary: 'Retrieve a user', + description: 'Retrieve a specific user by their ID.', + }) getUser(@Param() { id }: UUIDParamDto): Promise { return this.service.get(id); } @@ -119,6 +155,10 @@ export class UserController { @UseInterceptors(FileUploadInterceptor) @ApiConsumes('multipart/form-data') @ApiBody({ description: 'A new avatar for the user', type: CreateProfileImageDto }) + @ApiOperation({ + summary: 'Create user profile image', + description: 'Upload and set a new profile image for the current user.', + }) createProfileImage( @Auth() auth: AuthDto, @UploadedFile() fileInfo: Express.Multer.File, @@ -129,6 +169,10 @@ export class UserController { @Delete('profile-image') @Authenticated({ permission: Permission.UserProfileImageDelete }) @HttpCode(HttpStatus.NO_CONTENT) + @ApiOperation({ + summary: 'Delete user profile image', + description: 'Delete the profile image of the current user.', + }) deleteProfileImage(@Auth() auth: AuthDto): Promise { return this.service.deleteProfileImage(auth); } @@ -136,6 +180,10 @@ export class UserController { @Get(':id/profile-image') @FileResponse() @Authenticated({ permission: Permission.UserProfileImageRead }) + @ApiOperation({ + summary: 'Retrieve user profile image', + description: 'Retrieve the profile image file for a user.', + }) async getProfileImage(@Res() res: Response, @Next() next: NextFunction, @Param() { id }: UUIDParamDto) { await sendFile(res, next, () => this.service.getProfileImage(id), this.logger); } diff --git a/server/src/controllers/view.controller.ts b/server/src/controllers/view.controller.ts index b5e281e09..8d0cbb0d9 100644 --- a/server/src/controllers/view.controller.ts +++ b/server/src/controllers/view.controller.ts @@ -1,23 +1,32 @@ import { Controller, Get, Query } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; +import { ApiTag } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { ViewService } from 'src/services/view.service'; -@ApiTags('View') +@ApiTags(ApiTag.Views) @Controller('view') export class ViewController { constructor(private service: ViewService) {} @Get('folder/unique-paths') @Authenticated() + @ApiOperation({ + summary: 'Retrieve unique paths', + description: 'Retrieve a list of unique folder paths from asset original paths.', + }) getUniqueOriginalPaths(@Auth() auth: AuthDto): Promise { return this.service.getUniqueOriginalPaths(auth); } @Get('folder') @Authenticated() + @ApiOperation({ + summary: 'Retrieve assets by original path', + description: 'Retrieve assets that are children of a specific folder.', + }) getAssetsByOriginalPath(@Auth() auth: AuthDto, @Query('path') path: string): Promise { return this.service.getAssetsByOriginalPath(auth, path); } diff --git a/server/src/decorators.ts b/server/src/decorators.ts index 8a8e23d88..e9f27fa9e 100644 --- a/server/src/decorators.ts +++ b/server/src/decorators.ts @@ -2,7 +2,7 @@ import { SetMetadata, applyDecorators } from '@nestjs/common'; import { ApiExtension, ApiOperation, ApiOperationOptions, ApiProperty, ApiTags } from '@nestjs/swagger'; import _ from 'lodash'; import { ADDED_IN_PREFIX, DEPRECATED_IN_PREFIX, LIFECYCLE_EXTENSION } from 'src/constants'; -import { ImmichWorker, JobName, MetadataKey, QueueName } from 'src/enum'; +import { ApiTag, ImmichWorker, JobName, MetadataKey, QueueName } from 'src/enum'; import { EmitEvent } from 'src/repositories/event.repository'; import { immich_uuid_v7, updated_at } from 'src/schema/functions'; import { BeforeUpdateTrigger, Column, ColumnOptions } from 'src/sql-tools'; @@ -168,7 +168,7 @@ export const EndpointLifecycle = ({ const decorators: MethodDecorator[] = [ApiExtension(LIFECYCLE_EXTENSION, { addedAt, deprecatedAt })]; if (deprecatedAt) { decorators.push( - ApiTags('Deprecated'), + ApiTags(ApiTag.Deprecated), ApiOperation({ deprecated: true, description: DEPRECATED_IN_PREFIX + deprecatedAt + (description ? `. ${description}` : ''), diff --git a/server/src/enum.ts b/server/src/enum.ts index a98fee011..24f307f07 100644 --- a/server/src/enum.ts +++ b/server/src/enum.ts @@ -771,3 +771,38 @@ export enum CronJob { LibraryScan = 'LibraryScan', NightlyJobs = 'NightlyJobs', } + +export enum ApiTag { + Activities = 'Activities', + Albums = 'Albums', + ApiKeys = 'API keys', + Authentication = 'Authentication', + AuthenticationAdmin = 'Authentication (admin)', + Assets = 'Assets', + Deprecated = 'Deprecated', + Download = 'Download', + Duplicates = 'Duplicates', + Faces = 'Faces', + Jobs = 'Jobs', + Libraries = 'Libraries', + Map = 'Map', + Memories = 'Memories', + Notifications = 'Notifications', + NotificationsAdmin = 'Notifications (admin)', + Partners = 'Partners', + People = 'People', + Search = 'Search', + Server = 'Server', + Sessions = 'Sessions', + SharedLinks = 'Shared links', + Stacks = 'Stacks', + Sync = 'Sync', + SystemConfig = 'System config', + SystemMetadata = 'System metadata', + Tags = 'Tags', + Timeline = 'Timeline', + Trash = 'Trash', + UsersAdmin = 'Users (admin)', + Users = 'Users', + Views = 'Views', +} diff --git a/server/src/utils/misc.ts b/server/src/utils/misc.ts index b9741c3b4..eb548eab7 100644 --- a/server/src/utils/misc.ts +++ b/server/src/utils/misc.ts @@ -17,7 +17,7 @@ import path from 'node:path'; import picomatch from 'picomatch'; import parse from 'picomatch/lib/parse'; import { SystemConfig } from 'src/config'; -import { CLIP_MODEL_INFO, serverVersion } from 'src/constants'; +import { CLIP_MODEL_INFO, endpointTags, serverVersion } from 'src/constants'; import { extraSyncModels } from 'src/dtos/sync.dto'; import { ApiCustomExtension, ImmichCookie, ImmichHeader, MetadataKey } from 'src/enum'; import { LoggingRepository } from 'src/repositories/logging.repository'; @@ -218,25 +218,16 @@ const patchOpenAPI = (document: OpenAPIObject) => { delete operation.summary; } + if (operation.description === '') { + delete operation.description; + } + if (operation.operationId) { // console.log(`${routeToErrorMessage(operation.operationId).padEnd(40)} (${operation.operationId})`); } - const adminOnly = operation[ApiCustomExtension.AdminOnly] ?? false; - const permission = operation[ApiCustomExtension.Permission]; - if (permission) { - let description = (operation.description || '').trim(); - if (description && !description.endsWith('.')) { - description += '. '; - } - - operation.description = - description + - `This endpoint ${adminOnly ? 'is an admin-only route, and ' : ''}requires the \`${permission}\` permission.`; - - if (operation.parameters) { - operation.parameters = _.orderBy(operation.parameters, 'name'); - } + if (operation.parameters) { + operation.parameters = _.orderBy(operation.parameters, 'name'); } } } @@ -245,7 +236,7 @@ const patchOpenAPI = (document: OpenAPIObject) => { }; export const useSwagger = (app: INestApplication, { write }: { write: boolean }) => { - const config = new DocumentBuilder() + const builder = new DocumentBuilder() .setTitle('Immich') .setDescription('Immich API') .setVersion(serverVersion.toString()) @@ -263,8 +254,12 @@ export const useSwagger = (app: INestApplication, { write }: { write: boolean }) }, MetadataKey.ApiKeySecurity, ) - .addServer('/api') - .build(); + .addServer('/api'); + + for (const [tag, description] of Object.entries(endpointTags)) { + builder.addTag(tag, description); + } + const config = builder.build(); const options: SwaggerDocumentOptions = { operationIdFactory: (controllerKey: string, methodKey: string) => methodKey,