diff --git a/mobile/lib/services/api.service.dart b/mobile/lib/services/api.service.dart index 6ff62d4b3..4a3cfb19a 100644 --- a/mobile/lib/services/api.service.dart +++ b/mobile/lib/services/api.service.dart @@ -18,7 +18,7 @@ class ApiService implements Authentication { late AlbumsApi albumsApi; late AssetsApi assetsApi; late SearchApi searchApi; - late ServerInfoApi serverInfoApi; + late ServerApi serverInfoApi; late MapApi mapApi; late PartnersApi partnersApi; late PeopleApi peopleApi; @@ -50,7 +50,7 @@ class ApiService implements Authentication { oAuthApi = OAuthApi(_apiClient); albumsApi = AlbumsApi(_apiClient); assetsApi = AssetsApi(_apiClient); - serverInfoApi = ServerInfoApi(_apiClient); + serverInfoApi = ServerApi(_apiClient); searchApi = SearchApi(_apiClient); mapApi = MapApi(_apiClient); partnersApi = PartnersApi(_apiClient); diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index c49b5052d..4e7dfb35f 100644 Binary files a/mobile/openapi/README.md and b/mobile/openapi/README.md differ diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart index a6f860dda..1179bff56 100644 Binary files a/mobile/openapi/lib/api.dart and b/mobile/openapi/lib/api.dart differ diff --git a/mobile/openapi/lib/api/deprecated_api.dart b/mobile/openapi/lib/api/deprecated_api.dart index e1e09ae4b..96cb3c2ef 100644 Binary files a/mobile/openapi/lib/api/deprecated_api.dart and b/mobile/openapi/lib/api/deprecated_api.dart differ diff --git a/mobile/openapi/lib/api/server_api.dart b/mobile/openapi/lib/api/server_api.dart index 9cb52514c..bde8d595b 100644 Binary files a/mobile/openapi/lib/api/server_api.dart and b/mobile/openapi/lib/api/server_api.dart differ diff --git a/mobile/openapi/lib/api/server_info_api.dart b/mobile/openapi/lib/api/server_info_api.dart deleted file mode 100644 index dc58a94fd..000000000 Binary files a/mobile/openapi/lib/api/server_info_api.dart and /dev/null differ diff --git a/mobile/openapi/lib/model/permission.dart b/mobile/openapi/lib/model/permission.dart index 3a9b61d81..3f89c9826 100644 Binary files a/mobile/openapi/lib/model/permission.dart and b/mobile/openapi/lib/model/permission.dart differ diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index 16c25562a..35fecdb1e 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -3643,7 +3643,7 @@ "operationId": "unlinkOAuthAccount", "parameters": [], "responses": { - "201": { + "200": { "content": { "application/json": { "schema": { @@ -4771,10 +4771,8 @@ ] } }, - "/server-info/about": { + "/server/about": { "get": { - "deprecated": true, - "description": "This property was deprecated in v1.107.0", "operationId": "getAboutInfo", "parameters": [], "responses": { @@ -4801,18 +4799,12 @@ } ], "tags": [ - "Server Info", - "Deprecated" - ], - "x-immich-lifecycle": { - "deprecatedAt": "v1.107.0" - } + "Server" + ] } }, - "/server-info/config": { + "/server/config": { "get": { - "deprecated": true, - "description": "This property was deprecated in v1.107.0", "operationId": "getServerConfig", "parameters": [], "responses": { @@ -4828,18 +4820,12 @@ } }, "tags": [ - "Server Info", - "Deprecated" - ], - "x-immich-lifecycle": { - "deprecatedAt": "v1.107.0" - } + "Server" + ] } }, - "/server-info/features": { + "/server/features": { "get": { - "deprecated": true, - "description": "This property was deprecated in v1.107.0", "operationId": "getServerFeatures", "parameters": [], "responses": { @@ -4855,196 +4841,8 @@ } }, "tags": [ - "Server Info", - "Deprecated" - ], - "x-immich-lifecycle": { - "deprecatedAt": "v1.107.0" - } - } - }, - "/server-info/media-types": { - "get": { - "deprecated": true, - "description": "This property was deprecated in v1.107.0", - "operationId": "getSupportedMediaTypes", - "parameters": [], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServerMediaTypesResponseDto" - } - } - }, - "description": "" - } - }, - "tags": [ - "Server Info", - "Deprecated" - ], - "x-immich-lifecycle": { - "deprecatedAt": "v1.107.0" - } - } - }, - "/server-info/ping": { - "get": { - "deprecated": true, - "description": "This property was deprecated in v1.107.0", - "operationId": "pingServer", - "parameters": [], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServerPingResponse" - } - } - }, - "description": "" - } - }, - "tags": [ - "Server Info", - "Deprecated" - ], - "x-immich-lifecycle": { - "deprecatedAt": "v1.107.0" - } - } - }, - "/server-info/statistics": { - "get": { - "deprecated": true, - "description": "This property was deprecated in v1.107.0", - "operationId": "getServerStatistics", - "parameters": [], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServerStatsResponseDto" - } - } - }, - "description": "" - } - }, - "security": [ - { - "bearer": [] - }, - { - "cookie": [] - }, - { - "api_key": [] - } - ], - "tags": [ - "Server Info", - "Deprecated" - ], - "x-immich-lifecycle": { - "deprecatedAt": "v1.107.0" - } - } - }, - "/server-info/storage": { - "get": { - "deprecated": true, - "description": "This property was deprecated in v1.107.0", - "operationId": "getStorage", - "parameters": [], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServerStorageResponseDto" - } - } - }, - "description": "" - } - }, - "security": [ - { - "bearer": [] - }, - { - "cookie": [] - }, - { - "api_key": [] - } - ], - "tags": [ - "Server Info", - "Deprecated" - ], - "x-immich-lifecycle": { - "deprecatedAt": "v1.107.0" - } - } - }, - "/server-info/theme": { - "get": { - "deprecated": true, - "description": "This property was deprecated in v1.107.0", - "operationId": "getTheme", - "parameters": [], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServerThemeDto" - } - } - }, - "description": "" - } - }, - "tags": [ - "Server Info", - "Deprecated" - ], - "x-immich-lifecycle": { - "deprecatedAt": "v1.107.0" - } - } - }, - "/server-info/version": { - "get": { - "deprecated": true, - "description": "This property was deprecated in v1.107.0", - "operationId": "getServerVersion", - "parameters": [], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServerVersionResponseDto" - } - } - }, - "description": "" - } - }, - "tags": [ - "Server Info", - "Deprecated" - ], - "x-immich-lifecycle": { - "deprecatedAt": "v1.107.0" - } + "Server" + ] } }, "/server/license": { @@ -5145,6 +4943,154 @@ ] } }, + "/server/media-types": { + "get": { + "operationId": "getSupportedMediaTypes", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServerMediaTypesResponseDto" + } + } + }, + "description": "" + } + }, + "tags": [ + "Server" + ] + } + }, + "/server/ping": { + "get": { + "operationId": "pingServer", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServerPingResponse" + } + } + }, + "description": "" + } + }, + "tags": [ + "Server" + ] + } + }, + "/server/statistics": { + "get": { + "operationId": "getServerStatistics", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServerStatsResponseDto" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer": [] + }, + { + "cookie": [] + }, + { + "api_key": [] + } + ], + "tags": [ + "Server" + ] + } + }, + "/server/storage": { + "get": { + "operationId": "getStorage", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServerStorageResponseDto" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer": [] + }, + { + "cookie": [] + }, + { + "api_key": [] + } + ], + "tags": [ + "Server" + ] + } + }, + "/server/theme": { + "get": { + "operationId": "getTheme", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServerThemeDto" + } + } + }, + "description": "" + } + }, + "tags": [ + "Server" + ] + } + }, + "/server/version": { + "get": { + "operationId": "getServerVersion", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServerVersionResponseDto" + } + } + }, + "description": "" + } + }, + "tags": [ + "Server" + ] + } + }, "/sessions": { "delete": { "operationId": "deleteAllSessions", @@ -9972,7 +9918,6 @@ "asset.read", "asset.update", "asset.delete", - "asset.restore", "asset.share", "asset.view", "asset.download", @@ -10014,6 +9959,9 @@ "person.statistics", "person.merge", "person.reassign", + "session.read", + "session.update", + "session.delete", "sharedLink.create", "sharedLink.read", "sharedLink.update", diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index c6d8d3e3b..80394ad90 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -869,6 +869,15 @@ export type ServerFeaturesDto = { smartSearch: boolean; trash: boolean; }; +export type LicenseResponseDto = { + activatedAt: string; + activationKey: string; + licenseKey: string; +}; +export type LicenseKeyDto = { + activationKey: string; + licenseKey: string; +}; export type ServerMediaTypesResponseDto = { image: string[]; sidecar: string[]; @@ -909,15 +918,6 @@ export type ServerVersionResponseDto = { minor: number; patch: number; }; -export type LicenseResponseDto = { - activatedAt: string; - activationKey: string; - licenseKey: string; -}; -export type LicenseKeyDto = { - activationKey: string; - licenseKey: string; -}; export type SessionResponseDto = { createdAt: string; current: boolean; @@ -2168,7 +2168,7 @@ export function redirectOAuthToMobile(opts?: Oazapfts.RequestOpts) { } export function unlinkOAuthAccount(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ - status: 201; + status: 200; data: UserAdminResponseDto; }>("/oauth/unlink", { ...opts, @@ -2458,102 +2458,27 @@ export function getSearchSuggestions({ country, includeNull, make, model, state, ...opts })); } -/** - * This property was deprecated in v1.107.0 - */ export function getAboutInfo(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: ServerAboutResponseDto; - }>("/server-info/about", { + }>("/server/about", { ...opts })); } -/** - * This property was deprecated in v1.107.0 - */ export function getServerConfig(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: ServerConfigDto; - }>("/server-info/config", { + }>("/server/config", { ...opts })); } -/** - * This property was deprecated in v1.107.0 - */ export function getServerFeatures(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: ServerFeaturesDto; - }>("/server-info/features", { - ...opts - })); -} -/** - * This property was deprecated in v1.107.0 - */ -export function getSupportedMediaTypes(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: ServerMediaTypesResponseDto; - }>("/server-info/media-types", { - ...opts - })); -} -/** - * This property was deprecated in v1.107.0 - */ -export function pingServer(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: ServerPingResponseRead; - }>("/server-info/ping", { - ...opts - })); -} -/** - * This property was deprecated in v1.107.0 - */ -export function getServerStatistics(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: ServerStatsResponseDto; - }>("/server-info/statistics", { - ...opts - })); -} -/** - * This property was deprecated in v1.107.0 - */ -export function getStorage(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: ServerStorageResponseDto; - }>("/server-info/storage", { - ...opts - })); -} -/** - * This property was deprecated in v1.107.0 - */ -export function getTheme(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: ServerThemeDto; - }>("/server-info/theme", { - ...opts - })); -} -/** - * This property was deprecated in v1.107.0 - */ -export function getServerVersion(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: ServerVersionResponseDto; - }>("/server-info/version", { + }>("/server/features", { ...opts })); } @@ -2585,6 +2510,54 @@ export function setServerLicense({ licenseKeyDto }: { body: licenseKeyDto }))); } +export function getSupportedMediaTypes(opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: ServerMediaTypesResponseDto; + }>("/server/media-types", { + ...opts + })); +} +export function pingServer(opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: ServerPingResponseRead; + }>("/server/ping", { + ...opts + })); +} +export function getServerStatistics(opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: ServerStatsResponseDto; + }>("/server/statistics", { + ...opts + })); +} +export function getStorage(opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: ServerStorageResponseDto; + }>("/server/storage", { + ...opts + })); +} +export function getTheme(opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: ServerThemeDto; + }>("/server/theme", { + ...opts + })); +} +export function getServerVersion(opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: ServerVersionResponseDto; + }>("/server/version", { + ...opts + })); +} export function deleteAllSessions(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchText("/sessions", { ...opts, @@ -3205,7 +3178,6 @@ export enum Permission { AssetRead = "asset.read", AssetUpdate = "asset.update", AssetDelete = "asset.delete", - AssetRestore = "asset.restore", AssetShare = "asset.share", AssetView = "asset.view", AssetDownload = "asset.download", @@ -3247,6 +3219,9 @@ export enum Permission { PersonStatistics = "person.statistics", PersonMerge = "person.merge", PersonReassign = "person.reassign", + SessionRead = "session.read", + SessionUpdate = "session.update", + SessionDelete = "session.delete", SharedLinkCreate = "sharedLink.create", SharedLinkRead = "sharedLink.read", SharedLinkUpdate = "sharedLink.update", diff --git a/server/src/controllers/activity.controller.ts b/server/src/controllers/activity.controller.ts index 9b06f82f3..b91f2902d 100644 --- a/server/src/controllers/activity.controller.ts +++ b/server/src/controllers/activity.controller.ts @@ -25,12 +25,6 @@ export class ActivityController { return this.service.getAll(auth, dto); } - @Get('statistics') - @Authenticated({ permission: Permission.ACTIVITY_STATISTICS }) - getActivityStatistics(@Auth() auth: AuthDto, @Query() dto: ActivityDto): Promise { - return this.service.getStatistics(auth, dto); - } - @Post() @Authenticated({ permission: Permission.ACTIVITY_CREATE }) async createActivity( @@ -45,6 +39,12 @@ export class ActivityController { return value; } + @Get('statistics') + @Authenticated({ permission: Permission.ACTIVITY_STATISTICS }) + getActivityStatistics(@Auth() auth: AuthDto, @Query() dto: ActivityDto): Promise { + return this.service.getStatistics(auth, dto); + } + @Delete(':id') @HttpCode(HttpStatus.NO_CONTENT) @Authenticated({ permission: Permission.ACTIVITY_DELETE }) diff --git a/server/src/controllers/asset-media.controller.ts b/server/src/controllers/asset-media.controller.ts index 48fea8b8a..fb5ec58f2 100644 --- a/server/src/controllers/asset-media.controller.ts +++ b/server/src/controllers/asset-media.controller.ts @@ -93,8 +93,8 @@ export class AssetMediaController { @Put(':id/original') @UseInterceptors(FileUploadInterceptor) @ApiConsumes('multipart/form-data') - @Authenticated({ sharedLink: true }) @EndpointLifecycle({ addedAt: 'v1.106.0' }) + @Authenticated({ sharedLink: true }) async replaceAsset( @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, diff --git a/server/src/controllers/asset.controller.ts b/server/src/controllers/asset.controller.ts index f275aa724..c6fdac171 100644 --- a/server/src/controllers/asset.controller.ts +++ b/server/src/controllers/asset.controller.ts @@ -51,8 +51,8 @@ export class AssetController { } @Post('jobs') - @HttpCode(HttpStatus.NO_CONTENT) @Authenticated() + @HttpCode(HttpStatus.NO_CONTENT) runAssetJobs(@Auth() auth: AuthDto, @Body() dto: AssetJobsDto): Promise { return this.service.run(auth, dto); } diff --git a/server/src/controllers/library.controller.ts b/server/src/controllers/library.controller.ts index 18ba43c0a..a45617fc2 100644 --- a/server/src/controllers/library.controller.ts +++ b/server/src/controllers/library.controller.ts @@ -31,18 +31,18 @@ export class LibraryController { return this.service.create(dto); } - @Put(':id') - @Authenticated({ permission: Permission.LIBRARY_UPDATE, admin: true }) - updateLibrary(@Param() { id }: UUIDParamDto, @Body() dto: UpdateLibraryDto): Promise { - return this.service.update(id, dto); - } - @Get(':id') @Authenticated({ permission: Permission.LIBRARY_READ, admin: true }) getLibrary(@Param() { id }: UUIDParamDto): Promise { return this.service.get(id); } + @Put(':id') + @Authenticated({ permission: Permission.LIBRARY_UPDATE, admin: true }) + updateLibrary(@Param() { id }: UUIDParamDto, @Body() dto: UpdateLibraryDto): Promise { + return this.service.update(id, dto); + } + @Post(':id/validate') @HttpCode(200) @Authenticated({ admin: true }) diff --git a/server/src/controllers/notification.controller.ts b/server/src/controllers/notification.controller.ts index cc07022a9..2772e93b5 100644 --- a/server/src/controllers/notification.controller.ts +++ b/server/src/controllers/notification.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, HttpCode, Post } from '@nestjs/common'; +import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { AuthDto } from 'src/dtos/auth.dto'; import { SystemConfigSmtpDto } from 'src/dtos/system-config.dto'; @@ -11,7 +11,7 @@ export class NotificationController { constructor(private service: NotificationService) {} @Post('test-email') - @HttpCode(200) + @HttpCode(HttpStatus.OK) @Authenticated({ admin: true }) sendTestEmail(@Auth() auth: AuthDto, @Body() dto: SystemConfigSmtpDto) { return this.service.sendTestEmail(auth.user.id, dto); diff --git a/server/src/controllers/oauth.controller.ts b/server/src/controllers/oauth.controller.ts index 764e67d67..b733dc612 100644 --- a/server/src/controllers/oauth.controller.ts +++ b/server/src/controllers/oauth.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Get, HttpStatus, Post, Redirect, Req, Res } from '@nestjs/common'; +import { Body, Controller, Get, HttpCode, HttpStatus, Post, Redirect, Req, Res } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { Request, Response } from 'express'; import { AuthType } from 'src/constants'; @@ -58,6 +58,7 @@ export class OAuthController { } @Post('unlink') + @HttpCode(HttpStatus.OK) @Authenticated() unlinkOAuthAccount(@Auth() auth: AuthDto): Promise { return this.service.unlink(auth); diff --git a/server/src/controllers/partner.controller.ts b/server/src/controllers/partner.controller.ts index 0662243d6..6830fdd52 100644 --- a/server/src/controllers/partner.controller.ts +++ b/server/src/controllers/partner.controller.ts @@ -1,9 +1,8 @@ import { Body, Controller, Delete, Get, Param, Post, Put, Query } from '@nestjs/common'; -import { ApiQuery, ApiTags } from '@nestjs/swagger'; +import { ApiTags } from '@nestjs/swagger'; import { AuthDto } from 'src/dtos/auth.dto'; import { PartnerResponseDto, PartnerSearchDto, UpdatePartnerDto } from 'src/dtos/partner.dto'; import { Permission } from 'src/enum'; -import { PartnerDirection } from 'src/interfaces/partner.interface'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { PartnerService } from 'src/services/partner.service'; import { UUIDParamDto } from 'src/validation'; @@ -14,9 +13,7 @@ export class PartnerController { constructor(private service: PartnerService) {} @Get() - @ApiQuery({ name: 'direction', type: 'string', enum: PartnerDirection, required: true }) @Authenticated({ permission: Permission.PARTNER_READ }) - // TODO: remove 'direction' and convert to full query dto getPartners(@Auth() auth: AuthDto, @Query() dto: PartnerSearchDto): Promise { return this.service.search(auth, dto); } diff --git a/server/src/controllers/server-info.controller.ts b/server/src/controllers/server-info.controller.ts index 812016f4e..245bbbd34 100644 --- a/server/src/controllers/server-info.controller.ts +++ b/server/src/controllers/server-info.controller.ts @@ -1,5 +1,5 @@ import { Controller, Get } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiExcludeController, ApiTags } from '@nestjs/swagger'; import { EndpointLifecycle } from 'src/decorators'; import { ServerAboutResponseDto, @@ -16,6 +16,7 @@ import { Authenticated } from 'src/middleware/auth.guard'; import { ServerService } from 'src/services/server.service'; import { VersionService } from 'src/services/version.service'; +@ApiExcludeController() @ApiTags('Server Info') @Controller('server-info') export class ServerInfoController { @@ -68,9 +69,9 @@ export class ServerInfoController { return this.service.getConfig(); } - @Authenticated({ admin: true }) - @EndpointLifecycle({ deprecatedAt: 'v1.107.0' }) @Get('statistics') + @EndpointLifecycle({ deprecatedAt: 'v1.107.0' }) + @Authenticated({ admin: true }) getServerStatistics(): Promise { return this.service.getStatistics(); } diff --git a/server/src/controllers/server.controller.ts b/server/src/controllers/server.controller.ts index 0c615223e..75becfe34 100644 --- a/server/src/controllers/server.controller.ts +++ b/server/src/controllers/server.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Delete, Get, Put } from '@nestjs/common'; -import { ApiExcludeEndpoint, ApiNotFoundResponse, ApiTags } from '@nestjs/swagger'; +import { ApiNotFoundResponse, ApiTags } from '@nestjs/swagger'; import { LicenseKeyDto, LicenseResponseDto } from 'src/dtos/license.dto'; import { ServerAboutResponseDto, @@ -26,57 +26,48 @@ export class ServerController { @Get('about') @Authenticated() - @ApiExcludeEndpoint() getAboutInfo(): Promise { return this.service.getAboutInfo(); } @Get('storage') @Authenticated() - @ApiExcludeEndpoint() getStorage(): Promise { return this.service.getStorage(); } @Get('ping') - @ApiExcludeEndpoint() pingServer(): ServerPingResponse { return this.service.ping(); } @Get('version') - @ApiExcludeEndpoint() getServerVersion(): ServerVersionResponseDto { return this.versionService.getVersion(); } @Get('features') - @ApiExcludeEndpoint() getServerFeatures(): Promise { return this.service.getFeatures(); } @Get('theme') - @ApiExcludeEndpoint() getTheme(): Promise { return this.service.getTheme(); } @Get('config') - @ApiExcludeEndpoint() getServerConfig(): Promise { return this.service.getConfig(); } - @Authenticated({ admin: true }) @Get('statistics') - @ApiExcludeEndpoint() + @Authenticated({ admin: true }) getServerStatistics(): Promise { return this.service.getStatistics(); } @Get('media-types') - @ApiExcludeEndpoint() getSupportedMediaTypes(): ServerMediaTypesResponseDto { return this.service.getSupportedMediaTypes(); } diff --git a/server/src/controllers/session.controller.ts b/server/src/controllers/session.controller.ts index a1fb4779a..d526c2e59 100644 --- a/server/src/controllers/session.controller.ts +++ b/server/src/controllers/session.controller.ts @@ -2,6 +2,7 @@ import { Controller, Delete, Get, HttpCode, HttpStatus, Param } from '@nestjs/co import { ApiTags } from '@nestjs/swagger'; import { AuthDto } from 'src/dtos/auth.dto'; import { SessionResponseDto } from 'src/dtos/session.dto'; +import { Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { SessionService } from 'src/services/session.service'; import { UUIDParamDto } from 'src/validation'; @@ -12,21 +13,21 @@ export class SessionController { constructor(private service: SessionService) {} @Get() - @Authenticated() + @Authenticated({ permission: Permission.SESSION_READ }) getSessions(@Auth() auth: AuthDto): Promise { return this.service.getAll(auth); } @Delete() + @Authenticated({ permission: Permission.SESSION_DELETE }) @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() deleteAllSessions(@Auth() auth: AuthDto): Promise { return this.service.deleteAll(auth); } @Delete(':id') + @Authenticated({ permission: Permission.SESSION_DELETE }) @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() deleteSession(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise { return this.service.delete(auth, id); } diff --git a/server/src/controllers/stack.controller.ts b/server/src/controllers/stack.controller.ts index 184fa96b3..188952eba 100644 --- a/server/src/controllers/stack.controller.ts +++ b/server/src/controllers/stack.controller.ts @@ -26,8 +26,8 @@ export class StackController { } @Delete() - @HttpCode(HttpStatus.NO_CONTENT) @Authenticated({ permission: Permission.STACK_DELETE }) + @HttpCode(HttpStatus.NO_CONTENT) deleteStacks(@Auth() auth: AuthDto, @Body() dto: BulkIdsDto): Promise { return this.service.deleteAll(auth, dto); } diff --git a/server/src/controllers/timeline.controller.ts b/server/src/controllers/timeline.controller.ts index 53c62f70e..92de84d34 100644 --- a/server/src/controllers/timeline.controller.ts +++ b/server/src/controllers/timeline.controller.ts @@ -3,6 +3,7 @@ import { ApiTags } from '@nestjs/swagger'; import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { TimeBucketAssetDto, TimeBucketDto, TimeBucketResponseDto } from 'src/dtos/time-bucket.dto'; +import { Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { TimelineService } from 'src/services/timeline.service'; @@ -11,14 +12,14 @@ import { TimelineService } from 'src/services/timeline.service'; export class TimelineController { constructor(private service: TimelineService) {} - @Authenticated({ sharedLink: true }) @Get('buckets') + @Authenticated({ permission: Permission.ASSET_READ, sharedLink: true }) getTimeBuckets(@Auth() auth: AuthDto, @Query() dto: TimeBucketDto): Promise { return this.service.getTimeBuckets(auth, dto); } - @Authenticated({ sharedLink: true }) @Get('bucket') + @Authenticated({ permission: Permission.ASSET_READ, sharedLink: true }) getTimeBucket(@Auth() auth: AuthDto, @Query() dto: TimeBucketAssetDto): Promise { return this.service.getTimeBucket(auth, dto) as Promise; } diff --git a/server/src/controllers/trash.controller.ts b/server/src/controllers/trash.controller.ts index eae49d4ad..20adbb11b 100644 --- a/server/src/controllers/trash.controller.ts +++ b/server/src/controllers/trash.controller.ts @@ -2,6 +2,7 @@ import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { BulkIdsDto } from 'src/dtos/asset-ids.response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; +import { Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { TrashService } from 'src/services/trash.service'; @@ -12,21 +13,21 @@ export class TrashController { @Post('empty') @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() + @Authenticated({ permission: Permission.ASSET_DELETE }) emptyTrash(@Auth() auth: AuthDto): Promise { return this.service.empty(auth); } @Post('restore') @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() + @Authenticated({ permission: Permission.ASSET_DELETE }) restoreTrash(@Auth() auth: AuthDto): Promise { return this.service.restore(auth); } @Post('restore/assets') @HttpCode(HttpStatus.NO_CONTENT) - @Authenticated() + @Authenticated({ permission: Permission.ASSET_DELETE }) restoreAssets(@Auth() auth: AuthDto, @Body() dto: BulkIdsDto): Promise { return this.service.restoreAssets(auth, dto); } diff --git a/server/src/enum.ts b/server/src/enum.ts index 64cb1f118..25ccbf961 100644 --- a/server/src/enum.ts +++ b/server/src/enum.ts @@ -54,7 +54,6 @@ export enum Permission { ASSET_READ = 'asset.read', ASSET_UPDATE = 'asset.update', ASSET_DELETE = 'asset.delete', - ASSET_RESTORE = 'asset.restore', ASSET_SHARE = 'asset.share', ASSET_VIEW = 'asset.view', ASSET_DOWNLOAD = 'asset.download', @@ -107,6 +106,10 @@ export enum Permission { PERSON_MERGE = 'person.merge', PERSON_REASSIGN = 'person.reassign', + SESSION_READ = 'session.read', + SESSION_UPDATE = 'session.update', + SESSION_DELETE = 'session.delete', + SHARED_LINK_CREATE = 'sharedLink.create', SHARED_LINK_READ = 'sharedLink.read', SHARED_LINK_UPDATE = 'sharedLink.update', diff --git a/server/src/services/trash.service.ts b/server/src/services/trash.service.ts index f64aef051..8376ba922 100644 --- a/server/src/services/trash.service.ts +++ b/server/src/services/trash.service.ts @@ -20,7 +20,7 @@ export class TrashService { async restoreAssets(auth: AuthDto, dto: BulkIdsDto): Promise { const { ids } = dto; - await requireAccess(this.access, { auth, permission: Permission.ASSET_RESTORE, ids }); + await requireAccess(this.access, { auth, permission: Permission.ASSET_DELETE, ids }); await this.restoreAndSend(auth, ids); } diff --git a/server/src/utils/access.ts b/server/src/utils/access.ts index 9367b0987..45badeec7 100644 --- a/server/src/utils/access.ts +++ b/server/src/utils/access.ts @@ -147,10 +147,6 @@ const checkOtherAccess = async (access: IAccessRepository, request: OtherAccessR return await access.asset.checkOwnerAccess(auth.user.id, ids); } - case Permission.ASSET_RESTORE: { - return await access.asset.checkOwnerAccess(auth.user.id, ids); - } - case Permission.ALBUM_READ: { const isOwner = await access.album.checkOwnerAccess(auth.user.id, ids); const isShared = await access.album.checkSharedAlbumAccess(