diff --git a/cli/src/api/open-api/api.ts b/cli/src/api/open-api/api.ts index e79388602..9f4d765f2 100644 --- a/cli/src/api/open-api/api.ts +++ b/cli/src/api/open-api/api.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.83.0 + * The version of the OpenAPI document: 1.84.0 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -99,6 +99,103 @@ export interface APIKeyUpdateDto { */ 'name': string; } +/** + * + * @export + * @interface ActivityCreateDto + */ +export interface ActivityCreateDto { + /** + * + * @type {string} + * @memberof ActivityCreateDto + */ + 'albumId': string; + /** + * + * @type {string} + * @memberof ActivityCreateDto + */ + 'assetId'?: string; + /** + * + * @type {string} + * @memberof ActivityCreateDto + */ + 'comment'?: string; + /** + * + * @type {ReactionType} + * @memberof ActivityCreateDto + */ + 'type': ReactionType; +} + + +/** + * + * @export + * @interface ActivityResponseDto + */ +export interface ActivityResponseDto { + /** + * + * @type {string} + * @memberof ActivityResponseDto + */ + 'assetId': string | null; + /** + * + * @type {string} + * @memberof ActivityResponseDto + */ + 'comment'?: string | null; + /** + * + * @type {string} + * @memberof ActivityResponseDto + */ + 'createdAt': string; + /** + * + * @type {string} + * @memberof ActivityResponseDto + */ + 'id': string; + /** + * + * @type {string} + * @memberof ActivityResponseDto + */ + 'type': ActivityResponseDtoTypeEnum; + /** + * + * @type {UserDto} + * @memberof ActivityResponseDto + */ + 'user': UserDto; +} + +export const ActivityResponseDtoTypeEnum = { + Comment: 'comment', + Like: 'like' +} as const; + +export type ActivityResponseDtoTypeEnum = typeof ActivityResponseDtoTypeEnum[keyof typeof ActivityResponseDtoTypeEnum]; + +/** + * + * @export + * @interface ActivityStatisticsResponseDto + */ +export interface ActivityStatisticsResponseDto { + /** + * + * @type {number} + * @memberof ActivityStatisticsResponseDto + */ + 'comments': number; +} /** * * @export @@ -2490,6 +2587,20 @@ export interface QueueStatusDto { */ 'isPaused': boolean; } +/** + * + * @export + * @enum {string} + */ + +export const ReactionType = { + Comment: 'comment', + Like: 'like' +} as const; + +export type ReactionType = typeof ReactionType[keyof typeof ReactionType]; + + /** * * @export @@ -3283,6 +3394,12 @@ export interface SystemConfigDto { * @memberof SystemConfigDto */ 'job': SystemConfigJobDto; + /** + * + * @type {SystemConfigLibraryDto} + * @memberof SystemConfigDto + */ + 'library': SystemConfigLibraryDto; /** * * @type {SystemConfigMachineLearningDto} @@ -3534,6 +3651,38 @@ export interface SystemConfigJobDto { */ 'videoConversion': JobSettingsDto; } +/** + * + * @export + * @interface SystemConfigLibraryDto + */ +export interface SystemConfigLibraryDto { + /** + * + * @type {SystemConfigLibraryScanDto} + * @memberof SystemConfigLibraryDto + */ + 'scan': SystemConfigLibraryScanDto; +} +/** + * + * @export + * @interface SystemConfigLibraryScanDto + */ +export interface SystemConfigLibraryScanDto { + /** + * + * @type {string} + * @memberof SystemConfigLibraryScanDto + */ + 'cronExpression': string; + /** + * + * @type {boolean} + * @memberof SystemConfigLibraryScanDto + */ + 'enabled': boolean; +} /** * * @export @@ -4210,6 +4359,43 @@ export interface UsageByUserDto { */ 'videos': number; } +/** + * + * @export + * @interface UserDto + */ +export interface UserDto { + /** + * + * @type {string} + * @memberof UserDto + */ + 'email': string; + /** + * + * @type {string} + * @memberof UserDto + */ + 'firstName': string; + /** + * + * @type {string} + * @memberof UserDto + */ + 'id': string; + /** + * + * @type {string} + * @memberof UserDto + */ + 'lastName': string; + /** + * + * @type {string} + * @memberof UserDto + */ + 'profileImagePath': string; +} /** * * @export @@ -4342,9 +4528,9 @@ export const APIKeyApiAxiosParamCreator = function (configuration?: Configuratio * @param {*} [options] Override http request option. * @throws {RequiredError} */ - createKey: async (aPIKeyCreateDto: APIKeyCreateDto, options: AxiosRequestConfig = {}): Promise => { + createApiKey: async (aPIKeyCreateDto: APIKeyCreateDto, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'aPIKeyCreateDto' is not null or undefined - assertParamExists('createKey', 'aPIKeyCreateDto', aPIKeyCreateDto) + assertParamExists('createApiKey', 'aPIKeyCreateDto', aPIKeyCreateDto) const localVarPath = `/api-key`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -4386,9 +4572,9 @@ export const APIKeyApiAxiosParamCreator = function (configuration?: Configuratio * @param {*} [options] Override http request option. * @throws {RequiredError} */ - deleteKey: async (id: string, options: AxiosRequestConfig = {}): Promise => { + deleteApiKey: async (id: string, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'id' is not null or undefined - assertParamExists('deleteKey', 'id', id) + assertParamExists('deleteApiKey', 'id', id) const localVarPath = `/api-key/{id}` .replace(`{${"id"}}`, encodeURIComponent(String(id))); // use dummy base URL string because the URL constructor only accepts absolute URLs. @@ -4428,9 +4614,9 @@ export const APIKeyApiAxiosParamCreator = function (configuration?: Configuratio * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getKey: async (id: string, options: AxiosRequestConfig = {}): Promise => { + getApiKey: async (id: string, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'id' is not null or undefined - assertParamExists('getKey', 'id', id) + assertParamExists('getApiKey', 'id', id) const localVarPath = `/api-key/{id}` .replace(`{${"id"}}`, encodeURIComponent(String(id))); // use dummy base URL string because the URL constructor only accepts absolute URLs. @@ -4469,7 +4655,7 @@ export const APIKeyApiAxiosParamCreator = function (configuration?: Configuratio * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getKeys: async (options: AxiosRequestConfig = {}): Promise => { + getApiKeys: async (options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/api-key`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -4509,11 +4695,11 @@ export const APIKeyApiAxiosParamCreator = function (configuration?: Configuratio * @param {*} [options] Override http request option. * @throws {RequiredError} */ - updateKey: async (id: string, aPIKeyUpdateDto: APIKeyUpdateDto, options: AxiosRequestConfig = {}): Promise => { + updateApiKey: async (id: string, aPIKeyUpdateDto: APIKeyUpdateDto, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'id' is not null or undefined - assertParamExists('updateKey', 'id', id) + assertParamExists('updateApiKey', 'id', id) // verify required parameter 'aPIKeyUpdateDto' is not null or undefined - assertParamExists('updateKey', 'aPIKeyUpdateDto', aPIKeyUpdateDto) + assertParamExists('updateApiKey', 'aPIKeyUpdateDto', aPIKeyUpdateDto) const localVarPath = `/api-key/{id}` .replace(`{${"id"}}`, encodeURIComponent(String(id))); // use dummy base URL string because the URL constructor only accepts absolute URLs. @@ -4566,8 +4752,8 @@ export const APIKeyApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async createKey(aPIKeyCreateDto: APIKeyCreateDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.createKey(aPIKeyCreateDto, options); + async createApiKey(aPIKeyCreateDto: APIKeyCreateDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.createApiKey(aPIKeyCreateDto, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -4576,8 +4762,8 @@ export const APIKeyApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async deleteKey(id: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.deleteKey(id, options); + async deleteApiKey(id: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.deleteApiKey(id, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -4586,8 +4772,8 @@ export const APIKeyApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getKey(id: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getKey(id, options); + async getApiKey(id: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getApiKey(id, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -4595,8 +4781,8 @@ export const APIKeyApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getKeys(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getKeys(options); + async getApiKeys(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getApiKeys(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -4606,8 +4792,8 @@ export const APIKeyApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async updateKey(id: string, aPIKeyUpdateDto: APIKeyUpdateDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.updateKey(id, aPIKeyUpdateDto, options); + async updateApiKey(id: string, aPIKeyUpdateDto: APIKeyUpdateDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.updateApiKey(id, aPIKeyUpdateDto, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, } @@ -4622,110 +4808,110 @@ export const APIKeyApiFactory = function (configuration?: Configuration, basePat return { /** * - * @param {APIKeyApiCreateKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiCreateApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - createKey(requestParameters: APIKeyApiCreateKeyRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.createKey(requestParameters.aPIKeyCreateDto, options).then((request) => request(axios, basePath)); + createApiKey(requestParameters: APIKeyApiCreateApiKeyRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.createApiKey(requestParameters.aPIKeyCreateDto, options).then((request) => request(axios, basePath)); }, /** * - * @param {APIKeyApiDeleteKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiDeleteApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - deleteKey(requestParameters: APIKeyApiDeleteKeyRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.deleteKey(requestParameters.id, options).then((request) => request(axios, basePath)); + deleteApiKey(requestParameters: APIKeyApiDeleteApiKeyRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.deleteApiKey(requestParameters.id, options).then((request) => request(axios, basePath)); }, /** * - * @param {APIKeyApiGetKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiGetApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getKey(requestParameters: APIKeyApiGetKeyRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.getKey(requestParameters.id, options).then((request) => request(axios, basePath)); + getApiKey(requestParameters: APIKeyApiGetApiKeyRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.getApiKey(requestParameters.id, options).then((request) => request(axios, basePath)); }, /** * * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getKeys(options?: AxiosRequestConfig): AxiosPromise> { - return localVarFp.getKeys(options).then((request) => request(axios, basePath)); + getApiKeys(options?: AxiosRequestConfig): AxiosPromise> { + return localVarFp.getApiKeys(options).then((request) => request(axios, basePath)); }, /** * - * @param {APIKeyApiUpdateKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiUpdateApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - updateKey(requestParameters: APIKeyApiUpdateKeyRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.updateKey(requestParameters.id, requestParameters.aPIKeyUpdateDto, options).then((request) => request(axios, basePath)); + updateApiKey(requestParameters: APIKeyApiUpdateApiKeyRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.updateApiKey(requestParameters.id, requestParameters.aPIKeyUpdateDto, options).then((request) => request(axios, basePath)); }, }; }; /** - * Request parameters for createKey operation in APIKeyApi. + * Request parameters for createApiKey operation in APIKeyApi. * @export - * @interface APIKeyApiCreateKeyRequest + * @interface APIKeyApiCreateApiKeyRequest */ -export interface APIKeyApiCreateKeyRequest { +export interface APIKeyApiCreateApiKeyRequest { /** * * @type {APIKeyCreateDto} - * @memberof APIKeyApiCreateKey + * @memberof APIKeyApiCreateApiKey */ readonly aPIKeyCreateDto: APIKeyCreateDto } /** - * Request parameters for deleteKey operation in APIKeyApi. + * Request parameters for deleteApiKey operation in APIKeyApi. * @export - * @interface APIKeyApiDeleteKeyRequest + * @interface APIKeyApiDeleteApiKeyRequest */ -export interface APIKeyApiDeleteKeyRequest { +export interface APIKeyApiDeleteApiKeyRequest { /** * * @type {string} - * @memberof APIKeyApiDeleteKey + * @memberof APIKeyApiDeleteApiKey */ readonly id: string } /** - * Request parameters for getKey operation in APIKeyApi. + * Request parameters for getApiKey operation in APIKeyApi. * @export - * @interface APIKeyApiGetKeyRequest + * @interface APIKeyApiGetApiKeyRequest */ -export interface APIKeyApiGetKeyRequest { +export interface APIKeyApiGetApiKeyRequest { /** * * @type {string} - * @memberof APIKeyApiGetKey + * @memberof APIKeyApiGetApiKey */ readonly id: string } /** - * Request parameters for updateKey operation in APIKeyApi. + * Request parameters for updateApiKey operation in APIKeyApi. * @export - * @interface APIKeyApiUpdateKeyRequest + * @interface APIKeyApiUpdateApiKeyRequest */ -export interface APIKeyApiUpdateKeyRequest { +export interface APIKeyApiUpdateApiKeyRequest { /** * * @type {string} - * @memberof APIKeyApiUpdateKey + * @memberof APIKeyApiUpdateApiKey */ readonly id: string /** * * @type {APIKeyUpdateDto} - * @memberof APIKeyApiUpdateKey + * @memberof APIKeyApiUpdateApiKey */ readonly aPIKeyUpdateDto: APIKeyUpdateDto } @@ -4739,35 +4925,35 @@ export interface APIKeyApiUpdateKeyRequest { export class APIKeyApi extends BaseAPI { /** * - * @param {APIKeyApiCreateKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiCreateApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof APIKeyApi */ - public createKey(requestParameters: APIKeyApiCreateKeyRequest, options?: AxiosRequestConfig) { - return APIKeyApiFp(this.configuration).createKey(requestParameters.aPIKeyCreateDto, options).then((request) => request(this.axios, this.basePath)); + public createApiKey(requestParameters: APIKeyApiCreateApiKeyRequest, options?: AxiosRequestConfig) { + return APIKeyApiFp(this.configuration).createApiKey(requestParameters.aPIKeyCreateDto, options).then((request) => request(this.axios, this.basePath)); } /** * - * @param {APIKeyApiDeleteKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiDeleteApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof APIKeyApi */ - public deleteKey(requestParameters: APIKeyApiDeleteKeyRequest, options?: AxiosRequestConfig) { - return APIKeyApiFp(this.configuration).deleteKey(requestParameters.id, options).then((request) => request(this.axios, this.basePath)); + public deleteApiKey(requestParameters: APIKeyApiDeleteApiKeyRequest, options?: AxiosRequestConfig) { + return APIKeyApiFp(this.configuration).deleteApiKey(requestParameters.id, options).then((request) => request(this.axios, this.basePath)); } /** * - * @param {APIKeyApiGetKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiGetApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof APIKeyApi */ - public getKey(requestParameters: APIKeyApiGetKeyRequest, options?: AxiosRequestConfig) { - return APIKeyApiFp(this.configuration).getKey(requestParameters.id, options).then((request) => request(this.axios, this.basePath)); + public getApiKey(requestParameters: APIKeyApiGetApiKeyRequest, options?: AxiosRequestConfig) { + return APIKeyApiFp(this.configuration).getApiKey(requestParameters.id, options).then((request) => request(this.axios, this.basePath)); } /** @@ -4776,19 +4962,461 @@ export class APIKeyApi extends BaseAPI { * @throws {RequiredError} * @memberof APIKeyApi */ - public getKeys(options?: AxiosRequestConfig) { - return APIKeyApiFp(this.configuration).getKeys(options).then((request) => request(this.axios, this.basePath)); + public getApiKeys(options?: AxiosRequestConfig) { + return APIKeyApiFp(this.configuration).getApiKeys(options).then((request) => request(this.axios, this.basePath)); } /** * - * @param {APIKeyApiUpdateKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiUpdateApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof APIKeyApi */ - public updateKey(requestParameters: APIKeyApiUpdateKeyRequest, options?: AxiosRequestConfig) { - return APIKeyApiFp(this.configuration).updateKey(requestParameters.id, requestParameters.aPIKeyUpdateDto, options).then((request) => request(this.axios, this.basePath)); + public updateApiKey(requestParameters: APIKeyApiUpdateApiKeyRequest, options?: AxiosRequestConfig) { + return APIKeyApiFp(this.configuration).updateApiKey(requestParameters.id, requestParameters.aPIKeyUpdateDto, options).then((request) => request(this.axios, this.basePath)); + } +} + + +/** + * ActivityApi - axios parameter creator + * @export + */ +export const ActivityApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * + * @param {ActivityCreateDto} activityCreateDto + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createActivity: async (activityCreateDto: ActivityCreateDto, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'activityCreateDto' is not null or undefined + assertParamExists('createActivity', 'activityCreateDto', activityCreateDto) + const localVarPath = `/activity`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication cookie required + + // authentication api_key required + await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration) + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(activityCreateDto, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + deleteActivity: async (id: string, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'id' is not null or undefined + assertParamExists('deleteActivity', 'id', id) + const localVarPath = `/activity/{id}` + .replace(`{${"id"}}`, encodeURIComponent(String(id))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication cookie required + + // authentication api_key required + await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration) + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @param {string} albumId + * @param {string} [assetId] + * @param {ReactionType} [type] + * @param {string} [userId] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getActivities: async (albumId: string, assetId?: string, type?: ReactionType, userId?: string, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'albumId' is not null or undefined + assertParamExists('getActivities', 'albumId', albumId) + const localVarPath = `/activity`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication cookie required + + // authentication api_key required + await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration) + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + if (albumId !== undefined) { + localVarQueryParameter['albumId'] = albumId; + } + + if (assetId !== undefined) { + localVarQueryParameter['assetId'] = assetId; + } + + if (type !== undefined) { + localVarQueryParameter['type'] = type; + } + + if (userId !== undefined) { + localVarQueryParameter['userId'] = userId; + } + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @param {string} albumId + * @param {string} [assetId] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getActivityStatistics: async (albumId: string, assetId?: string, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'albumId' is not null or undefined + assertParamExists('getActivityStatistics', 'albumId', albumId) + const localVarPath = `/activity/statistics`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication cookie required + + // authentication api_key required + await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration) + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + if (albumId !== undefined) { + localVarQueryParameter['albumId'] = albumId; + } + + if (assetId !== undefined) { + localVarQueryParameter['assetId'] = assetId; + } + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * ActivityApi - functional programming interface + * @export + */ +export const ActivityApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = ActivityApiAxiosParamCreator(configuration) + return { + /** + * + * @param {ActivityCreateDto} activityCreateDto + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async createActivity(activityCreateDto: ActivityCreateDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.createActivity(activityCreateDto, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + /** + * + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async deleteActivity(id: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.deleteActivity(id, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + /** + * + * @param {string} albumId + * @param {string} [assetId] + * @param {ReactionType} [type] + * @param {string} [userId] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getActivities(albumId: string, assetId?: string, type?: ReactionType, userId?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getActivities(albumId, assetId, type, userId, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + /** + * + * @param {string} albumId + * @param {string} [assetId] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getActivityStatistics(albumId: string, assetId?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getActivityStatistics(albumId, assetId, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + } +}; + +/** + * ActivityApi - factory interface + * @export + */ +export const ActivityApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + const localVarFp = ActivityApiFp(configuration) + return { + /** + * + * @param {ActivityApiCreateActivityRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createActivity(requestParameters: ActivityApiCreateActivityRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.createActivity(requestParameters.activityCreateDto, options).then((request) => request(axios, basePath)); + }, + /** + * + * @param {ActivityApiDeleteActivityRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + deleteActivity(requestParameters: ActivityApiDeleteActivityRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.deleteActivity(requestParameters.id, options).then((request) => request(axios, basePath)); + }, + /** + * + * @param {ActivityApiGetActivitiesRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getActivities(requestParameters: ActivityApiGetActivitiesRequest, options?: AxiosRequestConfig): AxiosPromise> { + return localVarFp.getActivities(requestParameters.albumId, requestParameters.assetId, requestParameters.type, requestParameters.userId, options).then((request) => request(axios, basePath)); + }, + /** + * + * @param {ActivityApiGetActivityStatisticsRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getActivityStatistics(requestParameters: ActivityApiGetActivityStatisticsRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.getActivityStatistics(requestParameters.albumId, requestParameters.assetId, options).then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * Request parameters for createActivity operation in ActivityApi. + * @export + * @interface ActivityApiCreateActivityRequest + */ +export interface ActivityApiCreateActivityRequest { + /** + * + * @type {ActivityCreateDto} + * @memberof ActivityApiCreateActivity + */ + readonly activityCreateDto: ActivityCreateDto +} + +/** + * Request parameters for deleteActivity operation in ActivityApi. + * @export + * @interface ActivityApiDeleteActivityRequest + */ +export interface ActivityApiDeleteActivityRequest { + /** + * + * @type {string} + * @memberof ActivityApiDeleteActivity + */ + readonly id: string +} + +/** + * Request parameters for getActivities operation in ActivityApi. + * @export + * @interface ActivityApiGetActivitiesRequest + */ +export interface ActivityApiGetActivitiesRequest { + /** + * + * @type {string} + * @memberof ActivityApiGetActivities + */ + readonly albumId: string + + /** + * + * @type {string} + * @memberof ActivityApiGetActivities + */ + readonly assetId?: string + + /** + * + * @type {ReactionType} + * @memberof ActivityApiGetActivities + */ + readonly type?: ReactionType + + /** + * + * @type {string} + * @memberof ActivityApiGetActivities + */ + readonly userId?: string +} + +/** + * Request parameters for getActivityStatistics operation in ActivityApi. + * @export + * @interface ActivityApiGetActivityStatisticsRequest + */ +export interface ActivityApiGetActivityStatisticsRequest { + /** + * + * @type {string} + * @memberof ActivityApiGetActivityStatistics + */ + readonly albumId: string + + /** + * + * @type {string} + * @memberof ActivityApiGetActivityStatistics + */ + readonly assetId?: string +} + +/** + * ActivityApi - object-oriented interface + * @export + * @class ActivityApi + * @extends {BaseAPI} + */ +export class ActivityApi extends BaseAPI { + /** + * + * @param {ActivityApiCreateActivityRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ActivityApi + */ + public createActivity(requestParameters: ActivityApiCreateActivityRequest, options?: AxiosRequestConfig) { + return ActivityApiFp(this.configuration).createActivity(requestParameters.activityCreateDto, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @param {ActivityApiDeleteActivityRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ActivityApi + */ + public deleteActivity(requestParameters: ActivityApiDeleteActivityRequest, options?: AxiosRequestConfig) { + return ActivityApiFp(this.configuration).deleteActivity(requestParameters.id, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @param {ActivityApiGetActivitiesRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ActivityApi + */ + public getActivities(requestParameters: ActivityApiGetActivitiesRequest, options?: AxiosRequestConfig) { + return ActivityApiFp(this.configuration).getActivities(requestParameters.albumId, requestParameters.assetId, requestParameters.type, requestParameters.userId, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @param {ActivityApiGetActivityStatisticsRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ActivityApi + */ + public getActivityStatistics(requestParameters: ActivityApiGetActivityStatisticsRequest, options?: AxiosRequestConfig) { + return ActivityApiFp(this.configuration).getActivityStatistics(requestParameters.albumId, requestParameters.assetId, options).then((request) => request(this.axios, this.basePath)); } } @@ -5805,9 +6433,9 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration * @param {*} [options] Override http request option. * @throws {RequiredError} */ - bulkUploadCheck: async (assetBulkUploadCheckDto: AssetBulkUploadCheckDto, options: AxiosRequestConfig = {}): Promise => { + checkBulkUpload: async (assetBulkUploadCheckDto: AssetBulkUploadCheckDto, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'assetBulkUploadCheckDto' is not null or undefined - assertParamExists('bulkUploadCheck', 'assetBulkUploadCheckDto', assetBulkUploadCheckDto) + assertParamExists('checkBulkUpload', 'assetBulkUploadCheckDto', assetBulkUploadCheckDto) const localVarPath = `/asset/bulk-upload-check`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -6228,7 +6856,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getAssetStats: async (isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, options: AxiosRequestConfig = {}): Promise => { + getAssetStatistics: async (isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/asset/statistics`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -6316,98 +6944,6 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - /** - * - * @param {TimeBucketSize} size - * @param {string} timeBucket - * @param {string} [userId] - * @param {string} [albumId] - * @param {string} [personId] - * @param {boolean} [isArchived] - * @param {boolean} [isFavorite] - * @param {boolean} [isTrashed] - * @param {boolean} [withStacked] - * @param {string} [key] - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - getByTimeBucket: async (size: TimeBucketSize, timeBucket: string, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, key?: string, options: AxiosRequestConfig = {}): Promise => { - // verify required parameter 'size' is not null or undefined - assertParamExists('getByTimeBucket', 'size', size) - // verify required parameter 'timeBucket' is not null or undefined - assertParamExists('getByTimeBucket', 'timeBucket', timeBucket) - const localVarPath = `/asset/time-bucket`; - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - // authentication cookie required - - // authentication api_key required - await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration) - - // authentication bearer required - // http bearer authentication required - await setBearerAuthToObject(localVarHeaderParameter, configuration) - - if (size !== undefined) { - localVarQueryParameter['size'] = size; - } - - if (userId !== undefined) { - localVarQueryParameter['userId'] = userId; - } - - if (albumId !== undefined) { - localVarQueryParameter['albumId'] = albumId; - } - - if (personId !== undefined) { - localVarQueryParameter['personId'] = personId; - } - - if (isArchived !== undefined) { - localVarQueryParameter['isArchived'] = isArchived; - } - - if (isFavorite !== undefined) { - localVarQueryParameter['isFavorite'] = isFavorite; - } - - if (isTrashed !== undefined) { - localVarQueryParameter['isTrashed'] = isTrashed; - } - - if (withStacked !== undefined) { - localVarQueryParameter['withStacked'] = withStacked; - } - - if (timeBucket !== undefined) { - localVarQueryParameter['timeBucket'] = timeBucket; - } - - if (key !== undefined) { - localVarQueryParameter['key'] = key; - } - - - setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -6690,6 +7226,98 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @param {TimeBucketSize} size + * @param {string} timeBucket + * @param {string} [userId] + * @param {string} [albumId] + * @param {string} [personId] + * @param {boolean} [isArchived] + * @param {boolean} [isFavorite] + * @param {boolean} [isTrashed] + * @param {boolean} [withStacked] + * @param {string} [key] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getTimeBucket: async (size: TimeBucketSize, timeBucket: string, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, key?: string, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'size' is not null or undefined + assertParamExists('getTimeBucket', 'size', size) + // verify required parameter 'timeBucket' is not null or undefined + assertParamExists('getTimeBucket', 'timeBucket', timeBucket) + const localVarPath = `/asset/time-bucket`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication cookie required + + // authentication api_key required + await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration) + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + if (size !== undefined) { + localVarQueryParameter['size'] = size; + } + + if (userId !== undefined) { + localVarQueryParameter['userId'] = userId; + } + + if (albumId !== undefined) { + localVarQueryParameter['albumId'] = albumId; + } + + if (personId !== undefined) { + localVarQueryParameter['personId'] = personId; + } + + if (isArchived !== undefined) { + localVarQueryParameter['isArchived'] = isArchived; + } + + if (isFavorite !== undefined) { + localVarQueryParameter['isFavorite'] = isFavorite; + } + + if (isTrashed !== undefined) { + localVarQueryParameter['isTrashed'] = isTrashed; + } + + if (withStacked !== undefined) { + localVarQueryParameter['withStacked'] = withStacked; + } + + if (timeBucket !== undefined) { + localVarQueryParameter['timeBucket'] = timeBucket; + } + + if (key !== undefined) { + localVarQueryParameter['key'] = key; + } + + + setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -7383,8 +8011,8 @@ export const AssetApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async bulkUploadCheck(assetBulkUploadCheckDto: AssetBulkUploadCheckDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.bulkUploadCheck(assetBulkUploadCheckDto, options); + async checkBulkUpload(assetBulkUploadCheckDto: AssetBulkUploadCheckDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.checkBulkUpload(assetBulkUploadCheckDto, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -7481,8 +8109,8 @@ export const AssetApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getAssetStats(isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetStats(isArchived, isFavorite, isTrashed, options); + async getAssetStatistics(isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetStatistics(isArchived, isFavorite, isTrashed, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -7497,25 +8125,6 @@ export const AssetApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetThumbnail(id, format, key, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, - /** - * - * @param {TimeBucketSize} size - * @param {string} timeBucket - * @param {string} [userId] - * @param {string} [albumId] - * @param {string} [personId] - * @param {boolean} [isArchived] - * @param {boolean} [isFavorite] - * @param {boolean} [isTrashed] - * @param {boolean} [withStacked] - * @param {string} [key] - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async getByTimeBucket(size: TimeBucketSize, timeBucket: string, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getByTimeBucket(size, timeBucket, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); - }, /** * * @param {*} [options] Override http request option. @@ -7579,6 +8188,25 @@ export const AssetApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.getRandom(count, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * + * @param {TimeBucketSize} size + * @param {string} timeBucket + * @param {string} [userId] + * @param {string} [albumId] + * @param {string} [personId] + * @param {boolean} [isArchived] + * @param {boolean} [isFavorite] + * @param {boolean} [isTrashed] + * @param {boolean} [withStacked] + * @param {string} [key] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getTimeBucket(size: TimeBucketSize, timeBucket: string, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getTimeBucket(size, timeBucket, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @param {TimeBucketSize} size @@ -7737,12 +8365,12 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath return { /** * Checks if assets exist by checksums - * @param {AssetApiBulkUploadCheckRequest} requestParameters Request parameters. + * @param {AssetApiCheckBulkUploadRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - bulkUploadCheck(requestParameters: AssetApiBulkUploadCheckRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.bulkUploadCheck(requestParameters.assetBulkUploadCheckDto, options).then((request) => request(axios, basePath)); + checkBulkUpload(requestParameters: AssetApiCheckBulkUploadRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.checkBulkUpload(requestParameters.assetBulkUploadCheckDto, options).then((request) => request(axios, basePath)); }, /** * Checks if multiple assets exist on the server and returns all existing - used by background backup @@ -7816,12 +8444,12 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath }, /** * - * @param {AssetApiGetAssetStatsRequest} requestParameters Request parameters. + * @param {AssetApiGetAssetStatisticsRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getAssetStats(requestParameters: AssetApiGetAssetStatsRequest = {}, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.getAssetStats(requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, options).then((request) => request(axios, basePath)); + getAssetStatistics(requestParameters: AssetApiGetAssetStatisticsRequest = {}, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.getAssetStatistics(requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, options).then((request) => request(axios, basePath)); }, /** * @@ -7832,15 +8460,6 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath getAssetThumbnail(requestParameters: AssetApiGetAssetThumbnailRequest, options?: AxiosRequestConfig): AxiosPromise { return localVarFp.getAssetThumbnail(requestParameters.id, requestParameters.format, requestParameters.key, options).then((request) => request(axios, basePath)); }, - /** - * - * @param {AssetApiGetByTimeBucketRequest} requestParameters Request parameters. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - getByTimeBucket(requestParameters: AssetApiGetByTimeBucketRequest, options?: AxiosRequestConfig): AxiosPromise> { - return localVarFp.getByTimeBucket(requestParameters.size, requestParameters.timeBucket, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.key, options).then((request) => request(axios, basePath)); - }, /** * * @param {*} [options] Override http request option. @@ -7893,6 +8512,15 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath getRandom(requestParameters: AssetApiGetRandomRequest = {}, options?: AxiosRequestConfig): AxiosPromise> { return localVarFp.getRandom(requestParameters.count, options).then((request) => request(axios, basePath)); }, + /** + * + * @param {AssetApiGetTimeBucketRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getTimeBucket(requestParameters: AssetApiGetTimeBucketRequest, options?: AxiosRequestConfig): AxiosPromise> { + return localVarFp.getTimeBucket(requestParameters.size, requestParameters.timeBucket, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.key, options).then((request) => request(axios, basePath)); + }, /** * * @param {AssetApiGetTimeBucketsRequest} requestParameters Request parameters. @@ -8004,15 +8632,15 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath }; /** - * Request parameters for bulkUploadCheck operation in AssetApi. + * Request parameters for checkBulkUpload operation in AssetApi. * @export - * @interface AssetApiBulkUploadCheckRequest + * @interface AssetApiCheckBulkUploadRequest */ -export interface AssetApiBulkUploadCheckRequest { +export interface AssetApiCheckBulkUploadRequest { /** * * @type {AssetBulkUploadCheckDto} - * @memberof AssetApiBulkUploadCheck + * @memberof AssetApiCheckBulkUpload */ readonly assetBulkUploadCheckDto: AssetBulkUploadCheckDto } @@ -8158,29 +8786,29 @@ export interface AssetApiGetAssetByIdRequest { } /** - * Request parameters for getAssetStats operation in AssetApi. + * Request parameters for getAssetStatistics operation in AssetApi. * @export - * @interface AssetApiGetAssetStatsRequest + * @interface AssetApiGetAssetStatisticsRequest */ -export interface AssetApiGetAssetStatsRequest { +export interface AssetApiGetAssetStatisticsRequest { /** * * @type {boolean} - * @memberof AssetApiGetAssetStats + * @memberof AssetApiGetAssetStatistics */ readonly isArchived?: boolean /** * * @type {boolean} - * @memberof AssetApiGetAssetStats + * @memberof AssetApiGetAssetStatistics */ readonly isFavorite?: boolean /** * * @type {boolean} - * @memberof AssetApiGetAssetStats + * @memberof AssetApiGetAssetStatistics */ readonly isTrashed?: boolean } @@ -8213,83 +8841,6 @@ export interface AssetApiGetAssetThumbnailRequest { readonly key?: string } -/** - * Request parameters for getByTimeBucket operation in AssetApi. - * @export - * @interface AssetApiGetByTimeBucketRequest - */ -export interface AssetApiGetByTimeBucketRequest { - /** - * - * @type {TimeBucketSize} - * @memberof AssetApiGetByTimeBucket - */ - readonly size: TimeBucketSize - - /** - * - * @type {string} - * @memberof AssetApiGetByTimeBucket - */ - readonly timeBucket: string - - /** - * - * @type {string} - * @memberof AssetApiGetByTimeBucket - */ - readonly userId?: string - - /** - * - * @type {string} - * @memberof AssetApiGetByTimeBucket - */ - readonly albumId?: string - - /** - * - * @type {string} - * @memberof AssetApiGetByTimeBucket - */ - readonly personId?: string - - /** - * - * @type {boolean} - * @memberof AssetApiGetByTimeBucket - */ - readonly isArchived?: boolean - - /** - * - * @type {boolean} - * @memberof AssetApiGetByTimeBucket - */ - readonly isFavorite?: boolean - - /** - * - * @type {boolean} - * @memberof AssetApiGetByTimeBucket - */ - readonly isTrashed?: boolean - - /** - * - * @type {boolean} - * @memberof AssetApiGetByTimeBucket - */ - readonly withStacked?: boolean - - /** - * - * @type {string} - * @memberof AssetApiGetByTimeBucket - */ - readonly key?: string -} - /** * Request parameters for getDownloadInfo operation in AssetApi. * @export @@ -8381,6 +8932,83 @@ export interface AssetApiGetRandomRequest { readonly count?: number } +/** + * Request parameters for getTimeBucket operation in AssetApi. + * @export + * @interface AssetApiGetTimeBucketRequest + */ +export interface AssetApiGetTimeBucketRequest { + /** + * + * @type {TimeBucketSize} + * @memberof AssetApiGetTimeBucket + */ + readonly size: TimeBucketSize + + /** + * + * @type {string} + * @memberof AssetApiGetTimeBucket + */ + readonly timeBucket: string + + /** + * + * @type {string} + * @memberof AssetApiGetTimeBucket + */ + readonly userId?: string + + /** + * + * @type {string} + * @memberof AssetApiGetTimeBucket + */ + readonly albumId?: string + + /** + * + * @type {string} + * @memberof AssetApiGetTimeBucket + */ + readonly personId?: string + + /** + * + * @type {boolean} + * @memberof AssetApiGetTimeBucket + */ + readonly isArchived?: boolean + + /** + * + * @type {boolean} + * @memberof AssetApiGetTimeBucket + */ + readonly isFavorite?: boolean + + /** + * + * @type {boolean} + * @memberof AssetApiGetTimeBucket + */ + readonly isTrashed?: boolean + + /** + * + * @type {boolean} + * @memberof AssetApiGetTimeBucket + */ + readonly withStacked?: boolean + + /** + * + * @type {string} + * @memberof AssetApiGetTimeBucket + */ + readonly key?: string +} + /** * Request parameters for getTimeBuckets operation in AssetApi. * @export @@ -8733,13 +9361,13 @@ export interface AssetApiUploadFileRequest { export class AssetApi extends BaseAPI { /** * Checks if assets exist by checksums - * @param {AssetApiBulkUploadCheckRequest} requestParameters Request parameters. + * @param {AssetApiCheckBulkUploadRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AssetApi */ - public bulkUploadCheck(requestParameters: AssetApiBulkUploadCheckRequest, options?: AxiosRequestConfig) { - return AssetApiFp(this.configuration).bulkUploadCheck(requestParameters.assetBulkUploadCheckDto, options).then((request) => request(this.axios, this.basePath)); + public checkBulkUpload(requestParameters: AssetApiCheckBulkUploadRequest, options?: AxiosRequestConfig) { + return AssetApiFp(this.configuration).checkBulkUpload(requestParameters.assetBulkUploadCheckDto, options).then((request) => request(this.axios, this.basePath)); } /** @@ -8830,13 +9458,13 @@ export class AssetApi extends BaseAPI { /** * - * @param {AssetApiGetAssetStatsRequest} requestParameters Request parameters. + * @param {AssetApiGetAssetStatisticsRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AssetApi */ - public getAssetStats(requestParameters: AssetApiGetAssetStatsRequest = {}, options?: AxiosRequestConfig) { - return AssetApiFp(this.configuration).getAssetStats(requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, options).then((request) => request(this.axios, this.basePath)); + public getAssetStatistics(requestParameters: AssetApiGetAssetStatisticsRequest = {}, options?: AxiosRequestConfig) { + return AssetApiFp(this.configuration).getAssetStatistics(requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, options).then((request) => request(this.axios, this.basePath)); } /** @@ -8850,17 +9478,6 @@ export class AssetApi extends BaseAPI { return AssetApiFp(this.configuration).getAssetThumbnail(requestParameters.id, requestParameters.format, requestParameters.key, options).then((request) => request(this.axios, this.basePath)); } - /** - * - * @param {AssetApiGetByTimeBucketRequest} requestParameters Request parameters. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof AssetApi - */ - public getByTimeBucket(requestParameters: AssetApiGetByTimeBucketRequest, options?: AxiosRequestConfig) { - return AssetApiFp(this.configuration).getByTimeBucket(requestParameters.size, requestParameters.timeBucket, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.key, options).then((request) => request(this.axios, this.basePath)); - } - /** * * @param {*} [options] Override http request option. @@ -8925,6 +9542,17 @@ export class AssetApi extends BaseAPI { return AssetApiFp(this.configuration).getRandom(requestParameters.count, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @param {AssetApiGetTimeBucketRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof AssetApi + */ + public getTimeBucket(requestParameters: AssetApiGetTimeBucketRequest, options?: AxiosRequestConfig) { + return AssetApiFp(this.configuration).getTimeBucket(requestParameters.size, requestParameters.timeBucket, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.key, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @param {AssetApiGetTimeBucketsRequest} requestParameters Request parameters. @@ -9462,41 +10090,6 @@ export class AuditApi extends BaseAPI { */ export const AuthenticationApiAxiosParamCreator = function (configuration?: Configuration) { return { - /** - * - * @param {SignUpDto} signUpDto - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - adminSignUp: async (signUpDto: SignUpDto, options: AxiosRequestConfig = {}): Promise => { - // verify required parameter 'signUpDto' is not null or undefined - assertParamExists('adminSignUp', 'signUpDto', signUpDto) - const localVarPath = `/auth/admin-sign-up`; - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - - - localVarHeaderParameter['Content-Type'] = 'application/json'; - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - localVarRequestOptions.data = serializeDataIfNeeded(signUpDto, localVarRequestOptions, configuration) - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, /** * * @param {ChangePasswordDto} changePasswordDto @@ -9732,6 +10325,41 @@ export const AuthenticationApiAxiosParamCreator = function (configuration?: Conf options: localVarRequestOptions, }; }, + /** + * + * @param {SignUpDto} signUpDto + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + signUpAdmin: async (signUpDto: SignUpDto, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'signUpDto' is not null or undefined + assertParamExists('signUpAdmin', 'signUpDto', signUpDto) + const localVarPath = `/auth/admin-sign-up`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(signUpDto, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * * @param {*} [options] Override http request option. @@ -9780,16 +10408,6 @@ export const AuthenticationApiAxiosParamCreator = function (configuration?: Conf export const AuthenticationApiFp = function(configuration?: Configuration) { const localVarAxiosParamCreator = AuthenticationApiAxiosParamCreator(configuration) return { - /** - * - * @param {SignUpDto} signUpDto - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async adminSignUp(signUpDto: SignUpDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.adminSignUp(signUpDto, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); - }, /** * * @param {ChangePasswordDto} changePasswordDto @@ -9847,6 +10465,16 @@ export const AuthenticationApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.logoutAuthDevices(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * + * @param {SignUpDto} signUpDto + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async signUpAdmin(signUpDto: SignUpDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.signUpAdmin(signUpDto, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @param {*} [options] Override http request option. @@ -9866,15 +10494,6 @@ export const AuthenticationApiFp = function(configuration?: Configuration) { export const AuthenticationApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { const localVarFp = AuthenticationApiFp(configuration) return { - /** - * - * @param {AuthenticationApiAdminSignUpRequest} requestParameters Request parameters. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - adminSignUp(requestParameters: AuthenticationApiAdminSignUpRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.adminSignUp(requestParameters.signUpDto, options).then((request) => request(axios, basePath)); - }, /** * * @param {AuthenticationApiChangePasswordRequest} requestParameters Request parameters. @@ -9926,6 +10545,15 @@ export const AuthenticationApiFactory = function (configuration?: Configuration, logoutAuthDevices(options?: AxiosRequestConfig): AxiosPromise { return localVarFp.logoutAuthDevices(options).then((request) => request(axios, basePath)); }, + /** + * + * @param {AuthenticationApiSignUpAdminRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + signUpAdmin(requestParameters: AuthenticationApiSignUpAdminRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.signUpAdmin(requestParameters.signUpDto, options).then((request) => request(axios, basePath)); + }, /** * * @param {*} [options] Override http request option. @@ -9937,20 +10565,6 @@ export const AuthenticationApiFactory = function (configuration?: Configuration, }; }; -/** - * Request parameters for adminSignUp operation in AuthenticationApi. - * @export - * @interface AuthenticationApiAdminSignUpRequest - */ -export interface AuthenticationApiAdminSignUpRequest { - /** - * - * @type {SignUpDto} - * @memberof AuthenticationApiAdminSignUp - */ - readonly signUpDto: SignUpDto -} - /** * Request parameters for changePassword operation in AuthenticationApi. * @export @@ -9993,6 +10607,20 @@ export interface AuthenticationApiLogoutAuthDeviceRequest { readonly id: string } +/** + * Request parameters for signUpAdmin operation in AuthenticationApi. + * @export + * @interface AuthenticationApiSignUpAdminRequest + */ +export interface AuthenticationApiSignUpAdminRequest { + /** + * + * @type {SignUpDto} + * @memberof AuthenticationApiSignUpAdmin + */ + readonly signUpDto: SignUpDto +} + /** * AuthenticationApi - object-oriented interface * @export @@ -10000,17 +10628,6 @@ export interface AuthenticationApiLogoutAuthDeviceRequest { * @extends {BaseAPI} */ export class AuthenticationApi extends BaseAPI { - /** - * - * @param {AuthenticationApiAdminSignUpRequest} requestParameters Request parameters. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof AuthenticationApi - */ - public adminSignUp(requestParameters: AuthenticationApiAdminSignUpRequest, options?: AxiosRequestConfig) { - return AuthenticationApiFp(this.configuration).adminSignUp(requestParameters.signUpDto, options).then((request) => request(this.axios, this.basePath)); - } - /** * * @param {AuthenticationApiChangePasswordRequest} requestParameters Request parameters. @@ -10074,6 +10691,17 @@ export class AuthenticationApi extends BaseAPI { return AuthenticationApiFp(this.configuration).logoutAuthDevices(options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @param {AuthenticationApiSignUpAdminRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof AuthenticationApi + */ + public signUpAdmin(requestParameters: AuthenticationApiSignUpAdminRequest, options?: AxiosRequestConfig) { + return AuthenticationApiFp(this.configuration).signUpAdmin(requestParameters.signUpDto, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @param {*} [options] Override http request option. @@ -10386,7 +11014,7 @@ export const LibraryApiAxiosParamCreator = function (configuration?: Configurati * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getAllForUser: async (options: AxiosRequestConfig = {}): Promise => { + getLibraries: async (options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/library`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -10676,8 +11304,8 @@ export const LibraryApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getAllForUser(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getAllForUser(options); + async getLibraries(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getLibraries(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -10765,8 +11393,8 @@ export const LibraryApiFactory = function (configuration?: Configuration, basePa * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getAllForUser(options?: AxiosRequestConfig): AxiosPromise> { - return localVarFp.getAllForUser(options).then((request) => request(axios, basePath)); + getLibraries(options?: AxiosRequestConfig): AxiosPromise> { + return localVarFp.getLibraries(options).then((request) => request(axios, basePath)); }, /** * @@ -10963,8 +11591,8 @@ export class LibraryApi extends BaseAPI { * @throws {RequiredError} * @memberof LibraryApi */ - public getAllForUser(options?: AxiosRequestConfig) { - return LibraryApiFp(this.configuration).getAllForUser(options).then((request) => request(this.axios, this.basePath)); + public getLibraries(options?: AxiosRequestConfig) { + return LibraryApiFp(this.configuration).getLibraries(options).then((request) => request(this.axios, this.basePath)); } /** @@ -11030,50 +11658,15 @@ export class LibraryApi extends BaseAPI { */ export const OAuthApiAxiosParamCreator = function (configuration?: Configuration) { return { - /** - * - * @param {OAuthConfigDto} oAuthConfigDto - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - authorizeOAuth: async (oAuthConfigDto: OAuthConfigDto, options: AxiosRequestConfig = {}): Promise => { - // verify required parameter 'oAuthConfigDto' is not null or undefined - assertParamExists('authorizeOAuth', 'oAuthConfigDto', oAuthConfigDto) - const localVarPath = `/oauth/authorize`; - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - - - localVarHeaderParameter['Content-Type'] = 'application/json'; - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - localVarRequestOptions.data = serializeDataIfNeeded(oAuthConfigDto, localVarRequestOptions, configuration) - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, /** * * @param {OAuthCallbackDto} oAuthCallbackDto * @param {*} [options] Override http request option. * @throws {RequiredError} */ - callback: async (oAuthCallbackDto: OAuthCallbackDto, options: AxiosRequestConfig = {}): Promise => { + finishOAuth: async (oAuthCallbackDto: OAuthCallbackDto, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'oAuthCallbackDto' is not null or undefined - assertParamExists('callback', 'oAuthCallbackDto', oAuthCallbackDto) + assertParamExists('finishOAuth', 'oAuthCallbackDto', oAuthCallbackDto) const localVarPath = `/oauth/callback`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -11107,9 +11700,9 @@ export const OAuthApiAxiosParamCreator = function (configuration?: Configuration * @deprecated * @throws {RequiredError} */ - generateConfig: async (oAuthConfigDto: OAuthConfigDto, options: AxiosRequestConfig = {}): Promise => { + generateOAuthConfig: async (oAuthConfigDto: OAuthConfigDto, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'oAuthConfigDto' is not null or undefined - assertParamExists('generateConfig', 'oAuthConfigDto', oAuthConfigDto) + assertParamExists('generateOAuthConfig', 'oAuthConfigDto', oAuthConfigDto) const localVarPath = `/oauth/config`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -11142,9 +11735,9 @@ export const OAuthApiAxiosParamCreator = function (configuration?: Configuration * @param {*} [options] Override http request option. * @throws {RequiredError} */ - link: async (oAuthCallbackDto: OAuthCallbackDto, options: AxiosRequestConfig = {}): Promise => { + linkOAuthAccount: async (oAuthCallbackDto: OAuthCallbackDto, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'oAuthCallbackDto' is not null or undefined - assertParamExists('link', 'oAuthCallbackDto', oAuthCallbackDto) + assertParamExists('linkOAuthAccount', 'oAuthCallbackDto', oAuthCallbackDto) const localVarPath = `/oauth/link`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -11185,7 +11778,7 @@ export const OAuthApiAxiosParamCreator = function (configuration?: Configuration * @param {*} [options] Override http request option. * @throws {RequiredError} */ - mobileRedirect: async (options: AxiosRequestConfig = {}): Promise => { + redirectOAuthToMobile: async (options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/oauth/mobile-redirect`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -11211,10 +11804,45 @@ export const OAuthApiAxiosParamCreator = function (configuration?: Configuration }, /** * + * @param {OAuthConfigDto} oAuthConfigDto * @param {*} [options] Override http request option. * @throws {RequiredError} */ - unlink: async (options: AxiosRequestConfig = {}): Promise => { + startOAuth: async (oAuthConfigDto: OAuthConfigDto, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'oAuthConfigDto' is not null or undefined + assertParamExists('startOAuth', 'oAuthConfigDto', oAuthConfigDto) + const localVarPath = `/oauth/authorize`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(oAuthConfigDto, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + unlinkOAuthAccount: async (options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/oauth/unlink`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -11257,24 +11885,14 @@ export const OAuthApiAxiosParamCreator = function (configuration?: Configuration export const OAuthApiFp = function(configuration?: Configuration) { const localVarAxiosParamCreator = OAuthApiAxiosParamCreator(configuration) return { - /** - * - * @param {OAuthConfigDto} oAuthConfigDto - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async authorizeOAuth(oAuthConfigDto: OAuthConfigDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.authorizeOAuth(oAuthConfigDto, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); - }, /** * * @param {OAuthCallbackDto} oAuthCallbackDto * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async callback(oAuthCallbackDto: OAuthCallbackDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.callback(oAuthCallbackDto, options); + async finishOAuth(oAuthCallbackDto: OAuthCallbackDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.finishOAuth(oAuthCallbackDto, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -11284,8 +11902,8 @@ export const OAuthApiFp = function(configuration?: Configuration) { * @deprecated * @throws {RequiredError} */ - async generateConfig(oAuthConfigDto: OAuthConfigDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.generateConfig(oAuthConfigDto, options); + async generateOAuthConfig(oAuthConfigDto: OAuthConfigDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.generateOAuthConfig(oAuthConfigDto, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -11294,8 +11912,8 @@ export const OAuthApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async link(oAuthCallbackDto: OAuthCallbackDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.link(oAuthCallbackDto, options); + async linkOAuthAccount(oAuthCallbackDto: OAuthCallbackDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.linkOAuthAccount(oAuthCallbackDto, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -11303,8 +11921,18 @@ export const OAuthApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async mobileRedirect(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.mobileRedirect(options); + async redirectOAuthToMobile(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.redirectOAuthToMobile(options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + /** + * + * @param {OAuthConfigDto} oAuthConfigDto + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async startOAuth(oAuthConfigDto: OAuthConfigDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.startOAuth(oAuthConfigDto, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -11312,8 +11940,8 @@ export const OAuthApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async unlink(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.unlink(options); + async unlinkOAuthAccount(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.unlinkOAuthAccount(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, } @@ -11328,116 +11956,116 @@ export const OAuthApiFactory = function (configuration?: Configuration, basePath return { /** * - * @param {OAuthApiAuthorizeOAuthRequest} requestParameters Request parameters. + * @param {OAuthApiFinishOAuthRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - authorizeOAuth(requestParameters: OAuthApiAuthorizeOAuthRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.authorizeOAuth(requestParameters.oAuthConfigDto, options).then((request) => request(axios, basePath)); - }, - /** - * - * @param {OAuthApiCallbackRequest} requestParameters Request parameters. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - callback(requestParameters: OAuthApiCallbackRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.callback(requestParameters.oAuthCallbackDto, options).then((request) => request(axios, basePath)); + finishOAuth(requestParameters: OAuthApiFinishOAuthRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.finishOAuth(requestParameters.oAuthCallbackDto, options).then((request) => request(axios, basePath)); }, /** * @deprecated use feature flags and /oauth/authorize - * @param {OAuthApiGenerateConfigRequest} requestParameters Request parameters. + * @param {OAuthApiGenerateOAuthConfigRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @deprecated * @throws {RequiredError} */ - generateConfig(requestParameters: OAuthApiGenerateConfigRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.generateConfig(requestParameters.oAuthConfigDto, options).then((request) => request(axios, basePath)); + generateOAuthConfig(requestParameters: OAuthApiGenerateOAuthConfigRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.generateOAuthConfig(requestParameters.oAuthConfigDto, options).then((request) => request(axios, basePath)); }, /** * - * @param {OAuthApiLinkRequest} requestParameters Request parameters. + * @param {OAuthApiLinkOAuthAccountRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - link(requestParameters: OAuthApiLinkRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.link(requestParameters.oAuthCallbackDto, options).then((request) => request(axios, basePath)); + linkOAuthAccount(requestParameters: OAuthApiLinkOAuthAccountRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.linkOAuthAccount(requestParameters.oAuthCallbackDto, options).then((request) => request(axios, basePath)); }, /** * * @param {*} [options] Override http request option. * @throws {RequiredError} */ - mobileRedirect(options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.mobileRedirect(options).then((request) => request(axios, basePath)); + redirectOAuthToMobile(options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.redirectOAuthToMobile(options).then((request) => request(axios, basePath)); + }, + /** + * + * @param {OAuthApiStartOAuthRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + startOAuth(requestParameters: OAuthApiStartOAuthRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.startOAuth(requestParameters.oAuthConfigDto, options).then((request) => request(axios, basePath)); }, /** * * @param {*} [options] Override http request option. * @throws {RequiredError} */ - unlink(options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.unlink(options).then((request) => request(axios, basePath)); + unlinkOAuthAccount(options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.unlinkOAuthAccount(options).then((request) => request(axios, basePath)); }, }; }; /** - * Request parameters for authorizeOAuth operation in OAuthApi. + * Request parameters for finishOAuth operation in OAuthApi. * @export - * @interface OAuthApiAuthorizeOAuthRequest + * @interface OAuthApiFinishOAuthRequest */ -export interface OAuthApiAuthorizeOAuthRequest { - /** - * - * @type {OAuthConfigDto} - * @memberof OAuthApiAuthorizeOAuth - */ - readonly oAuthConfigDto: OAuthConfigDto -} - -/** - * Request parameters for callback operation in OAuthApi. - * @export - * @interface OAuthApiCallbackRequest - */ -export interface OAuthApiCallbackRequest { +export interface OAuthApiFinishOAuthRequest { /** * * @type {OAuthCallbackDto} - * @memberof OAuthApiCallback + * @memberof OAuthApiFinishOAuth */ readonly oAuthCallbackDto: OAuthCallbackDto } /** - * Request parameters for generateConfig operation in OAuthApi. + * Request parameters for generateOAuthConfig operation in OAuthApi. * @export - * @interface OAuthApiGenerateConfigRequest + * @interface OAuthApiGenerateOAuthConfigRequest */ -export interface OAuthApiGenerateConfigRequest { +export interface OAuthApiGenerateOAuthConfigRequest { /** * * @type {OAuthConfigDto} - * @memberof OAuthApiGenerateConfig + * @memberof OAuthApiGenerateOAuthConfig */ readonly oAuthConfigDto: OAuthConfigDto } /** - * Request parameters for link operation in OAuthApi. + * Request parameters for linkOAuthAccount operation in OAuthApi. * @export - * @interface OAuthApiLinkRequest + * @interface OAuthApiLinkOAuthAccountRequest */ -export interface OAuthApiLinkRequest { +export interface OAuthApiLinkOAuthAccountRequest { /** * * @type {OAuthCallbackDto} - * @memberof OAuthApiLink + * @memberof OAuthApiLinkOAuthAccount */ readonly oAuthCallbackDto: OAuthCallbackDto } +/** + * Request parameters for startOAuth operation in OAuthApi. + * @export + * @interface OAuthApiStartOAuthRequest + */ +export interface OAuthApiStartOAuthRequest { + /** + * + * @type {OAuthConfigDto} + * @memberof OAuthApiStartOAuth + */ + readonly oAuthConfigDto: OAuthConfigDto +} + /** * OAuthApi - object-oriented interface * @export @@ -11447,47 +12075,36 @@ export interface OAuthApiLinkRequest { export class OAuthApi extends BaseAPI { /** * - * @param {OAuthApiAuthorizeOAuthRequest} requestParameters Request parameters. + * @param {OAuthApiFinishOAuthRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof OAuthApi */ - public authorizeOAuth(requestParameters: OAuthApiAuthorizeOAuthRequest, options?: AxiosRequestConfig) { - return OAuthApiFp(this.configuration).authorizeOAuth(requestParameters.oAuthConfigDto, options).then((request) => request(this.axios, this.basePath)); - } - - /** - * - * @param {OAuthApiCallbackRequest} requestParameters Request parameters. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof OAuthApi - */ - public callback(requestParameters: OAuthApiCallbackRequest, options?: AxiosRequestConfig) { - return OAuthApiFp(this.configuration).callback(requestParameters.oAuthCallbackDto, options).then((request) => request(this.axios, this.basePath)); + public finishOAuth(requestParameters: OAuthApiFinishOAuthRequest, options?: AxiosRequestConfig) { + return OAuthApiFp(this.configuration).finishOAuth(requestParameters.oAuthCallbackDto, options).then((request) => request(this.axios, this.basePath)); } /** * @deprecated use feature flags and /oauth/authorize - * @param {OAuthApiGenerateConfigRequest} requestParameters Request parameters. + * @param {OAuthApiGenerateOAuthConfigRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @deprecated * @throws {RequiredError} * @memberof OAuthApi */ - public generateConfig(requestParameters: OAuthApiGenerateConfigRequest, options?: AxiosRequestConfig) { - return OAuthApiFp(this.configuration).generateConfig(requestParameters.oAuthConfigDto, options).then((request) => request(this.axios, this.basePath)); + public generateOAuthConfig(requestParameters: OAuthApiGenerateOAuthConfigRequest, options?: AxiosRequestConfig) { + return OAuthApiFp(this.configuration).generateOAuthConfig(requestParameters.oAuthConfigDto, options).then((request) => request(this.axios, this.basePath)); } /** * - * @param {OAuthApiLinkRequest} requestParameters Request parameters. + * @param {OAuthApiLinkOAuthAccountRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof OAuthApi */ - public link(requestParameters: OAuthApiLinkRequest, options?: AxiosRequestConfig) { - return OAuthApiFp(this.configuration).link(requestParameters.oAuthCallbackDto, options).then((request) => request(this.axios, this.basePath)); + public linkOAuthAccount(requestParameters: OAuthApiLinkOAuthAccountRequest, options?: AxiosRequestConfig) { + return OAuthApiFp(this.configuration).linkOAuthAccount(requestParameters.oAuthCallbackDto, options).then((request) => request(this.axios, this.basePath)); } /** @@ -11496,8 +12113,19 @@ export class OAuthApi extends BaseAPI { * @throws {RequiredError} * @memberof OAuthApi */ - public mobileRedirect(options?: AxiosRequestConfig) { - return OAuthApiFp(this.configuration).mobileRedirect(options).then((request) => request(this.axios, this.basePath)); + public redirectOAuthToMobile(options?: AxiosRequestConfig) { + return OAuthApiFp(this.configuration).redirectOAuthToMobile(options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @param {OAuthApiStartOAuthRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof OAuthApi + */ + public startOAuth(requestParameters: OAuthApiStartOAuthRequest, options?: AxiosRequestConfig) { + return OAuthApiFp(this.configuration).startOAuth(requestParameters.oAuthConfigDto, options).then((request) => request(this.axios, this.basePath)); } /** @@ -11506,8 +12134,8 @@ export class OAuthApi extends BaseAPI { * @throws {RequiredError} * @memberof OAuthApi */ - public unlink(options?: AxiosRequestConfig) { - return OAuthApiFp(this.configuration).unlink(options).then((request) => request(this.axios, this.basePath)); + public unlinkOAuthAccount(options?: AxiosRequestConfig) { + return OAuthApiFp(this.configuration).unlinkOAuthAccount(options).then((request) => request(this.axios, this.basePath)); } } @@ -13162,37 +13790,8 @@ export const ServerInfoApiAxiosParamCreator = function (configuration?: Configur * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getServerVersion: async (options: AxiosRequestConfig = {}): Promise => { - const localVarPath = `/server-info/version`; - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - /** - * - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - getStats: async (options: AxiosRequestConfig = {}): Promise => { - const localVarPath = `/server-info/stats`; + getServerStatistics: async (options: AxiosRequestConfig = {}): Promise => { + const localVarPath = `/server-info/statistics`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); let baseOptions; @@ -13215,6 +13814,35 @@ export const ServerInfoApiAxiosParamCreator = function (configuration?: Configur + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getServerVersion: async (options: AxiosRequestConfig = {}): Promise => { + const localVarPath = `/server-info/version`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -13353,8 +13981,8 @@ export const ServerInfoApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getServerVersion(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getServerVersion(options); + async getServerStatistics(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getServerStatistics(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -13362,8 +13990,8 @@ export const ServerInfoApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getStats(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getStats(options); + async getServerVersion(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getServerVersion(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -13432,16 +14060,16 @@ export const ServerInfoApiFactory = function (configuration?: Configuration, bas * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getServerVersion(options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.getServerVersion(options).then((request) => request(axios, basePath)); + getServerStatistics(options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.getServerStatistics(options).then((request) => request(axios, basePath)); }, /** * * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getStats(options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.getStats(options).then((request) => request(axios, basePath)); + getServerVersion(options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.getServerVersion(options).then((request) => request(axios, basePath)); }, /** * @@ -13513,8 +14141,8 @@ export class ServerInfoApi extends BaseAPI { * @throws {RequiredError} * @memberof ServerInfoApi */ - public getServerVersion(options?: AxiosRequestConfig) { - return ServerInfoApiFp(this.configuration).getServerVersion(options).then((request) => request(this.axios, this.basePath)); + public getServerStatistics(options?: AxiosRequestConfig) { + return ServerInfoApiFp(this.configuration).getServerStatistics(options).then((request) => request(this.axios, this.basePath)); } /** @@ -13523,8 +14151,8 @@ export class ServerInfoApi extends BaseAPI { * @throws {RequiredError} * @memberof ServerInfoApi */ - public getStats(options?: AxiosRequestConfig) { - return ServerInfoApiFp(this.configuration).getStats(options).then((request) => request(this.axios, this.basePath)); + public getServerVersion(options?: AxiosRequestConfig) { + return ServerInfoApiFp(this.configuration).getServerVersion(options).then((request) => request(this.axios, this.basePath)); } /** @@ -14410,7 +15038,7 @@ export const SystemConfigApiAxiosParamCreator = function (configuration?: Config * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getDefaults: async (options: AxiosRequestConfig = {}): Promise => { + getConfigDefaults: async (options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/system-config/defaults`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -14549,8 +15177,8 @@ export const SystemConfigApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getDefaults(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getDefaults(options); + async getConfigDefaults(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getConfigDefaults(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -14595,8 +15223,8 @@ export const SystemConfigApiFactory = function (configuration?: Configuration, b * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getDefaults(options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.getDefaults(options).then((request) => request(axios, basePath)); + getConfigDefaults(options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.getConfigDefaults(options).then((request) => request(axios, basePath)); }, /** * @@ -14655,8 +15283,8 @@ export class SystemConfigApi extends BaseAPI { * @throws {RequiredError} * @memberof SystemConfigApi */ - public getDefaults(options?: AxiosRequestConfig) { - return SystemConfigApiFp(this.configuration).getDefaults(options).then((request) => request(this.axios, this.basePath)); + public getConfigDefaults(options?: AxiosRequestConfig) { + return SystemConfigApiFp(this.configuration).getConfigDefaults(options).then((request) => request(this.axios, this.basePath)); } /** diff --git a/cli/src/api/open-api/base.ts b/cli/src/api/open-api/base.ts index 814dc8f92..9a534e7bd 100644 --- a/cli/src/api/open-api/base.ts +++ b/cli/src/api/open-api/base.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.83.0 + * The version of the OpenAPI document: 1.84.0 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/cli/src/api/open-api/common.ts b/cli/src/api/open-api/common.ts index 7d762d6ac..8997b2d52 100644 --- a/cli/src/api/open-api/common.ts +++ b/cli/src/api/open-api/common.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.83.0 + * The version of the OpenAPI document: 1.84.0 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/cli/src/api/open-api/configuration.ts b/cli/src/api/open-api/configuration.ts index 3ace8a93f..8058881d1 100644 --- a/cli/src/api/open-api/configuration.ts +++ b/cli/src/api/open-api/configuration.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.83.0 + * The version of the OpenAPI document: 1.84.0 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/cli/src/api/open-api/index.ts b/cli/src/api/open-api/index.ts index 62d163db6..d0651f28a 100644 --- a/cli/src/api/open-api/index.ts +++ b/cli/src/api/open-api/index.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.83.0 + * The version of the OpenAPI document: 1.84.0 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/docs/blog/2023/06-24/update.mdx b/docs/blog/2023/06-24/update.mdx index ea948321d..d4c714943 100644 --- a/docs/blog/2023/06-24/update.mdx +++ b/docs/blog/2023/06-24/update.mdx @@ -33,8 +33,6 @@ To be concise, Immich can now read in the gallery files, register the path into - Only new files that are added to the gallery will be detected. - Deleted and moved files will not be detected. -You can find more information on how to use the feature by reading the documentation [here](/docs/features/read-only-gallery). - ## Memory feature This is considered a fun feature that the team and I wanted to build for so long, but we had to put it off because of the refactoring of the code base. The code base is now in a good enough form to circle back and add more exciting features. diff --git a/docs/docs/administration/backup-and-restore.md b/docs/docs/administration/backup-and-restore.md index bfea5aa3c..da9e271b5 100644 --- a/docs/docs/administration/backup-and-restore.md +++ b/docs/docs/administration/backup-and-restore.md @@ -17,13 +17,13 @@ docker exec -t immich_postgres pg_dumpall -c -U postgres | gzip > "/path/to/back ``` ```bash title='Restore' -docker-compose down -v # CAUTION! Deletes all Immich data to start from scratch. -docker-compose pull # Update to latest version of Immich (if desired) -docker-compose create # Create Docker containers for Immich apps without running them. +docker compose down -v # CAUTION! Deletes all Immich data to start from scratch. +docker compose pull # Update to latest version of Immich (if desired) +docker compose create # Create Docker containers for Immich apps without running them. docker start immich_postgres # Start Postgres server sleep 10 # Wait for Postgres server to start up gunzip < "/path/to/backup/dump.sql.gz" | docker exec -i immich_postgres psql -U postgres -d immich # Restore Backup -docker-compose up -d # Start remainder of Immich apps +docker compose up -d # Start remainder of Immich apps ``` Note that for the database restore to proceed properly, it requires a completely fresh install (i.e. the Immich server has never run since creating the Docker containers). If the Immich app has run, Postgres conflicts may be encountered upon database restoration (relation already exists, violated foreign key constraints, multiple primary keys, etc.). diff --git a/docs/docs/features/bulk-upload.md b/docs/docs/features/bulk-upload.md index aed3b2ec9..5923e5c16 100644 --- a/docs/docs/features/bulk-upload.md +++ b/docs/docs/features/bulk-upload.md @@ -32,7 +32,6 @@ immich | --server / -s | Immich's server address | | --threads / -t | Number of threads to use (Default 5) | | --album/ -al | Create albums for assets based on the parent folder or a given name | -| --import/ -i | Import gallery (assets are not uploaded) | ## Quick Start @@ -108,70 +107,3 @@ npm run build ```bash title="Run the command" node bin/index.js upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api --recursive your/asset/directory ``` - ---- - -## Importing existing libraries - -If you do not wish to upload files into the server, existing files can be imported into the immich gallery through the use of the `--import` flag. - -``` -immich upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api --recursive directory/ --import -``` - -``` -immich upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api file1.jpg file2.jpg --import -``` - -The `immich-server` and `immich-microservices` containers must be able to access the files, or directories at the path referenced in the command. The directories referenced must be set under a user's `External Path` setting. More detailed instructions can be found [here](/docs/features/read-only-gallery). - -:::tip Matching volume references -The import command is most easily run on the machine running the immich service, as the path to the files on the machine running the command and the server much match identically. - -If you are running immich within docker, the volume pointing to your existing library should be identical with your host machine. - -```diff title="docker-compose.yml" - immich-server: - container_name: immich_server - image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release} - command: [ "start.sh", "immich" ] - volumes: - - ${UPLOAD_LOCATION}:/usr/src/app/upload -+ - /path/to/media:/path/to/media - env_file: - - .env - depends_on: - - redis - - database - - typesense - restart: always - - immich-microservices: - container_name: immich_microservices - image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release} - command: [ "start.sh", "microservices" ] - volumes: - - ${UPLOAD_LOCATION}:/usr/src/app/upload -+ - /path/to/media:/path/to/media - env_file: - - .env - depends_on: - - redis - - database - - typesense - restart: always -``` - -The proper command for above would be as shown below. You should have access to `/path/to/media` exactly on the environment the CLI command is being run on - -``` -immich upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api --recursive /path/to/media --import -``` - -If you are running the import using the docker command, please note that the volumes should point to the `/path/to/media` exactly on the environment the CLI command is being run on - -``` -docker run -it --rm -v "/path/to/media:/path/to/media" ghcr.io/immich-app/immich-cli:latest upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api --recursive /path/to/media --import -``` - -::: diff --git a/docs/docs/features/read-only-gallery.md b/docs/docs/features/read-only-gallery.md deleted file mode 100644 index 7b1cd605f..000000000 --- a/docs/docs/features/read-only-gallery.md +++ /dev/null @@ -1,97 +0,0 @@ -# Read-only Gallery [Deprecated] - -:::caution - -This feature is being deprecated in favor of [Libraries](/docs/features/libraries.md). - -::: - -## Overview - -This feature enables users to use an existing gallery without uploading the assets to Immich. - -Upon syncing the file information, it will be read by Immich to generate supported files. - -## Usage - -:::tip Example scenario - -On the VM/system that Immich is running, I have 2 galleries that I want to use with Immich. - -- My gallery is stored at `/mnt/media/precious-memory` -- My wife's gallery is stored at `/mnt/media/childhood-memory` - -We will use those values in the steps below. - -::: - -### Mount the gallery to the containers. - -`immich-server` and `immich-microservices` containers will need access to the gallery. Mount the directory path as in the example below - -```diff title="docker-compose.yml" - immich-server: - container_name: immich_server - image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release} - command: [ "start.sh", "immich" ] - volumes: - - ${UPLOAD_LOCATION}:/usr/src/app/upload -+ - /mnt/media/precious-memory:/mnt/media/precious-memory:ro -+ - /mnt/media/childhood-memory:/mnt/media/childhood-memory:ro - env_file: - - .env - depends_on: - - redis - - database - - typesense - restart: always - - immich-microservices: - container_name: immich_microservices - image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release} - command: [ "start.sh", "microservices" ] - volumes: - - ${UPLOAD_LOCATION}:/usr/src/app/upload -+ - /mnt/media/precious-memory:/mnt/media/precious-memory:ro -+ - /mnt/media/childhood-memory:/mnt/media/childhood-memory:ro - env_file: - - .env - depends_on: - - redis - - database - - typesense - restart: always -``` - -:::tip -Internal and external path have to be identical. -::: - -_Remember to bring the container down/up to register the changes. Make sure you can see the mounted path in the container._ - -### Register the path for the user. - -This action is done by the admin of the instance. - -- Navigate to `Administration > Users` page on the web. -- Click on the user edit button. -- Add the gallery path to the `External Path` field for the corresponding user and confirm the changes. - - - - - -### Sync with the CLI tool. - -- Install or update the [CLI Tool](/docs/features/bulk-upload.md). The import feature is supported from version `v0.39.0` of the CLI -- Run the command below to sync the gallery with Immich. - -```bash title="Import my gallery" -immich upload --key --server http://my-server-ip:2283/api /mnt/media/precious-memory --recursive --import -``` - -```bash title="Import my wife gallery" -immich upload --key --server http://my-server-ip:2283/api /mnt/media/childhood-memory --recursive --import -``` - -The `--import` flag will tell Immich to import the files by path instead of uploading them. diff --git a/machine-learning/pyproject.toml b/machine-learning/pyproject.toml index 272724d91..6fea1e5d5 100644 --- a/machine-learning/pyproject.toml +++ b/machine-learning/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "machine-learning" -version = "1.83.0" +version = "1.84.0" description = "" authors = ["Hau Tran "] readme = "README.md" diff --git a/mobile/android/fastlane/Fastfile b/mobile/android/fastlane/Fastfile index cd01d8761..281fa52d2 100644 --- a/mobile/android/fastlane/Fastfile +++ b/mobile/android/fastlane/Fastfile @@ -35,8 +35,8 @@ platform :android do task: 'bundle', build_type: 'Release', properties: { - "android.injected.version.code" => 107, - "android.injected.version.name" => "1.83.0", + "android.injected.version.code" => 108, + "android.injected.version.name" => "1.84.0", } ) upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab') diff --git a/mobile/android/fastlane/report.xml b/mobile/android/fastlane/report.xml index 7b7db96a2..a0530d9aa 100644 --- a/mobile/android/fastlane/report.xml +++ b/mobile/android/fastlane/report.xml @@ -5,17 +5,17 @@ - + - + - + diff --git a/mobile/assets/i18n/en-US.json b/mobile/assets/i18n/en-US.json index 252c1a20e..3ab114c14 100644 --- a/mobile/assets/i18n/en-US.json +++ b/mobile/assets/i18n/en-US.json @@ -23,6 +23,7 @@ "album_viewer_appbar_share_err_title": "Failed to change album title", "album_viewer_appbar_share_leave": "Leave album", "album_viewer_appbar_share_remove": "Remove from album", + "album_viewer_appbar_share_to": "Share To", "album_viewer_page_share_add_users": "Add users", "all_people_page_title": "People", "all_videos_page_title": "Videos", diff --git a/mobile/ios/Runner.xcodeproj/project.pbxproj b/mobile/ios/Runner.xcodeproj/project.pbxproj index 8639b13ad..b15f480e2 100644 --- a/mobile/ios/Runner.xcodeproj/project.pbxproj +++ b/mobile/ios/Runner.xcodeproj/project.pbxproj @@ -379,7 +379,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -515,7 +515,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -543,7 +543,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/mobile/ios/Runner/Info.plist b/mobile/ios/Runner/Info.plist index 022cf3886..a6fddc98a 100644 --- a/mobile/ios/Runner/Info.plist +++ b/mobile/ios/Runner/Info.plist @@ -59,11 +59,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.78.1 + 1.84.0 CFBundleSignature ???? CFBundleVersion - 118 + 124 FLTEnableImpeller ITSAppUsesNonExemptEncryption diff --git a/mobile/ios/fastlane/Fastfile b/mobile/ios/fastlane/Fastfile index 5ce704794..19cefc12f 100644 --- a/mobile/ios/fastlane/Fastfile +++ b/mobile/ios/fastlane/Fastfile @@ -19,7 +19,7 @@ platform :ios do desc "iOS Beta" lane :beta do increment_version_number( - version_number: "1.83.0" + version_number: "1.84.0" ) increment_build_number( build_number: latest_testflight_build_number + 1, diff --git a/mobile/ios/fastlane/report.xml b/mobile/ios/fastlane/report.xml index c640150e6..c61f1d5d2 100644 --- a/mobile/ios/fastlane/report.xml +++ b/mobile/ios/fastlane/report.xml @@ -5,32 +5,32 @@ - + - + - + - + - + - + diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index 3ad2f4b62..13eda9d6e 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:timezone/data/latest.dart'; import 'package:immich_mobile/constants/locales.dart'; import 'package:immich_mobile/modules/backup/background_service/background.service.dart'; import 'package:immich_mobile/modules/backup/models/backup_album.model.dart'; @@ -77,6 +78,8 @@ Future initApp() async { log.severe('Catch all error: ${error.toString()} - $error', error, stack); return true; }; + + initializeTimeZones(); } Future loadDb() async { diff --git a/mobile/lib/modules/album/ui/album_viewer_appbar.dart b/mobile/lib/modules/album/ui/album_viewer_appbar.dart index f369a35d1..221603ed9 100644 --- a/mobile/lib/modules/album/ui/album_viewer_appbar.dart +++ b/mobile/lib/modules/album/ui/album_viewer_appbar.dart @@ -7,6 +7,8 @@ import 'package:immich_mobile/modules/album/providers/album.provider.dart'; import 'package:immich_mobile/modules/album/providers/album_detail.provider.dart'; import 'package:immich_mobile/modules/album/providers/album_viewer.provider.dart'; import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart'; +import 'package:immich_mobile/shared/ui/share_dialog.dart'; +import 'package:immich_mobile/shared/services/share.service.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/shared/models/album.dart'; import 'package:immich_mobile/shared/models/asset.dart'; @@ -160,40 +162,77 @@ class AlbumViewerAppbar extends HookConsumerWidget ImmichLoadingOverlayController.appLoader.hide(); } - buildBottomSheetActionButton() { + void handleShareAssets( + WidgetRef ref, + BuildContext context, + Set selection, + ) { + showDialog( + context: context, + builder: (BuildContext buildContext) { + ref.watch(shareServiceProvider).shareAssets(selection.toList()).then( + (bool status) { + if (!status) { + ImmichToast.show( + context: context, + msg: 'image_viewer_page_state_provider_share_error'.tr(), + toastType: ToastType.error, + gravity: ToastGravity.BOTTOM, + ); + } + Navigator.of(buildContext).pop(); + }, + ); + return const ShareDialog(); + }, + barrierDismissible: false, + ); + } + + void onShareAssetsTo() async { + ImmichLoadingOverlayController.appLoader.show(); + handleShareAssets(ref, context, selected); + ImmichLoadingOverlayController.appLoader.hide(); + } + + buildBottomSheetActions() { if (selected.isNotEmpty) { - if (album.ownerId == userId) { - return ListTile( + return [ + ListTile( + leading: const Icon(Icons.ios_share_rounded), + title: const Text( + 'album_viewer_appbar_share_to', + style: TextStyle(fontWeight: FontWeight.bold), + ).tr(), + onTap: () => onShareAssetsTo(), + ), + album.ownerId == userId ? ListTile( leading: const Icon(Icons.delete_sweep_rounded), title: const Text( 'album_viewer_appbar_share_remove', style: TextStyle(fontWeight: FontWeight.bold), ).tr(), onTap: () => onRemoveFromAlbumPressed(), - ); - } else { - return const SizedBox(); - } + ) : const SizedBox(), + ]; } else { - if (album.ownerId == userId) { - return ListTile( + return [ + album.ownerId == userId ? ListTile( leading: const Icon(Icons.delete_forever_rounded), title: const Text( 'album_viewer_appbar_share_delete', style: TextStyle(fontWeight: FontWeight.bold), ).tr(), onTap: () => onDeleteAlbumPressed(), - ); - } else { - return ListTile( + ) : ListTile( leading: const Icon(Icons.person_remove_rounded), title: const Text( 'album_viewer_appbar_share_leave', style: TextStyle(fontWeight: FontWeight.bold), ).tr(), onTap: () => onLeaveAlbumPressed(), - ); - } + ), + ]; } } @@ -257,7 +296,7 @@ class AlbumViewerAppbar extends HookConsumerWidget child: Column( mainAxisSize: MainAxisSize.min, children: [ - buildBottomSheetActionButton(), + ...buildBottomSheetActions(), if (selected.isEmpty && onAddPhotos != null) ...commonActions, if (selected.isEmpty && onAddPhotos != null && diff --git a/mobile/lib/modules/asset_viewer/ui/exif_bottom_sheet.dart b/mobile/lib/modules/asset_viewer/ui/exif_bottom_sheet.dart index df1c8ba6f..f194738a2 100644 --- a/mobile/lib/modules/asset_viewer/ui/exif_bottom_sheet.dart +++ b/mobile/lib/modules/asset_viewer/ui/exif_bottom_sheet.dart @@ -4,6 +4,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:timezone/timezone.dart'; import 'package:immich_mobile/modules/asset_viewer/ui/description_input.dart'; import 'package:immich_mobile/modules/map/ui/map_thumbnail.dart'; import 'package:immich_mobile/shared/models/asset.dart'; @@ -26,12 +27,36 @@ class ExifBottomSheet extends HookConsumerWidget { exifInfo.latitude != 0 && exifInfo.longitude != 0; - String get formattedDateTime { - final fileCreatedAt = asset.fileCreatedAt.toLocal(); - final date = DateFormat.yMMMEd().format(fileCreatedAt); - final time = DateFormat.jm().format(fileCreatedAt); + String formatTimeZone(Duration d) => + "GMT${d.isNegative ? '-': '+'}${d.inHours.abs().toString().padLeft(2, '0')}:${d.inMinutes.abs().remainder(60).toString().padLeft(2, '0')}"; - return '$date • $time'; + String get formattedDateTime { + DateTime dt = asset.fileCreatedAt.toLocal(); + String? timeZone; + if (asset.exifInfo?.dateTimeOriginal != null) { + dt = asset.exifInfo!.dateTimeOriginal!; + if (asset.exifInfo?.timeZone != null) { + dt = dt.toUtc(); + try { + final location = getLocation(asset.exifInfo!.timeZone!); + dt = TZDateTime.from(dt, location); + } on LocationNotFoundException { + RegExp re = RegExp(r'^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$', caseSensitive: false); + final m = re.firstMatch(asset.exifInfo!.timeZone!); + if (m != null) { + final duration = Duration(hours: int.parse(m.group(1) ?? '0'), minutes: int.parse(m.group(2) ?? '0')); + dt = dt.add(duration); + timeZone = formatTimeZone(duration); + } + } + } + } + + final date = DateFormat.yMMMEd().format(dt); + final time = DateFormat.jm().format(dt); + timeZone ??= formatTimeZone(dt.timeZoneOffset); + + return '$date • $time $timeZone'; } Future _createCoordinatesUri(ExifInfo? exifInfo) async { diff --git a/mobile/lib/modules/asset_viewer/views/gallery_viewer.dart b/mobile/lib/modules/asset_viewer/views/gallery_viewer.dart index d62e63649..6a355a64e 100644 --- a/mobile/lib/modules/asset_viewer/views/gallery_viewer.dart +++ b/mobile/lib/modules/asset_viewer/views/gallery_viewer.dart @@ -443,7 +443,8 @@ class GalleryViewerPage extends HookConsumerWidget { decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(6), - border: index == stackIndex.value + border: (stackIndex.value == -1 && index == 0) || + index == stackIndex.value ? Border.all( color: Colors.white, width: 2, diff --git a/mobile/lib/modules/home/ui/control_bottom_app_bar.dart b/mobile/lib/modules/home/ui/control_bottom_app_bar.dart index c356dddf7..3938bfb99 100644 --- a/mobile/lib/modules/home/ui/control_bottom_app_bar.dart +++ b/mobile/lib/modules/home/ui/control_bottom_app_bar.dart @@ -124,7 +124,7 @@ class ControlBottomAppBar extends ConsumerWidget { label: "control_bottom_app_bar_stack".tr(), onPressed: enabled ? onStack : null, ), - if (!hasRemote) + if (hasLocal) ControlBoxButton( iconData: Icons.backup_outlined, label: "Upload", diff --git a/mobile/lib/modules/home/views/home_page.dart b/mobile/lib/modules/home/views/home_page.dart index e6ab03098..03e7be80f 100644 --- a/mobile/lib/modules/home/views/home_page.dart +++ b/mobile/lib/modules/home/views/home_page.dart @@ -191,9 +191,10 @@ class HomePage extends HookConsumerWidget { processing.value = true; selectionEnabledHook.value = false; try { - ref - .read(manualUploadProvider.notifier) - .uploadAssets(context, selection.value); + ref.read(manualUploadProvider.notifier).uploadAssets( + context, + selection.value.where((a) => a.storage == AssetState.local), + ); } finally { processing.value = false; } diff --git a/mobile/lib/modules/login/services/oauth.service.dart b/mobile/lib/modules/login/services/oauth.service.dart index e8b516d35..e7fd43344 100644 --- a/mobile/lib/modules/login/services/oauth.service.dart +++ b/mobile/lib/modules/login/services/oauth.service.dart @@ -17,7 +17,7 @@ class OAuthService { // Resolve API server endpoint from user provided serverUrl await _apiService.resolveAndSetEndpoint(serverUrl); - return await _apiService.oAuthApi.generateConfig( + return await _apiService.oAuthApi.generateOAuthConfig( OAuthConfigDto(redirectUri: '$callbackUrlScheme:/'), ); } @@ -29,7 +29,7 @@ class OAuthService { callbackUrlScheme: callbackUrlScheme, ); - return await _apiService.oAuthApi.callback( + return await _apiService.oAuthApi.finishOAuth( OAuthCallbackDto( url: result, ), diff --git a/mobile/lib/modules/login/ui/login_form.dart b/mobile/lib/modules/login/ui/login_form.dart index 7622b0b53..58c7feec2 100644 --- a/mobile/lib/modules/login/ui/login_form.dart +++ b/mobile/lib/modules/login/ui/login_form.dart @@ -65,7 +65,7 @@ class LoginForm extends HookConsumerWidget { isLoadingServer.value = true; final endpoint = await apiService.resolveAndSetEndpoint(serverUrl); - final loginConfig = await apiService.oAuthApi.generateConfig( + final loginConfig = await apiService.oAuthApi.generateOAuthConfig( OAuthConfigDto(redirectUri: serverUrl), ); diff --git a/mobile/lib/shared/models/exif_info.dart b/mobile/lib/shared/models/exif_info.dart index 568e4ce13..a61fd2c28 100644 --- a/mobile/lib/shared/models/exif_info.dart +++ b/mobile/lib/shared/models/exif_info.dart @@ -8,6 +8,8 @@ part 'exif_info.g.dart'; class ExifInfo { Id? id; int? fileSize; + DateTime? dateTimeOriginal; + String? timeZone; String? make; String? model; String? lens; @@ -47,6 +49,8 @@ class ExifInfo { ExifInfo.fromDto(ExifResponseDto dto) : fileSize = dto.fileSizeInByte, + dateTimeOriginal = dto.dateTimeOriginal, + timeZone = dto.timeZone, make = dto.make, model = dto.model, lens = dto.lensModel, @@ -64,6 +68,8 @@ class ExifInfo { ExifInfo({ this.id, this.fileSize, + this.dateTimeOriginal, + this.timeZone, this.make, this.model, this.lens, @@ -82,6 +88,8 @@ class ExifInfo { ExifInfo copyWith({ Id? id, int? fileSize, + DateTime? dateTimeOriginal, + String? timeZone, String? make, String? model, String? lens, @@ -99,6 +107,8 @@ class ExifInfo { ExifInfo( id: id ?? this.id, fileSize: fileSize ?? this.fileSize, + dateTimeOriginal: dateTimeOriginal ?? this.dateTimeOriginal, + timeZone: timeZone ?? this.timeZone, make: make ?? this.make, model: model ?? this.model, lens: lens ?? this.lens, @@ -119,6 +129,8 @@ class ExifInfo { if (other is! ExifInfo) return false; return id == other.id && fileSize == other.fileSize && + dateTimeOriginal == other.dateTimeOriginal && + timeZone == other.timeZone && make == other.make && model == other.model && lens == other.lens && @@ -139,6 +151,8 @@ class ExifInfo { int get hashCode => id.hashCode ^ fileSize.hashCode ^ + dateTimeOriginal.hashCode ^ + timeZone.hashCode ^ make.hashCode ^ model.hashCode ^ lens.hashCode ^ diff --git a/mobile/lib/shared/models/exif_info.g.dart b/mobile/lib/shared/models/exif_info.g.dart index 9122942bd..138e386c7 100644 --- a/mobile/lib/shared/models/exif_info.g.dart +++ b/mobile/lib/shared/models/exif_info.g.dart @@ -27,65 +27,75 @@ const ExifInfoSchema = CollectionSchema( name: r'country', type: IsarType.string, ), - r'description': PropertySchema( + r'dateTimeOriginal': PropertySchema( id: 2, + name: r'dateTimeOriginal', + type: IsarType.dateTime, + ), + r'description': PropertySchema( + id: 3, name: r'description', type: IsarType.string, ), r'exposureSeconds': PropertySchema( - id: 3, + id: 4, name: r'exposureSeconds', type: IsarType.float, ), r'f': PropertySchema( - id: 4, + id: 5, name: r'f', type: IsarType.float, ), r'fileSize': PropertySchema( - id: 5, + id: 6, name: r'fileSize', type: IsarType.long, ), r'iso': PropertySchema( - id: 6, + id: 7, name: r'iso', type: IsarType.int, ), r'lat': PropertySchema( - id: 7, + id: 8, name: r'lat', type: IsarType.float, ), r'lens': PropertySchema( - id: 8, + id: 9, name: r'lens', type: IsarType.string, ), r'long': PropertySchema( - id: 9, + id: 10, name: r'long', type: IsarType.float, ), r'make': PropertySchema( - id: 10, + id: 11, name: r'make', type: IsarType.string, ), r'mm': PropertySchema( - id: 11, + id: 12, name: r'mm', type: IsarType.float, ), r'model': PropertySchema( - id: 12, + id: 13, name: r'model', type: IsarType.string, ), r'state': PropertySchema( - id: 13, + id: 14, name: r'state', type: IsarType.string, + ), + r'timeZone': PropertySchema( + id: 15, + name: r'timeZone', + type: IsarType.string, ) }, estimateSize: _exifInfoEstimateSize, @@ -150,6 +160,12 @@ int _exifInfoEstimateSize( bytesCount += 3 + value.length * 3; } } + { + final value = object.timeZone; + if (value != null) { + bytesCount += 3 + value.length * 3; + } + } return bytesCount; } @@ -161,18 +177,20 @@ void _exifInfoSerialize( ) { writer.writeString(offsets[0], object.city); writer.writeString(offsets[1], object.country); - writer.writeString(offsets[2], object.description); - writer.writeFloat(offsets[3], object.exposureSeconds); - writer.writeFloat(offsets[4], object.f); - writer.writeLong(offsets[5], object.fileSize); - writer.writeInt(offsets[6], object.iso); - writer.writeFloat(offsets[7], object.lat); - writer.writeString(offsets[8], object.lens); - writer.writeFloat(offsets[9], object.long); - writer.writeString(offsets[10], object.make); - writer.writeFloat(offsets[11], object.mm); - writer.writeString(offsets[12], object.model); - writer.writeString(offsets[13], object.state); + writer.writeDateTime(offsets[2], object.dateTimeOriginal); + writer.writeString(offsets[3], object.description); + writer.writeFloat(offsets[4], object.exposureSeconds); + writer.writeFloat(offsets[5], object.f); + writer.writeLong(offsets[6], object.fileSize); + writer.writeInt(offsets[7], object.iso); + writer.writeFloat(offsets[8], object.lat); + writer.writeString(offsets[9], object.lens); + writer.writeFloat(offsets[10], object.long); + writer.writeString(offsets[11], object.make); + writer.writeFloat(offsets[12], object.mm); + writer.writeString(offsets[13], object.model); + writer.writeString(offsets[14], object.state); + writer.writeString(offsets[15], object.timeZone); } ExifInfo _exifInfoDeserialize( @@ -184,19 +202,21 @@ ExifInfo _exifInfoDeserialize( final object = ExifInfo( city: reader.readStringOrNull(offsets[0]), country: reader.readStringOrNull(offsets[1]), - description: reader.readStringOrNull(offsets[2]), - exposureSeconds: reader.readFloatOrNull(offsets[3]), - f: reader.readFloatOrNull(offsets[4]), - fileSize: reader.readLongOrNull(offsets[5]), + dateTimeOriginal: reader.readDateTimeOrNull(offsets[2]), + description: reader.readStringOrNull(offsets[3]), + exposureSeconds: reader.readFloatOrNull(offsets[4]), + f: reader.readFloatOrNull(offsets[5]), + fileSize: reader.readLongOrNull(offsets[6]), id: id, - iso: reader.readIntOrNull(offsets[6]), - lat: reader.readFloatOrNull(offsets[7]), - lens: reader.readStringOrNull(offsets[8]), - long: reader.readFloatOrNull(offsets[9]), - make: reader.readStringOrNull(offsets[10]), - mm: reader.readFloatOrNull(offsets[11]), - model: reader.readStringOrNull(offsets[12]), - state: reader.readStringOrNull(offsets[13]), + iso: reader.readIntOrNull(offsets[7]), + lat: reader.readFloatOrNull(offsets[8]), + lens: reader.readStringOrNull(offsets[9]), + long: reader.readFloatOrNull(offsets[10]), + make: reader.readStringOrNull(offsets[11]), + mm: reader.readFloatOrNull(offsets[12]), + model: reader.readStringOrNull(offsets[13]), + state: reader.readStringOrNull(offsets[14]), + timeZone: reader.readStringOrNull(offsets[15]), ); return object; } @@ -213,29 +233,33 @@ P _exifInfoDeserializeProp

( case 1: return (reader.readStringOrNull(offset)) as P; case 2: - return (reader.readStringOrNull(offset)) as P; + return (reader.readDateTimeOrNull(offset)) as P; case 3: - return (reader.readFloatOrNull(offset)) as P; + return (reader.readStringOrNull(offset)) as P; case 4: return (reader.readFloatOrNull(offset)) as P; case 5: - return (reader.readLongOrNull(offset)) as P; + return (reader.readFloatOrNull(offset)) as P; case 6: - return (reader.readIntOrNull(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 7: - return (reader.readFloatOrNull(offset)) as P; + return (reader.readIntOrNull(offset)) as P; case 8: - return (reader.readStringOrNull(offset)) as P; + return (reader.readFloatOrNull(offset)) as P; case 9: - return (reader.readFloatOrNull(offset)) as P; + return (reader.readStringOrNull(offset)) as P; case 10: - return (reader.readStringOrNull(offset)) as P; - case 11: return (reader.readFloatOrNull(offset)) as P; - case 12: + case 11: return (reader.readStringOrNull(offset)) as P; + case 12: + return (reader.readFloatOrNull(offset)) as P; case 13: return (reader.readStringOrNull(offset)) as P; + case 14: + return (reader.readStringOrNull(offset)) as P; + case 15: + return (reader.readStringOrNull(offset)) as P; default: throw IsarError('Unknown property with id $propertyId'); } @@ -622,6 +646,80 @@ extension ExifInfoQueryFilter }); } + QueryBuilder + dateTimeOriginalIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'dateTimeOriginal', + )); + }); + } + + QueryBuilder + dateTimeOriginalIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'dateTimeOriginal', + )); + }); + } + + QueryBuilder + dateTimeOriginalEqualTo(DateTime? value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'dateTimeOriginal', + value: value, + )); + }); + } + + QueryBuilder + dateTimeOriginalGreaterThan( + DateTime? value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'dateTimeOriginal', + value: value, + )); + }); + } + + QueryBuilder + dateTimeOriginalLessThan( + DateTime? value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'dateTimeOriginal', + value: value, + )); + }); + } + + QueryBuilder + dateTimeOriginalBetween( + DateTime? lower, + DateTime? upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'dateTimeOriginal', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + QueryBuilder descriptionIsNull() { return QueryBuilder.apply(this, (query) { return query.addFilterCondition(const FilterCondition.isNull( @@ -1956,6 +2054,152 @@ extension ExifInfoQueryFilter )); }); } + + QueryBuilder timeZoneIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'timeZone', + )); + }); + } + + QueryBuilder timeZoneIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'timeZone', + )); + }); + } + + QueryBuilder timeZoneEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'timeZone', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder timeZoneGreaterThan( + String? value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'timeZone', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder timeZoneLessThan( + String? value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'timeZone', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder timeZoneBetween( + String? lower, + String? upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'timeZone', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder timeZoneStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'timeZone', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder timeZoneEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'timeZone', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder timeZoneContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'timeZone', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder timeZoneMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'timeZone', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder timeZoneIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'timeZone', + value: '', + )); + }); + } + + QueryBuilder timeZoneIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'timeZone', + value: '', + )); + }); + } } extension ExifInfoQueryObject @@ -1989,6 +2233,18 @@ extension ExifInfoQuerySortBy on QueryBuilder { }); } + QueryBuilder sortByDateTimeOriginal() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'dateTimeOriginal', Sort.asc); + }); + } + + QueryBuilder sortByDateTimeOriginalDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'dateTimeOriginal', Sort.desc); + }); + } + QueryBuilder sortByDescription() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'description', Sort.asc); @@ -2132,6 +2388,18 @@ extension ExifInfoQuerySortBy on QueryBuilder { return query.addSortBy(r'state', Sort.desc); }); } + + QueryBuilder sortByTimeZone() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'timeZone', Sort.asc); + }); + } + + QueryBuilder sortByTimeZoneDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'timeZone', Sort.desc); + }); + } } extension ExifInfoQuerySortThenBy @@ -2160,6 +2428,18 @@ extension ExifInfoQuerySortThenBy }); } + QueryBuilder thenByDateTimeOriginal() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'dateTimeOriginal', Sort.asc); + }); + } + + QueryBuilder thenByDateTimeOriginalDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'dateTimeOriginal', Sort.desc); + }); + } + QueryBuilder thenByDescription() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'description', Sort.asc); @@ -2315,6 +2595,18 @@ extension ExifInfoQuerySortThenBy return query.addSortBy(r'state', Sort.desc); }); } + + QueryBuilder thenByTimeZone() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'timeZone', Sort.asc); + }); + } + + QueryBuilder thenByTimeZoneDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'timeZone', Sort.desc); + }); + } } extension ExifInfoQueryWhereDistinct @@ -2333,6 +2625,12 @@ extension ExifInfoQueryWhereDistinct }); } + QueryBuilder distinctByDateTimeOriginal() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'dateTimeOriginal'); + }); + } + QueryBuilder distinctByDescription( {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { @@ -2409,6 +2707,13 @@ extension ExifInfoQueryWhereDistinct return query.addDistinctBy(r'state', caseSensitive: caseSensitive); }); } + + QueryBuilder distinctByTimeZone( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'timeZone', caseSensitive: caseSensitive); + }); + } } extension ExifInfoQueryProperty @@ -2431,6 +2736,13 @@ extension ExifInfoQueryProperty }); } + QueryBuilder + dateTimeOriginalProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'dateTimeOriginal'); + }); + } + QueryBuilder descriptionProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'description'); @@ -2502,4 +2814,10 @@ extension ExifInfoQueryProperty return query.addPropertyName(r'state'); }); } + + QueryBuilder timeZoneProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'timeZone'); + }); + } } diff --git a/mobile/lib/shared/providers/server_info.provider.dart b/mobile/lib/shared/providers/server_info.provider.dart index 514b7b0e1..b0bcf89b1 100644 --- a/mobile/lib/shared/providers/server_info.provider.dart +++ b/mobile/lib/shared/providers/server_info.provider.dart @@ -66,7 +66,7 @@ class ServerInfoNotifier extends StateNotifier { state = state.copyWith( isVersionMismatch: true, versionMismatchErrorMessage: - "Server is out of date in major version. Some functionalities might not work correctly. Download and rebuild server", + "Server is out of date. Please update to the latest major version.", ); return; @@ -76,7 +76,7 @@ class ServerInfoNotifier extends StateNotifier { state = state.copyWith( isVersionMismatch: true, versionMismatchErrorMessage: - "Server is out of date in minor version. Some functionalities might not work correctly. Consider download and rebuild server", + "Server is out of date. Consider updating to the latest minor version.", ); return; diff --git a/mobile/lib/shared/ui/app_bar_dialog/app_bar_dialog.dart b/mobile/lib/shared/ui/app_bar_dialog/app_bar_dialog.dart index b17fce86d..ede113837 100644 --- a/mobile/lib/shared/ui/app_bar_dialog/app_bar_dialog.dart +++ b/mobile/lib/shared/ui/app_bar_dialog/app_bar_dialog.dart @@ -194,6 +194,7 @@ class ImmichAppBarDialog extends HookConsumerWidget { Navigator.of(context).pop(); launchUrl( Uri.parse('https://immich.app'), + mode: LaunchMode.externalApplication, ); }, child: Text( @@ -213,6 +214,7 @@ class ImmichAppBarDialog extends HookConsumerWidget { Navigator.of(context).pop(); launchUrl( Uri.parse('https://github.com/immich-app/immich'), + mode: LaunchMode.externalApplication, ); }, child: Text( diff --git a/mobile/lib/shared/ui/app_bar_dialog/app_bar_server_info.dart b/mobile/lib/shared/ui/app_bar_dialog/app_bar_server_info.dart index 8ef3c09b5..fa4a73536 100644 --- a/mobile/lib/shared/ui/app_bar_dialog/app_bar_server_info.dart +++ b/mobile/lib/shared/ui/app_bar_dialog/app_bar_server_info.dart @@ -182,19 +182,36 @@ class AppBarServerInfo extends HookConsumerWidget { child: Container( width: 200, padding: const EdgeInsets.only(right: 10.0), - child: Text( - getServerUrl() ?? '--', - style: TextStyle( - fontSize: 11, - color: Theme.of(context) - .textTheme - .labelSmall - ?.color - ?.withOpacity(0.5), - fontWeight: FontWeight.bold, - overflow: TextOverflow.ellipsis, + child: Tooltip( + verticalOffset: 0, + decoration: BoxDecoration( + color: + Theme.of(context).primaryColor.withOpacity(0.9), + borderRadius: BorderRadius.circular(10), + ), + textStyle: TextStyle( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.black + : Colors.white, + fontWeight: FontWeight.bold, + ), + message: getServerUrl() ?? '--', + preferBelow: false, + triggerMode: TooltipTriggerMode.tap, + child: Text( + getServerUrl() ?? '--', + style: TextStyle( + fontSize: 11, + color: Theme.of(context) + .textTheme + .labelSmall + ?.color + ?.withOpacity(0.5), + fontWeight: FontWeight.bold, + overflow: TextOverflow.ellipsis, + ), + textAlign: TextAlign.end, ), - textAlign: TextAlign.end, ), ), ), diff --git a/mobile/lib/shared/ui/immich_app_bar.dart b/mobile/lib/shared/ui/immich_app_bar.dart index ad8195354..3510931f6 100644 --- a/mobile/lib/shared/ui/immich_app_bar.dart +++ b/mobile/lib/shared/ui/immich_app_bar.dart @@ -31,7 +31,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget { final isDarkMode = Theme.of(context).brightness == Brightness.dark; const widgetSize = 30.0; - buildProfilePhoto() { + buildProfileIndicator() { return InkWell( onTap: () => showDialog( context: context, @@ -39,37 +39,33 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget { builder: (ctx) => const ImmichAppBarDialog(), ), borderRadius: BorderRadius.circular(12), - child: authState.profileImagePath.isEmpty || user == null - ? const Icon( - Icons.face_outlined, - size: widgetSize, - ) - : UserCircleAvatar( - radius: 15, - size: 27, - user: user, - ), - ); - } - - buildProfileIndicator() { - return Badge( - label: Container( - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(widgetSize / 2), - ), - child: const Icon( - Icons.info, - color: Color.fromARGB(255, 243, 188, 106), - size: widgetSize / 2, + child: Badge( + label: Container( + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(widgetSize / 2), + ), + child: const Icon( + Icons.info, + color: Color.fromARGB(255, 243, 188, 106), + size: widgetSize / 2, + ), ), + backgroundColor: Colors.transparent, + alignment: Alignment.bottomRight, + isLabelVisible: serverInfoState.isVersionMismatch, + offset: const Offset(2, 2), + child: authState.profileImagePath.isEmpty || user == null + ? const Icon( + Icons.face_outlined, + size: widgetSize, + ) + : UserCircleAvatar( + radius: 15, + size: 27, + user: user, + ), ), - backgroundColor: Colors.transparent, - alignment: Alignment.bottomRight, - isLabelVisible: serverInfoState.isVersionMismatch, - offset: const Offset(2, 2), - child: buildProfilePhoto(), ); } diff --git a/mobile/openapi/.openapi-generator/FILES b/mobile/openapi/.openapi-generator/FILES index 6350677f1..52b863a6f 100644 --- a/mobile/openapi/.openapi-generator/FILES +++ b/mobile/openapi/.openapi-generator/FILES @@ -8,6 +8,10 @@ doc/APIKeyCreateDto.md doc/APIKeyCreateResponseDto.md doc/APIKeyResponseDto.md doc/APIKeyUpdateDto.md +doc/ActivityApi.md +doc/ActivityCreateDto.md +doc/ActivityResponseDto.md +doc/ActivityStatisticsResponseDto.md doc/AddUsersDto.md doc/AdminSignupResponseDto.md doc/AlbumApi.md @@ -97,6 +101,7 @@ doc/PersonResponseDto.md doc/PersonStatisticsResponseDto.md doc/PersonUpdateDto.md doc/QueueStatusDto.md +doc/ReactionType.md doc/RecognitionConfig.md doc/ScanLibraryDto.md doc/SearchAlbumResponseDto.md @@ -128,6 +133,8 @@ doc/SystemConfigApi.md doc/SystemConfigDto.md doc/SystemConfigFFmpegDto.md doc/SystemConfigJobDto.md +doc/SystemConfigLibraryDto.md +doc/SystemConfigLibraryScanDto.md doc/SystemConfigMachineLearningDto.md doc/SystemConfigMapDto.md doc/SystemConfigNewVersionCheckDto.md @@ -156,11 +163,13 @@ doc/UpdateTagDto.md doc/UpdateUserDto.md doc/UsageByUserDto.md doc/UserApi.md +doc/UserDto.md doc/UserResponseDto.md doc/ValidateAccessTokenResponseDto.md doc/VideoCodec.md git_push.sh lib/api.dart +lib/api/activity_api.dart lib/api/album_api.dart lib/api/api_key_api.dart lib/api/asset_api.dart @@ -185,6 +194,9 @@ lib/auth/authentication.dart lib/auth/http_basic_auth.dart lib/auth/http_bearer_auth.dart lib/auth/oauth.dart +lib/model/activity_create_dto.dart +lib/model/activity_response_dto.dart +lib/model/activity_statistics_response_dto.dart lib/model/add_users_dto.dart lib/model/admin_signup_response_dto.dart lib/model/album_count_response_dto.dart @@ -269,6 +281,7 @@ lib/model/person_response_dto.dart lib/model/person_statistics_response_dto.dart lib/model/person_update_dto.dart lib/model/queue_status_dto.dart +lib/model/reaction_type.dart lib/model/recognition_config.dart lib/model/scan_library_dto.dart lib/model/search_album_response_dto.dart @@ -296,6 +309,8 @@ lib/model/smart_info_response_dto.dart lib/model/system_config_dto.dart lib/model/system_config_f_fmpeg_dto.dart lib/model/system_config_job_dto.dart +lib/model/system_config_library_dto.dart +lib/model/system_config_library_scan_dto.dart lib/model/system_config_machine_learning_dto.dart lib/model/system_config_map_dto.dart lib/model/system_config_new_version_check_dto.dart @@ -322,10 +337,15 @@ lib/model/update_stack_parent_dto.dart lib/model/update_tag_dto.dart lib/model/update_user_dto.dart lib/model/usage_by_user_dto.dart +lib/model/user_dto.dart lib/model/user_response_dto.dart lib/model/validate_access_token_response_dto.dart lib/model/video_codec.dart pubspec.yaml +test/activity_api_test.dart +test/activity_create_dto_test.dart +test/activity_response_dto_test.dart +test/activity_statistics_response_dto_test.dart test/add_users_dto_test.dart test/admin_signup_response_dto_test.dart test/album_api_test.dart @@ -420,6 +440,7 @@ test/person_response_dto_test.dart test/person_statistics_response_dto_test.dart test/person_update_dto_test.dart test/queue_status_dto_test.dart +test/reaction_type_test.dart test/recognition_config_test.dart test/scan_library_dto_test.dart test/search_album_response_dto_test.dart @@ -451,6 +472,8 @@ test/system_config_api_test.dart test/system_config_dto_test.dart test/system_config_f_fmpeg_dto_test.dart test/system_config_job_dto_test.dart +test/system_config_library_dto_test.dart +test/system_config_library_scan_dto_test.dart test/system_config_machine_learning_dto_test.dart test/system_config_map_dto_test.dart test/system_config_new_version_check_dto_test.dart @@ -479,6 +502,7 @@ test/update_tag_dto_test.dart test/update_user_dto_test.dart test/usage_by_user_dto_test.dart test/user_api_test.dart +test/user_dto_test.dart test/user_response_dto_test.dart test/validate_access_token_response_dto_test.dart test/video_codec_test.dart diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index 6ec603962..70ef217a5 100644 --- a/mobile/openapi/README.md +++ b/mobile/openapi/README.md @@ -3,7 +3,7 @@ Immich API This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: -- API version: 1.83.0 +- API version: 1.84.0 - Build package: org.openapitools.codegen.languages.DartClientCodegen ## Requirements @@ -58,10 +58,10 @@ final api_instance = APIKeyApi(); final aPIKeyCreateDto = APIKeyCreateDto(); // APIKeyCreateDto | try { - final result = api_instance.createKey(aPIKeyCreateDto); + final result = api_instance.createApiKey(aPIKeyCreateDto); print(result); } catch (e) { - print('Exception when calling APIKeyApi->createKey: $e\n'); + print('Exception when calling APIKeyApi->createApiKey: $e\n'); } ``` @@ -72,11 +72,15 @@ All URIs are relative to */api* Class | Method | HTTP request | Description ------------ | ------------- | ------------- | ------------- -*APIKeyApi* | [**createKey**](doc//APIKeyApi.md#createkey) | **POST** /api-key | -*APIKeyApi* | [**deleteKey**](doc//APIKeyApi.md#deletekey) | **DELETE** /api-key/{id} | -*APIKeyApi* | [**getKey**](doc//APIKeyApi.md#getkey) | **GET** /api-key/{id} | -*APIKeyApi* | [**getKeys**](doc//APIKeyApi.md#getkeys) | **GET** /api-key | -*APIKeyApi* | [**updateKey**](doc//APIKeyApi.md#updatekey) | **PUT** /api-key/{id} | +*APIKeyApi* | [**createApiKey**](doc//APIKeyApi.md#createapikey) | **POST** /api-key | +*APIKeyApi* | [**deleteApiKey**](doc//APIKeyApi.md#deleteapikey) | **DELETE** /api-key/{id} | +*APIKeyApi* | [**getApiKey**](doc//APIKeyApi.md#getapikey) | **GET** /api-key/{id} | +*APIKeyApi* | [**getApiKeys**](doc//APIKeyApi.md#getapikeys) | **GET** /api-key | +*APIKeyApi* | [**updateApiKey**](doc//APIKeyApi.md#updateapikey) | **PUT** /api-key/{id} | +*ActivityApi* | [**createActivity**](doc//ActivityApi.md#createactivity) | **POST** /activity | +*ActivityApi* | [**deleteActivity**](doc//ActivityApi.md#deleteactivity) | **DELETE** /activity/{id} | +*ActivityApi* | [**getActivities**](doc//ActivityApi.md#getactivities) | **GET** /activity | +*ActivityApi* | [**getActivityStatistics**](doc//ActivityApi.md#getactivitystatistics) | **GET** /activity/statistics | *AlbumApi* | [**addAssetsToAlbum**](doc//AlbumApi.md#addassetstoalbum) | **PUT** /album/{id}/assets | *AlbumApi* | [**addUsersToAlbum**](doc//AlbumApi.md#adduserstoalbum) | **PUT** /album/{id}/users | *AlbumApi* | [**createAlbum**](doc//AlbumApi.md#createalbum) | **POST** /album | @@ -87,7 +91,7 @@ Class | Method | HTTP request | Description *AlbumApi* | [**removeAssetFromAlbum**](doc//AlbumApi.md#removeassetfromalbum) | **DELETE** /album/{id}/assets | *AlbumApi* | [**removeUserFromAlbum**](doc//AlbumApi.md#removeuserfromalbum) | **DELETE** /album/{id}/user/{userId} | *AlbumApi* | [**updateAlbumInfo**](doc//AlbumApi.md#updatealbuminfo) | **PATCH** /album/{id} | -*AssetApi* | [**bulkUploadCheck**](doc//AssetApi.md#bulkuploadcheck) | **POST** /asset/bulk-upload-check | +*AssetApi* | [**checkBulkUpload**](doc//AssetApi.md#checkbulkupload) | **POST** /asset/bulk-upload-check | *AssetApi* | [**checkExistingAssets**](doc//AssetApi.md#checkexistingassets) | **POST** /asset/exist | *AssetApi* | [**deleteAssets**](doc//AssetApi.md#deleteassets) | **DELETE** /asset | *AssetApi* | [**downloadArchive**](doc//AssetApi.md#downloadarchive) | **POST** /asset/download/archive | @@ -96,15 +100,15 @@ Class | Method | HTTP request | Description *AssetApi* | [**getAllAssets**](doc//AssetApi.md#getallassets) | **GET** /asset | *AssetApi* | [**getAssetById**](doc//AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} | *AssetApi* | [**getAssetSearchTerms**](doc//AssetApi.md#getassetsearchterms) | **GET** /asset/search-terms | -*AssetApi* | [**getAssetStats**](doc//AssetApi.md#getassetstats) | **GET** /asset/statistics | +*AssetApi* | [**getAssetStatistics**](doc//AssetApi.md#getassetstatistics) | **GET** /asset/statistics | *AssetApi* | [**getAssetThumbnail**](doc//AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{id} | -*AssetApi* | [**getByTimeBucket**](doc//AssetApi.md#getbytimebucket) | **GET** /asset/time-bucket | *AssetApi* | [**getCuratedLocations**](doc//AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations | *AssetApi* | [**getCuratedObjects**](doc//AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects | *AssetApi* | [**getDownloadInfo**](doc//AssetApi.md#getdownloadinfo) | **POST** /asset/download/info | *AssetApi* | [**getMapMarkers**](doc//AssetApi.md#getmapmarkers) | **GET** /asset/map-marker | *AssetApi* | [**getMemoryLane**](doc//AssetApi.md#getmemorylane) | **GET** /asset/memory-lane | *AssetApi* | [**getRandom**](doc//AssetApi.md#getrandom) | **GET** /asset/random | +*AssetApi* | [**getTimeBucket**](doc//AssetApi.md#gettimebucket) | **GET** /asset/time-bucket | *AssetApi* | [**getTimeBuckets**](doc//AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets | *AssetApi* | [**getUserAssetsByDeviceId**](doc//AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} | *AssetApi* | [**importFile**](doc//AssetApi.md#importfile) | **POST** /asset/import | @@ -121,30 +125,30 @@ Class | Method | HTTP request | Description *AuditApi* | [**getAuditDeletes**](doc//AuditApi.md#getauditdeletes) | **GET** /audit/deletes | *AuditApi* | [**getAuditFiles**](doc//AuditApi.md#getauditfiles) | **GET** /audit/file-report | *AuditApi* | [**getFileChecksums**](doc//AuditApi.md#getfilechecksums) | **POST** /audit/file-report/checksum | -*AuthenticationApi* | [**adminSignUp**](doc//AuthenticationApi.md#adminsignup) | **POST** /auth/admin-sign-up | *AuthenticationApi* | [**changePassword**](doc//AuthenticationApi.md#changepassword) | **POST** /auth/change-password | *AuthenticationApi* | [**getAuthDevices**](doc//AuthenticationApi.md#getauthdevices) | **GET** /auth/devices | *AuthenticationApi* | [**login**](doc//AuthenticationApi.md#login) | **POST** /auth/login | *AuthenticationApi* | [**logout**](doc//AuthenticationApi.md#logout) | **POST** /auth/logout | *AuthenticationApi* | [**logoutAuthDevice**](doc//AuthenticationApi.md#logoutauthdevice) | **DELETE** /auth/devices/{id} | *AuthenticationApi* | [**logoutAuthDevices**](doc//AuthenticationApi.md#logoutauthdevices) | **DELETE** /auth/devices | +*AuthenticationApi* | [**signUpAdmin**](doc//AuthenticationApi.md#signupadmin) | **POST** /auth/admin-sign-up | *AuthenticationApi* | [**validateAccessToken**](doc//AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken | *JobApi* | [**getAllJobsStatus**](doc//JobApi.md#getalljobsstatus) | **GET** /jobs | *JobApi* | [**sendJobCommand**](doc//JobApi.md#sendjobcommand) | **PUT** /jobs/{id} | *LibraryApi* | [**createLibrary**](doc//LibraryApi.md#createlibrary) | **POST** /library | *LibraryApi* | [**deleteLibrary**](doc//LibraryApi.md#deletelibrary) | **DELETE** /library/{id} | -*LibraryApi* | [**getAllForUser**](doc//LibraryApi.md#getallforuser) | **GET** /library | +*LibraryApi* | [**getLibraries**](doc//LibraryApi.md#getlibraries) | **GET** /library | *LibraryApi* | [**getLibraryInfo**](doc//LibraryApi.md#getlibraryinfo) | **GET** /library/{id} | *LibraryApi* | [**getLibraryStatistics**](doc//LibraryApi.md#getlibrarystatistics) | **GET** /library/{id}/statistics | *LibraryApi* | [**removeOfflineFiles**](doc//LibraryApi.md#removeofflinefiles) | **POST** /library/{id}/removeOffline | *LibraryApi* | [**scanLibrary**](doc//LibraryApi.md#scanlibrary) | **POST** /library/{id}/scan | *LibraryApi* | [**updateLibrary**](doc//LibraryApi.md#updatelibrary) | **PUT** /library/{id} | -*OAuthApi* | [**authorizeOAuth**](doc//OAuthApi.md#authorizeoauth) | **POST** /oauth/authorize | -*OAuthApi* | [**callback**](doc//OAuthApi.md#callback) | **POST** /oauth/callback | -*OAuthApi* | [**generateConfig**](doc//OAuthApi.md#generateconfig) | **POST** /oauth/config | -*OAuthApi* | [**link**](doc//OAuthApi.md#link) | **POST** /oauth/link | -*OAuthApi* | [**mobileRedirect**](doc//OAuthApi.md#mobileredirect) | **GET** /oauth/mobile-redirect | -*OAuthApi* | [**unlink**](doc//OAuthApi.md#unlink) | **POST** /oauth/unlink | +*OAuthApi* | [**finishOAuth**](doc//OAuthApi.md#finishoauth) | **POST** /oauth/callback | +*OAuthApi* | [**generateOAuthConfig**](doc//OAuthApi.md#generateoauthconfig) | **POST** /oauth/config | +*OAuthApi* | [**linkOAuthAccount**](doc//OAuthApi.md#linkoauthaccount) | **POST** /oauth/link | +*OAuthApi* | [**redirectOAuthToMobile**](doc//OAuthApi.md#redirectoauthtomobile) | **GET** /oauth/mobile-redirect | +*OAuthApi* | [**startOAuth**](doc//OAuthApi.md#startoauth) | **POST** /oauth/authorize | +*OAuthApi* | [**unlinkOAuthAccount**](doc//OAuthApi.md#unlinkoauthaccount) | **POST** /oauth/unlink | *PartnerApi* | [**createPartner**](doc//PartnerApi.md#createpartner) | **POST** /partner/{id} | *PartnerApi* | [**getPartners**](doc//PartnerApi.md#getpartners) | **GET** /partner | *PartnerApi* | [**removePartner**](doc//PartnerApi.md#removepartner) | **DELETE** /partner/{id} | @@ -162,8 +166,8 @@ Class | Method | HTTP request | Description *ServerInfoApi* | [**getServerConfig**](doc//ServerInfoApi.md#getserverconfig) | **GET** /server-info/config | *ServerInfoApi* | [**getServerFeatures**](doc//ServerInfoApi.md#getserverfeatures) | **GET** /server-info/features | *ServerInfoApi* | [**getServerInfo**](doc//ServerInfoApi.md#getserverinfo) | **GET** /server-info | +*ServerInfoApi* | [**getServerStatistics**](doc//ServerInfoApi.md#getserverstatistics) | **GET** /server-info/statistics | *ServerInfoApi* | [**getServerVersion**](doc//ServerInfoApi.md#getserverversion) | **GET** /server-info/version | -*ServerInfoApi* | [**getStats**](doc//ServerInfoApi.md#getstats) | **GET** /server-info/stats | *ServerInfoApi* | [**getSupportedMediaTypes**](doc//ServerInfoApi.md#getsupportedmediatypes) | **GET** /server-info/media-types | *ServerInfoApi* | [**getTheme**](doc//ServerInfoApi.md#gettheme) | **GET** /server-info/theme | *ServerInfoApi* | [**pingServer**](doc//ServerInfoApi.md#pingserver) | **GET** /server-info/ping | @@ -176,7 +180,7 @@ Class | Method | HTTP request | Description *SharedLinkApi* | [**removeSharedLinkAssets**](doc//SharedLinkApi.md#removesharedlinkassets) | **DELETE** /shared-link/{id}/assets | *SharedLinkApi* | [**updateSharedLink**](doc//SharedLinkApi.md#updatesharedlink) | **PATCH** /shared-link/{id} | *SystemConfigApi* | [**getConfig**](doc//SystemConfigApi.md#getconfig) | **GET** /system-config | -*SystemConfigApi* | [**getDefaults**](doc//SystemConfigApi.md#getdefaults) | **GET** /system-config/defaults | +*SystemConfigApi* | [**getConfigDefaults**](doc//SystemConfigApi.md#getconfigdefaults) | **GET** /system-config/defaults | *SystemConfigApi* | [**getStorageTemplateOptions**](doc//SystemConfigApi.md#getstoragetemplateoptions) | **GET** /system-config/storage-template-options | *SystemConfigApi* | [**updateConfig**](doc//SystemConfigApi.md#updateconfig) | **PUT** /system-config | *TagApi* | [**createTag**](doc//TagApi.md#createtag) | **POST** /tag | @@ -204,6 +208,9 @@ Class | Method | HTTP request | Description - [APIKeyCreateResponseDto](doc//APIKeyCreateResponseDto.md) - [APIKeyResponseDto](doc//APIKeyResponseDto.md) - [APIKeyUpdateDto](doc//APIKeyUpdateDto.md) + - [ActivityCreateDto](doc//ActivityCreateDto.md) + - [ActivityResponseDto](doc//ActivityResponseDto.md) + - [ActivityStatisticsResponseDto](doc//ActivityStatisticsResponseDto.md) - [AddUsersDto](doc//AddUsersDto.md) - [AdminSignupResponseDto](doc//AdminSignupResponseDto.md) - [AlbumCountResponseDto](doc//AlbumCountResponseDto.md) @@ -284,6 +291,7 @@ Class | Method | HTTP request | Description - [PersonStatisticsResponseDto](doc//PersonStatisticsResponseDto.md) - [PersonUpdateDto](doc//PersonUpdateDto.md) - [QueueStatusDto](doc//QueueStatusDto.md) + - [ReactionType](doc//ReactionType.md) - [RecognitionConfig](doc//RecognitionConfig.md) - [ScanLibraryDto](doc//ScanLibraryDto.md) - [SearchAlbumResponseDto](doc//SearchAlbumResponseDto.md) @@ -311,6 +319,8 @@ Class | Method | HTTP request | Description - [SystemConfigDto](doc//SystemConfigDto.md) - [SystemConfigFFmpegDto](doc//SystemConfigFFmpegDto.md) - [SystemConfigJobDto](doc//SystemConfigJobDto.md) + - [SystemConfigLibraryDto](doc//SystemConfigLibraryDto.md) + - [SystemConfigLibraryScanDto](doc//SystemConfigLibraryScanDto.md) - [SystemConfigMachineLearningDto](doc//SystemConfigMachineLearningDto.md) - [SystemConfigMapDto](doc//SystemConfigMapDto.md) - [SystemConfigNewVersionCheckDto](doc//SystemConfigNewVersionCheckDto.md) @@ -337,6 +347,7 @@ Class | Method | HTTP request | Description - [UpdateTagDto](doc//UpdateTagDto.md) - [UpdateUserDto](doc//UpdateUserDto.md) - [UsageByUserDto](doc//UsageByUserDto.md) + - [UserDto](doc//UserDto.md) - [UserResponseDto](doc//UserResponseDto.md) - [ValidateAccessTokenResponseDto](doc//ValidateAccessTokenResponseDto.md) - [VideoCodec](doc//VideoCodec.md) diff --git a/mobile/openapi/doc/APIKeyApi.md b/mobile/openapi/doc/APIKeyApi.md index 807cb5317..69b0917bb 100644 --- a/mobile/openapi/doc/APIKeyApi.md +++ b/mobile/openapi/doc/APIKeyApi.md @@ -9,15 +9,15 @@ All URIs are relative to */api* Method | HTTP request | Description ------------- | ------------- | ------------- -[**createKey**](APIKeyApi.md#createkey) | **POST** /api-key | -[**deleteKey**](APIKeyApi.md#deletekey) | **DELETE** /api-key/{id} | -[**getKey**](APIKeyApi.md#getkey) | **GET** /api-key/{id} | -[**getKeys**](APIKeyApi.md#getkeys) | **GET** /api-key | -[**updateKey**](APIKeyApi.md#updatekey) | **PUT** /api-key/{id} | +[**createApiKey**](APIKeyApi.md#createapikey) | **POST** /api-key | +[**deleteApiKey**](APIKeyApi.md#deleteapikey) | **DELETE** /api-key/{id} | +[**getApiKey**](APIKeyApi.md#getapikey) | **GET** /api-key/{id} | +[**getApiKeys**](APIKeyApi.md#getapikeys) | **GET** /api-key | +[**updateApiKey**](APIKeyApi.md#updateapikey) | **PUT** /api-key/{id} | -# **createKey** -> APIKeyCreateResponseDto createKey(aPIKeyCreateDto) +# **createApiKey** +> APIKeyCreateResponseDto createApiKey(aPIKeyCreateDto) @@ -43,10 +43,10 @@ final api_instance = APIKeyApi(); final aPIKeyCreateDto = APIKeyCreateDto(); // APIKeyCreateDto | try { - final result = api_instance.createKey(aPIKeyCreateDto); + final result = api_instance.createApiKey(aPIKeyCreateDto); print(result); } catch (e) { - print('Exception when calling APIKeyApi->createKey: $e\n'); + print('Exception when calling APIKeyApi->createApiKey: $e\n'); } ``` @@ -71,8 +71,8 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **deleteKey** -> deleteKey(id) +# **deleteApiKey** +> deleteApiKey(id) @@ -98,9 +98,9 @@ final api_instance = APIKeyApi(); final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | try { - api_instance.deleteKey(id); + api_instance.deleteApiKey(id); } catch (e) { - print('Exception when calling APIKeyApi->deleteKey: $e\n'); + print('Exception when calling APIKeyApi->deleteApiKey: $e\n'); } ``` @@ -125,8 +125,8 @@ void (empty response body) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **getKey** -> APIKeyResponseDto getKey(id) +# **getApiKey** +> APIKeyResponseDto getApiKey(id) @@ -152,10 +152,10 @@ final api_instance = APIKeyApi(); final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | try { - final result = api_instance.getKey(id); + final result = api_instance.getApiKey(id); print(result); } catch (e) { - print('Exception when calling APIKeyApi->getKey: $e\n'); + print('Exception when calling APIKeyApi->getApiKey: $e\n'); } ``` @@ -180,8 +180,8 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **getKeys** -> List getKeys() +# **getApiKeys** +> List getApiKeys() @@ -206,10 +206,10 @@ import 'package:openapi/api.dart'; final api_instance = APIKeyApi(); try { - final result = api_instance.getKeys(); + final result = api_instance.getApiKeys(); print(result); } catch (e) { - print('Exception when calling APIKeyApi->getKeys: $e\n'); + print('Exception when calling APIKeyApi->getApiKeys: $e\n'); } ``` @@ -231,8 +231,8 @@ This endpoint does not need any parameter. [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **updateKey** -> APIKeyResponseDto updateKey(id, aPIKeyUpdateDto) +# **updateApiKey** +> APIKeyResponseDto updateApiKey(id, aPIKeyUpdateDto) @@ -259,10 +259,10 @@ final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | final aPIKeyUpdateDto = APIKeyUpdateDto(); // APIKeyUpdateDto | try { - final result = api_instance.updateKey(id, aPIKeyUpdateDto); + final result = api_instance.updateApiKey(id, aPIKeyUpdateDto); print(result); } catch (e) { - print('Exception when calling APIKeyApi->updateKey: $e\n'); + print('Exception when calling APIKeyApi->updateApiKey: $e\n'); } ``` diff --git a/mobile/openapi/doc/ActivityApi.md b/mobile/openapi/doc/ActivityApi.md new file mode 100644 index 000000000..1af3f1f49 --- /dev/null +++ b/mobile/openapi/doc/ActivityApi.md @@ -0,0 +1,244 @@ +# openapi.api.ActivityApi + +## Load the API package +```dart +import 'package:openapi/api.dart'; +``` + +All URIs are relative to */api* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**createActivity**](ActivityApi.md#createactivity) | **POST** /activity | +[**deleteActivity**](ActivityApi.md#deleteactivity) | **DELETE** /activity/{id} | +[**getActivities**](ActivityApi.md#getactivities) | **GET** /activity | +[**getActivityStatistics**](ActivityApi.md#getactivitystatistics) | **GET** /activity/statistics | + + +# **createActivity** +> ActivityResponseDto createActivity(activityCreateDto) + + + +### Example +```dart +import 'package:openapi/api.dart'; +// TODO Configure API key authorization: cookie +//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; +// uncomment below to setup prefix (e.g. Bearer) for API key, if needed +//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; +// TODO Configure API key authorization: api_key +//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; +// uncomment below to setup prefix (e.g. Bearer) for API key, if needed +//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; +// TODO Configure HTTP Bearer authorization: bearer +// Case 1. Use String Token +//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); +// Case 2. Use Function which generate token. +// String yourTokenGeneratorFunction() { ... } +//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); + +final api_instance = ActivityApi(); +final activityCreateDto = ActivityCreateDto(); // ActivityCreateDto | + +try { + final result = api_instance.createActivity(activityCreateDto); + print(result); +} catch (e) { + print('Exception when calling ActivityApi->createActivity: $e\n'); +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **activityCreateDto** | [**ActivityCreateDto**](ActivityCreateDto.md)| | + +### Return type + +[**ActivityResponseDto**](ActivityResponseDto.md) + +### Authorization + +[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **deleteActivity** +> deleteActivity(id) + + + +### Example +```dart +import 'package:openapi/api.dart'; +// TODO Configure API key authorization: cookie +//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; +// uncomment below to setup prefix (e.g. Bearer) for API key, if needed +//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; +// TODO Configure API key authorization: api_key +//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; +// uncomment below to setup prefix (e.g. Bearer) for API key, if needed +//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; +// TODO Configure HTTP Bearer authorization: bearer +// Case 1. Use String Token +//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); +// Case 2. Use Function which generate token. +// String yourTokenGeneratorFunction() { ... } +//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); + +final api_instance = ActivityApi(); +final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | + +try { + api_instance.deleteActivity(id); +} catch (e) { + print('Exception when calling ActivityApi->deleteActivity: $e\n'); +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **String**| | + +### Return type + +void (empty response body) + +### Authorization + +[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **getActivities** +> List getActivities(albumId, assetId, type, userId) + + + +### Example +```dart +import 'package:openapi/api.dart'; +// TODO Configure API key authorization: cookie +//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; +// uncomment below to setup prefix (e.g. Bearer) for API key, if needed +//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; +// TODO Configure API key authorization: api_key +//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; +// uncomment below to setup prefix (e.g. Bearer) for API key, if needed +//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; +// TODO Configure HTTP Bearer authorization: bearer +// Case 1. Use String Token +//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); +// Case 2. Use Function which generate token. +// String yourTokenGeneratorFunction() { ... } +//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); + +final api_instance = ActivityApi(); +final albumId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | +final assetId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | +final type = ; // ReactionType | +final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | + +try { + final result = api_instance.getActivities(albumId, assetId, type, userId); + print(result); +} catch (e) { + print('Exception when calling ActivityApi->getActivities: $e\n'); +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **albumId** | **String**| | + **assetId** | **String**| | [optional] + **type** | [**ReactionType**](.md)| | [optional] + **userId** | **String**| | [optional] + +### Return type + +[**List**](ActivityResponseDto.md) + +### Authorization + +[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **getActivityStatistics** +> ActivityStatisticsResponseDto getActivityStatistics(albumId, assetId) + + + +### Example +```dart +import 'package:openapi/api.dart'; +// TODO Configure API key authorization: cookie +//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; +// uncomment below to setup prefix (e.g. Bearer) for API key, if needed +//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; +// TODO Configure API key authorization: api_key +//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; +// uncomment below to setup prefix (e.g. Bearer) for API key, if needed +//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; +// TODO Configure HTTP Bearer authorization: bearer +// Case 1. Use String Token +//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); +// Case 2. Use Function which generate token. +// String yourTokenGeneratorFunction() { ... } +//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); + +final api_instance = ActivityApi(); +final albumId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | +final assetId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | + +try { + final result = api_instance.getActivityStatistics(albumId, assetId); + print(result); +} catch (e) { + print('Exception when calling ActivityApi->getActivityStatistics: $e\n'); +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **albumId** | **String**| | + **assetId** | **String**| | [optional] + +### Return type + +[**ActivityStatisticsResponseDto**](ActivityStatisticsResponseDto.md) + +### Authorization + +[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/mobile/openapi/doc/ActivityCreateDto.md b/mobile/openapi/doc/ActivityCreateDto.md new file mode 100644 index 000000000..32cfdb5c7 --- /dev/null +++ b/mobile/openapi/doc/ActivityCreateDto.md @@ -0,0 +1,18 @@ +# openapi.model.ActivityCreateDto + +## Load the model package +```dart +import 'package:openapi/api.dart'; +``` + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**albumId** | **String** | | +**assetId** | **String** | | [optional] +**comment** | **String** | | [optional] +**type** | [**ReactionType**](ReactionType.md) | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/mobile/openapi/doc/ActivityResponseDto.md b/mobile/openapi/doc/ActivityResponseDto.md new file mode 100644 index 000000000..3b8589b61 --- /dev/null +++ b/mobile/openapi/doc/ActivityResponseDto.md @@ -0,0 +1,20 @@ +# openapi.model.ActivityResponseDto + +## Load the model package +```dart +import 'package:openapi/api.dart'; +``` + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**assetId** | **String** | | +**comment** | **String** | | [optional] +**createdAt** | [**DateTime**](DateTime.md) | | +**id** | **String** | | +**type** | **String** | | +**user** | [**UserDto**](UserDto.md) | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/mobile/openapi/doc/ActivityStatisticsResponseDto.md b/mobile/openapi/doc/ActivityStatisticsResponseDto.md new file mode 100644 index 000000000..00583aea9 --- /dev/null +++ b/mobile/openapi/doc/ActivityStatisticsResponseDto.md @@ -0,0 +1,15 @@ +# openapi.model.ActivityStatisticsResponseDto + +## Load the model package +```dart +import 'package:openapi/api.dart'; +``` + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**comments** | **int** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/mobile/openapi/doc/AssetApi.md b/mobile/openapi/doc/AssetApi.md index d606e540f..cf50f659d 100644 --- a/mobile/openapi/doc/AssetApi.md +++ b/mobile/openapi/doc/AssetApi.md @@ -9,7 +9,7 @@ All URIs are relative to */api* Method | HTTP request | Description ------------- | ------------- | ------------- -[**bulkUploadCheck**](AssetApi.md#bulkuploadcheck) | **POST** /asset/bulk-upload-check | +[**checkBulkUpload**](AssetApi.md#checkbulkupload) | **POST** /asset/bulk-upload-check | [**checkExistingAssets**](AssetApi.md#checkexistingassets) | **POST** /asset/exist | [**deleteAssets**](AssetApi.md#deleteassets) | **DELETE** /asset | [**downloadArchive**](AssetApi.md#downloadarchive) | **POST** /asset/download/archive | @@ -18,15 +18,15 @@ Method | HTTP request | Description [**getAllAssets**](AssetApi.md#getallassets) | **GET** /asset | [**getAssetById**](AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} | [**getAssetSearchTerms**](AssetApi.md#getassetsearchterms) | **GET** /asset/search-terms | -[**getAssetStats**](AssetApi.md#getassetstats) | **GET** /asset/statistics | +[**getAssetStatistics**](AssetApi.md#getassetstatistics) | **GET** /asset/statistics | [**getAssetThumbnail**](AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{id} | -[**getByTimeBucket**](AssetApi.md#getbytimebucket) | **GET** /asset/time-bucket | [**getCuratedLocations**](AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations | [**getCuratedObjects**](AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects | [**getDownloadInfo**](AssetApi.md#getdownloadinfo) | **POST** /asset/download/info | [**getMapMarkers**](AssetApi.md#getmapmarkers) | **GET** /asset/map-marker | [**getMemoryLane**](AssetApi.md#getmemorylane) | **GET** /asset/memory-lane | [**getRandom**](AssetApi.md#getrandom) | **GET** /asset/random | +[**getTimeBucket**](AssetApi.md#gettimebucket) | **GET** /asset/time-bucket | [**getTimeBuckets**](AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets | [**getUserAssetsByDeviceId**](AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} | [**importFile**](AssetApi.md#importfile) | **POST** /asset/import | @@ -41,8 +41,8 @@ Method | HTTP request | Description [**uploadFile**](AssetApi.md#uploadfile) | **POST** /asset/upload | -# **bulkUploadCheck** -> AssetBulkUploadCheckResponseDto bulkUploadCheck(assetBulkUploadCheckDto) +# **checkBulkUpload** +> AssetBulkUploadCheckResponseDto checkBulkUpload(assetBulkUploadCheckDto) @@ -70,10 +70,10 @@ final api_instance = AssetApi(); final assetBulkUploadCheckDto = AssetBulkUploadCheckDto(); // AssetBulkUploadCheckDto | try { - final result = api_instance.bulkUploadCheck(assetBulkUploadCheckDto); + final result = api_instance.checkBulkUpload(assetBulkUploadCheckDto); print(result); } catch (e) { - print('Exception when calling AssetApi->bulkUploadCheck: $e\n'); + print('Exception when calling AssetApi->checkBulkUpload: $e\n'); } ``` @@ -550,8 +550,8 @@ This endpoint does not need any parameter. [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **getAssetStats** -> AssetStatsResponseDto getAssetStats(isArchived, isFavorite, isTrashed) +# **getAssetStatistics** +> AssetStatsResponseDto getAssetStatistics(isArchived, isFavorite, isTrashed) @@ -579,10 +579,10 @@ final isFavorite = true; // bool | final isTrashed = true; // bool | try { - final result = api_instance.getAssetStats(isArchived, isFavorite, isTrashed); + final result = api_instance.getAssetStatistics(isArchived, isFavorite, isTrashed); print(result); } catch (e) { - print('Exception when calling AssetApi->getAssetStats: $e\n'); + print('Exception when calling AssetApi->getAssetStatistics: $e\n'); } ``` @@ -668,79 +668,6 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **getByTimeBucket** -> List getByTimeBucket(size, timeBucket, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final size = ; // TimeBucketSize | -final timeBucket = timeBucket_example; // String | -final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final albumId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final personId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final isArchived = true; // bool | -final isFavorite = true; // bool | -final isTrashed = true; // bool | -final withStacked = true; // bool | -final key = key_example; // String | - -try { - final result = api_instance.getByTimeBucket(size, timeBucket, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key); - print(result); -} catch (e) { - print('Exception when calling AssetApi->getByTimeBucket: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **size** | [**TimeBucketSize**](.md)| | - **timeBucket** | **String**| | - **userId** | **String**| | [optional] - **albumId** | **String**| | [optional] - **personId** | **String**| | [optional] - **isArchived** | **bool**| | [optional] - **isFavorite** | **bool**| | [optional] - **isTrashed** | **bool**| | [optional] - **withStacked** | **bool**| | [optional] - **key** | **String**| | [optional] - -### Return type - -[**List**](AssetResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - # **getCuratedLocations** > List getCuratedLocations() @@ -1073,6 +1000,79 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **getTimeBucket** +> List getTimeBucket(size, timeBucket, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key) + + + +### Example +```dart +import 'package:openapi/api.dart'; +// TODO Configure API key authorization: cookie +//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; +// uncomment below to setup prefix (e.g. Bearer) for API key, if needed +//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; +// TODO Configure API key authorization: api_key +//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; +// uncomment below to setup prefix (e.g. Bearer) for API key, if needed +//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; +// TODO Configure HTTP Bearer authorization: bearer +// Case 1. Use String Token +//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); +// Case 2. Use Function which generate token. +// String yourTokenGeneratorFunction() { ... } +//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); + +final api_instance = AssetApi(); +final size = ; // TimeBucketSize | +final timeBucket = timeBucket_example; // String | +final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | +final albumId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | +final personId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | +final isArchived = true; // bool | +final isFavorite = true; // bool | +final isTrashed = true; // bool | +final withStacked = true; // bool | +final key = key_example; // String | + +try { + final result = api_instance.getTimeBucket(size, timeBucket, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key); + print(result); +} catch (e) { + print('Exception when calling AssetApi->getTimeBucket: $e\n'); +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **size** | [**TimeBucketSize**](.md)| | + **timeBucket** | **String**| | + **userId** | **String**| | [optional] + **albumId** | **String**| | [optional] + **personId** | **String**| | [optional] + **isArchived** | **bool**| | [optional] + **isFavorite** | **bool**| | [optional] + **isTrashed** | **bool**| | [optional] + **withStacked** | **bool**| | [optional] + **key** | **String**| | [optional] + +### Return type + +[**List**](AssetResponseDto.md) + +### Authorization + +[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **getTimeBuckets** > List getTimeBuckets(size, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key) diff --git a/mobile/openapi/doc/AuthenticationApi.md b/mobile/openapi/doc/AuthenticationApi.md index 67de70096..c56f88228 100644 --- a/mobile/openapi/doc/AuthenticationApi.md +++ b/mobile/openapi/doc/AuthenticationApi.md @@ -9,57 +9,16 @@ All URIs are relative to */api* Method | HTTP request | Description ------------- | ------------- | ------------- -[**adminSignUp**](AuthenticationApi.md#adminsignup) | **POST** /auth/admin-sign-up | [**changePassword**](AuthenticationApi.md#changepassword) | **POST** /auth/change-password | [**getAuthDevices**](AuthenticationApi.md#getauthdevices) | **GET** /auth/devices | [**login**](AuthenticationApi.md#login) | **POST** /auth/login | [**logout**](AuthenticationApi.md#logout) | **POST** /auth/logout | [**logoutAuthDevice**](AuthenticationApi.md#logoutauthdevice) | **DELETE** /auth/devices/{id} | [**logoutAuthDevices**](AuthenticationApi.md#logoutauthdevices) | **DELETE** /auth/devices | +[**signUpAdmin**](AuthenticationApi.md#signupadmin) | **POST** /auth/admin-sign-up | [**validateAccessToken**](AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken | -# **adminSignUp** -> AdminSignupResponseDto adminSignUp(signUpDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; - -final api_instance = AuthenticationApi(); -final signUpDto = SignUpDto(); // SignUpDto | - -try { - final result = api_instance.adminSignUp(signUpDto); - print(result); -} catch (e) { - print('Exception when calling AuthenticationApi->adminSignUp: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **signUpDto** | [**SignUpDto**](SignUpDto.md)| | - -### Return type - -[**AdminSignupResponseDto**](AdminSignupResponseDto.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - # **changePassword** > UserResponseDto changePassword(changePasswordDto) @@ -362,6 +321,47 @@ void (empty response body) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **signUpAdmin** +> AdminSignupResponseDto signUpAdmin(signUpDto) + + + +### Example +```dart +import 'package:openapi/api.dart'; + +final api_instance = AuthenticationApi(); +final signUpDto = SignUpDto(); // SignUpDto | + +try { + final result = api_instance.signUpAdmin(signUpDto); + print(result); +} catch (e) { + print('Exception when calling AuthenticationApi->signUpAdmin: $e\n'); +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **signUpDto** | [**SignUpDto**](SignUpDto.md)| | + +### Return type + +[**AdminSignupResponseDto**](AdminSignupResponseDto.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **validateAccessToken** > ValidateAccessTokenResponseDto validateAccessToken() diff --git a/mobile/openapi/doc/LibraryApi.md b/mobile/openapi/doc/LibraryApi.md index 2362dfaea..5ecd46503 100644 --- a/mobile/openapi/doc/LibraryApi.md +++ b/mobile/openapi/doc/LibraryApi.md @@ -11,7 +11,7 @@ Method | HTTP request | Description ------------- | ------------- | ------------- [**createLibrary**](LibraryApi.md#createlibrary) | **POST** /library | [**deleteLibrary**](LibraryApi.md#deletelibrary) | **DELETE** /library/{id} | -[**getAllForUser**](LibraryApi.md#getallforuser) | **GET** /library | +[**getLibraries**](LibraryApi.md#getlibraries) | **GET** /library | [**getLibraryInfo**](LibraryApi.md#getlibraryinfo) | **GET** /library/{id} | [**getLibraryStatistics**](LibraryApi.md#getlibrarystatistics) | **GET** /library/{id}/statistics | [**removeOfflineFiles**](LibraryApi.md#removeofflinefiles) | **POST** /library/{id}/removeOffline | @@ -128,8 +128,8 @@ void (empty response body) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **getAllForUser** -> List getAllForUser() +# **getLibraries** +> List getLibraries() @@ -154,10 +154,10 @@ import 'package:openapi/api.dart'; final api_instance = LibraryApi(); try { - final result = api_instance.getAllForUser(); + final result = api_instance.getLibraries(); print(result); } catch (e) { - print('Exception when calling LibraryApi->getAllForUser: $e\n'); + print('Exception when calling LibraryApi->getLibraries: $e\n'); } ``` diff --git a/mobile/openapi/doc/OAuthApi.md b/mobile/openapi/doc/OAuthApi.md index 5a5afc2a1..fa6b19df5 100644 --- a/mobile/openapi/doc/OAuthApi.md +++ b/mobile/openapi/doc/OAuthApi.md @@ -9,57 +9,16 @@ All URIs are relative to */api* Method | HTTP request | Description ------------- | ------------- | ------------- -[**authorizeOAuth**](OAuthApi.md#authorizeoauth) | **POST** /oauth/authorize | -[**callback**](OAuthApi.md#callback) | **POST** /oauth/callback | -[**generateConfig**](OAuthApi.md#generateconfig) | **POST** /oauth/config | -[**link**](OAuthApi.md#link) | **POST** /oauth/link | -[**mobileRedirect**](OAuthApi.md#mobileredirect) | **GET** /oauth/mobile-redirect | -[**unlink**](OAuthApi.md#unlink) | **POST** /oauth/unlink | +[**finishOAuth**](OAuthApi.md#finishoauth) | **POST** /oauth/callback | +[**generateOAuthConfig**](OAuthApi.md#generateoauthconfig) | **POST** /oauth/config | +[**linkOAuthAccount**](OAuthApi.md#linkoauthaccount) | **POST** /oauth/link | +[**redirectOAuthToMobile**](OAuthApi.md#redirectoauthtomobile) | **GET** /oauth/mobile-redirect | +[**startOAuth**](OAuthApi.md#startoauth) | **POST** /oauth/authorize | +[**unlinkOAuthAccount**](OAuthApi.md#unlinkoauthaccount) | **POST** /oauth/unlink | -# **authorizeOAuth** -> OAuthAuthorizeResponseDto authorizeOAuth(oAuthConfigDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; - -final api_instance = OAuthApi(); -final oAuthConfigDto = OAuthConfigDto(); // OAuthConfigDto | - -try { - final result = api_instance.authorizeOAuth(oAuthConfigDto); - print(result); -} catch (e) { - print('Exception when calling OAuthApi->authorizeOAuth: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **oAuthConfigDto** | [**OAuthConfigDto**](OAuthConfigDto.md)| | - -### Return type - -[**OAuthAuthorizeResponseDto**](OAuthAuthorizeResponseDto.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **callback** -> LoginResponseDto callback(oAuthCallbackDto) +# **finishOAuth** +> LoginResponseDto finishOAuth(oAuthCallbackDto) @@ -71,10 +30,10 @@ final api_instance = OAuthApi(); final oAuthCallbackDto = OAuthCallbackDto(); // OAuthCallbackDto | try { - final result = api_instance.callback(oAuthCallbackDto); + final result = api_instance.finishOAuth(oAuthCallbackDto); print(result); } catch (e) { - print('Exception when calling OAuthApi->callback: $e\n'); + print('Exception when calling OAuthApi->finishOAuth: $e\n'); } ``` @@ -99,8 +58,8 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **generateConfig** -> OAuthConfigResponseDto generateConfig(oAuthConfigDto) +# **generateOAuthConfig** +> OAuthConfigResponseDto generateOAuthConfig(oAuthConfigDto) @@ -114,10 +73,10 @@ final api_instance = OAuthApi(); final oAuthConfigDto = OAuthConfigDto(); // OAuthConfigDto | try { - final result = api_instance.generateConfig(oAuthConfigDto); + final result = api_instance.generateOAuthConfig(oAuthConfigDto); print(result); } catch (e) { - print('Exception when calling OAuthApi->generateConfig: $e\n'); + print('Exception when calling OAuthApi->generateOAuthConfig: $e\n'); } ``` @@ -142,8 +101,8 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **link** -> UserResponseDto link(oAuthCallbackDto) +# **linkOAuthAccount** +> UserResponseDto linkOAuthAccount(oAuthCallbackDto) @@ -169,10 +128,10 @@ final api_instance = OAuthApi(); final oAuthCallbackDto = OAuthCallbackDto(); // OAuthCallbackDto | try { - final result = api_instance.link(oAuthCallbackDto); + final result = api_instance.linkOAuthAccount(oAuthCallbackDto); print(result); } catch (e) { - print('Exception when calling OAuthApi->link: $e\n'); + print('Exception when calling OAuthApi->linkOAuthAccount: $e\n'); } ``` @@ -197,8 +156,8 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **mobileRedirect** -> mobileRedirect() +# **redirectOAuthToMobile** +> redirectOAuthToMobile() @@ -209,9 +168,9 @@ import 'package:openapi/api.dart'; final api_instance = OAuthApi(); try { - api_instance.mobileRedirect(); + api_instance.redirectOAuthToMobile(); } catch (e) { - print('Exception when calling OAuthApi->mobileRedirect: $e\n'); + print('Exception when calling OAuthApi->redirectOAuthToMobile: $e\n'); } ``` @@ -233,8 +192,49 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **unlink** -> UserResponseDto unlink() +# **startOAuth** +> OAuthAuthorizeResponseDto startOAuth(oAuthConfigDto) + + + +### Example +```dart +import 'package:openapi/api.dart'; + +final api_instance = OAuthApi(); +final oAuthConfigDto = OAuthConfigDto(); // OAuthConfigDto | + +try { + final result = api_instance.startOAuth(oAuthConfigDto); + print(result); +} catch (e) { + print('Exception when calling OAuthApi->startOAuth: $e\n'); +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **oAuthConfigDto** | [**OAuthConfigDto**](OAuthConfigDto.md)| | + +### Return type + +[**OAuthAuthorizeResponseDto**](OAuthAuthorizeResponseDto.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **unlinkOAuthAccount** +> UserResponseDto unlinkOAuthAccount() @@ -259,10 +259,10 @@ import 'package:openapi/api.dart'; final api_instance = OAuthApi(); try { - final result = api_instance.unlink(); + final result = api_instance.unlinkOAuthAccount(); print(result); } catch (e) { - print('Exception when calling OAuthApi->unlink: $e\n'); + print('Exception when calling OAuthApi->unlinkOAuthAccount: $e\n'); } ``` diff --git a/mobile/openapi/doc/ReactionType.md b/mobile/openapi/doc/ReactionType.md new file mode 100644 index 000000000..0cc41e23a --- /dev/null +++ b/mobile/openapi/doc/ReactionType.md @@ -0,0 +1,14 @@ +# openapi.model.ReactionType + +## Load the model package +```dart +import 'package:openapi/api.dart'; +``` + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/mobile/openapi/doc/ServerInfoApi.md b/mobile/openapi/doc/ServerInfoApi.md index 64a373cc0..e8121a800 100644 --- a/mobile/openapi/doc/ServerInfoApi.md +++ b/mobile/openapi/doc/ServerInfoApi.md @@ -12,8 +12,8 @@ Method | HTTP request | Description [**getServerConfig**](ServerInfoApi.md#getserverconfig) | **GET** /server-info/config | [**getServerFeatures**](ServerInfoApi.md#getserverfeatures) | **GET** /server-info/features | [**getServerInfo**](ServerInfoApi.md#getserverinfo) | **GET** /server-info | +[**getServerStatistics**](ServerInfoApi.md#getserverstatistics) | **GET** /server-info/statistics | [**getServerVersion**](ServerInfoApi.md#getserverversion) | **GET** /server-info/version | -[**getStats**](ServerInfoApi.md#getstats) | **GET** /server-info/stats | [**getSupportedMediaTypes**](ServerInfoApi.md#getsupportedmediatypes) | **GET** /server-info/media-types | [**getTheme**](ServerInfoApi.md#gettheme) | **GET** /server-info/theme | [**pingServer**](ServerInfoApi.md#pingserver) | **GET** /server-info/ping | @@ -144,6 +144,57 @@ This endpoint does not need any parameter. [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **getServerStatistics** +> ServerStatsResponseDto getServerStatistics() + + + +### Example +```dart +import 'package:openapi/api.dart'; +// TODO Configure API key authorization: cookie +//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; +// uncomment below to setup prefix (e.g. Bearer) for API key, if needed +//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; +// TODO Configure API key authorization: api_key +//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; +// uncomment below to setup prefix (e.g. Bearer) for API key, if needed +//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; +// TODO Configure HTTP Bearer authorization: bearer +// Case 1. Use String Token +//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); +// Case 2. Use Function which generate token. +// String yourTokenGeneratorFunction() { ... } +//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); + +final api_instance = ServerInfoApi(); + +try { + final result = api_instance.getServerStatistics(); + print(result); +} catch (e) { + print('Exception when calling ServerInfoApi->getServerStatistics: $e\n'); +} +``` + +### Parameters +This endpoint does not need any parameter. + +### Return type + +[**ServerStatsResponseDto**](ServerStatsResponseDto.md) + +### Authorization + +[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **getServerVersion** > ServerVersionResponseDto getServerVersion() @@ -181,57 +232,6 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **getStats** -> ServerStatsResponseDto getStats() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = ServerInfoApi(); - -try { - final result = api_instance.getStats(); - print(result); -} catch (e) { - print('Exception when calling ServerInfoApi->getStats: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**ServerStatsResponseDto**](ServerStatsResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - # **getSupportedMediaTypes** > ServerMediaTypesResponseDto getSupportedMediaTypes() diff --git a/mobile/openapi/doc/SystemConfigApi.md b/mobile/openapi/doc/SystemConfigApi.md index 5767f7bb5..9377b6e0b 100644 --- a/mobile/openapi/doc/SystemConfigApi.md +++ b/mobile/openapi/doc/SystemConfigApi.md @@ -10,7 +10,7 @@ All URIs are relative to */api* Method | HTTP request | Description ------------- | ------------- | ------------- [**getConfig**](SystemConfigApi.md#getconfig) | **GET** /system-config | -[**getDefaults**](SystemConfigApi.md#getdefaults) | **GET** /system-config/defaults | +[**getConfigDefaults**](SystemConfigApi.md#getconfigdefaults) | **GET** /system-config/defaults | [**getStorageTemplateOptions**](SystemConfigApi.md#getstoragetemplateoptions) | **GET** /system-config/storage-template-options | [**updateConfig**](SystemConfigApi.md#updateconfig) | **PUT** /system-config | @@ -66,8 +66,8 @@ This endpoint does not need any parameter. [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **getDefaults** -> SystemConfigDto getDefaults() +# **getConfigDefaults** +> SystemConfigDto getConfigDefaults() @@ -92,10 +92,10 @@ import 'package:openapi/api.dart'; final api_instance = SystemConfigApi(); try { - final result = api_instance.getDefaults(); + final result = api_instance.getConfigDefaults(); print(result); } catch (e) { - print('Exception when calling SystemConfigApi->getDefaults: $e\n'); + print('Exception when calling SystemConfigApi->getConfigDefaults: $e\n'); } ``` diff --git a/mobile/openapi/doc/SystemConfigDto.md b/mobile/openapi/doc/SystemConfigDto.md index 98a626640..73c5b70dc 100644 --- a/mobile/openapi/doc/SystemConfigDto.md +++ b/mobile/openapi/doc/SystemConfigDto.md @@ -10,6 +10,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **ffmpeg** | [**SystemConfigFFmpegDto**](SystemConfigFFmpegDto.md) | | **job** | [**SystemConfigJobDto**](SystemConfigJobDto.md) | | +**library_** | [**SystemConfigLibraryDto**](SystemConfigLibraryDto.md) | | **machineLearning** | [**SystemConfigMachineLearningDto**](SystemConfigMachineLearningDto.md) | | **map** | [**SystemConfigMapDto**](SystemConfigMapDto.md) | | **newVersionCheck** | [**SystemConfigNewVersionCheckDto**](SystemConfigNewVersionCheckDto.md) | | diff --git a/mobile/openapi/doc/SystemConfigLibraryDto.md b/mobile/openapi/doc/SystemConfigLibraryDto.md new file mode 100644 index 000000000..22c8ddf34 --- /dev/null +++ b/mobile/openapi/doc/SystemConfigLibraryDto.md @@ -0,0 +1,15 @@ +# openapi.model.SystemConfigLibraryDto + +## Load the model package +```dart +import 'package:openapi/api.dart'; +``` + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**scan** | [**SystemConfigLibraryScanDto**](SystemConfigLibraryScanDto.md) | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/mobile/openapi/doc/SystemConfigLibraryScanDto.md b/mobile/openapi/doc/SystemConfigLibraryScanDto.md new file mode 100644 index 000000000..d77bb03ce --- /dev/null +++ b/mobile/openapi/doc/SystemConfigLibraryScanDto.md @@ -0,0 +1,16 @@ +# openapi.model.SystemConfigLibraryScanDto + +## Load the model package +```dart +import 'package:openapi/api.dart'; +``` + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**cronExpression** | **String** | | +**enabled** | **bool** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/mobile/openapi/doc/UserDto.md b/mobile/openapi/doc/UserDto.md new file mode 100644 index 000000000..617ceb9d3 --- /dev/null +++ b/mobile/openapi/doc/UserDto.md @@ -0,0 +1,19 @@ +# openapi.model.UserDto + +## Load the model package +```dart +import 'package:openapi/api.dart'; +``` + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**email** | **String** | | +**firstName** | **String** | | +**id** | **String** | | +**lastName** | **String** | | +**profileImagePath** | **String** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart index 7a621b7f4..2bd437010 100644 --- a/mobile/openapi/lib/api.dart +++ b/mobile/openapi/lib/api.dart @@ -29,6 +29,7 @@ part 'auth/http_basic_auth.dart'; part 'auth/http_bearer_auth.dart'; part 'api/api_key_api.dart'; +part 'api/activity_api.dart'; part 'api/album_api.dart'; part 'api/asset_api.dart'; part 'api/audit_api.dart'; @@ -49,6 +50,9 @@ part 'model/api_key_create_dto.dart'; part 'model/api_key_create_response_dto.dart'; part 'model/api_key_response_dto.dart'; part 'model/api_key_update_dto.dart'; +part 'model/activity_create_dto.dart'; +part 'model/activity_response_dto.dart'; +part 'model/activity_statistics_response_dto.dart'; part 'model/add_users_dto.dart'; part 'model/admin_signup_response_dto.dart'; part 'model/album_count_response_dto.dart'; @@ -129,6 +133,7 @@ part 'model/person_response_dto.dart'; part 'model/person_statistics_response_dto.dart'; part 'model/person_update_dto.dart'; part 'model/queue_status_dto.dart'; +part 'model/reaction_type.dart'; part 'model/recognition_config.dart'; part 'model/scan_library_dto.dart'; part 'model/search_album_response_dto.dart'; @@ -156,6 +161,8 @@ part 'model/smart_info_response_dto.dart'; part 'model/system_config_dto.dart'; part 'model/system_config_f_fmpeg_dto.dart'; part 'model/system_config_job_dto.dart'; +part 'model/system_config_library_dto.dart'; +part 'model/system_config_library_scan_dto.dart'; part 'model/system_config_machine_learning_dto.dart'; part 'model/system_config_map_dto.dart'; part 'model/system_config_new_version_check_dto.dart'; @@ -182,6 +189,7 @@ part 'model/update_stack_parent_dto.dart'; part 'model/update_tag_dto.dart'; part 'model/update_user_dto.dart'; part 'model/usage_by_user_dto.dart'; +part 'model/user_dto.dart'; part 'model/user_response_dto.dart'; part 'model/validate_access_token_response_dto.dart'; part 'model/video_codec.dart'; diff --git a/mobile/openapi/lib/api/activity_api.dart b/mobile/openapi/lib/api/activity_api.dart new file mode 100644 index 000000000..458538a5d --- /dev/null +++ b/mobile/openapi/lib/api/activity_api.dart @@ -0,0 +1,234 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +part of openapi.api; + + +class ActivityApi { + ActivityApi([ApiClient? apiClient]) : apiClient = apiClient ?? defaultApiClient; + + final ApiClient apiClient; + + /// Performs an HTTP 'POST /activity' operation and returns the [Response]. + /// Parameters: + /// + /// * [ActivityCreateDto] activityCreateDto (required): + Future createActivityWithHttpInfo(ActivityCreateDto activityCreateDto,) async { + // ignore: prefer_const_declarations + final path = r'/activity'; + + // ignore: prefer_final_locals + Object? postBody = activityCreateDto; + + final queryParams = []; + final headerParams = {}; + final formParams = {}; + + const contentTypes = ['application/json']; + + + return apiClient.invokeAPI( + path, + 'POST', + queryParams, + postBody, + headerParams, + formParams, + contentTypes.isEmpty ? null : contentTypes.first, + ); + } + + /// Parameters: + /// + /// * [ActivityCreateDto] activityCreateDto (required): + Future createActivity(ActivityCreateDto activityCreateDto,) async { + final response = await createActivityWithHttpInfo(activityCreateDto,); + if (response.statusCode >= HttpStatus.badRequest) { + throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + } + // When a remote server returns no body with a status of 204, we shall not decode it. + // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" + // FormatException when trying to decode an empty string. + if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { + return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ActivityResponseDto',) as ActivityResponseDto; + + } + return null; + } + + /// Performs an HTTP 'DELETE /activity/{id}' operation and returns the [Response]. + /// Parameters: + /// + /// * [String] id (required): + Future deleteActivityWithHttpInfo(String id,) async { + // ignore: prefer_const_declarations + final path = r'/activity/{id}' + .replaceAll('{id}', id); + + // ignore: prefer_final_locals + Object? postBody; + + final queryParams = []; + final headerParams = {}; + final formParams = {}; + + const contentTypes = []; + + + return apiClient.invokeAPI( + path, + 'DELETE', + queryParams, + postBody, + headerParams, + formParams, + contentTypes.isEmpty ? null : contentTypes.first, + ); + } + + /// Parameters: + /// + /// * [String] id (required): + Future deleteActivity(String id,) async { + final response = await deleteActivityWithHttpInfo(id,); + if (response.statusCode >= HttpStatus.badRequest) { + throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + } + } + + /// Performs an HTTP 'GET /activity' operation and returns the [Response]. + /// Parameters: + /// + /// * [String] albumId (required): + /// + /// * [String] assetId: + /// + /// * [ReactionType] type: + /// + /// * [String] userId: + Future getActivitiesWithHttpInfo(String albumId, { String? assetId, ReactionType? type, String? userId, }) async { + // ignore: prefer_const_declarations + final path = r'/activity'; + + // ignore: prefer_final_locals + Object? postBody; + + final queryParams = []; + final headerParams = {}; + final formParams = {}; + + queryParams.addAll(_queryParams('', 'albumId', albumId)); + if (assetId != null) { + queryParams.addAll(_queryParams('', 'assetId', assetId)); + } + if (type != null) { + queryParams.addAll(_queryParams('', 'type', type)); + } + if (userId != null) { + queryParams.addAll(_queryParams('', 'userId', userId)); + } + + const contentTypes = []; + + + return apiClient.invokeAPI( + path, + 'GET', + queryParams, + postBody, + headerParams, + formParams, + contentTypes.isEmpty ? null : contentTypes.first, + ); + } + + /// Parameters: + /// + /// * [String] albumId (required): + /// + /// * [String] assetId: + /// + /// * [ReactionType] type: + /// + /// * [String] userId: + Future?> getActivities(String albumId, { String? assetId, ReactionType? type, String? userId, }) async { + final response = await getActivitiesWithHttpInfo(albumId, assetId: assetId, type: type, userId: userId, ); + if (response.statusCode >= HttpStatus.badRequest) { + throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + } + // When a remote server returns no body with a status of 204, we shall not decode it. + // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" + // FormatException when trying to decode an empty string. + if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { + final responseBody = await _decodeBodyBytes(response); + return (await apiClient.deserializeAsync(responseBody, 'List') as List) + .cast() + .toList(); + + } + return null; + } + + /// Performs an HTTP 'GET /activity/statistics' operation and returns the [Response]. + /// Parameters: + /// + /// * [String] albumId (required): + /// + /// * [String] assetId: + Future getActivityStatisticsWithHttpInfo(String albumId, { String? assetId, }) async { + // ignore: prefer_const_declarations + final path = r'/activity/statistics'; + + // ignore: prefer_final_locals + Object? postBody; + + final queryParams = []; + final headerParams = {}; + final formParams = {}; + + queryParams.addAll(_queryParams('', 'albumId', albumId)); + if (assetId != null) { + queryParams.addAll(_queryParams('', 'assetId', assetId)); + } + + const contentTypes = []; + + + return apiClient.invokeAPI( + path, + 'GET', + queryParams, + postBody, + headerParams, + formParams, + contentTypes.isEmpty ? null : contentTypes.first, + ); + } + + /// Parameters: + /// + /// * [String] albumId (required): + /// + /// * [String] assetId: + Future getActivityStatistics(String albumId, { String? assetId, }) async { + final response = await getActivityStatisticsWithHttpInfo(albumId, assetId: assetId, ); + if (response.statusCode >= HttpStatus.badRequest) { + throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + } + // When a remote server returns no body with a status of 204, we shall not decode it. + // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" + // FormatException when trying to decode an empty string. + if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { + return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ActivityStatisticsResponseDto',) as ActivityStatisticsResponseDto; + + } + return null; + } +} diff --git a/mobile/openapi/lib/api/api_key_api.dart b/mobile/openapi/lib/api/api_key_api.dart index fb6cc9941..de3bec0ca 100644 --- a/mobile/openapi/lib/api/api_key_api.dart +++ b/mobile/openapi/lib/api/api_key_api.dart @@ -20,7 +20,7 @@ class APIKeyApi { /// Parameters: /// /// * [APIKeyCreateDto] aPIKeyCreateDto (required): - Future createKeyWithHttpInfo(APIKeyCreateDto aPIKeyCreateDto,) async { + Future createApiKeyWithHttpInfo(APIKeyCreateDto aPIKeyCreateDto,) async { // ignore: prefer_const_declarations final path = r'/api-key'; @@ -48,8 +48,8 @@ class APIKeyApi { /// Parameters: /// /// * [APIKeyCreateDto] aPIKeyCreateDto (required): - Future createKey(APIKeyCreateDto aPIKeyCreateDto,) async { - final response = await createKeyWithHttpInfo(aPIKeyCreateDto,); + Future createApiKey(APIKeyCreateDto aPIKeyCreateDto,) async { + final response = await createApiKeyWithHttpInfo(aPIKeyCreateDto,); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -67,7 +67,7 @@ class APIKeyApi { /// Parameters: /// /// * [String] id (required): - Future deleteKeyWithHttpInfo(String id,) async { + Future deleteApiKeyWithHttpInfo(String id,) async { // ignore: prefer_const_declarations final path = r'/api-key/{id}' .replaceAll('{id}', id); @@ -96,8 +96,8 @@ class APIKeyApi { /// Parameters: /// /// * [String] id (required): - Future deleteKey(String id,) async { - final response = await deleteKeyWithHttpInfo(id,); + Future deleteApiKey(String id,) async { + final response = await deleteApiKeyWithHttpInfo(id,); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -107,7 +107,7 @@ class APIKeyApi { /// Parameters: /// /// * [String] id (required): - Future getKeyWithHttpInfo(String id,) async { + Future getApiKeyWithHttpInfo(String id,) async { // ignore: prefer_const_declarations final path = r'/api-key/{id}' .replaceAll('{id}', id); @@ -136,8 +136,8 @@ class APIKeyApi { /// Parameters: /// /// * [String] id (required): - Future getKey(String id,) async { - final response = await getKeyWithHttpInfo(id,); + Future getApiKey(String id,) async { + final response = await getApiKeyWithHttpInfo(id,); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -152,7 +152,7 @@ class APIKeyApi { } /// Performs an HTTP 'GET /api-key' operation and returns the [Response]. - Future getKeysWithHttpInfo() async { + Future getApiKeysWithHttpInfo() async { // ignore: prefer_const_declarations final path = r'/api-key'; @@ -177,8 +177,8 @@ class APIKeyApi { ); } - Future?> getKeys() async { - final response = await getKeysWithHttpInfo(); + Future?> getApiKeys() async { + final response = await getApiKeysWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -201,7 +201,7 @@ class APIKeyApi { /// * [String] id (required): /// /// * [APIKeyUpdateDto] aPIKeyUpdateDto (required): - Future updateKeyWithHttpInfo(String id, APIKeyUpdateDto aPIKeyUpdateDto,) async { + Future updateApiKeyWithHttpInfo(String id, APIKeyUpdateDto aPIKeyUpdateDto,) async { // ignore: prefer_const_declarations final path = r'/api-key/{id}' .replaceAll('{id}', id); @@ -232,8 +232,8 @@ class APIKeyApi { /// * [String] id (required): /// /// * [APIKeyUpdateDto] aPIKeyUpdateDto (required): - Future updateKey(String id, APIKeyUpdateDto aPIKeyUpdateDto,) async { - final response = await updateKeyWithHttpInfo(id, aPIKeyUpdateDto,); + Future updateApiKey(String id, APIKeyUpdateDto aPIKeyUpdateDto,) async { + final response = await updateApiKeyWithHttpInfo(id, aPIKeyUpdateDto,); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } diff --git a/mobile/openapi/lib/api/asset_api.dart b/mobile/openapi/lib/api/asset_api.dart index 866d11a37..b0e9c822d 100644 --- a/mobile/openapi/lib/api/asset_api.dart +++ b/mobile/openapi/lib/api/asset_api.dart @@ -23,7 +23,7 @@ class AssetApi { /// Parameters: /// /// * [AssetBulkUploadCheckDto] assetBulkUploadCheckDto (required): - Future bulkUploadCheckWithHttpInfo(AssetBulkUploadCheckDto assetBulkUploadCheckDto,) async { + Future checkBulkUploadWithHttpInfo(AssetBulkUploadCheckDto assetBulkUploadCheckDto,) async { // ignore: prefer_const_declarations final path = r'/asset/bulk-upload-check'; @@ -53,8 +53,8 @@ class AssetApi { /// Parameters: /// /// * [AssetBulkUploadCheckDto] assetBulkUploadCheckDto (required): - Future bulkUploadCheck(AssetBulkUploadCheckDto assetBulkUploadCheckDto,) async { - final response = await bulkUploadCheckWithHttpInfo(assetBulkUploadCheckDto,); + Future checkBulkUpload(AssetBulkUploadCheckDto assetBulkUploadCheckDto,) async { + final response = await checkBulkUploadWithHttpInfo(assetBulkUploadCheckDto,); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -513,7 +513,7 @@ class AssetApi { /// * [bool] isFavorite: /// /// * [bool] isTrashed: - Future getAssetStatsWithHttpInfo({ bool? isArchived, bool? isFavorite, bool? isTrashed, }) async { + Future getAssetStatisticsWithHttpInfo({ bool? isArchived, bool? isFavorite, bool? isTrashed, }) async { // ignore: prefer_const_declarations final path = r'/asset/statistics'; @@ -555,8 +555,8 @@ class AssetApi { /// * [bool] isFavorite: /// /// * [bool] isTrashed: - Future getAssetStats({ bool? isArchived, bool? isFavorite, bool? isTrashed, }) async { - final response = await getAssetStatsWithHttpInfo( isArchived: isArchived, isFavorite: isFavorite, isTrashed: isTrashed, ); + Future getAssetStatistics({ bool? isArchived, bool? isFavorite, bool? isTrashed, }) async { + final response = await getAssetStatisticsWithHttpInfo( isArchived: isArchived, isFavorite: isFavorite, isTrashed: isTrashed, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -633,119 +633,6 @@ class AssetApi { return null; } - /// Performs an HTTP 'GET /asset/time-bucket' operation and returns the [Response]. - /// Parameters: - /// - /// * [TimeBucketSize] size (required): - /// - /// * [String] timeBucket (required): - /// - /// * [String] userId: - /// - /// * [String] albumId: - /// - /// * [String] personId: - /// - /// * [bool] isArchived: - /// - /// * [bool] isFavorite: - /// - /// * [bool] isTrashed: - /// - /// * [bool] withStacked: - /// - /// * [String] key: - Future getByTimeBucketWithHttpInfo(TimeBucketSize size, String timeBucket, { String? userId, String? albumId, String? personId, bool? isArchived, bool? isFavorite, bool? isTrashed, bool? withStacked, String? key, }) async { - // ignore: prefer_const_declarations - final path = r'/asset/time-bucket'; - - // ignore: prefer_final_locals - Object? postBody; - - final queryParams = []; - final headerParams = {}; - final formParams = {}; - - queryParams.addAll(_queryParams('', 'size', size)); - if (userId != null) { - queryParams.addAll(_queryParams('', 'userId', userId)); - } - if (albumId != null) { - queryParams.addAll(_queryParams('', 'albumId', albumId)); - } - if (personId != null) { - queryParams.addAll(_queryParams('', 'personId', personId)); - } - if (isArchived != null) { - queryParams.addAll(_queryParams('', 'isArchived', isArchived)); - } - if (isFavorite != null) { - queryParams.addAll(_queryParams('', 'isFavorite', isFavorite)); - } - if (isTrashed != null) { - queryParams.addAll(_queryParams('', 'isTrashed', isTrashed)); - } - if (withStacked != null) { - queryParams.addAll(_queryParams('', 'withStacked', withStacked)); - } - queryParams.addAll(_queryParams('', 'timeBucket', timeBucket)); - if (key != null) { - queryParams.addAll(_queryParams('', 'key', key)); - } - - const contentTypes = []; - - - return apiClient.invokeAPI( - path, - 'GET', - queryParams, - postBody, - headerParams, - formParams, - contentTypes.isEmpty ? null : contentTypes.first, - ); - } - - /// Parameters: - /// - /// * [TimeBucketSize] size (required): - /// - /// * [String] timeBucket (required): - /// - /// * [String] userId: - /// - /// * [String] albumId: - /// - /// * [String] personId: - /// - /// * [bool] isArchived: - /// - /// * [bool] isFavorite: - /// - /// * [bool] isTrashed: - /// - /// * [bool] withStacked: - /// - /// * [String] key: - Future?> getByTimeBucket(TimeBucketSize size, String timeBucket, { String? userId, String? albumId, String? personId, bool? isArchived, bool? isFavorite, bool? isTrashed, bool? withStacked, String? key, }) async { - final response = await getByTimeBucketWithHttpInfo(size, timeBucket, userId: userId, albumId: albumId, personId: personId, isArchived: isArchived, isFavorite: isFavorite, isTrashed: isTrashed, withStacked: withStacked, key: key, ); - if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); - } - // When a remote server returns no body with a status of 204, we shall not decode it. - // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" - // FormatException when trying to decode an empty string. - if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - final responseBody = await _decodeBodyBytes(response); - return (await apiClient.deserializeAsync(responseBody, 'List') as List) - .cast() - .toList(); - - } - return null; - } - /// Performs an HTTP 'GET /asset/curated-locations' operation and returns the [Response]. Future getCuratedLocationsWithHttpInfo() async { // ignore: prefer_const_declarations @@ -1075,6 +962,119 @@ class AssetApi { return null; } + /// Performs an HTTP 'GET /asset/time-bucket' operation and returns the [Response]. + /// Parameters: + /// + /// * [TimeBucketSize] size (required): + /// + /// * [String] timeBucket (required): + /// + /// * [String] userId: + /// + /// * [String] albumId: + /// + /// * [String] personId: + /// + /// * [bool] isArchived: + /// + /// * [bool] isFavorite: + /// + /// * [bool] isTrashed: + /// + /// * [bool] withStacked: + /// + /// * [String] key: + Future getTimeBucketWithHttpInfo(TimeBucketSize size, String timeBucket, { String? userId, String? albumId, String? personId, bool? isArchived, bool? isFavorite, bool? isTrashed, bool? withStacked, String? key, }) async { + // ignore: prefer_const_declarations + final path = r'/asset/time-bucket'; + + // ignore: prefer_final_locals + Object? postBody; + + final queryParams = []; + final headerParams = {}; + final formParams = {}; + + queryParams.addAll(_queryParams('', 'size', size)); + if (userId != null) { + queryParams.addAll(_queryParams('', 'userId', userId)); + } + if (albumId != null) { + queryParams.addAll(_queryParams('', 'albumId', albumId)); + } + if (personId != null) { + queryParams.addAll(_queryParams('', 'personId', personId)); + } + if (isArchived != null) { + queryParams.addAll(_queryParams('', 'isArchived', isArchived)); + } + if (isFavorite != null) { + queryParams.addAll(_queryParams('', 'isFavorite', isFavorite)); + } + if (isTrashed != null) { + queryParams.addAll(_queryParams('', 'isTrashed', isTrashed)); + } + if (withStacked != null) { + queryParams.addAll(_queryParams('', 'withStacked', withStacked)); + } + queryParams.addAll(_queryParams('', 'timeBucket', timeBucket)); + if (key != null) { + queryParams.addAll(_queryParams('', 'key', key)); + } + + const contentTypes = []; + + + return apiClient.invokeAPI( + path, + 'GET', + queryParams, + postBody, + headerParams, + formParams, + contentTypes.isEmpty ? null : contentTypes.first, + ); + } + + /// Parameters: + /// + /// * [TimeBucketSize] size (required): + /// + /// * [String] timeBucket (required): + /// + /// * [String] userId: + /// + /// * [String] albumId: + /// + /// * [String] personId: + /// + /// * [bool] isArchived: + /// + /// * [bool] isFavorite: + /// + /// * [bool] isTrashed: + /// + /// * [bool] withStacked: + /// + /// * [String] key: + Future?> getTimeBucket(TimeBucketSize size, String timeBucket, { String? userId, String? albumId, String? personId, bool? isArchived, bool? isFavorite, bool? isTrashed, bool? withStacked, String? key, }) async { + final response = await getTimeBucketWithHttpInfo(size, timeBucket, userId: userId, albumId: albumId, personId: personId, isArchived: isArchived, isFavorite: isFavorite, isTrashed: isTrashed, withStacked: withStacked, key: key, ); + if (response.statusCode >= HttpStatus.badRequest) { + throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + } + // When a remote server returns no body with a status of 204, we shall not decode it. + // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" + // FormatException when trying to decode an empty string. + if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { + final responseBody = await _decodeBodyBytes(response); + return (await apiClient.deserializeAsync(responseBody, 'List') as List) + .cast() + .toList(); + + } + return null; + } + /// Performs an HTTP 'GET /asset/time-buckets' operation and returns the [Response]. /// Parameters: /// diff --git a/mobile/openapi/lib/api/authentication_api.dart b/mobile/openapi/lib/api/authentication_api.dart index 5035d5155..3b986d34d 100644 --- a/mobile/openapi/lib/api/authentication_api.dart +++ b/mobile/openapi/lib/api/authentication_api.dart @@ -16,53 +16,6 @@ class AuthenticationApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /auth/admin-sign-up' operation and returns the [Response]. - /// Parameters: - /// - /// * [SignUpDto] signUpDto (required): - Future adminSignUpWithHttpInfo(SignUpDto signUpDto,) async { - // ignore: prefer_const_declarations - final path = r'/auth/admin-sign-up'; - - // ignore: prefer_final_locals - Object? postBody = signUpDto; - - final queryParams = []; - final headerParams = {}; - final formParams = {}; - - const contentTypes = ['application/json']; - - - return apiClient.invokeAPI( - path, - 'POST', - queryParams, - postBody, - headerParams, - formParams, - contentTypes.isEmpty ? null : contentTypes.first, - ); - } - - /// Parameters: - /// - /// * [SignUpDto] signUpDto (required): - Future adminSignUp(SignUpDto signUpDto,) async { - final response = await adminSignUpWithHttpInfo(signUpDto,); - if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); - } - // When a remote server returns no body with a status of 204, we shall not decode it. - // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" - // FormatException when trying to decode an empty string. - if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AdminSignupResponseDto',) as AdminSignupResponseDto; - - } - return null; - } - /// Performs an HTTP 'POST /auth/change-password' operation and returns the [Response]. /// Parameters: /// @@ -315,6 +268,53 @@ class AuthenticationApi { } } + /// Performs an HTTP 'POST /auth/admin-sign-up' operation and returns the [Response]. + /// Parameters: + /// + /// * [SignUpDto] signUpDto (required): + Future signUpAdminWithHttpInfo(SignUpDto signUpDto,) async { + // ignore: prefer_const_declarations + final path = r'/auth/admin-sign-up'; + + // ignore: prefer_final_locals + Object? postBody = signUpDto; + + final queryParams = []; + final headerParams = {}; + final formParams = {}; + + const contentTypes = ['application/json']; + + + return apiClient.invokeAPI( + path, + 'POST', + queryParams, + postBody, + headerParams, + formParams, + contentTypes.isEmpty ? null : contentTypes.first, + ); + } + + /// Parameters: + /// + /// * [SignUpDto] signUpDto (required): + Future signUpAdmin(SignUpDto signUpDto,) async { + final response = await signUpAdminWithHttpInfo(signUpDto,); + if (response.statusCode >= HttpStatus.badRequest) { + throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + } + // When a remote server returns no body with a status of 204, we shall not decode it. + // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" + // FormatException when trying to decode an empty string. + if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { + return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AdminSignupResponseDto',) as AdminSignupResponseDto; + + } + return null; + } + /// Performs an HTTP 'POST /auth/validateToken' operation and returns the [Response]. Future validateAccessTokenWithHttpInfo() async { // ignore: prefer_const_declarations diff --git a/mobile/openapi/lib/api/library_api.dart b/mobile/openapi/lib/api/library_api.dart index ec08a646d..a5273dbb0 100644 --- a/mobile/openapi/lib/api/library_api.dart +++ b/mobile/openapi/lib/api/library_api.dart @@ -104,7 +104,7 @@ class LibraryApi { } /// Performs an HTTP 'GET /library' operation and returns the [Response]. - Future getAllForUserWithHttpInfo() async { + Future getLibrariesWithHttpInfo() async { // ignore: prefer_const_declarations final path = r'/library'; @@ -129,8 +129,8 @@ class LibraryApi { ); } - Future?> getAllForUser() async { - final response = await getAllForUserWithHttpInfo(); + Future?> getLibraries() async { + final response = await getLibrariesWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } diff --git a/mobile/openapi/lib/api/o_auth_api.dart b/mobile/openapi/lib/api/o_auth_api.dart index 0f2e72e2f..c0d6bc06e 100644 --- a/mobile/openapi/lib/api/o_auth_api.dart +++ b/mobile/openapi/lib/api/o_auth_api.dart @@ -16,58 +16,11 @@ class OAuthApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /oauth/authorize' operation and returns the [Response]. - /// Parameters: - /// - /// * [OAuthConfigDto] oAuthConfigDto (required): - Future authorizeOAuthWithHttpInfo(OAuthConfigDto oAuthConfigDto,) async { - // ignore: prefer_const_declarations - final path = r'/oauth/authorize'; - - // ignore: prefer_final_locals - Object? postBody = oAuthConfigDto; - - final queryParams = []; - final headerParams = {}; - final formParams = {}; - - const contentTypes = ['application/json']; - - - return apiClient.invokeAPI( - path, - 'POST', - queryParams, - postBody, - headerParams, - formParams, - contentTypes.isEmpty ? null : contentTypes.first, - ); - } - - /// Parameters: - /// - /// * [OAuthConfigDto] oAuthConfigDto (required): - Future authorizeOAuth(OAuthConfigDto oAuthConfigDto,) async { - final response = await authorizeOAuthWithHttpInfo(oAuthConfigDto,); - if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); - } - // When a remote server returns no body with a status of 204, we shall not decode it. - // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" - // FormatException when trying to decode an empty string. - if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'OAuthAuthorizeResponseDto',) as OAuthAuthorizeResponseDto; - - } - return null; - } - /// Performs an HTTP 'POST /oauth/callback' operation and returns the [Response]. /// Parameters: /// /// * [OAuthCallbackDto] oAuthCallbackDto (required): - Future callbackWithHttpInfo(OAuthCallbackDto oAuthCallbackDto,) async { + Future finishOAuthWithHttpInfo(OAuthCallbackDto oAuthCallbackDto,) async { // ignore: prefer_const_declarations final path = r'/oauth/callback'; @@ -95,8 +48,8 @@ class OAuthApi { /// Parameters: /// /// * [OAuthCallbackDto] oAuthCallbackDto (required): - Future callback(OAuthCallbackDto oAuthCallbackDto,) async { - final response = await callbackWithHttpInfo(oAuthCallbackDto,); + Future finishOAuth(OAuthCallbackDto oAuthCallbackDto,) async { + final response = await finishOAuthWithHttpInfo(oAuthCallbackDto,); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -117,7 +70,7 @@ class OAuthApi { /// Parameters: /// /// * [OAuthConfigDto] oAuthConfigDto (required): - Future generateConfigWithHttpInfo(OAuthConfigDto oAuthConfigDto,) async { + Future generateOAuthConfigWithHttpInfo(OAuthConfigDto oAuthConfigDto,) async { // ignore: prefer_const_declarations final path = r'/oauth/config'; @@ -147,8 +100,8 @@ class OAuthApi { /// Parameters: /// /// * [OAuthConfigDto] oAuthConfigDto (required): - Future generateConfig(OAuthConfigDto oAuthConfigDto,) async { - final response = await generateConfigWithHttpInfo(oAuthConfigDto,); + Future generateOAuthConfig(OAuthConfigDto oAuthConfigDto,) async { + final response = await generateOAuthConfigWithHttpInfo(oAuthConfigDto,); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -166,7 +119,7 @@ class OAuthApi { /// Parameters: /// /// * [OAuthCallbackDto] oAuthCallbackDto (required): - Future linkWithHttpInfo(OAuthCallbackDto oAuthCallbackDto,) async { + Future linkOAuthAccountWithHttpInfo(OAuthCallbackDto oAuthCallbackDto,) async { // ignore: prefer_const_declarations final path = r'/oauth/link'; @@ -194,8 +147,8 @@ class OAuthApi { /// Parameters: /// /// * [OAuthCallbackDto] oAuthCallbackDto (required): - Future link(OAuthCallbackDto oAuthCallbackDto,) async { - final response = await linkWithHttpInfo(oAuthCallbackDto,); + Future linkOAuthAccount(OAuthCallbackDto oAuthCallbackDto,) async { + final response = await linkOAuthAccountWithHttpInfo(oAuthCallbackDto,); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -210,7 +163,7 @@ class OAuthApi { } /// Performs an HTTP 'GET /oauth/mobile-redirect' operation and returns the [Response]. - Future mobileRedirectWithHttpInfo() async { + Future redirectOAuthToMobileWithHttpInfo() async { // ignore: prefer_const_declarations final path = r'/oauth/mobile-redirect'; @@ -235,15 +188,62 @@ class OAuthApi { ); } - Future mobileRedirect() async { - final response = await mobileRedirectWithHttpInfo(); + Future redirectOAuthToMobile() async { + final response = await redirectOAuthToMobileWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } } + /// Performs an HTTP 'POST /oauth/authorize' operation and returns the [Response]. + /// Parameters: + /// + /// * [OAuthConfigDto] oAuthConfigDto (required): + Future startOAuthWithHttpInfo(OAuthConfigDto oAuthConfigDto,) async { + // ignore: prefer_const_declarations + final path = r'/oauth/authorize'; + + // ignore: prefer_final_locals + Object? postBody = oAuthConfigDto; + + final queryParams = []; + final headerParams = {}; + final formParams = {}; + + const contentTypes = ['application/json']; + + + return apiClient.invokeAPI( + path, + 'POST', + queryParams, + postBody, + headerParams, + formParams, + contentTypes.isEmpty ? null : contentTypes.first, + ); + } + + /// Parameters: + /// + /// * [OAuthConfigDto] oAuthConfigDto (required): + Future startOAuth(OAuthConfigDto oAuthConfigDto,) async { + final response = await startOAuthWithHttpInfo(oAuthConfigDto,); + if (response.statusCode >= HttpStatus.badRequest) { + throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + } + // When a remote server returns no body with a status of 204, we shall not decode it. + // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" + // FormatException when trying to decode an empty string. + if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { + return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'OAuthAuthorizeResponseDto',) as OAuthAuthorizeResponseDto; + + } + return null; + } + /// Performs an HTTP 'POST /oauth/unlink' operation and returns the [Response]. - Future unlinkWithHttpInfo() async { + Future unlinkOAuthAccountWithHttpInfo() async { // ignore: prefer_const_declarations final path = r'/oauth/unlink'; @@ -268,8 +268,8 @@ class OAuthApi { ); } - Future unlink() async { - final response = await unlinkWithHttpInfo(); + Future unlinkOAuthAccount() async { + final response = await unlinkOAuthAccountWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } diff --git a/mobile/openapi/lib/api/server_info_api.dart b/mobile/openapi/lib/api/server_info_api.dart index b8ea50ba8..b67045add 100644 --- a/mobile/openapi/lib/api/server_info_api.dart +++ b/mobile/openapi/lib/api/server_info_api.dart @@ -139,6 +139,47 @@ class ServerInfoApi { return null; } + /// Performs an HTTP 'GET /server-info/statistics' operation and returns the [Response]. + Future getServerStatisticsWithHttpInfo() async { + // ignore: prefer_const_declarations + final path = r'/server-info/statistics'; + + // ignore: prefer_final_locals + Object? postBody; + + final queryParams = []; + final headerParams = {}; + final formParams = {}; + + const contentTypes = []; + + + return apiClient.invokeAPI( + path, + 'GET', + queryParams, + postBody, + headerParams, + formParams, + contentTypes.isEmpty ? null : contentTypes.first, + ); + } + + Future getServerStatistics() async { + final response = await getServerStatisticsWithHttpInfo(); + if (response.statusCode >= HttpStatus.badRequest) { + throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + } + // When a remote server returns no body with a status of 204, we shall not decode it. + // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" + // FormatException when trying to decode an empty string. + if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { + return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ServerStatsResponseDto',) as ServerStatsResponseDto; + + } + return null; + } + /// Performs an HTTP 'GET /server-info/version' operation and returns the [Response]. Future getServerVersionWithHttpInfo() async { // ignore: prefer_const_declarations @@ -180,47 +221,6 @@ class ServerInfoApi { return null; } - /// Performs an HTTP 'GET /server-info/stats' operation and returns the [Response]. - Future getStatsWithHttpInfo() async { - // ignore: prefer_const_declarations - final path = r'/server-info/stats'; - - // ignore: prefer_final_locals - Object? postBody; - - final queryParams = []; - final headerParams = {}; - final formParams = {}; - - const contentTypes = []; - - - return apiClient.invokeAPI( - path, - 'GET', - queryParams, - postBody, - headerParams, - formParams, - contentTypes.isEmpty ? null : contentTypes.first, - ); - } - - Future getStats() async { - final response = await getStatsWithHttpInfo(); - if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); - } - // When a remote server returns no body with a status of 204, we shall not decode it. - // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" - // FormatException when trying to decode an empty string. - if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ServerStatsResponseDto',) as ServerStatsResponseDto; - - } - return null; - } - /// Performs an HTTP 'GET /server-info/media-types' operation and returns the [Response]. Future getSupportedMediaTypesWithHttpInfo() async { // ignore: prefer_const_declarations diff --git a/mobile/openapi/lib/api/system_config_api.dart b/mobile/openapi/lib/api/system_config_api.dart index d2d0ac5ba..c8b0c58ec 100644 --- a/mobile/openapi/lib/api/system_config_api.dart +++ b/mobile/openapi/lib/api/system_config_api.dart @@ -58,7 +58,7 @@ class SystemConfigApi { } /// Performs an HTTP 'GET /system-config/defaults' operation and returns the [Response]. - Future getDefaultsWithHttpInfo() async { + Future getConfigDefaultsWithHttpInfo() async { // ignore: prefer_const_declarations final path = r'/system-config/defaults'; @@ -83,8 +83,8 @@ class SystemConfigApi { ); } - Future getDefaults() async { - final response = await getDefaultsWithHttpInfo(); + Future getConfigDefaults() async { + final response = await getConfigDefaultsWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } diff --git a/mobile/openapi/lib/api_client.dart b/mobile/openapi/lib/api_client.dart index fa16b0d60..76a849d71 100644 --- a/mobile/openapi/lib/api_client.dart +++ b/mobile/openapi/lib/api_client.dart @@ -189,6 +189,12 @@ class ApiClient { return APIKeyResponseDto.fromJson(value); case 'APIKeyUpdateDto': return APIKeyUpdateDto.fromJson(value); + case 'ActivityCreateDto': + return ActivityCreateDto.fromJson(value); + case 'ActivityResponseDto': + return ActivityResponseDto.fromJson(value); + case 'ActivityStatisticsResponseDto': + return ActivityStatisticsResponseDto.fromJson(value); case 'AddUsersDto': return AddUsersDto.fromJson(value); case 'AdminSignupResponseDto': @@ -349,6 +355,8 @@ class ApiClient { return PersonUpdateDto.fromJson(value); case 'QueueStatusDto': return QueueStatusDto.fromJson(value); + case 'ReactionType': + return ReactionTypeTypeTransformer().decode(value); case 'RecognitionConfig': return RecognitionConfig.fromJson(value); case 'ScanLibraryDto': @@ -403,6 +411,10 @@ class ApiClient { return SystemConfigFFmpegDto.fromJson(value); case 'SystemConfigJobDto': return SystemConfigJobDto.fromJson(value); + case 'SystemConfigLibraryDto': + return SystemConfigLibraryDto.fromJson(value); + case 'SystemConfigLibraryScanDto': + return SystemConfigLibraryScanDto.fromJson(value); case 'SystemConfigMachineLearningDto': return SystemConfigMachineLearningDto.fromJson(value); case 'SystemConfigMapDto': @@ -455,6 +467,8 @@ class ApiClient { return UpdateUserDto.fromJson(value); case 'UsageByUserDto': return UsageByUserDto.fromJson(value); + case 'UserDto': + return UserDto.fromJson(value); case 'UserResponseDto': return UserResponseDto.fromJson(value); case 'ValidateAccessTokenResponseDto': diff --git a/mobile/openapi/lib/api_helper.dart b/mobile/openapi/lib/api_helper.dart index 417a282e0..da870ea99 100644 --- a/mobile/openapi/lib/api_helper.dart +++ b/mobile/openapi/lib/api_helper.dart @@ -97,6 +97,9 @@ String parameterToString(dynamic value) { if (value is PathType) { return PathTypeTypeTransformer().encode(value).toString(); } + if (value is ReactionType) { + return ReactionTypeTypeTransformer().encode(value).toString(); + } if (value is SharedLinkType) { return SharedLinkTypeTypeTransformer().encode(value).toString(); } diff --git a/mobile/openapi/lib/model/activity_create_dto.dart b/mobile/openapi/lib/model/activity_create_dto.dart new file mode 100644 index 000000000..89618d403 --- /dev/null +++ b/mobile/openapi/lib/model/activity_create_dto.dart @@ -0,0 +1,140 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +part of openapi.api; + +class ActivityCreateDto { + /// Returns a new [ActivityCreateDto] instance. + ActivityCreateDto({ + required this.albumId, + this.assetId, + this.comment, + required this.type, + }); + + String albumId; + + /// + /// Please note: This property should have been non-nullable! Since the specification file + /// does not include a default value (using the "default:" property), however, the generated + /// source code must fall back to having a nullable type. + /// Consider adding a "default:" property in the specification file to hide this note. + /// + String? assetId; + + /// + /// Please note: This property should have been non-nullable! Since the specification file + /// does not include a default value (using the "default:" property), however, the generated + /// source code must fall back to having a nullable type. + /// Consider adding a "default:" property in the specification file to hide this note. + /// + String? comment; + + ReactionType type; + + @override + bool operator ==(Object other) => identical(this, other) || other is ActivityCreateDto && + other.albumId == albumId && + other.assetId == assetId && + other.comment == comment && + other.type == type; + + @override + int get hashCode => + // ignore: unnecessary_parenthesis + (albumId.hashCode) + + (assetId == null ? 0 : assetId!.hashCode) + + (comment == null ? 0 : comment!.hashCode) + + (type.hashCode); + + @override + String toString() => 'ActivityCreateDto[albumId=$albumId, assetId=$assetId, comment=$comment, type=$type]'; + + Map toJson() { + final json = {}; + json[r'albumId'] = this.albumId; + if (this.assetId != null) { + json[r'assetId'] = this.assetId; + } else { + // json[r'assetId'] = null; + } + if (this.comment != null) { + json[r'comment'] = this.comment; + } else { + // json[r'comment'] = null; + } + json[r'type'] = this.type; + return json; + } + + /// Returns a new [ActivityCreateDto] instance and imports its values from + /// [value] if it's a [Map], null otherwise. + // ignore: prefer_constructors_over_static_methods + static ActivityCreateDto? fromJson(dynamic value) { + if (value is Map) { + final json = value.cast(); + + return ActivityCreateDto( + albumId: mapValueOfType(json, r'albumId')!, + assetId: mapValueOfType(json, r'assetId'), + comment: mapValueOfType(json, r'comment'), + type: ReactionType.fromJson(json[r'type'])!, + ); + } + return null; + } + + static List listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + if (json is List && json.isNotEmpty) { + for (final row in json) { + final value = ActivityCreateDto.fromJson(row); + if (value != null) { + result.add(value); + } + } + } + return result.toList(growable: growable); + } + + static Map mapFromJson(dynamic json) { + final map = {}; + if (json is Map && json.isNotEmpty) { + json = json.cast(); // ignore: parameter_assignments + for (final entry in json.entries) { + final value = ActivityCreateDto.fromJson(entry.value); + if (value != null) { + map[entry.key] = value; + } + } + } + return map; + } + + // maps a json object with a list of ActivityCreateDto-objects as value to a dart map + static Map> mapListFromJson(dynamic json, {bool growable = false,}) { + final map = >{}; + if (json is Map && json.isNotEmpty) { + // ignore: parameter_assignments + json = json.cast(); + for (final entry in json.entries) { + map[entry.key] = ActivityCreateDto.listFromJson(entry.value, growable: growable,); + } + } + return map; + } + + /// The list of required keys that must be present in a JSON. + static const requiredKeys = { + 'albumId', + 'type', + }; +} + diff --git a/mobile/openapi/lib/model/activity_response_dto.dart b/mobile/openapi/lib/model/activity_response_dto.dart new file mode 100644 index 000000000..0f4cbd481 --- /dev/null +++ b/mobile/openapi/lib/model/activity_response_dto.dart @@ -0,0 +1,219 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +part of openapi.api; + +class ActivityResponseDto { + /// Returns a new [ActivityResponseDto] instance. + ActivityResponseDto({ + required this.assetId, + this.comment, + required this.createdAt, + required this.id, + required this.type, + required this.user, + }); + + String? assetId; + + String? comment; + + DateTime createdAt; + + String id; + + ActivityResponseDtoTypeEnum type; + + UserDto user; + + @override + bool operator ==(Object other) => identical(this, other) || other is ActivityResponseDto && + other.assetId == assetId && + other.comment == comment && + other.createdAt == createdAt && + other.id == id && + other.type == type && + other.user == user; + + @override + int get hashCode => + // ignore: unnecessary_parenthesis + (assetId == null ? 0 : assetId!.hashCode) + + (comment == null ? 0 : comment!.hashCode) + + (createdAt.hashCode) + + (id.hashCode) + + (type.hashCode) + + (user.hashCode); + + @override + String toString() => 'ActivityResponseDto[assetId=$assetId, comment=$comment, createdAt=$createdAt, id=$id, type=$type, user=$user]'; + + Map toJson() { + final json = {}; + if (this.assetId != null) { + json[r'assetId'] = this.assetId; + } else { + // json[r'assetId'] = null; + } + if (this.comment != null) { + json[r'comment'] = this.comment; + } else { + // json[r'comment'] = null; + } + json[r'createdAt'] = this.createdAt.toUtc().toIso8601String(); + json[r'id'] = this.id; + json[r'type'] = this.type; + json[r'user'] = this.user; + return json; + } + + /// Returns a new [ActivityResponseDto] instance and imports its values from + /// [value] if it's a [Map], null otherwise. + // ignore: prefer_constructors_over_static_methods + static ActivityResponseDto? fromJson(dynamic value) { + if (value is Map) { + final json = value.cast(); + + return ActivityResponseDto( + assetId: mapValueOfType(json, r'assetId'), + comment: mapValueOfType(json, r'comment'), + createdAt: mapDateTime(json, r'createdAt', '')!, + id: mapValueOfType(json, r'id')!, + type: ActivityResponseDtoTypeEnum.fromJson(json[r'type'])!, + user: UserDto.fromJson(json[r'user'])!, + ); + } + return null; + } + + static List listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + if (json is List && json.isNotEmpty) { + for (final row in json) { + final value = ActivityResponseDto.fromJson(row); + if (value != null) { + result.add(value); + } + } + } + return result.toList(growable: growable); + } + + static Map mapFromJson(dynamic json) { + final map = {}; + if (json is Map && json.isNotEmpty) { + json = json.cast(); // ignore: parameter_assignments + for (final entry in json.entries) { + final value = ActivityResponseDto.fromJson(entry.value); + if (value != null) { + map[entry.key] = value; + } + } + } + return map; + } + + // maps a json object with a list of ActivityResponseDto-objects as value to a dart map + static Map> mapListFromJson(dynamic json, {bool growable = false,}) { + final map = >{}; + if (json is Map && json.isNotEmpty) { + // ignore: parameter_assignments + json = json.cast(); + for (final entry in json.entries) { + map[entry.key] = ActivityResponseDto.listFromJson(entry.value, growable: growable,); + } + } + return map; + } + + /// The list of required keys that must be present in a JSON. + static const requiredKeys = { + 'assetId', + 'createdAt', + 'id', + 'type', + 'user', + }; +} + + +class ActivityResponseDtoTypeEnum { + /// Instantiate a new enum with the provided [value]. + const ActivityResponseDtoTypeEnum._(this.value); + + /// The underlying value of this enum member. + final String value; + + @override + String toString() => value; + + String toJson() => value; + + static const comment = ActivityResponseDtoTypeEnum._(r'comment'); + static const like = ActivityResponseDtoTypeEnum._(r'like'); + + /// List of all possible values in this [enum][ActivityResponseDtoTypeEnum]. + static const values = [ + comment, + like, + ]; + + static ActivityResponseDtoTypeEnum? fromJson(dynamic value) => ActivityResponseDtoTypeEnumTypeTransformer().decode(value); + + static List? listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + if (json is List && json.isNotEmpty) { + for (final row in json) { + final value = ActivityResponseDtoTypeEnum.fromJson(row); + if (value != null) { + result.add(value); + } + } + } + return result.toList(growable: growable); + } +} + +/// Transformation class that can [encode] an instance of [ActivityResponseDtoTypeEnum] to String, +/// and [decode] dynamic data back to [ActivityResponseDtoTypeEnum]. +class ActivityResponseDtoTypeEnumTypeTransformer { + factory ActivityResponseDtoTypeEnumTypeTransformer() => _instance ??= const ActivityResponseDtoTypeEnumTypeTransformer._(); + + const ActivityResponseDtoTypeEnumTypeTransformer._(); + + String encode(ActivityResponseDtoTypeEnum data) => data.value; + + /// Decodes a [dynamic value][data] to a ActivityResponseDtoTypeEnum. + /// + /// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully, + /// then null is returned. However, if [allowNull] is false and the [dynamic value][data] + /// cannot be decoded successfully, then an [UnimplementedError] is thrown. + /// + /// The [allowNull] is very handy when an API changes and a new enum value is added or removed, + /// and users are still using an old app with the old code. + ActivityResponseDtoTypeEnum? decode(dynamic data, {bool allowNull = true}) { + if (data != null) { + switch (data) { + case r'comment': return ActivityResponseDtoTypeEnum.comment; + case r'like': return ActivityResponseDtoTypeEnum.like; + default: + if (!allowNull) { + throw ArgumentError('Unknown enum value to decode: $data'); + } + } + } + return null; + } + + /// Singleton [ActivityResponseDtoTypeEnumTypeTransformer] instance. + static ActivityResponseDtoTypeEnumTypeTransformer? _instance; +} + + diff --git a/mobile/openapi/lib/model/activity_statistics_response_dto.dart b/mobile/openapi/lib/model/activity_statistics_response_dto.dart new file mode 100644 index 000000000..1b6af1229 --- /dev/null +++ b/mobile/openapi/lib/model/activity_statistics_response_dto.dart @@ -0,0 +1,98 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +part of openapi.api; + +class ActivityStatisticsResponseDto { + /// Returns a new [ActivityStatisticsResponseDto] instance. + ActivityStatisticsResponseDto({ + required this.comments, + }); + + int comments; + + @override + bool operator ==(Object other) => identical(this, other) || other is ActivityStatisticsResponseDto && + other.comments == comments; + + @override + int get hashCode => + // ignore: unnecessary_parenthesis + (comments.hashCode); + + @override + String toString() => 'ActivityStatisticsResponseDto[comments=$comments]'; + + Map toJson() { + final json = {}; + json[r'comments'] = this.comments; + return json; + } + + /// Returns a new [ActivityStatisticsResponseDto] instance and imports its values from + /// [value] if it's a [Map], null otherwise. + // ignore: prefer_constructors_over_static_methods + static ActivityStatisticsResponseDto? fromJson(dynamic value) { + if (value is Map) { + final json = value.cast(); + + return ActivityStatisticsResponseDto( + comments: mapValueOfType(json, r'comments')!, + ); + } + return null; + } + + static List listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + if (json is List && json.isNotEmpty) { + for (final row in json) { + final value = ActivityStatisticsResponseDto.fromJson(row); + if (value != null) { + result.add(value); + } + } + } + return result.toList(growable: growable); + } + + static Map mapFromJson(dynamic json) { + final map = {}; + if (json is Map && json.isNotEmpty) { + json = json.cast(); // ignore: parameter_assignments + for (final entry in json.entries) { + final value = ActivityStatisticsResponseDto.fromJson(entry.value); + if (value != null) { + map[entry.key] = value; + } + } + } + return map; + } + + // maps a json object with a list of ActivityStatisticsResponseDto-objects as value to a dart map + static Map> mapListFromJson(dynamic json, {bool growable = false,}) { + final map = >{}; + if (json is Map && json.isNotEmpty) { + // ignore: parameter_assignments + json = json.cast(); + for (final entry in json.entries) { + map[entry.key] = ActivityStatisticsResponseDto.listFromJson(entry.value, growable: growable,); + } + } + return map; + } + + /// The list of required keys that must be present in a JSON. + static const requiredKeys = { + 'comments', + }; +} + diff --git a/mobile/openapi/lib/model/reaction_type.dart b/mobile/openapi/lib/model/reaction_type.dart new file mode 100644 index 000000000..dbe6c11d2 --- /dev/null +++ b/mobile/openapi/lib/model/reaction_type.dart @@ -0,0 +1,85 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +part of openapi.api; + + +class ReactionType { + /// Instantiate a new enum with the provided [value]. + const ReactionType._(this.value); + + /// The underlying value of this enum member. + final String value; + + @override + String toString() => value; + + String toJson() => value; + + static const comment = ReactionType._(r'comment'); + static const like = ReactionType._(r'like'); + + /// List of all possible values in this [enum][ReactionType]. + static const values = [ + comment, + like, + ]; + + static ReactionType? fromJson(dynamic value) => ReactionTypeTypeTransformer().decode(value); + + static List? listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + if (json is List && json.isNotEmpty) { + for (final row in json) { + final value = ReactionType.fromJson(row); + if (value != null) { + result.add(value); + } + } + } + return result.toList(growable: growable); + } +} + +/// Transformation class that can [encode] an instance of [ReactionType] to String, +/// and [decode] dynamic data back to [ReactionType]. +class ReactionTypeTypeTransformer { + factory ReactionTypeTypeTransformer() => _instance ??= const ReactionTypeTypeTransformer._(); + + const ReactionTypeTypeTransformer._(); + + String encode(ReactionType data) => data.value; + + /// Decodes a [dynamic value][data] to a ReactionType. + /// + /// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully, + /// then null is returned. However, if [allowNull] is false and the [dynamic value][data] + /// cannot be decoded successfully, then an [UnimplementedError] is thrown. + /// + /// The [allowNull] is very handy when an API changes and a new enum value is added or removed, + /// and users are still using an old app with the old code. + ReactionType? decode(dynamic data, {bool allowNull = true}) { + if (data != null) { + switch (data) { + case r'comment': return ReactionType.comment; + case r'like': return ReactionType.like; + default: + if (!allowNull) { + throw ArgumentError('Unknown enum value to decode: $data'); + } + } + } + return null; + } + + /// Singleton [ReactionTypeTypeTransformer] instance. + static ReactionTypeTypeTransformer? _instance; +} + diff --git a/mobile/openapi/lib/model/system_config_dto.dart b/mobile/openapi/lib/model/system_config_dto.dart index 89c7e5f7d..c8407c2ce 100644 --- a/mobile/openapi/lib/model/system_config_dto.dart +++ b/mobile/openapi/lib/model/system_config_dto.dart @@ -15,6 +15,7 @@ class SystemConfigDto { SystemConfigDto({ required this.ffmpeg, required this.job, + required this.library_, required this.machineLearning, required this.map, required this.newVersionCheck, @@ -31,6 +32,8 @@ class SystemConfigDto { SystemConfigJobDto job; + SystemConfigLibraryDto library_; + SystemConfigMachineLearningDto machineLearning; SystemConfigMapDto map; @@ -55,6 +58,7 @@ class SystemConfigDto { bool operator ==(Object other) => identical(this, other) || other is SystemConfigDto && other.ffmpeg == ffmpeg && other.job == job && + other.library_ == library_ && other.machineLearning == machineLearning && other.map == map && other.newVersionCheck == newVersionCheck && @@ -71,6 +75,7 @@ class SystemConfigDto { // ignore: unnecessary_parenthesis (ffmpeg.hashCode) + (job.hashCode) + + (library_.hashCode) + (machineLearning.hashCode) + (map.hashCode) + (newVersionCheck.hashCode) + @@ -83,12 +88,13 @@ class SystemConfigDto { (trash.hashCode); @override - String toString() => 'SystemConfigDto[ffmpeg=$ffmpeg, job=$job, machineLearning=$machineLearning, map=$map, newVersionCheck=$newVersionCheck, oauth=$oauth, passwordLogin=$passwordLogin, reverseGeocoding=$reverseGeocoding, storageTemplate=$storageTemplate, theme=$theme, thumbnail=$thumbnail, trash=$trash]'; + String toString() => 'SystemConfigDto[ffmpeg=$ffmpeg, job=$job, library_=$library_, machineLearning=$machineLearning, map=$map, newVersionCheck=$newVersionCheck, oauth=$oauth, passwordLogin=$passwordLogin, reverseGeocoding=$reverseGeocoding, storageTemplate=$storageTemplate, theme=$theme, thumbnail=$thumbnail, trash=$trash]'; Map toJson() { final json = {}; json[r'ffmpeg'] = this.ffmpeg; json[r'job'] = this.job; + json[r'library'] = this.library_; json[r'machineLearning'] = this.machineLearning; json[r'map'] = this.map; json[r'newVersionCheck'] = this.newVersionCheck; @@ -112,6 +118,7 @@ class SystemConfigDto { return SystemConfigDto( ffmpeg: SystemConfigFFmpegDto.fromJson(json[r'ffmpeg'])!, job: SystemConfigJobDto.fromJson(json[r'job'])!, + library_: SystemConfigLibraryDto.fromJson(json[r'library'])!, machineLearning: SystemConfigMachineLearningDto.fromJson(json[r'machineLearning'])!, map: SystemConfigMapDto.fromJson(json[r'map'])!, newVersionCheck: SystemConfigNewVersionCheckDto.fromJson(json[r'newVersionCheck'])!, @@ -171,6 +178,7 @@ class SystemConfigDto { static const requiredKeys = { 'ffmpeg', 'job', + 'library', 'machineLearning', 'map', 'newVersionCheck', diff --git a/mobile/openapi/lib/model/system_config_library_dto.dart b/mobile/openapi/lib/model/system_config_library_dto.dart new file mode 100644 index 000000000..0dccb0a32 --- /dev/null +++ b/mobile/openapi/lib/model/system_config_library_dto.dart @@ -0,0 +1,98 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +part of openapi.api; + +class SystemConfigLibraryDto { + /// Returns a new [SystemConfigLibraryDto] instance. + SystemConfigLibraryDto({ + required this.scan, + }); + + SystemConfigLibraryScanDto scan; + + @override + bool operator ==(Object other) => identical(this, other) || other is SystemConfigLibraryDto && + other.scan == scan; + + @override + int get hashCode => + // ignore: unnecessary_parenthesis + (scan.hashCode); + + @override + String toString() => 'SystemConfigLibraryDto[scan=$scan]'; + + Map toJson() { + final json = {}; + json[r'scan'] = this.scan; + return json; + } + + /// Returns a new [SystemConfigLibraryDto] instance and imports its values from + /// [value] if it's a [Map], null otherwise. + // ignore: prefer_constructors_over_static_methods + static SystemConfigLibraryDto? fromJson(dynamic value) { + if (value is Map) { + final json = value.cast(); + + return SystemConfigLibraryDto( + scan: SystemConfigLibraryScanDto.fromJson(json[r'scan'])!, + ); + } + return null; + } + + static List listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + if (json is List && json.isNotEmpty) { + for (final row in json) { + final value = SystemConfigLibraryDto.fromJson(row); + if (value != null) { + result.add(value); + } + } + } + return result.toList(growable: growable); + } + + static Map mapFromJson(dynamic json) { + final map = {}; + if (json is Map && json.isNotEmpty) { + json = json.cast(); // ignore: parameter_assignments + for (final entry in json.entries) { + final value = SystemConfigLibraryDto.fromJson(entry.value); + if (value != null) { + map[entry.key] = value; + } + } + } + return map; + } + + // maps a json object with a list of SystemConfigLibraryDto-objects as value to a dart map + static Map> mapListFromJson(dynamic json, {bool growable = false,}) { + final map = >{}; + if (json is Map && json.isNotEmpty) { + // ignore: parameter_assignments + json = json.cast(); + for (final entry in json.entries) { + map[entry.key] = SystemConfigLibraryDto.listFromJson(entry.value, growable: growable,); + } + } + return map; + } + + /// The list of required keys that must be present in a JSON. + static const requiredKeys = { + 'scan', + }; +} + diff --git a/mobile/openapi/lib/model/system_config_library_scan_dto.dart b/mobile/openapi/lib/model/system_config_library_scan_dto.dart new file mode 100644 index 000000000..1de6e4d14 --- /dev/null +++ b/mobile/openapi/lib/model/system_config_library_scan_dto.dart @@ -0,0 +1,106 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +part of openapi.api; + +class SystemConfigLibraryScanDto { + /// Returns a new [SystemConfigLibraryScanDto] instance. + SystemConfigLibraryScanDto({ + required this.cronExpression, + required this.enabled, + }); + + String cronExpression; + + bool enabled; + + @override + bool operator ==(Object other) => identical(this, other) || other is SystemConfigLibraryScanDto && + other.cronExpression == cronExpression && + other.enabled == enabled; + + @override + int get hashCode => + // ignore: unnecessary_parenthesis + (cronExpression.hashCode) + + (enabled.hashCode); + + @override + String toString() => 'SystemConfigLibraryScanDto[cronExpression=$cronExpression, enabled=$enabled]'; + + Map toJson() { + final json = {}; + json[r'cronExpression'] = this.cronExpression; + json[r'enabled'] = this.enabled; + return json; + } + + /// Returns a new [SystemConfigLibraryScanDto] instance and imports its values from + /// [value] if it's a [Map], null otherwise. + // ignore: prefer_constructors_over_static_methods + static SystemConfigLibraryScanDto? fromJson(dynamic value) { + if (value is Map) { + final json = value.cast(); + + return SystemConfigLibraryScanDto( + cronExpression: mapValueOfType(json, r'cronExpression')!, + enabled: mapValueOfType(json, r'enabled')!, + ); + } + return null; + } + + static List listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + if (json is List && json.isNotEmpty) { + for (final row in json) { + final value = SystemConfigLibraryScanDto.fromJson(row); + if (value != null) { + result.add(value); + } + } + } + return result.toList(growable: growable); + } + + static Map mapFromJson(dynamic json) { + final map = {}; + if (json is Map && json.isNotEmpty) { + json = json.cast(); // ignore: parameter_assignments + for (final entry in json.entries) { + final value = SystemConfigLibraryScanDto.fromJson(entry.value); + if (value != null) { + map[entry.key] = value; + } + } + } + return map; + } + + // maps a json object with a list of SystemConfigLibraryScanDto-objects as value to a dart map + static Map> mapListFromJson(dynamic json, {bool growable = false,}) { + final map = >{}; + if (json is Map && json.isNotEmpty) { + // ignore: parameter_assignments + json = json.cast(); + for (final entry in json.entries) { + map[entry.key] = SystemConfigLibraryScanDto.listFromJson(entry.value, growable: growable,); + } + } + return map; + } + + /// The list of required keys that must be present in a JSON. + static const requiredKeys = { + 'cronExpression', + 'enabled', + }; +} + diff --git a/mobile/openapi/lib/model/user_dto.dart b/mobile/openapi/lib/model/user_dto.dart new file mode 100644 index 000000000..e96588cf5 --- /dev/null +++ b/mobile/openapi/lib/model/user_dto.dart @@ -0,0 +1,130 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +part of openapi.api; + +class UserDto { + /// Returns a new [UserDto] instance. + UserDto({ + required this.email, + required this.firstName, + required this.id, + required this.lastName, + required this.profileImagePath, + }); + + String email; + + String firstName; + + String id; + + String lastName; + + String profileImagePath; + + @override + bool operator ==(Object other) => identical(this, other) || other is UserDto && + other.email == email && + other.firstName == firstName && + other.id == id && + other.lastName == lastName && + other.profileImagePath == profileImagePath; + + @override + int get hashCode => + // ignore: unnecessary_parenthesis + (email.hashCode) + + (firstName.hashCode) + + (id.hashCode) + + (lastName.hashCode) + + (profileImagePath.hashCode); + + @override + String toString() => 'UserDto[email=$email, firstName=$firstName, id=$id, lastName=$lastName, profileImagePath=$profileImagePath]'; + + Map toJson() { + final json = {}; + json[r'email'] = this.email; + json[r'firstName'] = this.firstName; + json[r'id'] = this.id; + json[r'lastName'] = this.lastName; + json[r'profileImagePath'] = this.profileImagePath; + return json; + } + + /// Returns a new [UserDto] instance and imports its values from + /// [value] if it's a [Map], null otherwise. + // ignore: prefer_constructors_over_static_methods + static UserDto? fromJson(dynamic value) { + if (value is Map) { + final json = value.cast(); + + return UserDto( + email: mapValueOfType(json, r'email')!, + firstName: mapValueOfType(json, r'firstName')!, + id: mapValueOfType(json, r'id')!, + lastName: mapValueOfType(json, r'lastName')!, + profileImagePath: mapValueOfType(json, r'profileImagePath')!, + ); + } + return null; + } + + static List listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + if (json is List && json.isNotEmpty) { + for (final row in json) { + final value = UserDto.fromJson(row); + if (value != null) { + result.add(value); + } + } + } + return result.toList(growable: growable); + } + + static Map mapFromJson(dynamic json) { + final map = {}; + if (json is Map && json.isNotEmpty) { + json = json.cast(); // ignore: parameter_assignments + for (final entry in json.entries) { + final value = UserDto.fromJson(entry.value); + if (value != null) { + map[entry.key] = value; + } + } + } + return map; + } + + // maps a json object with a list of UserDto-objects as value to a dart map + static Map> mapListFromJson(dynamic json, {bool growable = false,}) { + final map = >{}; + if (json is Map && json.isNotEmpty) { + // ignore: parameter_assignments + json = json.cast(); + for (final entry in json.entries) { + map[entry.key] = UserDto.listFromJson(entry.value, growable: growable,); + } + } + return map; + } + + /// The list of required keys that must be present in a JSON. + static const requiredKeys = { + 'email', + 'firstName', + 'id', + 'lastName', + 'profileImagePath', + }; +} + diff --git a/mobile/openapi/test/activity_api_test.dart b/mobile/openapi/test/activity_api_test.dart new file mode 100644 index 000000000..9b6fe1a6c --- /dev/null +++ b/mobile/openapi/test/activity_api_test.dart @@ -0,0 +1,41 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +import 'package:openapi/api.dart'; +import 'package:test/test.dart'; + + +/// tests for ActivityApi +void main() { + // final instance = ActivityApi(); + + group('tests for ActivityApi', () { + //Future createActivity(ActivityCreateDto activityCreateDto) async + test('test createActivity', () async { + // TODO + }); + + //Future deleteActivity(String id) async + test('test deleteActivity', () async { + // TODO + }); + + //Future> getActivities(String albumId, { String assetId, ReactionType type, String userId }) async + test('test getActivities', () async { + // TODO + }); + + //Future getActivityStatistics(String albumId, { String assetId }) async + test('test getActivityStatistics', () async { + // TODO + }); + + }); +} diff --git a/mobile/openapi/test/activity_create_dto_test.dart b/mobile/openapi/test/activity_create_dto_test.dart new file mode 100644 index 000000000..263f1e27d --- /dev/null +++ b/mobile/openapi/test/activity_create_dto_test.dart @@ -0,0 +1,42 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +import 'package:openapi/api.dart'; +import 'package:test/test.dart'; + +// tests for ActivityCreateDto +void main() { + // final instance = ActivityCreateDto(); + + group('test ActivityCreateDto', () { + // String albumId + test('to test the property `albumId`', () async { + // TODO + }); + + // String assetId + test('to test the property `assetId`', () async { + // TODO + }); + + // String comment + test('to test the property `comment`', () async { + // TODO + }); + + // ReactionType type + test('to test the property `type`', () async { + // TODO + }); + + + }); + +} diff --git a/mobile/openapi/test/activity_response_dto_test.dart b/mobile/openapi/test/activity_response_dto_test.dart new file mode 100644 index 000000000..5f70944b6 --- /dev/null +++ b/mobile/openapi/test/activity_response_dto_test.dart @@ -0,0 +1,52 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +import 'package:openapi/api.dart'; +import 'package:test/test.dart'; + +// tests for ActivityResponseDto +void main() { + // final instance = ActivityResponseDto(); + + group('test ActivityResponseDto', () { + // String assetId + test('to test the property `assetId`', () async { + // TODO + }); + + // String comment + test('to test the property `comment`', () async { + // TODO + }); + + // DateTime createdAt + test('to test the property `createdAt`', () async { + // TODO + }); + + // String id + test('to test the property `id`', () async { + // TODO + }); + + // String type + test('to test the property `type`', () async { + // TODO + }); + + // UserDto user + test('to test the property `user`', () async { + // TODO + }); + + + }); + +} diff --git a/mobile/openapi/test/activity_statistics_response_dto_test.dart b/mobile/openapi/test/activity_statistics_response_dto_test.dart new file mode 100644 index 000000000..05f8bfdd0 --- /dev/null +++ b/mobile/openapi/test/activity_statistics_response_dto_test.dart @@ -0,0 +1,27 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +import 'package:openapi/api.dart'; +import 'package:test/test.dart'; + +// tests for ActivityStatisticsResponseDto +void main() { + // final instance = ActivityStatisticsResponseDto(); + + group('test ActivityStatisticsResponseDto', () { + // int comments + test('to test the property `comments`', () async { + // TODO + }); + + + }); + +} diff --git a/mobile/openapi/test/api_key_api_test.dart b/mobile/openapi/test/api_key_api_test.dart index 2e02bae72..679abffbd 100644 --- a/mobile/openapi/test/api_key_api_test.dart +++ b/mobile/openapi/test/api_key_api_test.dart @@ -17,28 +17,28 @@ void main() { // final instance = APIKeyApi(); group('tests for APIKeyApi', () { - //Future createKey(APIKeyCreateDto aPIKeyCreateDto) async - test('test createKey', () async { + //Future createApiKey(APIKeyCreateDto aPIKeyCreateDto) async + test('test createApiKey', () async { // TODO }); - //Future deleteKey(String id) async - test('test deleteKey', () async { + //Future deleteApiKey(String id) async + test('test deleteApiKey', () async { // TODO }); - //Future getKey(String id) async - test('test getKey', () async { + //Future getApiKey(String id) async + test('test getApiKey', () async { // TODO }); - //Future> getKeys() async - test('test getKeys', () async { + //Future> getApiKeys() async + test('test getApiKeys', () async { // TODO }); - //Future updateKey(String id, APIKeyUpdateDto aPIKeyUpdateDto) async - test('test updateKey', () async { + //Future updateApiKey(String id, APIKeyUpdateDto aPIKeyUpdateDto) async + test('test updateApiKey', () async { // TODO }); diff --git a/mobile/openapi/test/asset_api_test.dart b/mobile/openapi/test/asset_api_test.dart index c2a07323c..453982cf1 100644 --- a/mobile/openapi/test/asset_api_test.dart +++ b/mobile/openapi/test/asset_api_test.dart @@ -19,8 +19,8 @@ void main() { group('tests for AssetApi', () { // Checks if assets exist by checksums // - //Future bulkUploadCheck(AssetBulkUploadCheckDto assetBulkUploadCheckDto) async - test('test bulkUploadCheck', () async { + //Future checkBulkUpload(AssetBulkUploadCheckDto assetBulkUploadCheckDto) async + test('test checkBulkUpload', () async { // TODO }); @@ -70,8 +70,8 @@ void main() { // TODO }); - //Future getAssetStats({ bool isArchived, bool isFavorite, bool isTrashed }) async - test('test getAssetStats', () async { + //Future getAssetStatistics({ bool isArchived, bool isFavorite, bool isTrashed }) async + test('test getAssetStatistics', () async { // TODO }); @@ -80,11 +80,6 @@ void main() { // TODO }); - //Future> getByTimeBucket(TimeBucketSize size, String timeBucket, { String userId, String albumId, String personId, bool isArchived, bool isFavorite, bool isTrashed, bool withStacked, String key }) async - test('test getByTimeBucket', () async { - // TODO - }); - //Future> getCuratedLocations() async test('test getCuratedLocations', () async { // TODO @@ -115,6 +110,11 @@ void main() { // TODO }); + //Future> getTimeBucket(TimeBucketSize size, String timeBucket, { String userId, String albumId, String personId, bool isArchived, bool isFavorite, bool isTrashed, bool withStacked, String key }) async + test('test getTimeBucket', () async { + // TODO + }); + //Future> getTimeBuckets(TimeBucketSize size, { String userId, String albumId, String personId, bool isArchived, bool isFavorite, bool isTrashed, bool withStacked, String key }) async test('test getTimeBuckets', () async { // TODO diff --git a/mobile/openapi/test/authentication_api_test.dart b/mobile/openapi/test/authentication_api_test.dart index 9fed80d71..22eb7550f 100644 --- a/mobile/openapi/test/authentication_api_test.dart +++ b/mobile/openapi/test/authentication_api_test.dart @@ -17,11 +17,6 @@ void main() { // final instance = AuthenticationApi(); group('tests for AuthenticationApi', () { - //Future adminSignUp(SignUpDto signUpDto) async - test('test adminSignUp', () async { - // TODO - }); - //Future changePassword(ChangePasswordDto changePasswordDto) async test('test changePassword', () async { // TODO @@ -52,6 +47,11 @@ void main() { // TODO }); + //Future signUpAdmin(SignUpDto signUpDto) async + test('test signUpAdmin', () async { + // TODO + }); + //Future validateAccessToken() async test('test validateAccessToken', () async { // TODO diff --git a/mobile/openapi/test/library_api_test.dart b/mobile/openapi/test/library_api_test.dart index 485ecb4b4..85882edbd 100644 --- a/mobile/openapi/test/library_api_test.dart +++ b/mobile/openapi/test/library_api_test.dart @@ -27,8 +27,8 @@ void main() { // TODO }); - //Future> getAllForUser() async - test('test getAllForUser', () async { + //Future> getLibraries() async + test('test getLibraries', () async { // TODO }); diff --git a/mobile/openapi/test/o_auth_api_test.dart b/mobile/openapi/test/o_auth_api_test.dart index 7a3ee0a9f..52326d423 100644 --- a/mobile/openapi/test/o_auth_api_test.dart +++ b/mobile/openapi/test/o_auth_api_test.dart @@ -17,35 +17,35 @@ void main() { // final instance = OAuthApi(); group('tests for OAuthApi', () { - //Future authorizeOAuth(OAuthConfigDto oAuthConfigDto) async - test('test authorizeOAuth', () async { - // TODO - }); - - //Future callback(OAuthCallbackDto oAuthCallbackDto) async - test('test callback', () async { + //Future finishOAuth(OAuthCallbackDto oAuthCallbackDto) async + test('test finishOAuth', () async { // TODO }); // @deprecated use feature flags and /oauth/authorize // - //Future generateConfig(OAuthConfigDto oAuthConfigDto) async - test('test generateConfig', () async { + //Future generateOAuthConfig(OAuthConfigDto oAuthConfigDto) async + test('test generateOAuthConfig', () async { // TODO }); - //Future link(OAuthCallbackDto oAuthCallbackDto) async - test('test link', () async { + //Future linkOAuthAccount(OAuthCallbackDto oAuthCallbackDto) async + test('test linkOAuthAccount', () async { // TODO }); - //Future mobileRedirect() async - test('test mobileRedirect', () async { + //Future redirectOAuthToMobile() async + test('test redirectOAuthToMobile', () async { // TODO }); - //Future unlink() async - test('test unlink', () async { + //Future startOAuth(OAuthConfigDto oAuthConfigDto) async + test('test startOAuth', () async { + // TODO + }); + + //Future unlinkOAuthAccount() async + test('test unlinkOAuthAccount', () async { // TODO }); diff --git a/mobile/openapi/test/reaction_type_test.dart b/mobile/openapi/test/reaction_type_test.dart new file mode 100644 index 000000000..4c0dfc595 --- /dev/null +++ b/mobile/openapi/test/reaction_type_test.dart @@ -0,0 +1,21 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +import 'package:openapi/api.dart'; +import 'package:test/test.dart'; + +// tests for ReactionType +void main() { + + group('test ReactionType', () { + + }); + +} diff --git a/mobile/openapi/test/server_info_api_test.dart b/mobile/openapi/test/server_info_api_test.dart index f431f521b..dac465116 100644 --- a/mobile/openapi/test/server_info_api_test.dart +++ b/mobile/openapi/test/server_info_api_test.dart @@ -32,13 +32,13 @@ void main() { // TODO }); - //Future getServerVersion() async - test('test getServerVersion', () async { + //Future getServerStatistics() async + test('test getServerStatistics', () async { // TODO }); - //Future getStats() async - test('test getStats', () async { + //Future getServerVersion() async + test('test getServerVersion', () async { // TODO }); diff --git a/mobile/openapi/test/system_config_api_test.dart b/mobile/openapi/test/system_config_api_test.dart index 6cb7aa79d..b8e57aaae 100644 --- a/mobile/openapi/test/system_config_api_test.dart +++ b/mobile/openapi/test/system_config_api_test.dart @@ -22,8 +22,8 @@ void main() { // TODO }); - //Future getDefaults() async - test('test getDefaults', () async { + //Future getConfigDefaults() async + test('test getConfigDefaults', () async { // TODO }); diff --git a/mobile/openapi/test/system_config_dto_test.dart b/mobile/openapi/test/system_config_dto_test.dart index 75e604539..c8b5c0d9c 100644 --- a/mobile/openapi/test/system_config_dto_test.dart +++ b/mobile/openapi/test/system_config_dto_test.dart @@ -26,6 +26,11 @@ void main() { // TODO }); + // SystemConfigLibraryDto library_ + test('to test the property `library_`', () async { + // TODO + }); + // SystemConfigMachineLearningDto machineLearning test('to test the property `machineLearning`', () async { // TODO diff --git a/mobile/openapi/test/system_config_library_dto_test.dart b/mobile/openapi/test/system_config_library_dto_test.dart new file mode 100644 index 000000000..f7051c82e --- /dev/null +++ b/mobile/openapi/test/system_config_library_dto_test.dart @@ -0,0 +1,27 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +import 'package:openapi/api.dart'; +import 'package:test/test.dart'; + +// tests for SystemConfigLibraryDto +void main() { + // final instance = SystemConfigLibraryDto(); + + group('test SystemConfigLibraryDto', () { + // SystemConfigLibraryScanDto scan + test('to test the property `scan`', () async { + // TODO + }); + + + }); + +} diff --git a/mobile/openapi/test/system_config_library_scan_dto_test.dart b/mobile/openapi/test/system_config_library_scan_dto_test.dart new file mode 100644 index 000000000..574013e75 --- /dev/null +++ b/mobile/openapi/test/system_config_library_scan_dto_test.dart @@ -0,0 +1,32 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +import 'package:openapi/api.dart'; +import 'package:test/test.dart'; + +// tests for SystemConfigLibraryScanDto +void main() { + // final instance = SystemConfigLibraryScanDto(); + + group('test SystemConfigLibraryScanDto', () { + // String cronExpression + test('to test the property `cronExpression`', () async { + // TODO + }); + + // bool enabled + test('to test the property `enabled`', () async { + // TODO + }); + + + }); + +} diff --git a/mobile/openapi/test/user_dto_test.dart b/mobile/openapi/test/user_dto_test.dart new file mode 100644 index 000000000..fa1b7da86 --- /dev/null +++ b/mobile/openapi/test/user_dto_test.dart @@ -0,0 +1,47 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// ignore_for_file: unused_element, unused_import +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: lines_longer_than_80_chars + +import 'package:openapi/api.dart'; +import 'package:test/test.dart'; + +// tests for UserDto +void main() { + // final instance = UserDto(); + + group('test UserDto', () { + // String email + test('to test the property `email`', () async { + // TODO + }); + + // String firstName + test('to test the property `firstName`', () async { + // TODO + }); + + // String id + test('to test the property `id`', () async { + // TODO + }); + + // String lastName + test('to test the property `lastName`', () async { + // TODO + }); + + // String profileImagePath + test('to test the property `profileImagePath`', () async { + // TODO + }); + + + }); + +} diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index 73bfd11b0..3fc34f62e 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -1401,7 +1401,7 @@ packages: source: hosted version: "2.1.3" timezone: - dependency: transitive + dependency: "direct main" description: name: timezone sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0" diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index a38797830..6d5aa735d 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -2,7 +2,7 @@ name: immich_mobile description: Immich - selfhosted backup media file on mobile phone publish_to: "none" -version: 1.83.0+107 +version: 1.84.0+108 isar_version: &isar_version 3.1.0+1 environment: @@ -52,6 +52,7 @@ dependencies: crypto: ^3.0.3 # TODO remove once native crypto is used on iOS wakelock_plus: ^1.1.1 flutter_local_notifications: ^15.1.0+1 + timezone: ^0.9.2 openapi: path: openapi diff --git a/server/immich-openapi-specs.json b/server/immich-openapi-specs.json index 49567f7f6..75a57043f 100644 --- a/server/immich-openapi-specs.json +++ b/server/immich-openapi-specs.json @@ -1,6 +1,203 @@ { "openapi": "3.0.0", "paths": { + "/activity": { + "get": { + "operationId": "getActivities", + "parameters": [ + { + "name": "albumId", + "required": true, + "in": "query", + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "name": "assetId", + "required": false, + "in": "query", + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "name": "type", + "required": false, + "in": "query", + "schema": { + "$ref": "#/components/schemas/ReactionType" + } + }, + { + "name": "userId", + "required": false, + "in": "query", + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ActivityResponseDto" + }, + "type": "array" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer": [] + }, + { + "cookie": [] + }, + { + "api_key": [] + } + ], + "tags": [ + "Activity" + ] + }, + "post": { + "operationId": "createActivity", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActivityCreateDto" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActivityResponseDto" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer": [] + }, + { + "cookie": [] + }, + { + "api_key": [] + } + ], + "tags": [ + "Activity" + ] + } + }, + "/activity/statistics": { + "get": { + "operationId": "getActivityStatistics", + "parameters": [ + { + "name": "albumId", + "required": true, + "in": "query", + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "name": "assetId", + "required": false, + "in": "query", + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActivityStatisticsResponseDto" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer": [] + }, + { + "cookie": [] + }, + { + "api_key": [] + } + ], + "tags": [ + "Activity" + ] + } + }, + "/activity/{id}": { + "delete": { + "operationId": "deleteActivity", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "" + } + }, + "security": [ + { + "bearer": [] + }, + { + "cookie": [] + }, + { + "api_key": [] + } + ], + "tags": [ + "Activity" + ] + } + }, "/album": { "get": { "operationId": "getAllAlbums", @@ -481,7 +678,7 @@ }, "/api-key": { "get": { - "operationId": "getKeys", + "operationId": "getApiKeys", "parameters": [], "responses": { "200": { @@ -514,7 +711,7 @@ ] }, "post": { - "operationId": "createKey", + "operationId": "createApiKey", "parameters": [], "requestBody": { "content": { @@ -556,7 +753,7 @@ }, "/api-key/{id}": { "delete": { - "operationId": "deleteKey", + "operationId": "deleteApiKey", "parameters": [ { "name": "id", @@ -589,7 +786,7 @@ ] }, "get": { - "operationId": "getKey", + "operationId": "getApiKey", "parameters": [ { "name": "id", @@ -629,7 +826,7 @@ ] }, "put": { - "operationId": "updateKey", + "operationId": "updateApiKey", "parameters": [ { "name": "id", @@ -887,7 +1084,7 @@ "/asset/bulk-upload-check": { "post": { "description": "Checks if assets exist by checksums", - "operationId": "bulkUploadCheck", + "operationId": "checkBulkUpload", "parameters": [], "requestBody": { "content": { @@ -1658,7 +1855,7 @@ }, "/asset/statistics": { "get": { - "operationId": "getAssetStats", + "operationId": "getAssetStatistics", "parameters": [ { "name": "isArchived", @@ -1780,7 +1977,7 @@ }, "/asset/time-bucket": { "get": { - "operationId": "getByTimeBucket", + "operationId": "getTimeBucket", "parameters": [ { "name": "size", @@ -2399,7 +2596,7 @@ }, "/auth/admin-sign-up": { "post": { - "operationId": "adminSignUp", + "operationId": "signUpAdmin", "parameters": [], "requestBody": { "content": { @@ -2746,7 +2943,7 @@ }, "/library": { "get": { - "operationId": "getAllForUser", + "operationId": "getLibraries", "parameters": [], "responses": { "200": { @@ -3068,7 +3265,7 @@ }, "/oauth/authorize": { "post": { - "operationId": "authorizeOAuth", + "operationId": "startOAuth", "parameters": [], "requestBody": { "content": { @@ -3099,7 +3296,7 @@ }, "/oauth/callback": { "post": { - "operationId": "callback", + "operationId": "finishOAuth", "parameters": [], "requestBody": { "content": { @@ -3132,7 +3329,7 @@ "post": { "deprecated": true, "description": "@deprecated use feature flags and /oauth/authorize", - "operationId": "generateConfig", + "operationId": "generateOAuthConfig", "parameters": [], "requestBody": { "content": { @@ -3163,7 +3360,7 @@ }, "/oauth/link": { "post": { - "operationId": "link", + "operationId": "linkOAuthAccount", "parameters": [], "requestBody": { "content": { @@ -3205,7 +3402,7 @@ }, "/oauth/mobile-redirect": { "get": { - "operationId": "mobileRedirect", + "operationId": "redirectOAuthToMobile", "parameters": [], "responses": { "200": { @@ -3219,7 +3416,7 @@ }, "/oauth/unlink": { "post": { - "operationId": "unlink", + "operationId": "unlinkOAuthAccount", "parameters": [], "responses": { "201": { @@ -4110,9 +4307,9 @@ ] } }, - "/server-info/stats": { + "/server-info/statistics": { "get": { - "operationId": "getStats", + "operationId": "getServerStatistics", "parameters": [], "responses": { "200": { @@ -4640,7 +4837,7 @@ }, "/system-config/defaults": { "get": { - "operationId": "getDefaults", + "operationId": "getConfigDefaults", "parameters": [], "responses": { "200": { @@ -5424,7 +5621,7 @@ "info": { "title": "Immich", "description": "Immich API", - "version": "1.83.0", + "version": "1.84.0", "contact": {} }, "tags": [], @@ -5512,6 +5709,77 @@ ], "type": "object" }, + "ActivityCreateDto": { + "properties": { + "albumId": { + "format": "uuid", + "type": "string" + }, + "assetId": { + "format": "uuid", + "type": "string" + }, + "comment": { + "type": "string" + }, + "type": { + "$ref": "#/components/schemas/ReactionType" + } + }, + "required": [ + "albumId", + "type" + ], + "type": "object" + }, + "ActivityResponseDto": { + "properties": { + "assetId": { + "nullable": true, + "type": "string" + }, + "comment": { + "nullable": true, + "type": "string" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "id": { + "type": "string" + }, + "type": { + "enum": [ + "comment", + "like" + ], + "type": "string" + }, + "user": { + "$ref": "#/components/schemas/UserDto" + } + }, + "required": [ + "id", + "createdAt", + "type", + "user", + "assetId" + ], + "type": "object" + }, + "ActivityStatisticsResponseDto": { + "properties": { + "comments": { + "type": "integer" + } + }, + "required": [ + "comments" + ], + "type": "object" + }, "AddUsersDto": { "properties": { "sharedUserIds": { @@ -7432,6 +7700,13 @@ ], "type": "object" }, + "ReactionType": { + "enum": [ + "comment", + "like" + ], + "type": "string" + }, "RecognitionConfig": { "properties": { "enabled": { @@ -8061,6 +8336,9 @@ "job": { "$ref": "#/components/schemas/SystemConfigJobDto" }, + "library": { + "$ref": "#/components/schemas/SystemConfigLibraryDto" + }, "machineLearning": { "$ref": "#/components/schemas/SystemConfigMachineLearningDto" }, @@ -8104,7 +8382,8 @@ "job", "thumbnail", "trash", - "theme" + "theme", + "library" ], "type": "object" }, @@ -8238,6 +8517,32 @@ ], "type": "object" }, + "SystemConfigLibraryDto": { + "properties": { + "scan": { + "$ref": "#/components/schemas/SystemConfigLibraryScanDto" + } + }, + "required": [ + "scan" + ], + "type": "object" + }, + "SystemConfigLibraryScanDto": { + "properties": { + "cronExpression": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled", + "cronExpression" + ], + "type": "object" + }, "SystemConfigMachineLearningDto": { "properties": { "classification": { @@ -8727,6 +9032,33 @@ ], "type": "object" }, + "UserDto": { + "properties": { + "email": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "id": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "profileImagePath": { + "type": "string" + } + }, + "required": [ + "id", + "firstName", + "lastName", + "email", + "profileImagePath" + ], + "type": "object" + }, "UserResponseDto": { "properties": { "createdAt": { @@ -8780,12 +9112,12 @@ }, "required": [ "id", - "email", "firstName", "lastName", + "email", + "profileImagePath", "storageLabel", "externalPath", - "profileImagePath", "shouldChangePassword", "isAdmin", "createdAt", diff --git a/server/package-lock.json b/server/package-lock.json index 0842da092..6eb1fb7f3 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1,12 +1,12 @@ { "name": "immich", - "version": "1.83.0", + "version": "1.84.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "immich", - "version": "1.83.0", + "version": "1.84.0", "license": "UNLICENSED", "dependencies": { "@babel/runtime": "^7.22.11", @@ -1683,66 +1683,6 @@ "darwin" ] }, - "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", - "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", - "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", - "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", - "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", - "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@nestjs/bull-shared": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/@nestjs/bull-shared/-/bull-shared-10.0.1.tgz", @@ -6118,15 +6058,6 @@ "exiftool-vendored.pl": "12.67.0" } }, - "node_modules/exiftool-vendored.exe": { - "version": "12.67.0", - "resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.67.0.tgz", - "integrity": "sha512-wzgMDoL/VWH34l38g22cVUn43mVFtTSVj0HRjfjR46+4fGwpSvSueeYbwLCZ5NvBAVINCS5Rz9Rl2DVmqoIjsw==", - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/exiftool-vendored.pl": { "version": "12.67.0", "resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.67.0.tgz", @@ -14300,36 +14231,6 @@ "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", "optional": true }, - "@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", - "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", - "optional": true - }, - "@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", - "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", - "optional": true - }, - "@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", - "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", - "optional": true - }, - "@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", - "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", - "optional": true - }, - "@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", - "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", - "optional": true - }, "@nestjs/bull-shared": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/@nestjs/bull-shared/-/bull-shared-10.0.1.tgz", @@ -16944,6 +16845,11 @@ "luxon": "^3.2.1" } }, + "cron-validator": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cron-validator/-/cron-validator-1.3.1.tgz", + "integrity": "sha512-C1HsxuPCY/5opR55G5/WNzyEGDWFVG+6GLrA+fW/sCTcP6A6NTjUP2AK7B8n2PyFs90kDG2qzwm8LMheADku6A==" + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -17608,12 +17514,6 @@ } } }, - "exiftool-vendored.exe": { - "version": "12.67.0", - "resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.67.0.tgz", - "integrity": "sha512-wzgMDoL/VWH34l38g22cVUn43mVFtTSVj0HRjfjR46+4fGwpSvSueeYbwLCZ5NvBAVINCS5Rz9Rl2DVmqoIjsw==", - "optional": true - }, "exiftool-vendored.pl": { "version": "12.67.0", "resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.67.0.tgz", diff --git a/server/package.json b/server/package.json index 182d7f7d5..f073c738a 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "immich", - "version": "1.83.0", + "version": "1.84.0", "description": "", "author": "", "private": true, diff --git a/server/src/domain/access/access.core.ts b/server/src/domain/access/access.core.ts index 1ad971250..414252778 100644 --- a/server/src/domain/access/access.core.ts +++ b/server/src/domain/access/access.core.ts @@ -3,6 +3,9 @@ import { AuthUserDto } from '../auth'; import { IAccessRepository } from '../repositories'; export enum Permission { + ACTIVITY_CREATE = 'activity.create', + ACTIVITY_DELETE = 'activity.delete', + // ASSET_CREATE = 'asset.create', ASSET_READ = 'asset.read', ASSET_UPDATE = 'asset.update', @@ -133,6 +136,20 @@ export class AccessCore { private async hasOtherAccess(authUser: AuthUserDto, permission: Permission, id: string) { switch (permission) { + // uses album id + case Permission.ACTIVITY_CREATE: + return ( + (await this.repository.album.hasOwnerAccess(authUser.id, id)) || + (await this.repository.album.hasSharedAlbumAccess(authUser.id, id)) + ); + + // uses activity id + case Permission.ACTIVITY_DELETE: + return ( + (await this.repository.activity.hasOwnerAccess(authUser.id, id)) || + (await this.repository.activity.hasAlbumOwnerAccess(authUser.id, id)) + ); + case Permission.ASSET_READ: return ( (await this.repository.asset.hasOwnerAccess(authUser.id, id)) || diff --git a/server/src/domain/activity/activity.dto.ts b/server/src/domain/activity/activity.dto.ts new file mode 100644 index 000000000..e1a163b81 --- /dev/null +++ b/server/src/domain/activity/activity.dto.ts @@ -0,0 +1,68 @@ +import { ActivityEntity } from '@app/infra/entities'; +import { ApiProperty } from '@nestjs/swagger'; +import { IsEnum, IsNotEmpty, IsString, ValidateIf } from 'class-validator'; +import { Optional, ValidateUUID } from '../domain.util'; +import { UserDto, mapSimpleUser } from '../user/response-dto'; + +export enum ReactionType { + COMMENT = 'comment', + LIKE = 'like', +} + +export type MaybeDuplicate = { duplicate: boolean; value: T }; + +export class ActivityResponseDto { + id!: string; + createdAt!: Date; + type!: ReactionType; + user!: UserDto; + assetId!: string | null; + comment?: string | null; +} + +export class ActivityStatisticsResponseDto { + @ApiProperty({ type: 'integer' }) + comments!: number; +} + +export class ActivityDto { + @ValidateUUID() + albumId!: string; + + @ValidateUUID({ optional: true }) + assetId?: string; +} + +export class ActivitySearchDto extends ActivityDto { + @IsEnum(ReactionType) + @Optional() + @ApiProperty({ enumName: 'ReactionType', enum: ReactionType }) + type?: ReactionType; + + @ValidateUUID({ optional: true }) + userId?: string; +} + +const isComment = (dto: ActivityCreateDto) => dto.type === 'comment'; + +export class ActivityCreateDto extends ActivityDto { + @IsEnum(ReactionType) + @ApiProperty({ enumName: 'ReactionType', enum: ReactionType }) + type!: ReactionType; + + @ValidateIf(isComment) + @IsNotEmpty() + @IsString() + comment?: string; +} + +export function mapActivity(activity: ActivityEntity): ActivityResponseDto { + return { + id: activity.id, + assetId: activity.assetId, + createdAt: activity.createdAt, + comment: activity.comment, + type: activity.isLiked ? ReactionType.LIKE : ReactionType.COMMENT, + user: mapSimpleUser(activity.user), + }; +} diff --git a/server/src/domain/activity/activity.service.ts b/server/src/domain/activity/activity.service.ts new file mode 100644 index 000000000..bacdab317 --- /dev/null +++ b/server/src/domain/activity/activity.service.ts @@ -0,0 +1,81 @@ +import { ActivityEntity } from '@app/infra/entities'; +import { Inject, Injectable } from '@nestjs/common'; +import { AccessCore, Permission } from '../access'; +import { AuthUserDto } from '../auth'; +import { IAccessRepository, IActivityRepository } from '../repositories'; +import { + ActivityCreateDto, + ActivityDto, + ActivityResponseDto, + ActivitySearchDto, + ActivityStatisticsResponseDto, + MaybeDuplicate, + ReactionType, + mapActivity, +} from './activity.dto'; + +@Injectable() +export class ActivityService { + private access: AccessCore; + + constructor( + @Inject(IAccessRepository) accessRepository: IAccessRepository, + @Inject(IActivityRepository) private repository: IActivityRepository, + ) { + this.access = AccessCore.create(accessRepository); + } + + async getAll(authUser: AuthUserDto, dto: ActivitySearchDto): Promise { + await this.access.requirePermission(authUser, Permission.ALBUM_READ, dto.albumId); + const activities = await this.repository.search({ + userId: dto.userId, + albumId: dto.albumId, + assetId: dto.assetId, + isLiked: dto.type && dto.type === ReactionType.LIKE, + }); + + return activities.map(mapActivity); + } + + async getStatistics(authUser: AuthUserDto, dto: ActivityDto): Promise { + await this.access.requirePermission(authUser, Permission.ALBUM_READ, dto.albumId); + return { comments: await this.repository.getStatistics(dto.assetId, dto.albumId) }; + } + + async create(authUser: AuthUserDto, dto: ActivityCreateDto): Promise> { + await this.access.requirePermission(authUser, Permission.ACTIVITY_CREATE, dto.albumId); + + const common = { + userId: authUser.id, + assetId: dto.assetId, + albumId: dto.albumId, + }; + + let activity: ActivityEntity | null = null; + let duplicate = false; + + if (dto.type === 'like') { + delete dto.comment; + [activity] = await this.repository.search({ + ...common, + isLiked: true, + }); + duplicate = !!activity; + } + + if (!activity) { + activity = await this.repository.create({ + ...common, + isLiked: dto.type === ReactionType.LIKE, + comment: dto.comment, + }); + } + + return { duplicate, value: mapActivity(activity) }; + } + + async delete(authUser: AuthUserDto, id: string): Promise { + await this.access.requirePermission(authUser, Permission.ACTIVITY_DELETE, id); + await this.repository.delete(id); + } +} diff --git a/server/src/domain/activity/activity.spec.ts b/server/src/domain/activity/activity.spec.ts new file mode 100644 index 000000000..968f7421a --- /dev/null +++ b/server/src/domain/activity/activity.spec.ts @@ -0,0 +1,168 @@ +import { BadRequestException } from '@nestjs/common'; +import { authStub, IAccessRepositoryMock, newAccessRepositoryMock } from '@test'; +import { activityStub } from '@test/fixtures/activity.stub'; +import { newActivityRepositoryMock } from '@test/repositories/activity.repository.mock'; +import { IActivityRepository } from '../repositories'; +import { ReactionType } from './activity.dto'; +import { ActivityService } from './activity.service'; + +describe(ActivityService.name, () => { + let sut: ActivityService; + let accessMock: IAccessRepositoryMock; + let activityMock: jest.Mocked; + + beforeEach(async () => { + accessMock = newAccessRepositoryMock(); + activityMock = newActivityRepositoryMock(); + + sut = new ActivityService(accessMock, activityMock); + }); + + it('should work', () => { + expect(sut).toBeDefined(); + }); + + describe('getAll', () => { + it('should get all', async () => { + accessMock.album.hasOwnerAccess.mockResolvedValue(true); + activityMock.search.mockResolvedValue([]); + + await expect(sut.getAll(authStub.admin, { assetId: 'asset-id', albumId: 'album-id' })).resolves.toEqual([]); + + expect(activityMock.search).toHaveBeenCalledWith({ + assetId: 'asset-id', + albumId: 'album-id', + isLiked: undefined, + }); + }); + + it('should filter by type=like', async () => { + accessMock.album.hasOwnerAccess.mockResolvedValue(true); + activityMock.search.mockResolvedValue([]); + + await expect( + sut.getAll(authStub.admin, { assetId: 'asset-id', albumId: 'album-id', type: ReactionType.LIKE }), + ).resolves.toEqual([]); + + expect(activityMock.search).toHaveBeenCalledWith({ + assetId: 'asset-id', + albumId: 'album-id', + isLiked: true, + }); + }); + + it('should filter by type=comment', async () => { + accessMock.album.hasOwnerAccess.mockResolvedValue(true); + activityMock.search.mockResolvedValue([]); + + await expect( + sut.getAll(authStub.admin, { assetId: 'asset-id', albumId: 'album-id', type: ReactionType.COMMENT }), + ).resolves.toEqual([]); + + expect(activityMock.search).toHaveBeenCalledWith({ + assetId: 'asset-id', + albumId: 'album-id', + isLiked: false, + }); + }); + }); + + describe('getStatistics', () => { + it('should get the comment count', async () => { + activityMock.getStatistics.mockResolvedValue(1); + accessMock.album.hasOwnerAccess.mockResolvedValue(true); + await expect( + sut.getStatistics(authStub.admin, { + assetId: 'asset-id', + albumId: activityStub.oneComment.albumId, + }), + ).resolves.toEqual({ comments: 1 }); + }); + }); + + describe('addComment', () => { + it('should require access to the album', async () => { + accessMock.album.hasOwnerAccess.mockResolvedValue(false); + await expect( + sut.create(authStub.admin, { + albumId: 'album-id', + assetId: 'asset-id', + type: ReactionType.COMMENT, + comment: 'comment', + }), + ).rejects.toBeInstanceOf(BadRequestException); + }); + + it('should create a comment', async () => { + accessMock.album.hasOwnerAccess.mockResolvedValue(true); + activityMock.create.mockResolvedValue(activityStub.oneComment); + + await sut.create(authStub.admin, { + albumId: 'album-id', + assetId: 'asset-id', + type: ReactionType.COMMENT, + comment: 'comment', + }); + + expect(activityMock.create).toHaveBeenCalledWith({ + userId: 'admin_id', + albumId: 'album-id', + assetId: 'asset-id', + comment: 'comment', + isLiked: false, + }); + }); + + it('should create a like', async () => { + accessMock.album.hasOwnerAccess.mockResolvedValue(true); + activityMock.create.mockResolvedValue(activityStub.liked); + activityMock.search.mockResolvedValue([]); + + await sut.create(authStub.admin, { + albumId: 'album-id', + assetId: 'asset-id', + type: ReactionType.LIKE, + }); + + expect(activityMock.create).toHaveBeenCalledWith({ + userId: 'admin_id', + albumId: 'album-id', + assetId: 'asset-id', + isLiked: true, + }); + }); + + it('should skip if like exists', async () => { + accessMock.album.hasOwnerAccess.mockResolvedValue(true); + activityMock.search.mockResolvedValue([activityStub.liked]); + + await sut.create(authStub.admin, { + albumId: 'album-id', + assetId: 'asset-id', + type: ReactionType.LIKE, + }); + + expect(activityMock.create).not.toHaveBeenCalled(); + }); + }); + + describe('delete', () => { + it('should require access', async () => { + accessMock.activity.hasOwnerAccess.mockResolvedValue(false); + await expect(sut.delete(authStub.admin, activityStub.oneComment.id)).rejects.toBeInstanceOf(BadRequestException); + expect(activityMock.delete).not.toHaveBeenCalled(); + }); + + it('should let the activity owner delete a comment', async () => { + accessMock.activity.hasOwnerAccess.mockResolvedValue(true); + await sut.delete(authStub.admin, 'activity-id'); + expect(activityMock.delete).toHaveBeenCalledWith('activity-id'); + }); + + it('should let the album owner delete a comment', async () => { + accessMock.activity.hasAlbumOwnerAccess.mockResolvedValue(true); + await sut.delete(authStub.admin, 'activity-id'); + expect(activityMock.delete).toHaveBeenCalledWith('activity-id'); + }); + }); +}); diff --git a/server/src/domain/activity/index.ts b/server/src/domain/activity/index.ts new file mode 100644 index 000000000..f0d954014 --- /dev/null +++ b/server/src/domain/activity/index.ts @@ -0,0 +1,2 @@ +export * from './activity.dto'; +export * from './activity.service'; diff --git a/server/src/domain/album/album.service.spec.ts b/server/src/domain/album/album.service.spec.ts index 25b616ad6..a93cb0ad1 100644 --- a/server/src/domain/album/album.service.spec.ts +++ b/server/src/domain/album/album.service.spec.ts @@ -174,7 +174,7 @@ describe(AlbumService.name, () => { albumThumbnailAssetId: '123', }); - expect(userMock.get).toHaveBeenCalledWith('user-id'); + expect(userMock.get).toHaveBeenCalledWith('user-id', {}); }); it('should require valid userIds', async () => { @@ -185,7 +185,7 @@ describe(AlbumService.name, () => { sharedWithUserIds: ['user-3'], }), ).rejects.toBeInstanceOf(BadRequestException); - expect(userMock.get).toHaveBeenCalledWith('user-3'); + expect(userMock.get).toHaveBeenCalledWith('user-3', {}); expect(albumMock.create).not.toHaveBeenCalled(); }); }); diff --git a/server/src/domain/album/album.service.ts b/server/src/domain/album/album.service.ts index ecff9f49d..b8e789943 100644 --- a/server/src/domain/album/album.service.ts +++ b/server/src/domain/album/album.service.ts @@ -95,7 +95,7 @@ export class AlbumService { async create(authUser: AuthUserDto, dto: CreateAlbumDto): Promise { for (const userId of dto.sharedWithUserIds || []) { - const exists = await this.userRepository.get(userId); + const exists = await this.userRepository.get(userId, {}); if (!exists) { throw new BadRequestException('User not found'); } @@ -238,7 +238,7 @@ export class AlbumService { throw new BadRequestException('User already added'); } - const user = await this.userRepository.get(userId); + const user = await this.userRepository.get(userId, {}); if (!user) { throw new BadRequestException('User not found'); } diff --git a/server/src/domain/asset/asset.service.spec.ts b/server/src/domain/asset/asset.service.spec.ts index 663769d9c..7b93935f6 100644 --- a/server/src/domain/asset/asset.service.spec.ts +++ b/server/src/domain/asset/asset.service.spec.ts @@ -331,17 +331,17 @@ describe(AssetService.name, () => { }); }); - describe('getByTimeBucket', () => { + describe('getTimeBucket', () => { it('should return the assets for a album time bucket if user has album.read', async () => { accessMock.album.hasOwnerAccess.mockResolvedValue(true); - assetMock.getByTimeBucket.mockResolvedValue([assetStub.image]); + assetMock.getTimeBucket.mockResolvedValue([assetStub.image]); await expect( - sut.getByTimeBucket(authStub.admin, { size: TimeBucketSize.DAY, timeBucket: 'bucket', albumId: 'album-id' }), + sut.getTimeBucket(authStub.admin, { size: TimeBucketSize.DAY, timeBucket: 'bucket', albumId: 'album-id' }), ).resolves.toEqual(expect.arrayContaining([expect.objectContaining({ id: 'asset-id' })])); expect(accessMock.album.hasOwnerAccess).toHaveBeenCalledWith(authStub.admin.id, 'album-id'); - expect(assetMock.getByTimeBucket).toBeCalledWith('bucket', { + expect(assetMock.getTimeBucket).toBeCalledWith('bucket', { size: TimeBucketSize.DAY, timeBucket: 'bucket', albumId: 'album-id', @@ -349,17 +349,17 @@ describe(AssetService.name, () => { }); it('should return the assets for a archive time bucket if user has archive.read', async () => { - assetMock.getByTimeBucket.mockResolvedValue([assetStub.image]); + assetMock.getTimeBucket.mockResolvedValue([assetStub.image]); await expect( - sut.getByTimeBucket(authStub.admin, { + sut.getTimeBucket(authStub.admin, { size: TimeBucketSize.DAY, timeBucket: 'bucket', isArchived: true, userId: authStub.admin.id, }), ).resolves.toEqual(expect.arrayContaining([expect.objectContaining({ id: 'asset-id' })])); - expect(assetMock.getByTimeBucket).toBeCalledWith('bucket', { + expect(assetMock.getTimeBucket).toBeCalledWith('bucket', { size: TimeBucketSize.DAY, timeBucket: 'bucket', isArchived: true, @@ -368,16 +368,16 @@ describe(AssetService.name, () => { }); it('should return the assets for a library time bucket if user has library.read', async () => { - assetMock.getByTimeBucket.mockResolvedValue([assetStub.image]); + assetMock.getTimeBucket.mockResolvedValue([assetStub.image]); await expect( - sut.getByTimeBucket(authStub.admin, { + sut.getTimeBucket(authStub.admin, { size: TimeBucketSize.DAY, timeBucket: 'bucket', userId: authStub.admin.id, }), ).resolves.toEqual(expect.arrayContaining([expect.objectContaining({ id: 'asset-id' })])); - expect(assetMock.getByTimeBucket).toBeCalledWith('bucket', { + expect(assetMock.getTimeBucket).toBeCalledWith('bucket', { size: TimeBucketSize.DAY, timeBucket: 'bucket', userId: authStub.admin.id, diff --git a/server/src/domain/asset/asset.service.ts b/server/src/domain/asset/asset.service.ts index 9b6322dac..34da78680 100644 --- a/server/src/domain/asset/asset.service.ts +++ b/server/src/domain/asset/asset.service.ts @@ -194,12 +194,12 @@ export class AssetService { return this.assetRepository.getTimeBuckets(dto); } - async getByTimeBucket( + async getTimeBucket( authUser: AuthUserDto, dto: TimeBucketAssetDto, ): Promise { await this.timeBucketChecks(authUser, dto); - const assets = await this.assetRepository.getByTimeBucket(dto.timeBucket, dto); + const assets = await this.assetRepository.getTimeBucket(dto.timeBucket, dto); if (authUser.isShowMetadata) { return assets.map((asset) => mapAsset(asset, { withStack: true })); } else { diff --git a/server/src/domain/asset/response-dto/asset-response.dto.ts b/server/src/domain/asset/response-dto/asset-response.dto.ts index 0f5e01320..bacd4bfe6 100644 --- a/server/src/domain/asset/response-dto/asset-response.dto.ts +++ b/server/src/domain/asset/response-dto/asset-response.dto.ts @@ -98,7 +98,14 @@ export function mapAsset(entity: AssetEntity, options: AssetMapOptions = {}): As tags: entity.tags?.map(mapTag), people: entity.faces ?.map(mapFace) - .filter((person): person is PersonResponseDto => person !== null && !person.isHidden), + .filter((person): person is PersonResponseDto => person !== null && !person.isHidden) + .reduce((people, person) => { + const existingPerson = people.find((p) => p.id === person.id); + if (!existingPerson) { + people.push(person); + } + return people; + }, [] as PersonResponseDto[]), checksum: entity.checksum.toString('base64'), stackParentId: entity.stackParentId, stack: withStack ? entity.stack?.map((a) => mapAsset(a, { stripMetadata })) ?? undefined : undefined, diff --git a/server/src/domain/auth/auth.service.ts b/server/src/domain/auth/auth.service.ts index 5b65909fa..289f50bfb 100644 --- a/server/src/domain/auth/auth.service.ts +++ b/server/src/domain/auth/auth.service.ts @@ -315,13 +315,8 @@ export class AuthService { const redirectUri = this.normalize(config, url.split('?')[0]); const client = await this.getOAuthClient(config); const params = client.callbackParams(url); - try { - const tokens = await client.callback(redirectUri, params, { state: params.state }); - return client.userinfo(tokens.access_token || ''); - } catch (error: Error | any) { - this.logger.error(`Unable to complete OAuth login: ${error}`, error?.stack); - throw new InternalServerErrorException(`Unable to complete OAuth login: ${error}`, { cause: error }); - } + const tokens = await client.callback(redirectUri, params, { state: params.state }); + return client.userinfo(tokens.access_token || ''); } private async getOAuthClient(config: SystemConfig) { diff --git a/server/src/domain/domain.module.ts b/server/src/domain/domain.module.ts index dc00c692e..d03fd27d4 100644 --- a/server/src/domain/domain.module.ts +++ b/server/src/domain/domain.module.ts @@ -1,4 +1,5 @@ import { DynamicModule, Global, Module, ModuleMetadata, OnApplicationShutdown, Provider } from '@nestjs/common'; +import { ActivityService } from './activity'; import { AlbumService } from './album'; import { APIKeyService } from './api-key'; import { AssetService } from './asset'; @@ -21,6 +22,7 @@ import { TagService } from './tag'; import { UserService } from './user'; const providers: Provider[] = [ + ActivityService, AlbumService, APIKeyService, AssetService, diff --git a/server/src/domain/domain.util.ts b/server/src/domain/domain.util.ts index 9b7ee7521..04ec4f430 100644 --- a/server/src/domain/domain.util.ts +++ b/server/src/domain/domain.util.ts @@ -1,6 +1,7 @@ import { applyDecorators } from '@nestjs/common'; import { ApiProperty } from '@nestjs/swagger'; import { IsArray, IsNotEmpty, IsOptional, IsString, IsUUID, ValidateIf, ValidationOptions } from 'class-validator'; +import { CronJob } from 'cron'; import { basename, extname } from 'node:path'; import sanitize from 'sanitize-filename'; @@ -18,6 +19,16 @@ export function ValidateUUID({ optional, each }: Options = { optional: false, ea ); } +export function validateCronExpression(expression: string) { + try { + new CronJob(expression, () => {}); + } catch (error) { + return false; + } + + return true; +} + interface IValue { value?: string; } diff --git a/server/src/domain/index.ts b/server/src/domain/index.ts index f2b05ac76..e76159d40 100644 --- a/server/src/domain/index.ts +++ b/server/src/domain/index.ts @@ -1,4 +1,5 @@ export * from './access'; +export * from './activity'; export * from './album'; export * from './api-key'; export * from './asset'; diff --git a/server/src/domain/job/job.service.spec.ts b/server/src/domain/job/job.service.spec.ts index dac22a3ec..fa909d1ae 100644 --- a/server/src/domain/job/job.service.spec.ts +++ b/server/src/domain/job/job.service.spec.ts @@ -61,7 +61,6 @@ describe(JobService.name, () => { [{ name: JobName.PERSON_CLEANUP }], [{ name: JobName.QUEUE_GENERATE_THUMBNAILS, data: { force: false } }], [{ name: JobName.CLEAN_OLD_AUDIT_LOGS }], - [{ name: JobName.LIBRARY_QUEUE_SCAN_ALL, data: { force: false } }], ]); }); }); diff --git a/server/src/domain/job/job.service.ts b/server/src/domain/job/job.service.ts index 7b65467af..7ebffcc69 100644 --- a/server/src/domain/job/job.service.ts +++ b/server/src/domain/job/job.service.ts @@ -153,7 +153,6 @@ export class JobService { await this.jobRepository.queue({ name: JobName.PERSON_CLEANUP }); await this.jobRepository.queue({ name: JobName.QUEUE_GENERATE_THUMBNAILS, data: { force: false } }); await this.jobRepository.queue({ name: JobName.CLEAN_OLD_AUDIT_LOGS }); - await this.jobRepository.queue({ name: JobName.LIBRARY_QUEUE_SCAN_ALL, data: { force: false } }); } /** diff --git a/server/src/domain/library/library.service.spec.ts b/server/src/domain/library/library.service.spec.ts index b13675a35..3d7d68736 100644 --- a/server/src/domain/library/library.service.spec.ts +++ b/server/src/domain/library/library.service.spec.ts @@ -1,4 +1,4 @@ -import { AssetType, LibraryType, UserEntity } from '@app/infra/entities'; +import { AssetType, LibraryType, SystemConfig, SystemConfigKey, UserEntity } from '@app/infra/entities'; import { BadRequestException } from '@nestjs/common'; import { @@ -12,6 +12,7 @@ import { newJobRepositoryMock, newLibraryRepositoryMock, newStorageRepositoryMock, + newSystemConfigRepositoryMock, newUserRepositoryMock, userStub, } from '@test'; @@ -23,8 +24,10 @@ import { IJobRepository, ILibraryRepository, IStorageRepository, + ISystemConfigRepository, IUserRepository, } from '../repositories'; +import { SystemConfigCore } from '../system-config/system-config.core'; import { LibraryService } from './library.service'; describe(LibraryService.name, () => { @@ -32,6 +35,7 @@ describe(LibraryService.name, () => { let accessMock: IAccessRepositoryMock; let assetMock: jest.Mocked; + let configMock: jest.Mocked; let cryptoMock: jest.Mocked; let userMock: jest.Mocked; let jobMock: jest.Mocked; @@ -40,6 +44,7 @@ describe(LibraryService.name, () => { beforeEach(() => { accessMock = newAccessRepositoryMock(); + configMock = newSystemConfigRepositoryMock(); libraryMock = newLibraryRepositoryMock(); userMock = newUserRepositoryMock(); assetMock = newAssetRepositoryMock(); @@ -55,13 +60,46 @@ describe(LibraryService.name, () => { accessMock.library.hasOwnerAccess.mockResolvedValue(true); - sut = new LibraryService(accessMock, assetMock, cryptoMock, jobMock, libraryMock, storageMock, userMock); + sut = new LibraryService( + accessMock, + assetMock, + configMock, + cryptoMock, + jobMock, + libraryMock, + storageMock, + userMock, + ); }); it('should work', () => { expect(sut).toBeDefined(); }); + describe('init', () => { + it('should init cron job and subscribe to config changes', async () => { + configMock.load.mockResolvedValue([ + { key: SystemConfigKey.LIBRARY_SCAN_ENABLED, value: true }, + { key: SystemConfigKey.LIBRARY_SCAN_CRON_EXPRESSION, value: '0 0 * * *' }, + ]); + + await sut.init(); + expect(configMock.load).toHaveBeenCalled(); + expect(jobMock.addCronJob).toHaveBeenCalled(); + + SystemConfigCore.create(newSystemConfigRepositoryMock(false)).config$.next({ + library: { + scan: { + enabled: true, + cronExpression: '0 1 * * *', + }, + }, + } as SystemConfig); + + expect(jobMock.updateCronJob).toHaveBeenCalledWith('libraryScan', '0 1 * * *', true); + }); + }); + describe('handleQueueAssetRefresh', () => { it("should not queue assets outside of user's external path", async () => { const mockLibraryJob: ILibraryRefreshJob = { diff --git a/server/src/domain/library/library.service.ts b/server/src/domain/library/library.service.ts index d226b22c7..6bec17c6b 100644 --- a/server/src/domain/library/library.service.ts +++ b/server/src/domain/library/library.service.ts @@ -7,7 +7,7 @@ import { basename, parse } from 'path'; import { AccessCore, Permission } from '../access'; import { AuthUserDto } from '../auth'; import { mimeTypes } from '../domain.constant'; -import { usePagination } from '../domain.util'; +import { usePagination, validateCronExpression } from '../domain.util'; import { IBaseJob, IEntityJob, ILibraryFileJob, ILibraryRefreshJob, JOBS_ASSET_PAGINATION_SIZE, JobName } from '../job'; import { @@ -17,9 +17,11 @@ import { IJobRepository, ILibraryRepository, IStorageRepository, + ISystemConfigRepository, IUserRepository, WithProperty, } from '../repositories'; +import { SystemConfigCore } from '../system-config'; import { CreateLibraryDto, LibraryResponseDto, @@ -33,10 +35,12 @@ import { export class LibraryService { readonly logger = new Logger(LibraryService.name); private access: AccessCore; + private configCore: SystemConfigCore; constructor( @Inject(IAccessRepository) accessRepository: IAccessRepository, @Inject(IAssetRepository) private assetRepository: IAssetRepository, + @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, @Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository, @Inject(IJobRepository) private jobRepository: IJobRepository, @Inject(ILibraryRepository) private repository: ILibraryRepository, @@ -44,6 +48,26 @@ export class LibraryService { @Inject(IUserRepository) private userRepository: IUserRepository, ) { this.access = AccessCore.create(accessRepository); + this.configCore = SystemConfigCore.create(configRepository); + this.configCore.addValidator((config) => { + if (!validateCronExpression(config.library.scan.cronExpression)) { + throw new Error(`Invalid cron expression ${config.library.scan.cronExpression}`); + } + }); + } + + async init() { + const config = await this.configCore.getConfig(); + this.jobRepository.addCronJob( + 'libraryScan', + config.library.scan.cronExpression, + () => this.jobRepository.queue({ name: JobName.LIBRARY_QUEUE_SCAN_ALL, data: { force: false } }), + config.library.scan.enabled, + ); + + this.configCore.config$.subscribe((config) => { + this.jobRepository.updateCronJob('libraryScan', config.library.scan.cronExpression, config.library.scan.enabled); + }); } async getStatistics(authUser: AuthUserDto, id: string): Promise { @@ -343,7 +367,7 @@ export class LibraryService { return false; } - const user = await this.userRepository.get(library.ownerId); + const user = await this.userRepository.get(library.ownerId, {}); if (!user?.externalPath) { this.logger.warn('User has no external path set, cannot refresh library'); return false; diff --git a/server/src/domain/metadata/metadata.service.spec.ts b/server/src/domain/metadata/metadata.service.spec.ts index e6ca7f199..f31605b12 100644 --- a/server/src/domain/metadata/metadata.service.spec.ts +++ b/server/src/domain/metadata/metadata.service.spec.ts @@ -67,6 +67,10 @@ describe(MetadataService.name, () => { ); }); + afterEach(async () => { + await sut.teardown(); + }); + it('should be defined', () => { expect(sut).toBeDefined(); }); diff --git a/server/src/domain/metadata/metadata.service.ts b/server/src/domain/metadata/metadata.service.ts index 8829f6c6f..45193c2e1 100644 --- a/server/src/domain/metadata/metadata.service.ts +++ b/server/src/domain/metadata/metadata.service.ts @@ -4,6 +4,7 @@ import { ExifDateTime, Tags } from 'exiftool-vendored'; import { firstDateTime } from 'exiftool-vendored/dist/FirstDateTime'; import { constants } from 'fs/promises'; import { Duration } from 'luxon'; +import { Subscription } from 'rxjs'; import { usePagination } from '../domain.util'; import { IBaseJob, IEntityJob, JOBS_ASSET_PAGINATION_SIZE, JobName, QueueName } from '../job'; import { @@ -67,6 +68,7 @@ export class MetadataService { private storageCore: StorageCore; private configCore: SystemConfigCore; private oldCities?: string; + private subscription: Subscription | null = null; constructor( @Inject(IAlbumRepository) private albumRepository: IAlbumRepository, @@ -81,10 +83,13 @@ export class MetadataService { ) { this.configCore = SystemConfigCore.create(configRepository); this.storageCore = StorageCore.create(assetRepository, moveRepository, personRepository, storageRepository); - this.configCore.config$.subscribe(() => this.init()); } async init(deleteCache = false) { + if (!this.subscription) { + this.subscription = this.configCore.config$.subscribe(() => this.init()); + } + const { reverseGeocoding } = await this.configCore.getConfig(); const { citiesFileOverride } = reverseGeocoding; @@ -111,6 +116,7 @@ export class MetadataService { } async teardown() { + this.subscription?.unsubscribe(); await this.repository.teardown(); } diff --git a/server/src/domain/repositories/access.repository.ts b/server/src/domain/repositories/access.repository.ts index 7584762fc..43b53e605 100644 --- a/server/src/domain/repositories/access.repository.ts +++ b/server/src/domain/repositories/access.repository.ts @@ -1,6 +1,10 @@ export const IAccessRepository = 'IAccessRepository'; export interface IAccessRepository { + activity: { + hasOwnerAccess(userId: string, albumId: string): Promise; + hasAlbumOwnerAccess(userId: string, albumId: string): Promise; + }; asset: { hasOwnerAccess(userId: string, assetId: string): Promise; hasAlbumAccess(userId: string, assetId: string): Promise; diff --git a/server/src/domain/repositories/activity.repository.ts b/server/src/domain/repositories/activity.repository.ts new file mode 100644 index 000000000..6f5476a28 --- /dev/null +++ b/server/src/domain/repositories/activity.repository.ts @@ -0,0 +1,11 @@ +import { ActivityEntity } from '@app/infra/entities/activity.entity'; +import { ActivitySearch } from '@app/infra/repositories'; + +export const IActivityRepository = 'IActivityRepository'; + +export interface IActivityRepository { + search(options: ActivitySearch): Promise; + create(activity: Partial): Promise; + delete(id: string): Promise; + getStatistics(assetId: string | undefined, albumId: string): Promise; +} diff --git a/server/src/domain/repositories/asset.repository.ts b/server/src/domain/repositories/asset.repository.ts index 086b9ba1a..bdbdd78f2 100644 --- a/server/src/domain/repositories/asset.repository.ts +++ b/server/src/domain/repositories/asset.repository.ts @@ -123,6 +123,6 @@ export interface IAssetRepository { getMapMarkers(ownerId: string, options?: MapMarkerSearchOptions): Promise; getStatistics(ownerId: string, options: AssetStatsOptions): Promise; getTimeBuckets(options: TimeBucketOptions): Promise; - getByTimeBucket(timeBucket: string, options: TimeBucketOptions): Promise; + getTimeBucket(timeBucket: string, options: TimeBucketOptions): Promise; upsertExif(exif: Partial): Promise; } diff --git a/server/src/domain/repositories/index.ts b/server/src/domain/repositories/index.ts index 2c4a10cc2..ff098d8db 100644 --- a/server/src/domain/repositories/index.ts +++ b/server/src/domain/repositories/index.ts @@ -1,4 +1,5 @@ export * from './access.repository'; +export * from './activity.repository'; export * from './album.repository'; export * from './api-key.repository'; export * from './asset.repository'; diff --git a/server/src/domain/repositories/job.repository.ts b/server/src/domain/repositories/job.repository.ts index 3527c9ea6..4b426062f 100644 --- a/server/src/domain/repositories/job.repository.ts +++ b/server/src/domain/repositories/job.repository.ts @@ -111,6 +111,9 @@ export const IJobRepository = 'IJobRepository'; export interface IJobRepository { addHandler(queueName: QueueName, concurrency: number, handler: JobItemHandler): void; + addCronJob(name: string, expression: string, onTick: () => void, start?: boolean): void; + updateCronJob(name: string, expression?: string, start?: boolean): void; + deleteCronJob(name: string): void; setConcurrency(queueName: QueueName, concurrency: number): void; queue(item: JobItem): Promise; pause(name: QueueName): Promise; diff --git a/server/src/domain/repositories/user.repository.ts b/server/src/domain/repositories/user.repository.ts index 3e546c05e..c4647d571 100644 --- a/server/src/domain/repositories/user.repository.ts +++ b/server/src/domain/repositories/user.repository.ts @@ -13,10 +13,14 @@ export interface UserStatsQueryResponse { usage: number; } +export interface UserFindOptions { + withDeleted?: boolean; +} + export const IUserRepository = 'IUserRepository'; export interface IUserRepository { - get(id: string, withDeleted?: boolean): Promise; + get(id: string, options: UserFindOptions): Promise; getAdmin(): Promise; hasAdmin(): Promise; getByEmail(email: string, withPassword?: boolean): Promise; diff --git a/server/src/domain/server-info/server-info.service.spec.ts b/server/src/domain/server-info/server-info.service.spec.ts index 4f6b24680..f4025a331 100644 --- a/server/src/domain/server-info/server-info.service.spec.ts +++ b/server/src/domain/server-info/server-info.service.spec.ts @@ -220,7 +220,7 @@ describe(ServerInfoService.name, () => { }, ]); - await expect(sut.getStats()).resolves.toEqual({ + await expect(sut.getStatistics()).resolves.toEqual({ photos: 120, videos: 31, usage: 1123455, diff --git a/server/src/domain/server-info/server-info.service.ts b/server/src/domain/server-info/server-info.service.ts index f2d312343..dc2efd416 100644 --- a/server/src/domain/server-info/server-info.service.ts +++ b/server/src/domain/server-info/server-info.service.ts @@ -92,7 +92,7 @@ export class ServerInfoService { }; } - async getStats(): Promise { + async getStatistics(): Promise { const userStats: UserStatsQueryResponse[] = await this.userRepository.getUserStats(); const serverStats = new ServerStatsResponseDto(); diff --git a/server/src/domain/storage-template/storage-template.service.ts b/server/src/domain/storage-template/storage-template.service.ts index b14d21bcf..8e8bd81ea 100644 --- a/server/src/domain/storage-template/storage-template.service.ts +++ b/server/src/domain/storage-template/storage-template.service.ts @@ -75,7 +75,7 @@ export class StorageTemplateService { async handleMigrationSingle({ id }: IEntityJob) { const [asset] = await this.assetRepository.getByIds([id]); - const user = await this.userRepository.get(asset.ownerId); + const user = await this.userRepository.get(asset.ownerId, {}); const storageLabel = user?.storageLabel || null; const filename = asset.originalFileName || asset.id; await this.moveAsset(asset, { storageLabel, filename }); diff --git a/server/src/domain/system-config/dto/index.ts b/server/src/domain/system-config/dto/index.ts index 4a94b4cc8..652e34cc5 100644 --- a/server/src/domain/system-config/dto/index.ts +++ b/server/src/domain/system-config/dto/index.ts @@ -1,4 +1,5 @@ export * from './system-config-ffmpeg.dto'; +export * from './system-config-library.dto'; export * from './system-config-oauth.dto'; export * from './system-config-password-login.dto'; export * from './system-config-storage-template.dto'; diff --git a/server/src/domain/system-config/dto/system-config-library.dto.ts b/server/src/domain/system-config/dto/system-config-library.dto.ts new file mode 100644 index 000000000..2280e7093 --- /dev/null +++ b/server/src/domain/system-config/dto/system-config-library.dto.ts @@ -0,0 +1,40 @@ +import { validateCronExpression } from '@app/domain'; +import { Type } from 'class-transformer'; +import { + IsBoolean, + IsNotEmpty, + IsObject, + IsString, + Validate, + ValidateIf, + ValidateNested, + ValidatorConstraint, + ValidatorConstraintInterface, +} from 'class-validator'; + +const isEnabled = (config: SystemConfigLibraryScanDto) => config.enabled; + +@ValidatorConstraint({ name: 'cronValidator' }) +class CronValidator implements ValidatorConstraintInterface { + validate(expression: string): boolean { + return validateCronExpression(expression); + } +} + +export class SystemConfigLibraryScanDto { + @IsBoolean() + enabled!: boolean; + + @ValidateIf(isEnabled) + @IsNotEmpty() + @Validate(CronValidator, { message: 'Invalid cron expression' }) + @IsString() + cronExpression!: string; +} + +export class SystemConfigLibraryDto { + @Type(() => SystemConfigLibraryScanDto) + @ValidateNested() + @IsObject() + scan!: SystemConfigLibraryScanDto; +} diff --git a/server/src/domain/system-config/dto/system-config.dto.ts b/server/src/domain/system-config/dto/system-config.dto.ts index 975f5df89..dbd45855c 100644 --- a/server/src/domain/system-config/dto/system-config.dto.ts +++ b/server/src/domain/system-config/dto/system-config.dto.ts @@ -3,6 +3,7 @@ import { Type } from 'class-transformer'; import { IsObject, ValidateNested } from 'class-validator'; import { SystemConfigFFmpegDto } from './system-config-ffmpeg.dto'; import { SystemConfigJobDto } from './system-config-job.dto'; +import { SystemConfigLibraryDto } from './system-config-library.dto'; import { SystemConfigMachineLearningDto } from './system-config-machine-learning.dto'; import { SystemConfigMapDto } from './system-config-map.dto'; import { SystemConfigNewVersionCheckDto } from './system-config-new-version-check.dto'; @@ -74,6 +75,11 @@ export class SystemConfigDto implements SystemConfig { @ValidateNested() @IsObject() theme!: SystemConfigThemeDto; + + @Type(() => SystemConfigLibraryDto) + @ValidateNested() + @IsObject() + library!: SystemConfigLibraryDto; } export function mapConfig(config: SystemConfig): SystemConfigDto { diff --git a/server/src/domain/system-config/system-config.core.ts b/server/src/domain/system-config/system-config.core.ts index df4ef374b..4596370a4 100644 --- a/server/src/domain/system-config/system-config.core.ts +++ b/server/src/domain/system-config/system-config.core.ts @@ -13,6 +13,7 @@ import { VideoCodec, } from '@app/infra/entities'; import { BadRequestException, ForbiddenException, Injectable, Logger } from '@nestjs/common'; +import { CronExpression } from '@nestjs/schedule'; import { plainToInstance } from 'class-transformer'; import { validate } from 'class-validator'; import * as _ from 'lodash'; @@ -120,6 +121,12 @@ export const defaults = Object.freeze({ theme: { customCss: '', }, + library: { + scan: { + enabled: true, + cronExpression: CronExpression.EVERY_DAY_AT_MIDNIGHT, + }, + }, }); export enum FeatureFlag { diff --git a/server/src/domain/system-config/system-config.service.spec.ts b/server/src/domain/system-config/system-config.service.spec.ts index c3808a8cd..29ed44e91 100644 --- a/server/src/domain/system-config/system-config.service.spec.ts +++ b/server/src/domain/system-config/system-config.service.spec.ts @@ -121,6 +121,12 @@ const updatedConfig = Object.freeze({ theme: { customCss: '', }, + library: { + scan: { + enabled: true, + cronExpression: '0 0 * * *', + }, + }, }); describe(SystemConfigService.name, () => { diff --git a/server/src/domain/user/response-dto/user-response.dto.ts b/server/src/domain/user/response-dto/user-response.dto.ts index 59a387de1..b9f990378 100644 --- a/server/src/domain/user/response-dto/user-response.dto.ts +++ b/server/src/domain/user/response-dto/user-response.dto.ts @@ -1,13 +1,16 @@ import { UserEntity } from '@app/infra/entities'; -export class UserResponseDto { +export class UserDto { id!: string; - email!: string; firstName!: string; lastName!: string; + email!: string; + profileImagePath!: string; +} + +export class UserResponseDto extends UserDto { storageLabel!: string | null; externalPath!: string | null; - profileImagePath!: string; shouldChangePassword!: boolean; isAdmin!: boolean; createdAt!: Date; @@ -17,15 +20,21 @@ export class UserResponseDto { memoriesEnabled?: boolean; } -export function mapUser(entity: UserEntity): UserResponseDto { +export const mapSimpleUser = (entity: UserEntity): UserDto => { return { id: entity.id, email: entity.email, firstName: entity.firstName, lastName: entity.lastName, + profileImagePath: entity.profileImagePath, + }; +}; + +export function mapUser(entity: UserEntity): UserResponseDto { + return { + ...mapSimpleUser(entity), storageLabel: entity.storageLabel, externalPath: entity.externalPath, - profileImagePath: entity.profileImagePath, shouldChangePassword: entity.shouldChangePassword, isAdmin: entity.isAdmin, createdAt: entity.createdAt, diff --git a/server/src/domain/user/user.core.ts b/server/src/domain/user/user.core.ts index a26247781..431caa8e1 100644 --- a/server/src/domain/user/user.core.ts +++ b/server/src/domain/user/user.core.ts @@ -1,5 +1,5 @@ import { LibraryType, UserEntity } from '@app/infra/entities'; -import { BadRequestException, ForbiddenException, InternalServerErrorException, Logger } from '@nestjs/common'; +import { BadRequestException, ForbiddenException } from '@nestjs/common'; import path from 'path'; import sanitize from 'sanitize-filename'; import { AuthUserDto } from '../auth'; @@ -61,26 +61,21 @@ export class UserCore { } } - try { - if (dto.password) { - dto.password = await this.cryptoRepository.hashBcrypt(dto.password, SALT_ROUNDS); - } - - if (dto.storageLabel === '') { - dto.storageLabel = null; - } - - if (dto.externalPath === '') { - dto.externalPath = null; - } else if (dto.externalPath) { - dto.externalPath = path.normalize(dto.externalPath); - } - - return this.userRepository.update(id, dto); - } catch (e) { - Logger.error(e, 'Failed to update user info'); - throw new InternalServerErrorException('Failed to update user info'); + if (dto.password) { + dto.password = await this.cryptoRepository.hashBcrypt(dto.password, SALT_ROUNDS); } + + if (dto.storageLabel === '') { + dto.storageLabel = null; + } + + if (dto.externalPath === '') { + dto.externalPath = null; + } else if (dto.externalPath) { + dto.externalPath = path.normalize(dto.externalPath); + } + + return this.userRepository.update(id, dto); } async createUser(dto: Partial & { email: string }): Promise { @@ -96,59 +91,25 @@ export class UserCore { } } - try { - const payload: Partial = { ...dto }; - if (payload.password) { - payload.password = await this.cryptoRepository.hashBcrypt(payload.password, SALT_ROUNDS); - } - if (payload.storageLabel) { - payload.storageLabel = sanitize(payload.storageLabel); - } - - const userEntity = await this.userRepository.create(payload); - await this.libraryRepository.create({ - owner: { id: userEntity.id } as UserEntity, - name: 'Default Library', - assets: [], - type: LibraryType.UPLOAD, - importPaths: [], - exclusionPatterns: [], - isVisible: true, - }); - - return userEntity; - } catch (e) { - Logger.error(e, 'Create new user'); - throw new InternalServerErrorException('Failed to register new user'); + const payload: Partial = { ...dto }; + if (payload.password) { + payload.password = await this.cryptoRepository.hashBcrypt(payload.password, SALT_ROUNDS); } - } - - async restoreUser(authUser: AuthUserDto, userToRestore: UserEntity): Promise { - if (!authUser.isAdmin) { - throw new ForbiddenException('Unauthorized'); - } - try { - return this.userRepository.restore(userToRestore); - } catch (e) { - Logger.error(e, 'Failed to restore deleted user'); - throw new InternalServerErrorException('Failed to restore deleted user'); - } - } - - async deleteUser(authUser: AuthUserDto, userToDelete: UserEntity): Promise { - if (!authUser.isAdmin) { - throw new ForbiddenException('Unauthorized'); + if (payload.storageLabel) { + payload.storageLabel = sanitize(payload.storageLabel); } - if (userToDelete.isAdmin) { - throw new ForbiddenException('Cannot delete admin user'); - } + const userEntity = await this.userRepository.create(payload); + await this.libraryRepository.create({ + owner: { id: userEntity.id } as UserEntity, + name: 'Default Library', + assets: [], + type: LibraryType.UPLOAD, + importPaths: [], + exclusionPatterns: [], + isVisible: true, + }); - try { - return this.userRepository.delete(userToDelete); - } catch (e) { - Logger.error(e, 'Failed to delete user'); - throw new InternalServerErrorException('Failed to delete user'); - } + return userEntity; } } diff --git a/server/src/domain/user/user.service.spec.ts b/server/src/domain/user/user.service.spec.ts index 180337dff..1f9918fec 100644 --- a/server/src/domain/user/user.service.spec.ts +++ b/server/src/domain/user/user.service.spec.ts @@ -6,6 +6,7 @@ import { NotFoundException, } from '@nestjs/common'; import { + authStub, newAlbumRepositoryMock, newAssetRepositoryMock, newCryptoRepositoryMock, @@ -17,7 +18,6 @@ import { } from '@test'; import { when } from 'jest-when'; import { Readable } from 'stream'; -import { AuthUserDto } from '../auth'; import { JobName } from '../job'; import { IAlbumRepository, @@ -29,7 +29,7 @@ import { IUserRepository, } from '../repositories'; import { UpdateUserDto } from './dto/update-user.dto'; -import { UserResponseDto, mapUser } from './response-dto'; +import { mapUser } from './response-dto'; import { UserService } from './user.service'; const makeDeletedAt = (daysAgo: number) => { @@ -38,95 +38,6 @@ const makeDeletedAt = (daysAgo: number) => { return deletedAt; }; -const adminUserAuth: AuthUserDto = Object.freeze({ - id: 'admin_id', - email: 'admin@test.com', - isAdmin: true, -}); - -const immichUserAuth: AuthUserDto = Object.freeze({ - id: 'user-id', - email: 'immich@test.com', - isAdmin: false, -}); - -const adminUser: UserEntity = Object.freeze({ - id: adminUserAuth.id, - email: 'admin@test.com', - password: 'admin_password', - firstName: 'admin_first_name', - lastName: 'admin_last_name', - isAdmin: true, - oauthId: '', - shouldChangePassword: false, - profileImagePath: '', - createdAt: new Date('2021-01-01'), - deletedAt: null, - updatedAt: new Date('2021-01-01'), - tags: [], - assets: [], - storageLabel: 'admin', - externalPath: null, - memoriesEnabled: true, -}); - -const immichUser: UserEntity = Object.freeze({ - id: immichUserAuth.id, - email: 'immich@test.com', - password: 'immich_password', - firstName: 'immich_first_name', - lastName: 'immich_last_name', - isAdmin: false, - oauthId: '', - shouldChangePassword: false, - profileImagePath: '', - createdAt: new Date('2021-01-01'), - deletedAt: null, - updatedAt: new Date('2021-01-01'), - tags: [], - assets: [], - storageLabel: null, - externalPath: null, - memoriesEnabled: true, -}); - -const updatedImmichUser = Object.freeze({ - id: immichUserAuth.id, - email: 'immich@test.com', - password: 'immich_password', - firstName: 'updated_immich_first_name', - lastName: 'updated_immich_last_name', - isAdmin: false, - oauthId: '', - shouldChangePassword: true, - profileImagePath: '', - createdAt: new Date('2021-01-01'), - deletedAt: null, - updatedAt: new Date('2021-01-01'), - tags: [], - assets: [], - storageLabel: null, - externalPath: null, - memoriesEnabled: true, -}); - -const adminUserResponse = Object.freeze({ - id: adminUserAuth.id, - email: 'admin@test.com', - firstName: 'admin_first_name', - lastName: 'admin_last_name', - isAdmin: true, - oauthId: '', - shouldChangePassword: false, - profileImagePath: '', - createdAt: new Date('2021-01-01'), - deletedAt: null, - updatedAt: new Date('2021-01-01'), - storageLabel: 'admin', - externalPath: null, - memoriesEnabled: true, -}); - describe(UserService.name, () => { let sut: UserService; let userMock: jest.Mocked; @@ -149,119 +60,92 @@ describe(UserService.name, () => { sut = new UserService(albumMock, assetMock, cryptoRepositoryMock, jobMock, libraryMock, storageMock, userMock); - when(userMock.get).calledWith(adminUser.id).mockResolvedValue(adminUser); - when(userMock.get).calledWith(immichUser.id).mockResolvedValue(immichUser); + when(userMock.get).calledWith(authStub.admin.id, {}).mockResolvedValue(userStub.admin); + when(userMock.get).calledWith(authStub.admin.id, { withDeleted: true }).mockResolvedValue(userStub.admin); + when(userMock.get).calledWith(authStub.user1.id, {}).mockResolvedValue(userStub.user1); + when(userMock.get).calledWith(authStub.user1.id, { withDeleted: true }).mockResolvedValue(userStub.user1); }); describe('getAll', () => { it('should get all users', async () => { - userMock.getList.mockResolvedValue([adminUser]); - - const response = await sut.getAll(adminUserAuth, false); - - expect(userMock.getList).toHaveBeenCalledWith({ withDeleted: true }); - expect(response).toEqual([ - { - id: adminUserAuth.id, - email: 'admin@test.com', - firstName: 'admin_first_name', - lastName: 'admin_last_name', - isAdmin: true, - oauthId: '', - shouldChangePassword: false, - profileImagePath: '', - createdAt: new Date('2021-01-01'), - deletedAt: null, - updatedAt: new Date('2021-01-01'), - storageLabel: 'admin', - externalPath: null, - memoriesEnabled: true, - }, + userMock.getList.mockResolvedValue([userStub.admin]); + await expect(sut.getAll(authStub.admin, false)).resolves.toEqual([ + expect.objectContaining({ + id: authStub.admin.id, + email: authStub.admin.email, + }), ]); + expect(userMock.getList).toHaveBeenCalledWith({ withDeleted: true }); }); }); describe('get', () => { it('should get a user by id', async () => { - userMock.get.mockResolvedValue(adminUser); - - const response = await sut.get(adminUser.id); - - expect(userMock.get).toHaveBeenCalledWith(adminUser.id, false); - expect(response).toEqual(adminUserResponse); + userMock.get.mockResolvedValue(userStub.admin); + await sut.get(authStub.admin.id); + expect(userMock.get).toHaveBeenCalledWith(authStub.admin.id, { withDeleted: false }); }); it('should throw an error if a user is not found', async () => { userMock.get.mockResolvedValue(null); - - await expect(sut.get(adminUser.id)).rejects.toBeInstanceOf(NotFoundException); - - expect(userMock.get).toHaveBeenCalledWith(adminUser.id, false); + await expect(sut.get(authStub.admin.id)).rejects.toBeInstanceOf(NotFoundException); + expect(userMock.get).toHaveBeenCalledWith(authStub.admin.id, { withDeleted: false }); }); }); describe('getMe', () => { it("should get the auth user's info", async () => { - userMock.get.mockResolvedValue(adminUser); - - const response = await sut.getMe(adminUser); - - expect(userMock.get).toHaveBeenCalledWith(adminUser.id); - expect(response).toEqual(adminUserResponse); + userMock.get.mockResolvedValue(userStub.admin); + await sut.getMe(authStub.admin); + expect(userMock.get).toHaveBeenCalledWith(authStub.admin.id, {}); }); it('should throw an error if a user is not found', async () => { userMock.get.mockResolvedValue(null); - - await expect(sut.getMe(adminUser)).rejects.toBeInstanceOf(BadRequestException); - - expect(userMock.get).toHaveBeenCalledWith(adminUser.id); + await expect(sut.getMe(authStub.admin)).rejects.toBeInstanceOf(BadRequestException); + expect(userMock.get).toHaveBeenCalledWith(authStub.admin.id, {}); }); }); describe('update', () => { it('should update user', async () => { const update: UpdateUserDto = { - id: immichUser.id, + id: userStub.user1.id, shouldChangePassword: true, email: 'immich@test.com', storageLabel: 'storage_label', }; userMock.getByEmail.mockResolvedValue(null); userMock.getByStorageLabel.mockResolvedValue(null); - userMock.update.mockResolvedValue({ ...updatedImmichUser, isAdmin: true, storageLabel: 'storage_label' }); + userMock.update.mockResolvedValue(userStub.user1); + + await sut.update({ ...authStub.user1, isAdmin: true }, update); - const updatedUser = await sut.update({ ...immichUserAuth, isAdmin: true }, update); - expect(updatedUser.shouldChangePassword).toEqual(true); expect(userMock.getByEmail).toHaveBeenCalledWith(update.email); expect(userMock.getByStorageLabel).toHaveBeenCalledWith(update.storageLabel); }); it('should not set an empty string for storage label', async () => { - userMock.update.mockResolvedValue(updatedImmichUser); - - await sut.update(adminUserAuth, { id: immichUser.id, storageLabel: '' }); - - expect(userMock.update).toHaveBeenCalledWith(immichUser.id, { id: immichUser.id, storageLabel: null }); + userMock.update.mockResolvedValue(userStub.user1); + await sut.update(userStub.admin, { id: userStub.user1.id, storageLabel: '' }); + expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, { id: userStub.user1.id, storageLabel: null }); }); it('should omit a storage label set by non-admin users', async () => { - userMock.update.mockResolvedValue(updatedImmichUser); - - await sut.update(immichUserAuth, { id: immichUser.id, storageLabel: 'admin' }); - - expect(userMock.update).toHaveBeenCalledWith(immichUser.id, { id: immichUser.id }); + userMock.update.mockResolvedValue(userStub.user1); + await sut.update(userStub.user1, { id: userStub.user1.id, storageLabel: 'admin' }); + expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, { id: userStub.user1.id }); }); it('user can only update its information', async () => { when(userMock.get) - .calledWith('not_immich_auth_user_id') + .calledWith('not_immich_auth_user_id', {}) .mockResolvedValueOnce({ - ...immichUser, + ...userStub.user1, id: 'not_immich_auth_user_id', }); - const result = sut.update(immichUserAuth, { + const result = sut.update(userStub.user1, { id: 'not_immich_auth_user_id', password: 'I take over your account now', }); @@ -269,107 +153,104 @@ describe(UserService.name, () => { }); it('should let a user change their email', async () => { - const dto = { id: immichUser.id, email: 'updated@test.com' }; + const dto = { id: userStub.user1.id, email: 'updated@test.com' }; - userMock.get.mockResolvedValue(immichUser); - userMock.update.mockResolvedValue(immichUser); + userMock.get.mockResolvedValue(userStub.user1); + userMock.update.mockResolvedValue(userStub.user1); - await sut.update(immichUser, dto); + await sut.update(userStub.user1, dto); - expect(userMock.update).toHaveBeenCalledWith(immichUser.id, { + expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, { id: 'user-id', email: 'updated@test.com', }); }); it('should not let a user change their email to one already in use', async () => { - const dto = { id: immichUser.id, email: 'updated@test.com' }; + const dto = { id: userStub.user1.id, email: 'updated@test.com' }; - userMock.get.mockResolvedValue(immichUser); - userMock.getByEmail.mockResolvedValue(adminUser); + userMock.get.mockResolvedValue(userStub.user1); + userMock.getByEmail.mockResolvedValue(userStub.admin); - await expect(sut.update(immichUser, dto)).rejects.toBeInstanceOf(BadRequestException); + await expect(sut.update(userStub.user1, dto)).rejects.toBeInstanceOf(BadRequestException); expect(userMock.update).not.toHaveBeenCalled(); }); it('should not let the admin change the storage label to one already in use', async () => { - const dto = { id: immichUser.id, storageLabel: 'admin' }; + const dto = { id: userStub.user1.id, storageLabel: 'admin' }; - userMock.get.mockResolvedValue(immichUser); - userMock.getByStorageLabel.mockResolvedValue(adminUser); + userMock.get.mockResolvedValue(userStub.user1); + userMock.getByStorageLabel.mockResolvedValue(userStub.admin); - await expect(sut.update(adminUser, dto)).rejects.toBeInstanceOf(BadRequestException); + await expect(sut.update(userStub.admin, dto)).rejects.toBeInstanceOf(BadRequestException); expect(userMock.update).not.toHaveBeenCalled(); }); it('admin can update any user information', async () => { const update: UpdateUserDto = { - id: immichUser.id, + id: userStub.user1.id, shouldChangePassword: true, }; - when(userMock.update).calledWith(immichUser.id, update).mockResolvedValueOnce(updatedImmichUser); - - const result = await sut.update(adminUserAuth, update); - - expect(result).toBeDefined(); - expect(result.id).toEqual(updatedImmichUser.id); - expect(result.shouldChangePassword).toEqual(updatedImmichUser.shouldChangePassword); + when(userMock.update).calledWith(userStub.user1.id, update).mockResolvedValueOnce(userStub.user1); + await sut.update(userStub.admin, update); + expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, { + id: 'user-id', + shouldChangePassword: true, + }); }); it('update user information should throw error if user not found', async () => { - when(userMock.get).calledWith(immichUser.id).mockResolvedValueOnce(null); + when(userMock.get).calledWith(userStub.user1.id, {}).mockResolvedValueOnce(null); - const result = sut.update(adminUser, { - id: immichUser.id, + const result = sut.update(userStub.admin, { + id: userStub.user1.id, shouldChangePassword: true, }); - await expect(result).rejects.toBeInstanceOf(NotFoundException); + await expect(result).rejects.toBeInstanceOf(BadRequestException); }); it('should let the admin update himself', async () => { - const dto = { id: adminUser.id, shouldChangePassword: true, isAdmin: true }; + const dto = { id: userStub.admin.id, shouldChangePassword: true, isAdmin: true }; - when(userMock.update).calledWith(adminUser.id, dto).mockResolvedValueOnce(adminUser); + when(userMock.update).calledWith(userStub.admin.id, dto).mockResolvedValueOnce(userStub.admin); - await sut.update(adminUser, dto); + await sut.update(userStub.admin, dto); - expect(userMock.update).toHaveBeenCalledWith(adminUser.id, dto); + expect(userMock.update).toHaveBeenCalledWith(userStub.admin.id, dto); }); it('should not let the another user become an admin', async () => { - const dto = { id: immichUser.id, shouldChangePassword: true, isAdmin: true }; + const dto = { id: userStub.user1.id, shouldChangePassword: true, isAdmin: true }; - when(userMock.get).calledWith(immichUser.id).mockResolvedValueOnce(immichUser); + when(userMock.get).calledWith(userStub.user1.id, {}).mockResolvedValueOnce(userStub.user1); - await expect(sut.update(adminUser, dto)).rejects.toBeInstanceOf(BadRequestException); + await expect(sut.update(userStub.admin, dto)).rejects.toBeInstanceOf(BadRequestException); }); }); describe('restore', () => { it('should throw error if user could not be found', async () => { - userMock.get.mockResolvedValue(null); - - await expect(sut.restore(immichUserAuth, adminUser.id)).rejects.toThrowError(BadRequestException); + when(userMock.get).calledWith(userStub.admin.id, { withDeleted: true }).mockResolvedValue(null); + await expect(sut.restore(authStub.admin, userStub.admin.id)).rejects.toThrowError(BadRequestException); expect(userMock.restore).not.toHaveBeenCalled(); }); it('should require an admin', async () => { - when(userMock.get).calledWith(adminUser.id, true).mockResolvedValue(adminUser); - await expect(sut.restore(immichUserAuth, adminUser.id)).rejects.toBeInstanceOf(ForbiddenException); - expect(userMock.get).toHaveBeenCalledWith(adminUser.id, true); + when(userMock.get).calledWith(userStub.admin.id, { withDeleted: true }).mockResolvedValue(userStub.admin); + await expect(sut.restore(authStub.user1, userStub.admin.id)).rejects.toBeInstanceOf(ForbiddenException); }); it('should restore an user', async () => { - userMock.get.mockResolvedValue(immichUser); - userMock.restore.mockResolvedValue(immichUser); + userMock.get.mockResolvedValue(userStub.user1); + userMock.restore.mockResolvedValue(userStub.user1); - await expect(sut.restore(adminUserAuth, immichUser.id)).resolves.toEqual(mapUser(immichUser)); - expect(userMock.get).toHaveBeenCalledWith(immichUser.id, true); - expect(userMock.restore).toHaveBeenCalledWith(immichUser); + await expect(sut.restore(authStub.admin, userStub.user1.id)).resolves.toEqual(mapUser(userStub.user1)); + expect(userMock.get).toHaveBeenCalledWith(userStub.user1.id, { withDeleted: true }); + expect(userMock.restore).toHaveBeenCalledWith(userStub.user1); }); }); @@ -377,27 +258,27 @@ describe(UserService.name, () => { it('should throw error if user could not be found', async () => { userMock.get.mockResolvedValue(null); - await expect(sut.delete(immichUserAuth, adminUser.id)).rejects.toThrowError(BadRequestException); + await expect(sut.delete(authStub.admin, userStub.admin.id)).rejects.toThrowError(BadRequestException); expect(userMock.delete).not.toHaveBeenCalled(); }); it('cannot delete admin user', async () => { - await expect(sut.delete(adminUserAuth, adminUserAuth.id)).rejects.toBeInstanceOf(ForbiddenException); + await expect(sut.delete(authStub.admin, userStub.admin.id)).rejects.toBeInstanceOf(ForbiddenException); }); it('should require the auth user be an admin', async () => { - await expect(sut.delete(immichUserAuth, adminUserAuth.id)).rejects.toBeInstanceOf(ForbiddenException); + await expect(sut.delete(authStub.user1, authStub.admin.id)).rejects.toBeInstanceOf(ForbiddenException); expect(userMock.delete).not.toHaveBeenCalled(); }); it('should delete user', async () => { - userMock.get.mockResolvedValue(immichUser); - userMock.delete.mockResolvedValue(immichUser); + userMock.get.mockResolvedValue(userStub.user1); + userMock.delete.mockResolvedValue(userStub.user1); - await expect(sut.delete(adminUserAuth, immichUser.id)).resolves.toEqual(mapUser(immichUser)); - expect(userMock.get).toHaveBeenCalledWith(immichUser.id); - expect(userMock.delete).toHaveBeenCalledWith(immichUser); + await expect(sut.delete(userStub.admin, userStub.user1.id)).resolves.toEqual(mapUser(userStub.user1)); + expect(userMock.get).toHaveBeenCalledWith(userStub.user1.id, {}); + expect(userMock.delete).toHaveBeenCalledWith(userStub.user1); }); }); @@ -443,18 +324,18 @@ describe(UserService.name, () => { describe('createProfileImage', () => { it('should throw an error if the user does not exist', async () => { const file = { path: '/profile/path' } as Express.Multer.File; - userMock.update.mockResolvedValue({ ...adminUser, profileImagePath: file.path }); + userMock.update.mockResolvedValue({ ...userStub.admin, profileImagePath: file.path }); - await sut.createProfileImage(adminUserAuth, file); + await sut.createProfileImage(userStub.admin, file); - expect(userMock.update).toHaveBeenCalledWith(adminUserAuth.id, { profileImagePath: file.path }); + expect(userMock.update).toHaveBeenCalledWith(userStub.admin.id, { profileImagePath: file.path }); }); it('should throw an error if the user profile could not be updated with the new image', async () => { const file = { path: '/profile/path' } as Express.Multer.File; userMock.update.mockRejectedValue(new InternalServerErrorException('mocked error')); - await expect(sut.createProfileImage(adminUserAuth, file)).rejects.toThrowError(InternalServerErrorException); + await expect(sut.createProfileImage(userStub.admin, file)).rejects.toThrowError(InternalServerErrorException); }); }); @@ -462,17 +343,17 @@ describe(UserService.name, () => { it('should throw an error if the user does not exist', async () => { userMock.get.mockResolvedValue(null); - await expect(sut.getProfileImage(adminUserAuth.id)).rejects.toBeInstanceOf(BadRequestException); + await expect(sut.getProfileImage(userStub.admin.id)).rejects.toBeInstanceOf(BadRequestException); - expect(userMock.get).toHaveBeenCalledWith(adminUserAuth.id); + expect(userMock.get).toHaveBeenCalledWith(userStub.admin.id, {}); }); it('should throw an error if the user does not have a picture', async () => { - userMock.get.mockResolvedValue(adminUser); + userMock.get.mockResolvedValue(userStub.admin); - await expect(sut.getProfileImage(adminUserAuth.id)).rejects.toBeInstanceOf(NotFoundException); + await expect(sut.getProfileImage(userStub.admin.id)).rejects.toBeInstanceOf(NotFoundException); - expect(userMock.get).toHaveBeenCalledWith(adminUserAuth.id); + expect(userMock.get).toHaveBeenCalledWith(userStub.admin.id, {}); }); it('should return the profile picture', async () => { @@ -483,7 +364,7 @@ describe(UserService.name, () => { await expect(sut.getProfileImage(userStub.profilePath.id)).resolves.toEqual({ stream }); - expect(userMock.get).toHaveBeenCalledWith(userStub.profilePath.id); + expect(userMock.get).toHaveBeenCalledWith(userStub.profilePath.id, {}); expect(storageMock.createReadStream).toHaveBeenCalledWith('/path/to/profile.jpg', 'image/jpeg'); }); }); @@ -499,7 +380,7 @@ describe(UserService.name, () => { }); it('should default to a random password', async () => { - userMock.getAdmin.mockResolvedValue(adminUser); + userMock.getAdmin.mockResolvedValue(userStub.admin); const ask = jest.fn().mockResolvedValue(undefined); const response = await sut.resetAdminPassword(ask); @@ -508,12 +389,12 @@ describe(UserService.name, () => { expect(response.provided).toBe(false); expect(ask).toHaveBeenCalled(); - expect(id).toEqual(adminUser.id); + expect(id).toEqual(userStub.admin.id); expect(update.password).toBeDefined(); }); it('should use the supplied password', async () => { - userMock.getAdmin.mockResolvedValue(adminUser); + userMock.getAdmin.mockResolvedValue(userStub.admin); const ask = jest.fn().mockResolvedValue('new-password'); const response = await sut.resetAdminPassword(ask); @@ -522,7 +403,7 @@ describe(UserService.name, () => { expect(response.provided).toBe(true); expect(ask).toHaveBeenCalled(); - expect(id).toEqual(adminUser.id); + expect(id).toEqual(userStub.admin.id); expect(update.password).toBeDefined(); }); }); diff --git a/server/src/domain/user/user.service.ts b/server/src/domain/user/user.service.ts index 3f36f2bec..a155d401d 100644 --- a/server/src/domain/user/user.service.ts +++ b/server/src/domain/user/user.service.ts @@ -1,5 +1,5 @@ import { UserEntity } from '@app/infra/entities'; -import { BadRequestException, Inject, Injectable, Logger, NotFoundException } from '@nestjs/common'; +import { BadRequestException, ForbiddenException, Inject, Injectable, Logger, NotFoundException } from '@nestjs/common'; import { randomBytes } from 'crypto'; import { AuthUserDto } from '../auth'; import { IEntityJob, JobName } from '../job'; @@ -12,6 +12,7 @@ import { IStorageRepository, IUserRepository, ImmichReadStream, + UserFindOptions, } from '../repositories'; import { StorageCore, StorageFolder } from '../storage'; import { CreateUserDto, UpdateUserDto } from './dto'; @@ -41,7 +42,7 @@ export class UserService { } async get(userId: string): Promise { - const user = await this.userRepository.get(userId, false); + const user = await this.userRepository.get(userId, { withDeleted: false }); if (!user) { throw new NotFoundException('User not found'); } @@ -49,47 +50,43 @@ export class UserService { return mapUser(user); } - async getMe(authUser: AuthUserDto): Promise { - const user = await this.userRepository.get(authUser.id); - if (!user) { - throw new BadRequestException('User not found'); - } - return mapUser(user); + getMe(authUser: AuthUserDto): Promise { + return this.findOrFail(authUser.id, {}).then(mapUser); } - async create(createUserDto: CreateUserDto): Promise { - const createdUser = await this.userCore.createUser(createUserDto); - return mapUser(createdUser); + create(createUserDto: CreateUserDto): Promise { + return this.userCore.createUser(createUserDto).then(mapUser); } async update(authUser: AuthUserDto, dto: UpdateUserDto): Promise { - const user = await this.userRepository.get(dto.id); - if (!user) { - throw new NotFoundException('User not found'); - } - - const updatedUser = await this.userCore.updateUser(authUser, dto.id, dto); - return mapUser(updatedUser); + await this.findOrFail(dto.id, {}); + return this.userCore.updateUser(authUser, dto.id, dto).then(mapUser); } - async delete(authUser: AuthUserDto, userId: string): Promise { - const user = await this.userRepository.get(userId); - if (!user) { - throw new BadRequestException('User not found'); + async delete(authUser: AuthUserDto, id: string): Promise { + if (!authUser.isAdmin) { + throw new ForbiddenException('Unauthorized'); } - await this.albumRepository.softDeleteAll(userId); - const deletedUser = await this.userCore.deleteUser(authUser, user); - return mapUser(deletedUser); + + const user = await this.findOrFail(id, {}); + if (user.isAdmin) { + throw new ForbiddenException('Cannot delete admin user'); + } + + await this.albumRepository.softDeleteAll(id); + + return this.userRepository.delete(user).then(mapUser); } - async restore(authUser: AuthUserDto, userId: string): Promise { - const user = await this.userRepository.get(userId, true); - if (!user) { - throw new BadRequestException('User not found'); + async restore(authUser: AuthUserDto, id: string): Promise { + if (!authUser.isAdmin) { + throw new ForbiddenException('Unauthorized'); } - const updatedUser = await this.userCore.restoreUser(authUser, user); - await this.albumRepository.restoreAll(userId); - return mapUser(updatedUser); + + let user = await this.findOrFail(id, { withDeleted: true }); + user = await this.userRepository.restore(user); + await this.albumRepository.restoreAll(id); + return mapUser(user); } async createProfileImage( @@ -101,7 +98,7 @@ export class UserService { } async getProfileImage(id: string): Promise { - const user = await this.findOrFail(id); + const user = await this.findOrFail(id, {}); if (!user.profileImagePath) { throw new NotFoundException('User does not have a profile image'); } @@ -134,7 +131,7 @@ export class UserService { } async handleUserDelete({ id }: IEntityJob) { - const user = await this.userRepository.get(id, true); + const user = await this.userRepository.get(id, { withDeleted: true }); if (!user) { return false; } @@ -181,8 +178,8 @@ export class UserService { return msSinceDelete >= msDeleteWait; } - private async findOrFail(id: string) { - const user = await this.userRepository.get(id); + private async findOrFail(id: string, options: UserFindOptions) { + const user = await this.userRepository.get(id, options); if (!user) { throw new BadRequestException('User not found'); } diff --git a/server/src/immich/api-v1/asset/asset-repository.ts b/server/src/immich/api-v1/asset/asset-repository.ts index e0e239f6d..9dac7e604 100644 --- a/server/src/immich/api-v1/asset/asset-repository.ts +++ b/server/src/immich/api-v1/asset/asset-repository.ts @@ -109,7 +109,9 @@ export class AssetRepository implements IAssetRepository { faces: { person: true, }, - stack: true, + stack: { + exifInfo: true, + }, }, // We are specifically asking for this asset. Return it even if it is soft deleted withDeleted: true, diff --git a/server/src/immich/api-v1/asset/asset.controller.ts b/server/src/immich/api-v1/asset/asset.controller.ts index ed50e3bec..24127e873 100644 --- a/server/src/immich/api-v1/asset/asset.controller.ts +++ b/server/src/immich/api-v1/asset/asset.controller.ts @@ -17,8 +17,8 @@ import { import { ApiBody, ApiConsumes, ApiHeader, ApiOkResponse, ApiTags } from '@nestjs/swagger'; import { Response as Res } from 'express'; import { AuthUser, Authenticated, SharedLinkRoute } from '../../app.guard'; -import { FileUploadInterceptor, ImmichFile, Route, mapToUploadFile } from '../../app.interceptor'; import { UUIDParamDto } from '../../controllers/dto/uuid-param.dto'; +import { FileUploadInterceptor, ImmichFile, Route, mapToUploadFile } from '../../interceptors'; import FileNotEmptyValidator from '../validation/file-not-empty-validator'; import { AssetService } from './asset.service'; import { AssetBulkUploadCheckDto } from './dto/asset-check.dto'; @@ -204,7 +204,7 @@ export class AssetController { */ @Post('/bulk-upload-check') @HttpCode(HttpStatus.OK) - bulkUploadCheck( + checkBulkUpload( @AuthUser() authUser: AuthUserDto, @Body(ValidationPipe) dto: AssetBulkUploadCheckDto, ): Promise { diff --git a/server/src/immich/app.module.ts b/server/src/immich/app.module.ts index 25771d147..cf95eb236 100644 --- a/server/src/immich/app.module.ts +++ b/server/src/immich/app.module.ts @@ -2,17 +2,17 @@ import { DomainModule } from '@app/domain'; import { InfraModule } from '@app/infra'; import { AssetEntity } from '@app/infra/entities'; import { Module, OnModuleDestroy, OnModuleInit } from '@nestjs/common'; -import { APP_GUARD } from '@nestjs/core'; +import { APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core'; import { ScheduleModule } from '@nestjs/schedule'; import { TypeOrmModule } from '@nestjs/typeorm'; import { AssetRepository, IAssetRepository } from './api-v1/asset/asset-repository'; import { AssetController as AssetControllerV1 } from './api-v1/asset/asset.controller'; import { AssetService } from './api-v1/asset/asset.service'; import { AppGuard } from './app.guard'; -import { FileUploadInterceptor } from './app.interceptor'; import { AppService } from './app.service'; import { APIKeyController, + ActivityController, AlbumController, AppController, AssetController, @@ -30,6 +30,7 @@ import { TagController, UserController, } from './controllers'; +import { ErrorInterceptor, FileUploadInterceptor } from './interceptors'; @Module({ imports: [ @@ -39,6 +40,7 @@ import { TypeOrmModule.forFeature([AssetEntity]), ], controllers: [ + ActivityController, AssetController, AssetControllerV1, AppController, @@ -59,10 +61,9 @@ import { PersonController, ], providers: [ - // - { provide: APP_GUARD, useExisting: AppGuard }, + { provide: APP_INTERCEPTOR, useClass: ErrorInterceptor }, + { provide: APP_GUARD, useClass: AppGuard }, { provide: IAssetRepository, useClass: AssetRepository }, - AppGuard, AppService, AssetService, FileUploadInterceptor, diff --git a/server/src/immich/app.service.ts b/server/src/immich/app.service.ts index 110380753..ef9975d8c 100644 --- a/server/src/immich/app.service.ts +++ b/server/src/immich/app.service.ts @@ -1,4 +1,4 @@ -import { JobService, ONE_HOUR, SearchService, ServerInfoService, StorageService } from '@app/domain'; +import { JobService, LibraryService, ONE_HOUR, SearchService, ServerInfoService, StorageService } from '@app/domain'; import { Injectable, Logger } from '@nestjs/common'; import { Cron, CronExpression, Interval } from '@nestjs/schedule'; @@ -8,6 +8,7 @@ export class AppService { constructor( private jobService: JobService, + private libraryService: LibraryService, private searchService: SearchService, private storageService: StorageService, private serverService: ServerInfoService, @@ -28,6 +29,7 @@ export class AppService { await this.searchService.init(); await this.serverService.handleVersionCheck(); this.logger.log(`Feature Flags: ${JSON.stringify(await this.serverService.getFeatures(), null, 2)}`); + await this.libraryService.init(); } async destroy() { diff --git a/server/src/immich/app.utils.ts b/server/src/immich/app.utils.ts index 1a27b6f30..a7584cb1a 100644 --- a/server/src/immich/app.utils.ts +++ b/server/src/immich/app.utils.ts @@ -47,6 +47,9 @@ function sortKeys(obj: T): T { return result as T; } +export const routeToErrorMessage = (methodName: string) => + 'Failed to ' + methodName.replace(/[A-Z]+/g, (letter) => ` ${letter.toLowerCase()}`); + const patchOpenAPI = (document: OpenAPIObject) => { document.paths = sortKeys(document.paths); if (document.components?.schemas) { @@ -78,6 +81,10 @@ const patchOpenAPI = (document: OpenAPIObject) => { delete operation.summary; } + if (operation.operationId) { + // console.log(`${routeToErrorMessage(operation.operationId).padEnd(40)} (${operation.operationId})`); + } + if (operation.description === '') { delete operation.description; } diff --git a/server/src/immich/controllers/activity.controller.ts b/server/src/immich/controllers/activity.controller.ts new file mode 100644 index 000000000..d6c2ea762 --- /dev/null +++ b/server/src/immich/controllers/activity.controller.ts @@ -0,0 +1,52 @@ +import { AuthUserDto } from '@app/domain'; +import { + ActivityDto, + ActivitySearchDto, + ActivityService, + ActivityCreateDto as CreateDto, + ActivityResponseDto as ResponseDto, + ActivityStatisticsResponseDto as StatsResponseDto, +} from '@app/domain/activity'; +import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Query, Res } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { Response } from 'express'; +import { AuthUser, Authenticated } from '../app.guard'; +import { UseValidation } from '../app.utils'; +import { UUIDParamDto } from './dto/uuid-param.dto'; + +@ApiTags('Activity') +@Controller('activity') +@Authenticated() +@UseValidation() +export class ActivityController { + constructor(private service: ActivityService) {} + + @Get() + getActivities(@AuthUser() authUser: AuthUserDto, @Query() dto: ActivitySearchDto): Promise { + return this.service.getAll(authUser, dto); + } + + @Get('statistics') + getActivityStatistics(@AuthUser() authUser: AuthUserDto, @Query() dto: ActivityDto): Promise { + return this.service.getStatistics(authUser, dto); + } + + @Post() + async createActivity( + @AuthUser() authUser: AuthUserDto, + @Body() dto: CreateDto, + @Res({ passthrough: true }) res: Response, + ): Promise { + const { duplicate, value } = await this.service.create(authUser, dto); + if (duplicate) { + res.status(HttpStatus.OK); + } + return value; + } + + @Delete(':id') + @HttpCode(HttpStatus.NO_CONTENT) + deleteActivity(@AuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto): Promise { + return this.service.delete(authUser, id); + } +} diff --git a/server/src/immich/controllers/api-key.controller.ts b/server/src/immich/controllers/api-key.controller.ts index dc995ddf7..10e0394cf 100644 --- a/server/src/immich/controllers/api-key.controller.ts +++ b/server/src/immich/controllers/api-key.controller.ts @@ -20,22 +20,22 @@ export class APIKeyController { constructor(private service: APIKeyService) {} @Post() - createKey(@AuthUser() authUser: AuthUserDto, @Body() dto: APIKeyCreateDto): Promise { + createApiKey(@AuthUser() authUser: AuthUserDto, @Body() dto: APIKeyCreateDto): Promise { return this.service.create(authUser, dto); } @Get() - getKeys(@AuthUser() authUser: AuthUserDto): Promise { + getApiKeys(@AuthUser() authUser: AuthUserDto): Promise { return this.service.getAll(authUser); } @Get(':id') - getKey(@AuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto): Promise { + getApiKey(@AuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto): Promise { return this.service.getById(authUser, id); } @Put(':id') - updateKey( + updateApiKey( @AuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto, @Body() dto: APIKeyUpdateDto, @@ -44,7 +44,7 @@ export class APIKeyController { } @Delete(':id') - deleteKey(@AuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto): Promise { + deleteApiKey(@AuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto): Promise { return this.service.delete(authUser, id); } } diff --git a/server/src/immich/controllers/asset.controller.ts b/server/src/immich/controllers/asset.controller.ts index 6a91bad30..d0f294d1e 100644 --- a/server/src/immich/controllers/asset.controller.ts +++ b/server/src/immich/controllers/asset.controller.ts @@ -39,10 +39,11 @@ import { import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; import { AuthUser, Authenticated, SharedLinkRoute } from '../app.guard'; import { UseValidation, asStreamableFile } from '../app.utils'; +import { Route } from '../interceptors'; import { UUIDParamDto } from './dto/uuid-param.dto'; @ApiTags('Asset') -@Controller('asset') +@Controller(Route.ASSET) @Authenticated() @UseValidation() export class AssetController { @@ -86,7 +87,7 @@ export class AssetController { } @Get('statistics') - getAssetStats(@AuthUser() authUser: AuthUserDto, @Query() dto: AssetStatsDto): Promise { + getAssetStatistics(@AuthUser() authUser: AuthUserDto, @Query() dto: AssetStatsDto): Promise { return this.service.getStatistics(authUser, dto); } @@ -98,8 +99,8 @@ export class AssetController { @Authenticated({ isShared: true }) @Get('time-bucket') - getByTimeBucket(@AuthUser() authUser: AuthUserDto, @Query() dto: TimeBucketAssetDto): Promise { - return this.service.getByTimeBucket(authUser, dto) as Promise; + getTimeBucket(@AuthUser() authUser: AuthUserDto, @Query() dto: TimeBucketAssetDto): Promise { + return this.service.getTimeBucket(authUser, dto) as Promise; } @Post('jobs') diff --git a/server/src/immich/controllers/auth.controller.ts b/server/src/immich/controllers/auth.controller.ts index 2124cc8b8..83e4b5145 100644 --- a/server/src/immich/controllers/auth.controller.ts +++ b/server/src/immich/controllers/auth.controller.ts @@ -43,7 +43,7 @@ export class AuthController { @PublicRoute() @Post('admin-sign-up') @ApiBadRequestResponse({ description: 'The server already has an admin' }) - adminSignUp(@Body() signUpCredential: SignUpDto): Promise { + signUpAdmin(@Body() signUpCredential: SignUpDto): Promise { return this.service.adminSignUp(signUpCredential); } diff --git a/server/src/immich/controllers/index.ts b/server/src/immich/controllers/index.ts index fd6f0b01e..b54a63d86 100644 --- a/server/src/immich/controllers/index.ts +++ b/server/src/immich/controllers/index.ts @@ -1,3 +1,4 @@ +export * from './activity.controller'; export * from './album.controller'; export * from './api-key.controller'; export * from './app.controller'; diff --git a/server/src/immich/controllers/library.controller.ts b/server/src/immich/controllers/library.controller.ts index 23b1ec7fc..ad1676ee0 100644 --- a/server/src/immich/controllers/library.controller.ts +++ b/server/src/immich/controllers/library.controller.ts @@ -21,7 +21,7 @@ export class LibraryController { constructor(private service: LibraryService) {} @Get() - getAllForUser(@AuthUser() authUser: AuthUserDto): Promise { + getLibraries(@AuthUser() authUser: AuthUserDto): Promise { return this.service.getAllForUser(authUser); } diff --git a/server/src/immich/controllers/oauth.controller.ts b/server/src/immich/controllers/oauth.controller.ts index 176ce62bc..a55cc03ce 100644 --- a/server/src/immich/controllers/oauth.controller.ts +++ b/server/src/immich/controllers/oauth.controller.ts @@ -25,7 +25,7 @@ export class OAuthController { @PublicRoute() @Get('mobile-redirect') @Redirect() - mobileRedirect(@Req() req: Request) { + redirectOAuthToMobile(@Req() req: Request) { return { url: this.service.getMobileRedirect(req.url), statusCode: HttpStatus.TEMPORARY_REDIRECT, @@ -35,19 +35,19 @@ export class OAuthController { /** @deprecated use feature flags and /oauth/authorize */ @PublicRoute() @Post('config') - generateConfig(@Body() dto: OAuthConfigDto): Promise { + generateOAuthConfig(@Body() dto: OAuthConfigDto): Promise { return this.service.generateConfig(dto); } @PublicRoute() @Post('authorize') - authorizeOAuth(@Body() dto: OAuthConfigDto): Promise { + startOAuth(@Body() dto: OAuthConfigDto): Promise { return this.service.authorize(dto); } @PublicRoute() @Post('callback') - async callback( + async finishOAuth( @Res({ passthrough: true }) res: Response, @Body() dto: OAuthCallbackDto, @GetLoginDetails() loginDetails: LoginDetails, @@ -58,12 +58,12 @@ export class OAuthController { } @Post('link') - link(@AuthUser() authUser: AuthUserDto, @Body() dto: OAuthCallbackDto): Promise { + linkOAuthAccount(@AuthUser() authUser: AuthUserDto, @Body() dto: OAuthCallbackDto): Promise { return this.service.link(authUser, dto); } @Post('unlink') - unlink(@AuthUser() authUser: AuthUserDto): Promise { + unlinkOAuthAccount(@AuthUser() authUser: AuthUserDto): Promise { return this.service.unlink(authUser); } } diff --git a/server/src/immich/controllers/server-info.controller.ts b/server/src/immich/controllers/server-info.controller.ts index 7355583ac..52e9ea8d2 100644 --- a/server/src/immich/controllers/server-info.controller.ts +++ b/server/src/immich/controllers/server-info.controller.ts @@ -57,9 +57,9 @@ export class ServerInfoController { } @AdminRoute() - @Get('stats') - getStats(): Promise { - return this.service.getStats(); + @Get('statistics') + getServerStatistics(): Promise { + return this.service.getStatistics(); } @PublicRoute() diff --git a/server/src/immich/controllers/system-config.controller.ts b/server/src/immich/controllers/system-config.controller.ts index 646c9a629..aa44c7acd 100644 --- a/server/src/immich/controllers/system-config.controller.ts +++ b/server/src/immich/controllers/system-config.controller.ts @@ -17,7 +17,7 @@ export class SystemConfigController { } @Get('defaults') - getDefaults(): SystemConfigDto { + getConfigDefaults(): SystemConfigDto { return this.service.getDefaults(); } diff --git a/server/src/immich/controllers/user.controller.ts b/server/src/immich/controllers/user.controller.ts index 7ca8b1c6e..92b3fdcc0 100644 --- a/server/src/immich/controllers/user.controller.ts +++ b/server/src/immich/controllers/user.controller.ts @@ -22,8 +22,8 @@ import { } from '@nestjs/common'; import { ApiBody, ApiConsumes, ApiTags } from '@nestjs/swagger'; import { AdminRoute, AuthUser, Authenticated } from '../app.guard'; -import { FileUploadInterceptor, Route } from '../app.interceptor'; import { UseValidation, asStreamableFile } from '../app.utils'; +import { FileUploadInterceptor, Route } from '../interceptors'; import { UUIDParamDto } from './dto/uuid-param.dto'; @ApiTags('User') diff --git a/server/src/immich/interceptors/error.interceptor.ts b/server/src/immich/interceptors/error.interceptor.ts new file mode 100644 index 000000000..5e18684fd --- /dev/null +++ b/server/src/immich/interceptors/error.interceptor.ts @@ -0,0 +1,32 @@ +import { + CallHandler, + ExecutionContext, + HttpException, + Injectable, + InternalServerErrorException, + Logger, + NestInterceptor, +} from '@nestjs/common'; +import { Observable, catchError, throwError } from 'rxjs'; +import { routeToErrorMessage } from '../app.utils'; + +@Injectable() +export class ErrorInterceptor implements NestInterceptor { + private logger = new Logger(ErrorInterceptor.name); + + async intercept(context: ExecutionContext, next: CallHandler): Promise> { + return next.handle().pipe( + catchError((error) => + throwError(() => { + if (error instanceof HttpException === false) { + const errorMessage = routeToErrorMessage(context.getHandler().name); + this.logger.error(errorMessage, error, error?.errors); + return new InternalServerErrorException(errorMessage); + } else { + return error; + } + }), + ), + ); + } +} diff --git a/server/src/immich/app.interceptor.ts b/server/src/immich/interceptors/file.interceptor.ts similarity index 99% rename from server/src/immich/app.interceptor.ts rename to server/src/immich/interceptors/file.interceptor.ts index 67a09ca73..7388df457 100644 --- a/server/src/immich/app.interceptor.ts +++ b/server/src/immich/interceptors/file.interceptor.ts @@ -7,7 +7,7 @@ import { createHash } from 'crypto'; import { NextFunction, RequestHandler } from 'express'; import multer, { StorageEngine, diskStorage } from 'multer'; import { Observable } from 'rxjs'; -import { AuthRequest } from './app.guard'; +import { AuthRequest } from '../app.guard'; export enum Route { ASSET = 'asset', diff --git a/server/src/immich/interceptors/index.ts b/server/src/immich/interceptors/index.ts new file mode 100644 index 000000000..27c858aba --- /dev/null +++ b/server/src/immich/interceptors/index.ts @@ -0,0 +1,2 @@ +export * from './error.interceptor'; +export * from './file.interceptor'; diff --git a/server/src/infra/entities/activity.entity.ts b/server/src/infra/entities/activity.entity.ts new file mode 100644 index 000000000..255a3a708 --- /dev/null +++ b/server/src/infra/entities/activity.entity.ts @@ -0,0 +1,51 @@ +import { + Check, + Column, + CreateDateColumn, + Entity, + Index, + ManyToOne, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm'; +import { AlbumEntity } from './album.entity'; +import { AssetEntity } from './asset.entity'; +import { UserEntity } from './user.entity'; + +@Entity('activity') +@Index('IDX_activity_like', ['assetId', 'userId', 'albumId'], { unique: true, where: '("isLiked" = true)' }) +@Check(`("comment" IS NULL AND "isLiked" = true) OR ("comment" IS NOT NULL AND "isLiked" = false)`) +export class ActivityEntity { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @CreateDateColumn({ type: 'timestamptz' }) + createdAt!: Date; + + @UpdateDateColumn({ type: 'timestamptz' }) + updatedAt!: Date; + + @Column() + albumId!: string; + + @Column() + userId!: string; + + @Column({ nullable: true, type: 'uuid' }) + assetId!: string | null; + + @Column({ type: 'text', default: null }) + comment!: string | null; + + @Column({ type: 'boolean', default: false }) + isLiked!: boolean; + + @ManyToOne(() => AssetEntity, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: true }) + asset!: AssetEntity | null; + + @ManyToOne(() => UserEntity, { onDelete: 'CASCADE', onUpdate: 'CASCADE' }) + user!: UserEntity; + + @ManyToOne(() => AlbumEntity, { onDelete: 'CASCADE', onUpdate: 'CASCADE' }) + album!: AlbumEntity; +} diff --git a/server/src/infra/entities/index.ts b/server/src/infra/entities/index.ts index ef4d635b0..cbe2bf6c3 100644 --- a/server/src/infra/entities/index.ts +++ b/server/src/infra/entities/index.ts @@ -1,3 +1,4 @@ +import { ActivityEntity } from './activity.entity'; import { AlbumEntity } from './album.entity'; import { APIKeyEntity } from './api-key.entity'; import { AssetFaceEntity } from './asset-face.entity'; @@ -15,6 +16,7 @@ import { TagEntity } from './tag.entity'; import { UserTokenEntity } from './user-token.entity'; import { UserEntity } from './user.entity'; +export * from './activity.entity'; export * from './album.entity'; export * from './api-key.entity'; export * from './asset-face.entity'; @@ -33,6 +35,7 @@ export * from './user-token.entity'; export * from './user.entity'; export const databaseEntities = [ + ActivityEntity, AlbumEntity, APIKeyEntity, AssetEntity, diff --git a/server/src/infra/entities/system-config.entity.ts b/server/src/infra/entities/system-config.entity.ts index de31bad32..b71a44c0a 100644 --- a/server/src/infra/entities/system-config.entity.ts +++ b/server/src/infra/entities/system-config.entity.ts @@ -94,6 +94,9 @@ export enum SystemConfigKey { TRASH_DAYS = 'trash.days', THEME_CUSTOM_CSS = 'theme.customCss', + + LIBRARY_SCAN_ENABLED = 'library.scan.enabled', + LIBRARY_SCAN_CRON_EXPRESSION = 'library.scan.cronExpression', } export enum TranscodePolicy { @@ -232,4 +235,10 @@ export interface SystemConfig { theme: { customCss: string; }; + library: { + scan: { + enabled: boolean; + cronExpression: string; + }; + }; } diff --git a/server/src/infra/infra.module.ts b/server/src/infra/infra.module.ts index 367458169..276058c0b 100644 --- a/server/src/infra/infra.module.ts +++ b/server/src/infra/infra.module.ts @@ -1,5 +1,6 @@ import { IAccessRepository, + IActivityRepository, IAlbumRepository, IAssetRepository, IAuditRepository, @@ -28,6 +29,7 @@ import { import { BullModule } from '@nestjs/bullmq'; import { Global, Module, Provider } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; +import { ScheduleModule, SchedulerRegistry } from '@nestjs/schedule'; import { TypeOrmModule } from '@nestjs/typeorm'; import { databaseConfig } from './database.config'; import { databaseEntities } from './entities'; @@ -35,6 +37,7 @@ import { bullConfig, bullQueues } from './infra.config'; import { APIKeyRepository, AccessRepository, + ActivityRepository, AlbumRepository, AssetRepository, AuditRepository, @@ -60,6 +63,7 @@ import { } from './repositories'; const providers: Provider[] = [ + { provide: IActivityRepository, useClass: ActivityRepository }, { provide: IAccessRepository, useClass: AccessRepository }, { provide: IAlbumRepository, useClass: AlbumRepository }, { provide: IAssetRepository, useClass: AssetRepository }, @@ -84,12 +88,14 @@ const providers: Provider[] = [ { provide: IMediaRepository, useClass: MediaRepository }, { provide: IUserRepository, useClass: UserRepository }, { provide: IUserTokenRepository, useClass: UserTokenRepository }, + SchedulerRegistry, ]; const imports = [ ConfigModule.forRoot(immichAppConfig), TypeOrmModule.forRoot(databaseConfig), TypeOrmModule.forFeature(databaseEntities), + ScheduleModule, ]; const moduleExports = [...providers]; diff --git a/server/src/infra/migrations/1698693294632-AddActivity.ts b/server/src/infra/migrations/1698693294632-AddActivity.ts new file mode 100644 index 000000000..46041570e --- /dev/null +++ b/server/src/infra/migrations/1698693294632-AddActivity.ts @@ -0,0 +1,22 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddActivity1698693294632 implements MigrationInterface { + name = 'AddActivity1698693294632' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "activity" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "albumId" uuid NOT NULL, "userId" uuid NOT NULL, "assetId" uuid, "comment" text, "isLiked" boolean NOT NULL DEFAULT false, CONSTRAINT "CHK_2ab1e70f113f450eb40c1e3ec8" CHECK (("comment" IS NULL AND "isLiked" = true) OR ("comment" IS NOT NULL AND "isLiked" = false)), CONSTRAINT "PK_24625a1d6b1b089c8ae206fe467" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_activity_like" ON "activity" ("assetId", "userId", "albumId") WHERE ("isLiked" = true)`); + await queryRunner.query(`ALTER TABLE "activity" ADD CONSTRAINT "FK_8091ea76b12338cb4428d33d782" FOREIGN KEY ("assetId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE`); + await queryRunner.query(`ALTER TABLE "activity" ADD CONSTRAINT "FK_3571467bcbe021f66e2bdce96ea" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`); + await queryRunner.query(`ALTER TABLE "activity" ADD CONSTRAINT "FK_1af8519996fbfb3684b58df280b" FOREIGN KEY ("albumId") REFERENCES "albums"("id") ON DELETE CASCADE ON UPDATE CASCADE`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "activity" DROP CONSTRAINT "FK_1af8519996fbfb3684b58df280b"`); + await queryRunner.query(`ALTER TABLE "activity" DROP CONSTRAINT "FK_3571467bcbe021f66e2bdce96ea"`); + await queryRunner.query(`ALTER TABLE "activity" DROP CONSTRAINT "FK_8091ea76b12338cb4428d33d782"`); + await queryRunner.query(`DROP INDEX "public"."IDX_activity_like"`); + await queryRunner.query(`DROP TABLE "activity"`); + } + +} diff --git a/server/src/infra/repositories/access.repository.ts b/server/src/infra/repositories/access.repository.ts index 50085c4aa..566514796 100644 --- a/server/src/infra/repositories/access.repository.ts +++ b/server/src/infra/repositories/access.repository.ts @@ -2,6 +2,7 @@ import { IAccessRepository } from '@app/domain'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { + ActivityEntity, AlbumEntity, AssetEntity, LibraryEntity, @@ -13,6 +14,7 @@ import { export class AccessRepository implements IAccessRepository { constructor( + @InjectRepository(ActivityEntity) private activityRepository: Repository, @InjectRepository(AssetEntity) private assetRepository: Repository, @InjectRepository(AlbumEntity) private albumRepository: Repository, @InjectRepository(LibraryEntity) private libraryRepository: Repository, @@ -22,6 +24,26 @@ export class AccessRepository implements IAccessRepository { @InjectRepository(UserTokenEntity) private tokenRepository: Repository, ) {} + activity = { + hasOwnerAccess: (userId: string, activityId: string): Promise => { + return this.activityRepository.exist({ + where: { + id: activityId, + userId, + }, + }); + }, + hasAlbumOwnerAccess: (userId: string, activityId: string): Promise => { + return this.activityRepository.exist({ + where: { + id: activityId, + album: { + ownerId: userId, + }, + }, + }); + }, + }; library = { hasOwnerAccess: (userId: string, libraryId: string): Promise => { return this.libraryRepository.exist({ diff --git a/server/src/infra/repositories/activity.repository.ts b/server/src/infra/repositories/activity.repository.ts new file mode 100644 index 000000000..271124db5 --- /dev/null +++ b/server/src/infra/repositories/activity.repository.ts @@ -0,0 +1,64 @@ +import { IActivityRepository } from '@app/domain'; +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { ActivityEntity } from '../entities/activity.entity'; + +export interface ActivitySearch { + albumId?: string; + assetId?: string; + userId?: string; + isLiked?: boolean; +} + +@Injectable() +export class ActivityRepository implements IActivityRepository { + constructor(@InjectRepository(ActivityEntity) private repository: Repository) {} + + search(options: ActivitySearch): Promise { + const { userId, assetId, albumId, isLiked } = options; + return this.repository.find({ + where: { + userId, + assetId, + albumId, + isLiked, + }, + relations: { + user: true, + }, + order: { + createdAt: 'ASC', + }, + }); + } + + create(entity: Partial): Promise { + return this.save(entity); + } + + async delete(id: string): Promise { + await this.repository.delete(id); + } + + getStatistics(assetId: string, albumId: string): Promise { + return this.repository.count({ + where: { assetId, albumId, isLiked: false }, + relations: { + user: true, + }, + }); + } + + private async save(entity: Partial) { + const { id } = await this.repository.save(entity); + return this.repository.findOneOrFail({ + where: { + id, + }, + relations: { + user: true, + }, + }); + } +} diff --git a/server/src/infra/repositories/asset.repository.ts b/server/src/infra/repositories/asset.repository.ts index 4947c0d76..c237a3604 100644 --- a/server/src/infra/repositories/asset.repository.ts +++ b/server/src/infra/repositories/asset.repository.ts @@ -493,7 +493,7 @@ export class AssetRepository implements IAssetRepository { .getRawMany(); } - getByTimeBucket(timeBucket: string, options: TimeBucketOptions): Promise { + getTimeBucket(timeBucket: string, options: TimeBucketOptions): Promise { const truncated = dateTrunc(options); return ( this.getBuilder(options) diff --git a/server/src/infra/repositories/communication.repository.ts b/server/src/infra/repositories/communication.repository.ts index 908044f40..e1bbc77de 100644 --- a/server/src/infra/repositories/communication.repository.ts +++ b/server/src/infra/repositories/communication.repository.ts @@ -10,7 +10,7 @@ export class CommunicationRepository implements OnGatewayConnection, OnGatewayDi constructor(private authService: AuthService) {} - @WebSocketServer() server!: Server; + @WebSocketServer() server?: Server; addEventListener(event: 'connect', callback: Callback) { this.onConnectCallbacks.push(callback); @@ -37,10 +37,10 @@ export class CommunicationRepository implements OnGatewayConnection, OnGatewayDi } send(event: CommunicationEvent, userId: string, data: any) { - this.server.to(userId).emit(event, data); + this.server?.to(userId).emit(event, data); } broadcast(event: CommunicationEvent, data: any) { - this.server.emit(event, data); + this.server?.emit(event, data); } } diff --git a/server/src/infra/repositories/index.ts b/server/src/infra/repositories/index.ts index bc2fba766..81ea7dd81 100644 --- a/server/src/infra/repositories/index.ts +++ b/server/src/infra/repositories/index.ts @@ -1,4 +1,5 @@ export * from './access.repository'; +export * from './activity.repository'; export * from './album.repository'; export * from './api-key.repository'; export * from './asset.repository'; diff --git a/server/src/infra/repositories/job.repository.ts b/server/src/infra/repositories/job.repository.ts index d34ee6819..067ba9bbf 100644 --- a/server/src/infra/repositories/job.repository.ts +++ b/server/src/infra/repositories/job.repository.ts @@ -2,7 +2,9 @@ import { IJobRepository, JobCounts, JobItem, JobName, JOBS_TO_QUEUE, QueueName, import { getQueueToken } from '@nestjs/bullmq'; import { Injectable, Logger } from '@nestjs/common'; import { ModuleRef } from '@nestjs/core'; +import { SchedulerRegistry } from '@nestjs/schedule'; import { Job, JobsOptions, Processor, Queue, Worker, WorkerOptions } from 'bullmq'; +import { CronJob, CronTime } from 'cron'; import { bullConfig } from '../infra.config'; @Injectable() @@ -10,7 +12,10 @@ export class JobRepository implements IJobRepository { private workers: Partial> = {}; private logger = new Logger(JobRepository.name); - constructor(private moduleRef: ModuleRef) {} + constructor( + private moduleRef: ModuleRef, + private schedulerReqistry: SchedulerRegistry, + ) {} addHandler(queueName: QueueName, concurrency: number, handler: (item: JobItem) => Promise) { const workerHandler: Processor = async (job: Job) => handler(job as JobItem); @@ -18,6 +23,43 @@ export class JobRepository implements IJobRepository { this.workers[queueName] = new Worker(queueName, workerHandler, workerOptions); } + addCronJob(name: string, expression: string, onTick: () => void, start = true): void { + const job = new CronJob( + expression, + onTick, + // function to run onComplete + undefined, + // whether it should start directly + start, + // timezone + undefined, + // context + undefined, + // runOnInit + undefined, + // utcOffset + undefined, + // prevents memory leaking by automatically stopping when the node process finishes + true, + ); + + this.schedulerReqistry.addCronJob(name, job); + } + + updateCronJob(name: string, expression?: string, start?: boolean): void { + const job = this.schedulerReqistry.getCronJob(name); + if (expression) { + job.setTime(new CronTime(expression)); + } + if (start !== undefined) { + start ? job.start() : job.stop(); + } + } + + deleteCronJob(name: string): void { + this.schedulerReqistry.deleteCronJob(name); + } + setConcurrency(queueName: QueueName, concurrency: number) { const worker = this.workers[queueName]; if (!worker) { diff --git a/server/src/infra/repositories/user.repository.ts b/server/src/infra/repositories/user.repository.ts index 559f16aa2..9809ec75d 100644 --- a/server/src/infra/repositories/user.repository.ts +++ b/server/src/infra/repositories/user.repository.ts @@ -1,5 +1,5 @@ -import { IUserRepository, UserListFilter, UserStatsQueryResponse } from '@app/domain'; -import { Injectable, InternalServerErrorException } from '@nestjs/common'; +import { IUserRepository, UserFindOptions, UserListFilter, UserStatsQueryResponse } from '@app/domain'; +import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { IsNull, Not, Repository } from 'typeorm'; import { UserEntity } from '../entities'; @@ -8,8 +8,12 @@ import { UserEntity } from '../entities'; export class UserRepository implements IUserRepository { constructor(@InjectRepository(UserEntity) private userRepository: Repository) {} - async get(userId: string, withDeleted?: boolean): Promise { - return this.userRepository.findOne({ where: { id: userId }, withDeleted: withDeleted }); + async get(userId: string, options: UserFindOptions): Promise { + options = options || {}; + return this.userRepository.findOne({ + where: { id: userId }, + withDeleted: options.withDeleted, + }); } async getAdmin(): Promise { @@ -51,19 +55,13 @@ export class UserRepository implements IUserRepository { }); } - async create(user: Partial): Promise { - return this.userRepository.save(user); + create(user: Partial): Promise { + return this.save(user); } - async update(id: string, user: Partial): Promise { - user.id = id; - - await this.userRepository.save(user); - const updatedUser = await this.get(id); - if (!updatedUser) { - throw new InternalServerErrorException('Cannot reload user after update'); - } - return updatedUser; + // TODO change to (user: Partial) + update(id: string, user: Partial): Promise { + return this.save({ ...user, id }); } async delete(user: UserEntity, hard?: boolean): Promise { @@ -101,4 +99,9 @@ export class UserRepository implements IUserRepository { return stats; } + + private async save(user: Partial) { + const { id } = await this.userRepository.save(user); + return this.userRepository.findOneByOrFail({ id }); + } } diff --git a/server/test/api/activity-api.ts b/server/test/api/activity-api.ts new file mode 100644 index 000000000..f7cac4562 --- /dev/null +++ b/server/test/api/activity-api.ts @@ -0,0 +1,14 @@ +import { ActivityCreateDto, ActivityResponseDto } from '@app/domain'; +import request from 'supertest'; + +export const activityApi = { + create: async (server: any, accessToken: string, dto: ActivityCreateDto) => { + const res = await request(server).post('/activity').set('Authorization', `Bearer ${accessToken}`).send(dto); + expect(res.status === 200 || res.status === 201).toBe(true); + return res.body as ActivityResponseDto; + }, + delete: async (server: any, accessToken: string, id: string) => { + const res = await request(server).delete(`/activity/${id}`).set('Authorization', `Bearer ${accessToken}`); + expect(res.status).toEqual(204); + }, +}; diff --git a/server/test/api/album-api.ts b/server/test/api/album-api.ts index 3364c3452..70a016da1 100644 --- a/server/test/api/album-api.ts +++ b/server/test/api/album-api.ts @@ -1,4 +1,4 @@ -import { AlbumResponseDto, BulkIdResponseDto, BulkIdsDto, CreateAlbumDto } from '@app/domain'; +import { AddUsersDto, AlbumResponseDto, BulkIdResponseDto, BulkIdsDto, CreateAlbumDto } from '@app/domain'; import request from 'supertest'; export const albumApi = { @@ -15,4 +15,9 @@ export const albumApi = { expect(res.status).toEqual(200); return res.body as BulkIdResponseDto[]; }, + addUsers: async (server: any, accessToken: string, id: string, dto: AddUsersDto) => { + const res = await request(server).put(`/album/${id}/users`).set('Authorization', `Bearer ${accessToken}`).send(dto); + expect(res.status).toEqual(200); + return res.body as AlbumResponseDto; + }, }; diff --git a/server/test/api/index.ts b/server/test/api/index.ts index f04a3a209..d9321df27 100644 --- a/server/test/api/index.ts +++ b/server/test/api/index.ts @@ -1,3 +1,4 @@ +import { activityApi } from './activity-api'; import { albumApi } from './album-api'; import { assetApi } from './asset-api'; import { authApi } from './auth-api'; @@ -6,6 +7,7 @@ import { sharedLinkApi } from './shared-link-api'; import { userApi } from './user-api'; export const api = { + activityApi, authApi, assetApi, libraryApi, diff --git a/server/test/e2e/activity.e2e-spec.ts b/server/test/e2e/activity.e2e-spec.ts new file mode 100644 index 000000000..5cc86fc6a --- /dev/null +++ b/server/test/e2e/activity.e2e-spec.ts @@ -0,0 +1,399 @@ +import { AlbumResponseDto, LoginResponseDto, ReactionType } from '@app/domain'; +import { ActivityController } from '@app/immich'; +import { AssetFileUploadResponseDto } from '@app/immich/api-v1/asset/response-dto/asset-file-upload-response.dto'; +import { api } from '@test/api'; +import { db } from '@test/db'; +import { errorStub, uuidStub } from '@test/fixtures'; +import { testApp } from '@test/test-utils'; +import request from 'supertest'; + +describe(`${ActivityController.name} (e2e)`, () => { + let server: any; + let admin: LoginResponseDto; + let asset: AssetFileUploadResponseDto; + let album: AlbumResponseDto; + + beforeAll(async () => { + [server] = await testApp.create(); + }); + + afterAll(async () => { + await testApp.teardown(); + }); + + beforeEach(async () => { + await db.reset(); + await api.authApi.adminSignUp(server); + admin = await api.authApi.adminLogin(server); + asset = await api.assetApi.upload(server, admin.accessToken, 'example'); + album = await api.albumApi.create(server, admin.accessToken, { albumName: 'Album 1', assetIds: [asset.id] }); + }); + + describe('GET /activity', () => { + it('should require authentication', async () => { + const { status, body } = await request(server).get('/activity'); + expect(status).toBe(401); + expect(body).toEqual(errorStub.unauthorized); + }); + + it('should require an albumId', async () => { + const { status, body } = await request(server) + .get('/activity') + .set('Authorization', `Bearer ${admin.accessToken}`); + expect(status).toEqual(400); + expect(body).toEqual(errorStub.badRequest(expect.arrayContaining(['albumId must be a UUID']))); + }); + + it('should reject an invalid albumId', async () => { + const { status, body } = await request(server) + .get('/activity') + .query({ albumId: uuidStub.invalid }) + .set('Authorization', `Bearer ${admin.accessToken}`); + expect(status).toEqual(400); + expect(body).toEqual(errorStub.badRequest(expect.arrayContaining(['albumId must be a UUID']))); + }); + + it('should reject an invalid assetId', async () => { + const { status, body } = await request(server) + .get('/activity') + .query({ albumId: uuidStub.notFound, assetId: uuidStub.invalid }) + .set('Authorization', `Bearer ${admin.accessToken}`); + expect(status).toEqual(400); + expect(body).toEqual(errorStub.badRequest(expect.arrayContaining(['assetId must be a UUID']))); + }); + + it('should start off empty', async () => { + const { status, body } = await request(server) + .get('/activity') + .query({ albumId: album.id }) + .set('Authorization', `Bearer ${admin.accessToken}`); + expect(body).toEqual([]); + expect(status).toEqual(200); + }); + + it('should filter by album id', async () => { + const album2 = await api.albumApi.create(server, admin.accessToken, { + albumName: 'Album 2', + assetIds: [asset.id], + }); + const [reaction] = await Promise.all([ + api.activityApi.create(server, admin.accessToken, { + albumId: album.id, + type: ReactionType.LIKE, + }), + api.activityApi.create(server, admin.accessToken, { + albumId: album2.id, + type: ReactionType.LIKE, + }), + ]); + + const { status, body } = await request(server) + .get('/activity') + .query({ albumId: album.id }) + .set('Authorization', `Bearer ${admin.accessToken}`); + expect(status).toEqual(200); + expect(body.length).toBe(1); + expect(body[0]).toEqual(reaction); + }); + + it('should filter by type=comment', async () => { + const [reaction] = await Promise.all([ + api.activityApi.create(server, admin.accessToken, { + albumId: album.id, + type: ReactionType.COMMENT, + comment: 'comment', + }), + api.activityApi.create(server, admin.accessToken, { albumId: album.id, type: ReactionType.LIKE }), + ]); + + const { status, body } = await request(server) + .get('/activity') + .query({ albumId: album.id, type: 'comment' }) + .set('Authorization', `Bearer ${admin.accessToken}`); + expect(status).toEqual(200); + expect(body.length).toBe(1); + expect(body[0]).toEqual(reaction); + }); + + it('should filter by type=like', async () => { + const [reaction] = await Promise.all([ + api.activityApi.create(server, admin.accessToken, { albumId: album.id, type: ReactionType.LIKE }), + api.activityApi.create(server, admin.accessToken, { + albumId: album.id, + type: ReactionType.COMMENT, + comment: 'comment', + }), + ]); + + const { status, body } = await request(server) + .get('/activity') + .query({ albumId: album.id, type: 'like' }) + .set('Authorization', `Bearer ${admin.accessToken}`); + expect(status).toEqual(200); + expect(body.length).toBe(1); + expect(body[0]).toEqual(reaction); + }); + + it('should filter by userId', async () => { + const [reaction] = await Promise.all([ + api.activityApi.create(server, admin.accessToken, { albumId: album.id, type: ReactionType.LIKE }), + ]); + + const response1 = await request(server) + .get('/activity') + .query({ albumId: album.id, userId: uuidStub.notFound }) + .set('Authorization', `Bearer ${admin.accessToken}`); + + expect(response1.status).toEqual(200); + expect(response1.body.length).toBe(0); + + const response2 = await request(server) + .get('/activity') + .query({ albumId: album.id, userId: admin.userId }) + .set('Authorization', `Bearer ${admin.accessToken}`); + + expect(response2.status).toEqual(200); + expect(response2.body.length).toBe(1); + expect(response2.body[0]).toEqual(reaction); + }); + + it('should filter by assetId', async () => { + const [reaction] = await Promise.all([ + api.activityApi.create(server, admin.accessToken, { + albumId: album.id, + assetId: asset.id, + type: ReactionType.LIKE, + }), + api.activityApi.create(server, admin.accessToken, { albumId: album.id, type: ReactionType.LIKE }), + ]); + + const { status, body } = await request(server) + .get('/activity') + .query({ albumId: album.id, assetId: asset.id }) + .set('Authorization', `Bearer ${admin.accessToken}`); + expect(status).toEqual(200); + expect(body.length).toBe(1); + expect(body[0]).toEqual(reaction); + }); + }); + + describe('POST /activity', () => { + it('should require authentication', async () => { + const { status, body } = await request(server).post('/activity'); + expect(status).toBe(401); + expect(body).toEqual(errorStub.unauthorized); + }); + + it('should require an albumId', async () => { + const { status, body } = await request(server) + .post('/activity') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send({ albumId: uuidStub.invalid }); + expect(status).toEqual(400); + expect(body).toEqual(errorStub.badRequest(expect.arrayContaining(['albumId must be a UUID']))); + }); + + it('should require a comment when type is comment', async () => { + const { status, body } = await request(server) + .post('/activity') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send({ albumId: uuidStub.notFound, type: 'comment', comment: null }); + expect(status).toEqual(400); + expect(body).toEqual(errorStub.badRequest(['comment must be a string', 'comment should not be empty'])); + }); + + it('should add a comment to an album', async () => { + const { status, body } = await request(server) + .post('/activity') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send({ albumId: album.id, type: 'comment', comment: 'This is my first comment' }); + expect(status).toEqual(201); + expect(body).toEqual({ + id: expect.any(String), + assetId: null, + createdAt: expect.any(String), + type: 'comment', + comment: 'This is my first comment', + user: expect.objectContaining({ email: admin.userEmail }), + }); + }); + + it('should add a like to an album', async () => { + const { status, body } = await request(server) + .post('/activity') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send({ albumId: album.id, type: 'like' }); + expect(status).toEqual(201); + expect(body).toEqual({ + id: expect.any(String), + assetId: null, + createdAt: expect.any(String), + type: 'like', + comment: null, + user: expect.objectContaining({ email: admin.userEmail }), + }); + }); + + it('should return a 200 for a duplicate like on the album', async () => { + const reaction = await api.activityApi.create(server, admin.accessToken, { + albumId: album.id, + type: ReactionType.LIKE, + }); + const { status, body } = await request(server) + .post('/activity') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send({ albumId: album.id, type: 'like' }); + expect(status).toEqual(200); + expect(body).toEqual(reaction); + }); + + it('should add a comment to an asset', async () => { + const { status, body } = await request(server) + .post('/activity') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send({ albumId: album.id, assetId: asset.id, type: 'comment', comment: 'This is my first comment' }); + expect(status).toEqual(201); + expect(body).toEqual({ + id: expect.any(String), + assetId: asset.id, + createdAt: expect.any(String), + type: 'comment', + comment: 'This is my first comment', + user: expect.objectContaining({ email: admin.userEmail }), + }); + }); + + it('should add a like to an asset', async () => { + const { status, body } = await request(server) + .post('/activity') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send({ albumId: album.id, assetId: asset.id, type: 'like' }); + expect(status).toEqual(201); + expect(body).toEqual({ + id: expect.any(String), + assetId: asset.id, + createdAt: expect.any(String), + type: 'like', + comment: null, + user: expect.objectContaining({ email: admin.userEmail }), + }); + }); + + it('should return a 200 for a duplicate like on an asset', async () => { + const reaction = await api.activityApi.create(server, admin.accessToken, { + albumId: album.id, + assetId: asset.id, + type: ReactionType.LIKE, + }); + const { status, body } = await request(server) + .post('/activity') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send({ albumId: album.id, assetId: asset.id, type: 'like' }); + expect(status).toEqual(200); + expect(body).toEqual(reaction); + }); + }); + + describe('DELETE /activity/:id', () => { + it('should require authentication', async () => { + const { status, body } = await request(server).delete(`/activity/${uuidStub.notFound}`); + expect(status).toBe(401); + expect(body).toEqual(errorStub.unauthorized); + }); + + it('should require a valid uuid', async () => { + const { status, body } = await request(server) + .delete(`/activity/${uuidStub.invalid}`) + .set('Authorization', `Bearer ${admin.accessToken}`); + expect(status).toBe(400); + expect(body).toEqual(errorStub.badRequest(['id must be a UUID'])); + }); + + it('should remove a comment from an album', async () => { + const reaction = await api.activityApi.create(server, admin.accessToken, { + albumId: album.id, + type: ReactionType.COMMENT, + comment: 'This is a test comment', + }); + const { status } = await request(server) + .delete(`/activity/${reaction.id}`) + .set('Authorization', `Bearer ${admin.accessToken}`); + expect(status).toEqual(204); + }); + + it('should remove a like from an album', async () => { + const reaction = await api.activityApi.create(server, admin.accessToken, { + albumId: album.id, + type: ReactionType.LIKE, + }); + const { status } = await request(server) + .delete(`/activity/${reaction.id}`) + .set('Authorization', `Bearer ${admin.accessToken}`); + expect(status).toEqual(204); + }); + + it('should let the owner remove a comment by another user', async () => { + const { id: userId } = await api.userApi.create(server, admin.accessToken, { + email: 'user1@immich.app', + password: 'Password123', + firstName: 'User 1', + lastName: 'Test', + }); + await api.albumApi.addUsers(server, admin.accessToken, album.id, { sharedUserIds: [userId] }); + const nonOwner = await api.authApi.login(server, { email: 'user1@immich.app', password: 'Password123' }); + const reaction = await api.activityApi.create(server, nonOwner.accessToken, { + albumId: album.id, + type: ReactionType.COMMENT, + comment: 'This is a test comment', + }); + + const { status } = await request(server) + .delete(`/activity/${reaction.id}`) + .set('Authorization', `Bearer ${admin.accessToken}`); + expect(status).toEqual(204); + }); + + it('should not let a user remove a comment by another user', async () => { + const { id: userId } = await api.userApi.create(server, admin.accessToken, { + email: 'user1@immich.app', + password: 'Password123', + firstName: 'User 1', + lastName: 'Test', + }); + await api.albumApi.addUsers(server, admin.accessToken, album.id, { sharedUserIds: [userId] }); + const nonOwner = await api.authApi.login(server, { email: 'user1@immich.app', password: 'Password123' }); + const reaction = await api.activityApi.create(server, admin.accessToken, { + albumId: album.id, + type: ReactionType.COMMENT, + comment: 'This is a test comment', + }); + + const { status, body } = await request(server) + .delete(`/activity/${reaction.id}`) + .set('Authorization', `Bearer ${nonOwner.accessToken}`); + expect(status).toBe(400); + expect(body).toEqual(errorStub.badRequest('Not found or no activity.delete access')); + }); + + it('should let a non-owner remove their own comment', async () => { + const { id: userId } = await api.userApi.create(server, admin.accessToken, { + email: 'user1@immich.app', + password: 'Password123', + firstName: 'User 1', + lastName: 'Test', + }); + await api.albumApi.addUsers(server, admin.accessToken, album.id, { sharedUserIds: [userId] }); + const nonOwner = await api.authApi.login(server, { email: 'user1@immich.app', password: 'Password123' }); + const reaction = await api.activityApi.create(server, nonOwner.accessToken, { + albumId: album.id, + type: ReactionType.COMMENT, + comment: 'This is a test comment', + }); + + const { status } = await request(server) + .delete(`/activity/${reaction.id}`) + .set('Authorization', `Bearer ${nonOwner.accessToken}`); + expect(status).toBe(204); + }); + }); +}); diff --git a/server/test/e2e/server-info.e2e-spec.ts b/server/test/e2e/server-info.e2e-spec.ts index a19c6235e..33b7c5693 100644 --- a/server/test/e2e/server-info.e2e-spec.ts +++ b/server/test/e2e/server-info.e2e-spec.ts @@ -103,9 +103,9 @@ describe(`${ServerInfoController.name} (e2e)`, () => { }); }); - describe('GET /server-info/stats', () => { + describe('GET /server-info/statistics', () => { it('should require authentication', async () => { - const { status, body } = await request(server).get('/server-info/stats'); + const { status, body } = await request(server).get('/server-info/statistics'); expect(status).toBe(401); expect(body).toEqual(errorStub.unauthorized); }); @@ -115,7 +115,7 @@ describe(`${ServerInfoController.name} (e2e)`, () => { await api.userApi.create(server, accessToken, { ...loginDto, firstName: 'test', lastName: 'test' }); const { accessToken: userAccessToken } = await api.authApi.login(server, loginDto); const { status, body } = await request(server) - .get('/server-info/stats') + .get('/server-info/statistics') .set('Authorization', `Bearer ${userAccessToken}`); expect(status).toBe(403); expect(body).toEqual(errorStub.forbidden); @@ -123,7 +123,7 @@ describe(`${ServerInfoController.name} (e2e)`, () => { it('should return the server stats', async () => { const { status, body } = await request(server) - .get('/server-info/stats') + .get('/server-info/statistics') .set('Authorization', `Bearer ${accessToken}`); expect(status).toBe(200); expect(body).toEqual({ diff --git a/server/test/fixtures/activity.stub.ts b/server/test/fixtures/activity.stub.ts new file mode 100644 index 000000000..91c699cec --- /dev/null +++ b/server/test/fixtures/activity.stub.ts @@ -0,0 +1,34 @@ +import { ActivityEntity } from '@app/infra/entities'; +import { albumStub } from './album.stub'; +import { assetStub } from './asset.stub'; +import { authStub } from './auth.stub'; +import { userStub } from './user.stub'; + +export const activityStub = { + oneComment: Object.freeze({ + id: 'activity-1', + comment: 'comment', + isLiked: false, + userId: authStub.admin.id, + user: userStub.admin, + assetId: assetStub.image.id, + asset: assetStub.image, + albumId: albumStub.oneAsset.id, + album: albumStub.oneAsset, + createdAt: new Date(), + updatedAt: new Date(), + }), + liked: Object.freeze({ + id: 'activity-2', + comment: null, + isLiked: true, + userId: authStub.admin.id, + user: userStub.admin, + assetId: assetStub.image.id, + asset: assetStub.image, + albumId: albumStub.oneAsset.id, + album: albumStub.oneAsset, + createdAt: new Date(), + updatedAt: new Date(), + }), +}; diff --git a/server/test/repositories/access.repository.mock.ts b/server/test/repositories/access.repository.mock.ts index 9fbf7922d..4f7992e86 100644 --- a/server/test/repositories/access.repository.mock.ts +++ b/server/test/repositories/access.repository.mock.ts @@ -1,6 +1,7 @@ import { AccessCore, IAccessRepository } from '@app/domain'; export interface IAccessRepositoryMock { + activity: jest.Mocked; asset: jest.Mocked; album: jest.Mocked; authDevice: jest.Mocked; @@ -15,6 +16,10 @@ export const newAccessRepositoryMock = (reset = true): IAccessRepositoryMock => } return { + activity: { + hasOwnerAccess: jest.fn(), + hasAlbumOwnerAccess: jest.fn(), + }, asset: { hasOwnerAccess: jest.fn(), hasAlbumAccess: jest.fn(), diff --git a/server/test/repositories/activity.repository.mock.ts b/server/test/repositories/activity.repository.mock.ts new file mode 100644 index 000000000..349fa4636 --- /dev/null +++ b/server/test/repositories/activity.repository.mock.ts @@ -0,0 +1,10 @@ +import { IActivityRepository } from '@app/domain'; + +export const newActivityRepositoryMock = (): jest.Mocked => { + return { + search: jest.fn(), + create: jest.fn(), + delete: jest.fn(), + getStatistics: jest.fn(), + }; +}; diff --git a/server/test/repositories/asset.repository.mock.ts b/server/test/repositories/asset.repository.mock.ts index 57020001c..c185d3983 100644 --- a/server/test/repositories/asset.repository.mock.ts +++ b/server/test/repositories/asset.repository.mock.ts @@ -26,7 +26,7 @@ export const newAssetRepositoryMock = (): jest.Mocked => { findLivePhotoMatch: jest.fn(), getMapMarkers: jest.fn(), getStatistics: jest.fn(), - getByTimeBucket: jest.fn(), + getTimeBucket: jest.fn(), getTimeBuckets: jest.fn(), restoreAll: jest.fn(), softDeleteAll: jest.fn(), diff --git a/server/test/repositories/job.repository.mock.ts b/server/test/repositories/job.repository.mock.ts index 16db4ca69..fe794d1dc 100644 --- a/server/test/repositories/job.repository.mock.ts +++ b/server/test/repositories/job.repository.mock.ts @@ -3,6 +3,9 @@ import { IJobRepository } from '@app/domain'; export const newJobRepositoryMock = (): jest.Mocked => { return { addHandler: jest.fn(), + addCronJob: jest.fn(), + deleteCronJob: jest.fn(), + updateCronJob: jest.fn(), setConcurrency: jest.fn(), empty: jest.fn(), pause: jest.fn(), diff --git a/server/test/test-utils.ts b/server/test/test-utils.ts index 6b45c6ee6..4ac0cf0bf 100644 --- a/server/test/test-utils.ts +++ b/server/test/test-utils.ts @@ -49,6 +49,10 @@ export const testApp = { .overrideProvider(IJobRepository) .useValue({ addHandler: (_queueName: QueueName, _concurrency: number, handler: JobItemHandler) => (_handler = handler), + addCronJob: jest.fn(), + updateCronJob: jest.fn(), + deleteCronJob: jest.fn(), + validateCronExpression: jest.fn(), queue: (item: JobItem) => jobs && _handler(item), resume: jest.fn(), empty: jest.fn(), diff --git a/web/src/api/api.ts b/web/src/api/api.ts index 9beb370d3..3a3584ed4 100644 --- a/web/src/api/api.ts +++ b/web/src/api/api.ts @@ -20,12 +20,14 @@ import { UserApi, UserApiFp, AuditApi, + ActivityApi, } from './open-api'; import { BASE_PATH } from './open-api/base'; import { DUMMY_BASE_URL, toPathString } from './open-api/common'; import type { ApiParams } from './types'; export class ImmichApi { + public activityApi: ActivityApi; public albumApi: AlbumApi; public libraryApi: LibraryApi; public assetApi: AssetApi; @@ -52,6 +54,7 @@ export class ImmichApi { constructor(params: ConfigurationParameters) { this.config = new Configuration(params); + this.activityApi = new ActivityApi(this.config); this.albumApi = new AlbumApi(this.config); this.auditApi = new AuditApi(this.config); this.libraryApi = new LibraryApi(this.config); diff --git a/web/src/api/open-api/api.ts b/web/src/api/open-api/api.ts index e79388602..9f4d765f2 100644 --- a/web/src/api/open-api/api.ts +++ b/web/src/api/open-api/api.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.83.0 + * The version of the OpenAPI document: 1.84.0 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -99,6 +99,103 @@ export interface APIKeyUpdateDto { */ 'name': string; } +/** + * + * @export + * @interface ActivityCreateDto + */ +export interface ActivityCreateDto { + /** + * + * @type {string} + * @memberof ActivityCreateDto + */ + 'albumId': string; + /** + * + * @type {string} + * @memberof ActivityCreateDto + */ + 'assetId'?: string; + /** + * + * @type {string} + * @memberof ActivityCreateDto + */ + 'comment'?: string; + /** + * + * @type {ReactionType} + * @memberof ActivityCreateDto + */ + 'type': ReactionType; +} + + +/** + * + * @export + * @interface ActivityResponseDto + */ +export interface ActivityResponseDto { + /** + * + * @type {string} + * @memberof ActivityResponseDto + */ + 'assetId': string | null; + /** + * + * @type {string} + * @memberof ActivityResponseDto + */ + 'comment'?: string | null; + /** + * + * @type {string} + * @memberof ActivityResponseDto + */ + 'createdAt': string; + /** + * + * @type {string} + * @memberof ActivityResponseDto + */ + 'id': string; + /** + * + * @type {string} + * @memberof ActivityResponseDto + */ + 'type': ActivityResponseDtoTypeEnum; + /** + * + * @type {UserDto} + * @memberof ActivityResponseDto + */ + 'user': UserDto; +} + +export const ActivityResponseDtoTypeEnum = { + Comment: 'comment', + Like: 'like' +} as const; + +export type ActivityResponseDtoTypeEnum = typeof ActivityResponseDtoTypeEnum[keyof typeof ActivityResponseDtoTypeEnum]; + +/** + * + * @export + * @interface ActivityStatisticsResponseDto + */ +export interface ActivityStatisticsResponseDto { + /** + * + * @type {number} + * @memberof ActivityStatisticsResponseDto + */ + 'comments': number; +} /** * * @export @@ -2490,6 +2587,20 @@ export interface QueueStatusDto { */ 'isPaused': boolean; } +/** + * + * @export + * @enum {string} + */ + +export const ReactionType = { + Comment: 'comment', + Like: 'like' +} as const; + +export type ReactionType = typeof ReactionType[keyof typeof ReactionType]; + + /** * * @export @@ -3283,6 +3394,12 @@ export interface SystemConfigDto { * @memberof SystemConfigDto */ 'job': SystemConfigJobDto; + /** + * + * @type {SystemConfigLibraryDto} + * @memberof SystemConfigDto + */ + 'library': SystemConfigLibraryDto; /** * * @type {SystemConfigMachineLearningDto} @@ -3534,6 +3651,38 @@ export interface SystemConfigJobDto { */ 'videoConversion': JobSettingsDto; } +/** + * + * @export + * @interface SystemConfigLibraryDto + */ +export interface SystemConfigLibraryDto { + /** + * + * @type {SystemConfigLibraryScanDto} + * @memberof SystemConfigLibraryDto + */ + 'scan': SystemConfigLibraryScanDto; +} +/** + * + * @export + * @interface SystemConfigLibraryScanDto + */ +export interface SystemConfigLibraryScanDto { + /** + * + * @type {string} + * @memberof SystemConfigLibraryScanDto + */ + 'cronExpression': string; + /** + * + * @type {boolean} + * @memberof SystemConfigLibraryScanDto + */ + 'enabled': boolean; +} /** * * @export @@ -4210,6 +4359,43 @@ export interface UsageByUserDto { */ 'videos': number; } +/** + * + * @export + * @interface UserDto + */ +export interface UserDto { + /** + * + * @type {string} + * @memberof UserDto + */ + 'email': string; + /** + * + * @type {string} + * @memberof UserDto + */ + 'firstName': string; + /** + * + * @type {string} + * @memberof UserDto + */ + 'id': string; + /** + * + * @type {string} + * @memberof UserDto + */ + 'lastName': string; + /** + * + * @type {string} + * @memberof UserDto + */ + 'profileImagePath': string; +} /** * * @export @@ -4342,9 +4528,9 @@ export const APIKeyApiAxiosParamCreator = function (configuration?: Configuratio * @param {*} [options] Override http request option. * @throws {RequiredError} */ - createKey: async (aPIKeyCreateDto: APIKeyCreateDto, options: AxiosRequestConfig = {}): Promise => { + createApiKey: async (aPIKeyCreateDto: APIKeyCreateDto, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'aPIKeyCreateDto' is not null or undefined - assertParamExists('createKey', 'aPIKeyCreateDto', aPIKeyCreateDto) + assertParamExists('createApiKey', 'aPIKeyCreateDto', aPIKeyCreateDto) const localVarPath = `/api-key`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -4386,9 +4572,9 @@ export const APIKeyApiAxiosParamCreator = function (configuration?: Configuratio * @param {*} [options] Override http request option. * @throws {RequiredError} */ - deleteKey: async (id: string, options: AxiosRequestConfig = {}): Promise => { + deleteApiKey: async (id: string, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'id' is not null or undefined - assertParamExists('deleteKey', 'id', id) + assertParamExists('deleteApiKey', 'id', id) const localVarPath = `/api-key/{id}` .replace(`{${"id"}}`, encodeURIComponent(String(id))); // use dummy base URL string because the URL constructor only accepts absolute URLs. @@ -4428,9 +4614,9 @@ export const APIKeyApiAxiosParamCreator = function (configuration?: Configuratio * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getKey: async (id: string, options: AxiosRequestConfig = {}): Promise => { + getApiKey: async (id: string, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'id' is not null or undefined - assertParamExists('getKey', 'id', id) + assertParamExists('getApiKey', 'id', id) const localVarPath = `/api-key/{id}` .replace(`{${"id"}}`, encodeURIComponent(String(id))); // use dummy base URL string because the URL constructor only accepts absolute URLs. @@ -4469,7 +4655,7 @@ export const APIKeyApiAxiosParamCreator = function (configuration?: Configuratio * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getKeys: async (options: AxiosRequestConfig = {}): Promise => { + getApiKeys: async (options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/api-key`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -4509,11 +4695,11 @@ export const APIKeyApiAxiosParamCreator = function (configuration?: Configuratio * @param {*} [options] Override http request option. * @throws {RequiredError} */ - updateKey: async (id: string, aPIKeyUpdateDto: APIKeyUpdateDto, options: AxiosRequestConfig = {}): Promise => { + updateApiKey: async (id: string, aPIKeyUpdateDto: APIKeyUpdateDto, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'id' is not null or undefined - assertParamExists('updateKey', 'id', id) + assertParamExists('updateApiKey', 'id', id) // verify required parameter 'aPIKeyUpdateDto' is not null or undefined - assertParamExists('updateKey', 'aPIKeyUpdateDto', aPIKeyUpdateDto) + assertParamExists('updateApiKey', 'aPIKeyUpdateDto', aPIKeyUpdateDto) const localVarPath = `/api-key/{id}` .replace(`{${"id"}}`, encodeURIComponent(String(id))); // use dummy base URL string because the URL constructor only accepts absolute URLs. @@ -4566,8 +4752,8 @@ export const APIKeyApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async createKey(aPIKeyCreateDto: APIKeyCreateDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.createKey(aPIKeyCreateDto, options); + async createApiKey(aPIKeyCreateDto: APIKeyCreateDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.createApiKey(aPIKeyCreateDto, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -4576,8 +4762,8 @@ export const APIKeyApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async deleteKey(id: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.deleteKey(id, options); + async deleteApiKey(id: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.deleteApiKey(id, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -4586,8 +4772,8 @@ export const APIKeyApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getKey(id: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getKey(id, options); + async getApiKey(id: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getApiKey(id, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -4595,8 +4781,8 @@ export const APIKeyApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getKeys(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getKeys(options); + async getApiKeys(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getApiKeys(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -4606,8 +4792,8 @@ export const APIKeyApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async updateKey(id: string, aPIKeyUpdateDto: APIKeyUpdateDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.updateKey(id, aPIKeyUpdateDto, options); + async updateApiKey(id: string, aPIKeyUpdateDto: APIKeyUpdateDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.updateApiKey(id, aPIKeyUpdateDto, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, } @@ -4622,110 +4808,110 @@ export const APIKeyApiFactory = function (configuration?: Configuration, basePat return { /** * - * @param {APIKeyApiCreateKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiCreateApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - createKey(requestParameters: APIKeyApiCreateKeyRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.createKey(requestParameters.aPIKeyCreateDto, options).then((request) => request(axios, basePath)); + createApiKey(requestParameters: APIKeyApiCreateApiKeyRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.createApiKey(requestParameters.aPIKeyCreateDto, options).then((request) => request(axios, basePath)); }, /** * - * @param {APIKeyApiDeleteKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiDeleteApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - deleteKey(requestParameters: APIKeyApiDeleteKeyRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.deleteKey(requestParameters.id, options).then((request) => request(axios, basePath)); + deleteApiKey(requestParameters: APIKeyApiDeleteApiKeyRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.deleteApiKey(requestParameters.id, options).then((request) => request(axios, basePath)); }, /** * - * @param {APIKeyApiGetKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiGetApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getKey(requestParameters: APIKeyApiGetKeyRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.getKey(requestParameters.id, options).then((request) => request(axios, basePath)); + getApiKey(requestParameters: APIKeyApiGetApiKeyRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.getApiKey(requestParameters.id, options).then((request) => request(axios, basePath)); }, /** * * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getKeys(options?: AxiosRequestConfig): AxiosPromise> { - return localVarFp.getKeys(options).then((request) => request(axios, basePath)); + getApiKeys(options?: AxiosRequestConfig): AxiosPromise> { + return localVarFp.getApiKeys(options).then((request) => request(axios, basePath)); }, /** * - * @param {APIKeyApiUpdateKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiUpdateApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - updateKey(requestParameters: APIKeyApiUpdateKeyRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.updateKey(requestParameters.id, requestParameters.aPIKeyUpdateDto, options).then((request) => request(axios, basePath)); + updateApiKey(requestParameters: APIKeyApiUpdateApiKeyRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.updateApiKey(requestParameters.id, requestParameters.aPIKeyUpdateDto, options).then((request) => request(axios, basePath)); }, }; }; /** - * Request parameters for createKey operation in APIKeyApi. + * Request parameters for createApiKey operation in APIKeyApi. * @export - * @interface APIKeyApiCreateKeyRequest + * @interface APIKeyApiCreateApiKeyRequest */ -export interface APIKeyApiCreateKeyRequest { +export interface APIKeyApiCreateApiKeyRequest { /** * * @type {APIKeyCreateDto} - * @memberof APIKeyApiCreateKey + * @memberof APIKeyApiCreateApiKey */ readonly aPIKeyCreateDto: APIKeyCreateDto } /** - * Request parameters for deleteKey operation in APIKeyApi. + * Request parameters for deleteApiKey operation in APIKeyApi. * @export - * @interface APIKeyApiDeleteKeyRequest + * @interface APIKeyApiDeleteApiKeyRequest */ -export interface APIKeyApiDeleteKeyRequest { +export interface APIKeyApiDeleteApiKeyRequest { /** * * @type {string} - * @memberof APIKeyApiDeleteKey + * @memberof APIKeyApiDeleteApiKey */ readonly id: string } /** - * Request parameters for getKey operation in APIKeyApi. + * Request parameters for getApiKey operation in APIKeyApi. * @export - * @interface APIKeyApiGetKeyRequest + * @interface APIKeyApiGetApiKeyRequest */ -export interface APIKeyApiGetKeyRequest { +export interface APIKeyApiGetApiKeyRequest { /** * * @type {string} - * @memberof APIKeyApiGetKey + * @memberof APIKeyApiGetApiKey */ readonly id: string } /** - * Request parameters for updateKey operation in APIKeyApi. + * Request parameters for updateApiKey operation in APIKeyApi. * @export - * @interface APIKeyApiUpdateKeyRequest + * @interface APIKeyApiUpdateApiKeyRequest */ -export interface APIKeyApiUpdateKeyRequest { +export interface APIKeyApiUpdateApiKeyRequest { /** * * @type {string} - * @memberof APIKeyApiUpdateKey + * @memberof APIKeyApiUpdateApiKey */ readonly id: string /** * * @type {APIKeyUpdateDto} - * @memberof APIKeyApiUpdateKey + * @memberof APIKeyApiUpdateApiKey */ readonly aPIKeyUpdateDto: APIKeyUpdateDto } @@ -4739,35 +4925,35 @@ export interface APIKeyApiUpdateKeyRequest { export class APIKeyApi extends BaseAPI { /** * - * @param {APIKeyApiCreateKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiCreateApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof APIKeyApi */ - public createKey(requestParameters: APIKeyApiCreateKeyRequest, options?: AxiosRequestConfig) { - return APIKeyApiFp(this.configuration).createKey(requestParameters.aPIKeyCreateDto, options).then((request) => request(this.axios, this.basePath)); + public createApiKey(requestParameters: APIKeyApiCreateApiKeyRequest, options?: AxiosRequestConfig) { + return APIKeyApiFp(this.configuration).createApiKey(requestParameters.aPIKeyCreateDto, options).then((request) => request(this.axios, this.basePath)); } /** * - * @param {APIKeyApiDeleteKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiDeleteApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof APIKeyApi */ - public deleteKey(requestParameters: APIKeyApiDeleteKeyRequest, options?: AxiosRequestConfig) { - return APIKeyApiFp(this.configuration).deleteKey(requestParameters.id, options).then((request) => request(this.axios, this.basePath)); + public deleteApiKey(requestParameters: APIKeyApiDeleteApiKeyRequest, options?: AxiosRequestConfig) { + return APIKeyApiFp(this.configuration).deleteApiKey(requestParameters.id, options).then((request) => request(this.axios, this.basePath)); } /** * - * @param {APIKeyApiGetKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiGetApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof APIKeyApi */ - public getKey(requestParameters: APIKeyApiGetKeyRequest, options?: AxiosRequestConfig) { - return APIKeyApiFp(this.configuration).getKey(requestParameters.id, options).then((request) => request(this.axios, this.basePath)); + public getApiKey(requestParameters: APIKeyApiGetApiKeyRequest, options?: AxiosRequestConfig) { + return APIKeyApiFp(this.configuration).getApiKey(requestParameters.id, options).then((request) => request(this.axios, this.basePath)); } /** @@ -4776,19 +4962,461 @@ export class APIKeyApi extends BaseAPI { * @throws {RequiredError} * @memberof APIKeyApi */ - public getKeys(options?: AxiosRequestConfig) { - return APIKeyApiFp(this.configuration).getKeys(options).then((request) => request(this.axios, this.basePath)); + public getApiKeys(options?: AxiosRequestConfig) { + return APIKeyApiFp(this.configuration).getApiKeys(options).then((request) => request(this.axios, this.basePath)); } /** * - * @param {APIKeyApiUpdateKeyRequest} requestParameters Request parameters. + * @param {APIKeyApiUpdateApiKeyRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof APIKeyApi */ - public updateKey(requestParameters: APIKeyApiUpdateKeyRequest, options?: AxiosRequestConfig) { - return APIKeyApiFp(this.configuration).updateKey(requestParameters.id, requestParameters.aPIKeyUpdateDto, options).then((request) => request(this.axios, this.basePath)); + public updateApiKey(requestParameters: APIKeyApiUpdateApiKeyRequest, options?: AxiosRequestConfig) { + return APIKeyApiFp(this.configuration).updateApiKey(requestParameters.id, requestParameters.aPIKeyUpdateDto, options).then((request) => request(this.axios, this.basePath)); + } +} + + +/** + * ActivityApi - axios parameter creator + * @export + */ +export const ActivityApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * + * @param {ActivityCreateDto} activityCreateDto + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createActivity: async (activityCreateDto: ActivityCreateDto, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'activityCreateDto' is not null or undefined + assertParamExists('createActivity', 'activityCreateDto', activityCreateDto) + const localVarPath = `/activity`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication cookie required + + // authentication api_key required + await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration) + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(activityCreateDto, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + deleteActivity: async (id: string, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'id' is not null or undefined + assertParamExists('deleteActivity', 'id', id) + const localVarPath = `/activity/{id}` + .replace(`{${"id"}}`, encodeURIComponent(String(id))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication cookie required + + // authentication api_key required + await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration) + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @param {string} albumId + * @param {string} [assetId] + * @param {ReactionType} [type] + * @param {string} [userId] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getActivities: async (albumId: string, assetId?: string, type?: ReactionType, userId?: string, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'albumId' is not null or undefined + assertParamExists('getActivities', 'albumId', albumId) + const localVarPath = `/activity`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication cookie required + + // authentication api_key required + await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration) + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + if (albumId !== undefined) { + localVarQueryParameter['albumId'] = albumId; + } + + if (assetId !== undefined) { + localVarQueryParameter['assetId'] = assetId; + } + + if (type !== undefined) { + localVarQueryParameter['type'] = type; + } + + if (userId !== undefined) { + localVarQueryParameter['userId'] = userId; + } + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @param {string} albumId + * @param {string} [assetId] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getActivityStatistics: async (albumId: string, assetId?: string, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'albumId' is not null or undefined + assertParamExists('getActivityStatistics', 'albumId', albumId) + const localVarPath = `/activity/statistics`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication cookie required + + // authentication api_key required + await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration) + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + if (albumId !== undefined) { + localVarQueryParameter['albumId'] = albumId; + } + + if (assetId !== undefined) { + localVarQueryParameter['assetId'] = assetId; + } + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * ActivityApi - functional programming interface + * @export + */ +export const ActivityApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = ActivityApiAxiosParamCreator(configuration) + return { + /** + * + * @param {ActivityCreateDto} activityCreateDto + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async createActivity(activityCreateDto: ActivityCreateDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.createActivity(activityCreateDto, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + /** + * + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async deleteActivity(id: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.deleteActivity(id, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + /** + * + * @param {string} albumId + * @param {string} [assetId] + * @param {ReactionType} [type] + * @param {string} [userId] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getActivities(albumId: string, assetId?: string, type?: ReactionType, userId?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getActivities(albumId, assetId, type, userId, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + /** + * + * @param {string} albumId + * @param {string} [assetId] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getActivityStatistics(albumId: string, assetId?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getActivityStatistics(albumId, assetId, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + } +}; + +/** + * ActivityApi - factory interface + * @export + */ +export const ActivityApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + const localVarFp = ActivityApiFp(configuration) + return { + /** + * + * @param {ActivityApiCreateActivityRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createActivity(requestParameters: ActivityApiCreateActivityRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.createActivity(requestParameters.activityCreateDto, options).then((request) => request(axios, basePath)); + }, + /** + * + * @param {ActivityApiDeleteActivityRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + deleteActivity(requestParameters: ActivityApiDeleteActivityRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.deleteActivity(requestParameters.id, options).then((request) => request(axios, basePath)); + }, + /** + * + * @param {ActivityApiGetActivitiesRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getActivities(requestParameters: ActivityApiGetActivitiesRequest, options?: AxiosRequestConfig): AxiosPromise> { + return localVarFp.getActivities(requestParameters.albumId, requestParameters.assetId, requestParameters.type, requestParameters.userId, options).then((request) => request(axios, basePath)); + }, + /** + * + * @param {ActivityApiGetActivityStatisticsRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getActivityStatistics(requestParameters: ActivityApiGetActivityStatisticsRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.getActivityStatistics(requestParameters.albumId, requestParameters.assetId, options).then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * Request parameters for createActivity operation in ActivityApi. + * @export + * @interface ActivityApiCreateActivityRequest + */ +export interface ActivityApiCreateActivityRequest { + /** + * + * @type {ActivityCreateDto} + * @memberof ActivityApiCreateActivity + */ + readonly activityCreateDto: ActivityCreateDto +} + +/** + * Request parameters for deleteActivity operation in ActivityApi. + * @export + * @interface ActivityApiDeleteActivityRequest + */ +export interface ActivityApiDeleteActivityRequest { + /** + * + * @type {string} + * @memberof ActivityApiDeleteActivity + */ + readonly id: string +} + +/** + * Request parameters for getActivities operation in ActivityApi. + * @export + * @interface ActivityApiGetActivitiesRequest + */ +export interface ActivityApiGetActivitiesRequest { + /** + * + * @type {string} + * @memberof ActivityApiGetActivities + */ + readonly albumId: string + + /** + * + * @type {string} + * @memberof ActivityApiGetActivities + */ + readonly assetId?: string + + /** + * + * @type {ReactionType} + * @memberof ActivityApiGetActivities + */ + readonly type?: ReactionType + + /** + * + * @type {string} + * @memberof ActivityApiGetActivities + */ + readonly userId?: string +} + +/** + * Request parameters for getActivityStatistics operation in ActivityApi. + * @export + * @interface ActivityApiGetActivityStatisticsRequest + */ +export interface ActivityApiGetActivityStatisticsRequest { + /** + * + * @type {string} + * @memberof ActivityApiGetActivityStatistics + */ + readonly albumId: string + + /** + * + * @type {string} + * @memberof ActivityApiGetActivityStatistics + */ + readonly assetId?: string +} + +/** + * ActivityApi - object-oriented interface + * @export + * @class ActivityApi + * @extends {BaseAPI} + */ +export class ActivityApi extends BaseAPI { + /** + * + * @param {ActivityApiCreateActivityRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ActivityApi + */ + public createActivity(requestParameters: ActivityApiCreateActivityRequest, options?: AxiosRequestConfig) { + return ActivityApiFp(this.configuration).createActivity(requestParameters.activityCreateDto, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @param {ActivityApiDeleteActivityRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ActivityApi + */ + public deleteActivity(requestParameters: ActivityApiDeleteActivityRequest, options?: AxiosRequestConfig) { + return ActivityApiFp(this.configuration).deleteActivity(requestParameters.id, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @param {ActivityApiGetActivitiesRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ActivityApi + */ + public getActivities(requestParameters: ActivityApiGetActivitiesRequest, options?: AxiosRequestConfig) { + return ActivityApiFp(this.configuration).getActivities(requestParameters.albumId, requestParameters.assetId, requestParameters.type, requestParameters.userId, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @param {ActivityApiGetActivityStatisticsRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ActivityApi + */ + public getActivityStatistics(requestParameters: ActivityApiGetActivityStatisticsRequest, options?: AxiosRequestConfig) { + return ActivityApiFp(this.configuration).getActivityStatistics(requestParameters.albumId, requestParameters.assetId, options).then((request) => request(this.axios, this.basePath)); } } @@ -5805,9 +6433,9 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration * @param {*} [options] Override http request option. * @throws {RequiredError} */ - bulkUploadCheck: async (assetBulkUploadCheckDto: AssetBulkUploadCheckDto, options: AxiosRequestConfig = {}): Promise => { + checkBulkUpload: async (assetBulkUploadCheckDto: AssetBulkUploadCheckDto, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'assetBulkUploadCheckDto' is not null or undefined - assertParamExists('bulkUploadCheck', 'assetBulkUploadCheckDto', assetBulkUploadCheckDto) + assertParamExists('checkBulkUpload', 'assetBulkUploadCheckDto', assetBulkUploadCheckDto) const localVarPath = `/asset/bulk-upload-check`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -6228,7 +6856,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getAssetStats: async (isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, options: AxiosRequestConfig = {}): Promise => { + getAssetStatistics: async (isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/asset/statistics`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -6316,98 +6944,6 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - /** - * - * @param {TimeBucketSize} size - * @param {string} timeBucket - * @param {string} [userId] - * @param {string} [albumId] - * @param {string} [personId] - * @param {boolean} [isArchived] - * @param {boolean} [isFavorite] - * @param {boolean} [isTrashed] - * @param {boolean} [withStacked] - * @param {string} [key] - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - getByTimeBucket: async (size: TimeBucketSize, timeBucket: string, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, key?: string, options: AxiosRequestConfig = {}): Promise => { - // verify required parameter 'size' is not null or undefined - assertParamExists('getByTimeBucket', 'size', size) - // verify required parameter 'timeBucket' is not null or undefined - assertParamExists('getByTimeBucket', 'timeBucket', timeBucket) - const localVarPath = `/asset/time-bucket`; - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - // authentication cookie required - - // authentication api_key required - await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration) - - // authentication bearer required - // http bearer authentication required - await setBearerAuthToObject(localVarHeaderParameter, configuration) - - if (size !== undefined) { - localVarQueryParameter['size'] = size; - } - - if (userId !== undefined) { - localVarQueryParameter['userId'] = userId; - } - - if (albumId !== undefined) { - localVarQueryParameter['albumId'] = albumId; - } - - if (personId !== undefined) { - localVarQueryParameter['personId'] = personId; - } - - if (isArchived !== undefined) { - localVarQueryParameter['isArchived'] = isArchived; - } - - if (isFavorite !== undefined) { - localVarQueryParameter['isFavorite'] = isFavorite; - } - - if (isTrashed !== undefined) { - localVarQueryParameter['isTrashed'] = isTrashed; - } - - if (withStacked !== undefined) { - localVarQueryParameter['withStacked'] = withStacked; - } - - if (timeBucket !== undefined) { - localVarQueryParameter['timeBucket'] = timeBucket; - } - - if (key !== undefined) { - localVarQueryParameter['key'] = key; - } - - - setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -6690,6 +7226,98 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @param {TimeBucketSize} size + * @param {string} timeBucket + * @param {string} [userId] + * @param {string} [albumId] + * @param {string} [personId] + * @param {boolean} [isArchived] + * @param {boolean} [isFavorite] + * @param {boolean} [isTrashed] + * @param {boolean} [withStacked] + * @param {string} [key] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getTimeBucket: async (size: TimeBucketSize, timeBucket: string, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, key?: string, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'size' is not null or undefined + assertParamExists('getTimeBucket', 'size', size) + // verify required parameter 'timeBucket' is not null or undefined + assertParamExists('getTimeBucket', 'timeBucket', timeBucket) + const localVarPath = `/asset/time-bucket`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication cookie required + + // authentication api_key required + await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration) + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + if (size !== undefined) { + localVarQueryParameter['size'] = size; + } + + if (userId !== undefined) { + localVarQueryParameter['userId'] = userId; + } + + if (albumId !== undefined) { + localVarQueryParameter['albumId'] = albumId; + } + + if (personId !== undefined) { + localVarQueryParameter['personId'] = personId; + } + + if (isArchived !== undefined) { + localVarQueryParameter['isArchived'] = isArchived; + } + + if (isFavorite !== undefined) { + localVarQueryParameter['isFavorite'] = isFavorite; + } + + if (isTrashed !== undefined) { + localVarQueryParameter['isTrashed'] = isTrashed; + } + + if (withStacked !== undefined) { + localVarQueryParameter['withStacked'] = withStacked; + } + + if (timeBucket !== undefined) { + localVarQueryParameter['timeBucket'] = timeBucket; + } + + if (key !== undefined) { + localVarQueryParameter['key'] = key; + } + + + setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -7383,8 +8011,8 @@ export const AssetApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async bulkUploadCheck(assetBulkUploadCheckDto: AssetBulkUploadCheckDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.bulkUploadCheck(assetBulkUploadCheckDto, options); + async checkBulkUpload(assetBulkUploadCheckDto: AssetBulkUploadCheckDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.checkBulkUpload(assetBulkUploadCheckDto, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -7481,8 +8109,8 @@ export const AssetApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getAssetStats(isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetStats(isArchived, isFavorite, isTrashed, options); + async getAssetStatistics(isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetStatistics(isArchived, isFavorite, isTrashed, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -7497,25 +8125,6 @@ export const AssetApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetThumbnail(id, format, key, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, - /** - * - * @param {TimeBucketSize} size - * @param {string} timeBucket - * @param {string} [userId] - * @param {string} [albumId] - * @param {string} [personId] - * @param {boolean} [isArchived] - * @param {boolean} [isFavorite] - * @param {boolean} [isTrashed] - * @param {boolean} [withStacked] - * @param {string} [key] - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async getByTimeBucket(size: TimeBucketSize, timeBucket: string, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getByTimeBucket(size, timeBucket, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); - }, /** * * @param {*} [options] Override http request option. @@ -7579,6 +8188,25 @@ export const AssetApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.getRandom(count, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * + * @param {TimeBucketSize} size + * @param {string} timeBucket + * @param {string} [userId] + * @param {string} [albumId] + * @param {string} [personId] + * @param {boolean} [isArchived] + * @param {boolean} [isFavorite] + * @param {boolean} [isTrashed] + * @param {boolean} [withStacked] + * @param {string} [key] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getTimeBucket(size: TimeBucketSize, timeBucket: string, userId?: string, albumId?: string, personId?: string, isArchived?: boolean, isFavorite?: boolean, isTrashed?: boolean, withStacked?: boolean, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getTimeBucket(size, timeBucket, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @param {TimeBucketSize} size @@ -7737,12 +8365,12 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath return { /** * Checks if assets exist by checksums - * @param {AssetApiBulkUploadCheckRequest} requestParameters Request parameters. + * @param {AssetApiCheckBulkUploadRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - bulkUploadCheck(requestParameters: AssetApiBulkUploadCheckRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.bulkUploadCheck(requestParameters.assetBulkUploadCheckDto, options).then((request) => request(axios, basePath)); + checkBulkUpload(requestParameters: AssetApiCheckBulkUploadRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.checkBulkUpload(requestParameters.assetBulkUploadCheckDto, options).then((request) => request(axios, basePath)); }, /** * Checks if multiple assets exist on the server and returns all existing - used by background backup @@ -7816,12 +8444,12 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath }, /** * - * @param {AssetApiGetAssetStatsRequest} requestParameters Request parameters. + * @param {AssetApiGetAssetStatisticsRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getAssetStats(requestParameters: AssetApiGetAssetStatsRequest = {}, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.getAssetStats(requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, options).then((request) => request(axios, basePath)); + getAssetStatistics(requestParameters: AssetApiGetAssetStatisticsRequest = {}, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.getAssetStatistics(requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, options).then((request) => request(axios, basePath)); }, /** * @@ -7832,15 +8460,6 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath getAssetThumbnail(requestParameters: AssetApiGetAssetThumbnailRequest, options?: AxiosRequestConfig): AxiosPromise { return localVarFp.getAssetThumbnail(requestParameters.id, requestParameters.format, requestParameters.key, options).then((request) => request(axios, basePath)); }, - /** - * - * @param {AssetApiGetByTimeBucketRequest} requestParameters Request parameters. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - getByTimeBucket(requestParameters: AssetApiGetByTimeBucketRequest, options?: AxiosRequestConfig): AxiosPromise> { - return localVarFp.getByTimeBucket(requestParameters.size, requestParameters.timeBucket, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.key, options).then((request) => request(axios, basePath)); - }, /** * * @param {*} [options] Override http request option. @@ -7893,6 +8512,15 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath getRandom(requestParameters: AssetApiGetRandomRequest = {}, options?: AxiosRequestConfig): AxiosPromise> { return localVarFp.getRandom(requestParameters.count, options).then((request) => request(axios, basePath)); }, + /** + * + * @param {AssetApiGetTimeBucketRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getTimeBucket(requestParameters: AssetApiGetTimeBucketRequest, options?: AxiosRequestConfig): AxiosPromise> { + return localVarFp.getTimeBucket(requestParameters.size, requestParameters.timeBucket, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.key, options).then((request) => request(axios, basePath)); + }, /** * * @param {AssetApiGetTimeBucketsRequest} requestParameters Request parameters. @@ -8004,15 +8632,15 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath }; /** - * Request parameters for bulkUploadCheck operation in AssetApi. + * Request parameters for checkBulkUpload operation in AssetApi. * @export - * @interface AssetApiBulkUploadCheckRequest + * @interface AssetApiCheckBulkUploadRequest */ -export interface AssetApiBulkUploadCheckRequest { +export interface AssetApiCheckBulkUploadRequest { /** * * @type {AssetBulkUploadCheckDto} - * @memberof AssetApiBulkUploadCheck + * @memberof AssetApiCheckBulkUpload */ readonly assetBulkUploadCheckDto: AssetBulkUploadCheckDto } @@ -8158,29 +8786,29 @@ export interface AssetApiGetAssetByIdRequest { } /** - * Request parameters for getAssetStats operation in AssetApi. + * Request parameters for getAssetStatistics operation in AssetApi. * @export - * @interface AssetApiGetAssetStatsRequest + * @interface AssetApiGetAssetStatisticsRequest */ -export interface AssetApiGetAssetStatsRequest { +export interface AssetApiGetAssetStatisticsRequest { /** * * @type {boolean} - * @memberof AssetApiGetAssetStats + * @memberof AssetApiGetAssetStatistics */ readonly isArchived?: boolean /** * * @type {boolean} - * @memberof AssetApiGetAssetStats + * @memberof AssetApiGetAssetStatistics */ readonly isFavorite?: boolean /** * * @type {boolean} - * @memberof AssetApiGetAssetStats + * @memberof AssetApiGetAssetStatistics */ readonly isTrashed?: boolean } @@ -8213,83 +8841,6 @@ export interface AssetApiGetAssetThumbnailRequest { readonly key?: string } -/** - * Request parameters for getByTimeBucket operation in AssetApi. - * @export - * @interface AssetApiGetByTimeBucketRequest - */ -export interface AssetApiGetByTimeBucketRequest { - /** - * - * @type {TimeBucketSize} - * @memberof AssetApiGetByTimeBucket - */ - readonly size: TimeBucketSize - - /** - * - * @type {string} - * @memberof AssetApiGetByTimeBucket - */ - readonly timeBucket: string - - /** - * - * @type {string} - * @memberof AssetApiGetByTimeBucket - */ - readonly userId?: string - - /** - * - * @type {string} - * @memberof AssetApiGetByTimeBucket - */ - readonly albumId?: string - - /** - * - * @type {string} - * @memberof AssetApiGetByTimeBucket - */ - readonly personId?: string - - /** - * - * @type {boolean} - * @memberof AssetApiGetByTimeBucket - */ - readonly isArchived?: boolean - - /** - * - * @type {boolean} - * @memberof AssetApiGetByTimeBucket - */ - readonly isFavorite?: boolean - - /** - * - * @type {boolean} - * @memberof AssetApiGetByTimeBucket - */ - readonly isTrashed?: boolean - - /** - * - * @type {boolean} - * @memberof AssetApiGetByTimeBucket - */ - readonly withStacked?: boolean - - /** - * - * @type {string} - * @memberof AssetApiGetByTimeBucket - */ - readonly key?: string -} - /** * Request parameters for getDownloadInfo operation in AssetApi. * @export @@ -8381,6 +8932,83 @@ export interface AssetApiGetRandomRequest { readonly count?: number } +/** + * Request parameters for getTimeBucket operation in AssetApi. + * @export + * @interface AssetApiGetTimeBucketRequest + */ +export interface AssetApiGetTimeBucketRequest { + /** + * + * @type {TimeBucketSize} + * @memberof AssetApiGetTimeBucket + */ + readonly size: TimeBucketSize + + /** + * + * @type {string} + * @memberof AssetApiGetTimeBucket + */ + readonly timeBucket: string + + /** + * + * @type {string} + * @memberof AssetApiGetTimeBucket + */ + readonly userId?: string + + /** + * + * @type {string} + * @memberof AssetApiGetTimeBucket + */ + readonly albumId?: string + + /** + * + * @type {string} + * @memberof AssetApiGetTimeBucket + */ + readonly personId?: string + + /** + * + * @type {boolean} + * @memberof AssetApiGetTimeBucket + */ + readonly isArchived?: boolean + + /** + * + * @type {boolean} + * @memberof AssetApiGetTimeBucket + */ + readonly isFavorite?: boolean + + /** + * + * @type {boolean} + * @memberof AssetApiGetTimeBucket + */ + readonly isTrashed?: boolean + + /** + * + * @type {boolean} + * @memberof AssetApiGetTimeBucket + */ + readonly withStacked?: boolean + + /** + * + * @type {string} + * @memberof AssetApiGetTimeBucket + */ + readonly key?: string +} + /** * Request parameters for getTimeBuckets operation in AssetApi. * @export @@ -8733,13 +9361,13 @@ export interface AssetApiUploadFileRequest { export class AssetApi extends BaseAPI { /** * Checks if assets exist by checksums - * @param {AssetApiBulkUploadCheckRequest} requestParameters Request parameters. + * @param {AssetApiCheckBulkUploadRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AssetApi */ - public bulkUploadCheck(requestParameters: AssetApiBulkUploadCheckRequest, options?: AxiosRequestConfig) { - return AssetApiFp(this.configuration).bulkUploadCheck(requestParameters.assetBulkUploadCheckDto, options).then((request) => request(this.axios, this.basePath)); + public checkBulkUpload(requestParameters: AssetApiCheckBulkUploadRequest, options?: AxiosRequestConfig) { + return AssetApiFp(this.configuration).checkBulkUpload(requestParameters.assetBulkUploadCheckDto, options).then((request) => request(this.axios, this.basePath)); } /** @@ -8830,13 +9458,13 @@ export class AssetApi extends BaseAPI { /** * - * @param {AssetApiGetAssetStatsRequest} requestParameters Request parameters. + * @param {AssetApiGetAssetStatisticsRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AssetApi */ - public getAssetStats(requestParameters: AssetApiGetAssetStatsRequest = {}, options?: AxiosRequestConfig) { - return AssetApiFp(this.configuration).getAssetStats(requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, options).then((request) => request(this.axios, this.basePath)); + public getAssetStatistics(requestParameters: AssetApiGetAssetStatisticsRequest = {}, options?: AxiosRequestConfig) { + return AssetApiFp(this.configuration).getAssetStatistics(requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, options).then((request) => request(this.axios, this.basePath)); } /** @@ -8850,17 +9478,6 @@ export class AssetApi extends BaseAPI { return AssetApiFp(this.configuration).getAssetThumbnail(requestParameters.id, requestParameters.format, requestParameters.key, options).then((request) => request(this.axios, this.basePath)); } - /** - * - * @param {AssetApiGetByTimeBucketRequest} requestParameters Request parameters. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof AssetApi - */ - public getByTimeBucket(requestParameters: AssetApiGetByTimeBucketRequest, options?: AxiosRequestConfig) { - return AssetApiFp(this.configuration).getByTimeBucket(requestParameters.size, requestParameters.timeBucket, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.key, options).then((request) => request(this.axios, this.basePath)); - } - /** * * @param {*} [options] Override http request option. @@ -8925,6 +9542,17 @@ export class AssetApi extends BaseAPI { return AssetApiFp(this.configuration).getRandom(requestParameters.count, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @param {AssetApiGetTimeBucketRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof AssetApi + */ + public getTimeBucket(requestParameters: AssetApiGetTimeBucketRequest, options?: AxiosRequestConfig) { + return AssetApiFp(this.configuration).getTimeBucket(requestParameters.size, requestParameters.timeBucket, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.key, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @param {AssetApiGetTimeBucketsRequest} requestParameters Request parameters. @@ -9462,41 +10090,6 @@ export class AuditApi extends BaseAPI { */ export const AuthenticationApiAxiosParamCreator = function (configuration?: Configuration) { return { - /** - * - * @param {SignUpDto} signUpDto - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - adminSignUp: async (signUpDto: SignUpDto, options: AxiosRequestConfig = {}): Promise => { - // verify required parameter 'signUpDto' is not null or undefined - assertParamExists('adminSignUp', 'signUpDto', signUpDto) - const localVarPath = `/auth/admin-sign-up`; - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - - - localVarHeaderParameter['Content-Type'] = 'application/json'; - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - localVarRequestOptions.data = serializeDataIfNeeded(signUpDto, localVarRequestOptions, configuration) - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, /** * * @param {ChangePasswordDto} changePasswordDto @@ -9732,6 +10325,41 @@ export const AuthenticationApiAxiosParamCreator = function (configuration?: Conf options: localVarRequestOptions, }; }, + /** + * + * @param {SignUpDto} signUpDto + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + signUpAdmin: async (signUpDto: SignUpDto, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'signUpDto' is not null or undefined + assertParamExists('signUpAdmin', 'signUpDto', signUpDto) + const localVarPath = `/auth/admin-sign-up`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(signUpDto, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * * @param {*} [options] Override http request option. @@ -9780,16 +10408,6 @@ export const AuthenticationApiAxiosParamCreator = function (configuration?: Conf export const AuthenticationApiFp = function(configuration?: Configuration) { const localVarAxiosParamCreator = AuthenticationApiAxiosParamCreator(configuration) return { - /** - * - * @param {SignUpDto} signUpDto - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async adminSignUp(signUpDto: SignUpDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.adminSignUp(signUpDto, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); - }, /** * * @param {ChangePasswordDto} changePasswordDto @@ -9847,6 +10465,16 @@ export const AuthenticationApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.logoutAuthDevices(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * + * @param {SignUpDto} signUpDto + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async signUpAdmin(signUpDto: SignUpDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.signUpAdmin(signUpDto, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @param {*} [options] Override http request option. @@ -9866,15 +10494,6 @@ export const AuthenticationApiFp = function(configuration?: Configuration) { export const AuthenticationApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { const localVarFp = AuthenticationApiFp(configuration) return { - /** - * - * @param {AuthenticationApiAdminSignUpRequest} requestParameters Request parameters. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - adminSignUp(requestParameters: AuthenticationApiAdminSignUpRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.adminSignUp(requestParameters.signUpDto, options).then((request) => request(axios, basePath)); - }, /** * * @param {AuthenticationApiChangePasswordRequest} requestParameters Request parameters. @@ -9926,6 +10545,15 @@ export const AuthenticationApiFactory = function (configuration?: Configuration, logoutAuthDevices(options?: AxiosRequestConfig): AxiosPromise { return localVarFp.logoutAuthDevices(options).then((request) => request(axios, basePath)); }, + /** + * + * @param {AuthenticationApiSignUpAdminRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + signUpAdmin(requestParameters: AuthenticationApiSignUpAdminRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.signUpAdmin(requestParameters.signUpDto, options).then((request) => request(axios, basePath)); + }, /** * * @param {*} [options] Override http request option. @@ -9937,20 +10565,6 @@ export const AuthenticationApiFactory = function (configuration?: Configuration, }; }; -/** - * Request parameters for adminSignUp operation in AuthenticationApi. - * @export - * @interface AuthenticationApiAdminSignUpRequest - */ -export interface AuthenticationApiAdminSignUpRequest { - /** - * - * @type {SignUpDto} - * @memberof AuthenticationApiAdminSignUp - */ - readonly signUpDto: SignUpDto -} - /** * Request parameters for changePassword operation in AuthenticationApi. * @export @@ -9993,6 +10607,20 @@ export interface AuthenticationApiLogoutAuthDeviceRequest { readonly id: string } +/** + * Request parameters for signUpAdmin operation in AuthenticationApi. + * @export + * @interface AuthenticationApiSignUpAdminRequest + */ +export interface AuthenticationApiSignUpAdminRequest { + /** + * + * @type {SignUpDto} + * @memberof AuthenticationApiSignUpAdmin + */ + readonly signUpDto: SignUpDto +} + /** * AuthenticationApi - object-oriented interface * @export @@ -10000,17 +10628,6 @@ export interface AuthenticationApiLogoutAuthDeviceRequest { * @extends {BaseAPI} */ export class AuthenticationApi extends BaseAPI { - /** - * - * @param {AuthenticationApiAdminSignUpRequest} requestParameters Request parameters. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof AuthenticationApi - */ - public adminSignUp(requestParameters: AuthenticationApiAdminSignUpRequest, options?: AxiosRequestConfig) { - return AuthenticationApiFp(this.configuration).adminSignUp(requestParameters.signUpDto, options).then((request) => request(this.axios, this.basePath)); - } - /** * * @param {AuthenticationApiChangePasswordRequest} requestParameters Request parameters. @@ -10074,6 +10691,17 @@ export class AuthenticationApi extends BaseAPI { return AuthenticationApiFp(this.configuration).logoutAuthDevices(options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @param {AuthenticationApiSignUpAdminRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof AuthenticationApi + */ + public signUpAdmin(requestParameters: AuthenticationApiSignUpAdminRequest, options?: AxiosRequestConfig) { + return AuthenticationApiFp(this.configuration).signUpAdmin(requestParameters.signUpDto, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @param {*} [options] Override http request option. @@ -10386,7 +11014,7 @@ export const LibraryApiAxiosParamCreator = function (configuration?: Configurati * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getAllForUser: async (options: AxiosRequestConfig = {}): Promise => { + getLibraries: async (options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/library`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -10676,8 +11304,8 @@ export const LibraryApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getAllForUser(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getAllForUser(options); + async getLibraries(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getLibraries(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -10765,8 +11393,8 @@ export const LibraryApiFactory = function (configuration?: Configuration, basePa * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getAllForUser(options?: AxiosRequestConfig): AxiosPromise> { - return localVarFp.getAllForUser(options).then((request) => request(axios, basePath)); + getLibraries(options?: AxiosRequestConfig): AxiosPromise> { + return localVarFp.getLibraries(options).then((request) => request(axios, basePath)); }, /** * @@ -10963,8 +11591,8 @@ export class LibraryApi extends BaseAPI { * @throws {RequiredError} * @memberof LibraryApi */ - public getAllForUser(options?: AxiosRequestConfig) { - return LibraryApiFp(this.configuration).getAllForUser(options).then((request) => request(this.axios, this.basePath)); + public getLibraries(options?: AxiosRequestConfig) { + return LibraryApiFp(this.configuration).getLibraries(options).then((request) => request(this.axios, this.basePath)); } /** @@ -11030,50 +11658,15 @@ export class LibraryApi extends BaseAPI { */ export const OAuthApiAxiosParamCreator = function (configuration?: Configuration) { return { - /** - * - * @param {OAuthConfigDto} oAuthConfigDto - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - authorizeOAuth: async (oAuthConfigDto: OAuthConfigDto, options: AxiosRequestConfig = {}): Promise => { - // verify required parameter 'oAuthConfigDto' is not null or undefined - assertParamExists('authorizeOAuth', 'oAuthConfigDto', oAuthConfigDto) - const localVarPath = `/oauth/authorize`; - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - - - localVarHeaderParameter['Content-Type'] = 'application/json'; - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - localVarRequestOptions.data = serializeDataIfNeeded(oAuthConfigDto, localVarRequestOptions, configuration) - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, /** * * @param {OAuthCallbackDto} oAuthCallbackDto * @param {*} [options] Override http request option. * @throws {RequiredError} */ - callback: async (oAuthCallbackDto: OAuthCallbackDto, options: AxiosRequestConfig = {}): Promise => { + finishOAuth: async (oAuthCallbackDto: OAuthCallbackDto, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'oAuthCallbackDto' is not null or undefined - assertParamExists('callback', 'oAuthCallbackDto', oAuthCallbackDto) + assertParamExists('finishOAuth', 'oAuthCallbackDto', oAuthCallbackDto) const localVarPath = `/oauth/callback`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -11107,9 +11700,9 @@ export const OAuthApiAxiosParamCreator = function (configuration?: Configuration * @deprecated * @throws {RequiredError} */ - generateConfig: async (oAuthConfigDto: OAuthConfigDto, options: AxiosRequestConfig = {}): Promise => { + generateOAuthConfig: async (oAuthConfigDto: OAuthConfigDto, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'oAuthConfigDto' is not null or undefined - assertParamExists('generateConfig', 'oAuthConfigDto', oAuthConfigDto) + assertParamExists('generateOAuthConfig', 'oAuthConfigDto', oAuthConfigDto) const localVarPath = `/oauth/config`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -11142,9 +11735,9 @@ export const OAuthApiAxiosParamCreator = function (configuration?: Configuration * @param {*} [options] Override http request option. * @throws {RequiredError} */ - link: async (oAuthCallbackDto: OAuthCallbackDto, options: AxiosRequestConfig = {}): Promise => { + linkOAuthAccount: async (oAuthCallbackDto: OAuthCallbackDto, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'oAuthCallbackDto' is not null or undefined - assertParamExists('link', 'oAuthCallbackDto', oAuthCallbackDto) + assertParamExists('linkOAuthAccount', 'oAuthCallbackDto', oAuthCallbackDto) const localVarPath = `/oauth/link`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -11185,7 +11778,7 @@ export const OAuthApiAxiosParamCreator = function (configuration?: Configuration * @param {*} [options] Override http request option. * @throws {RequiredError} */ - mobileRedirect: async (options: AxiosRequestConfig = {}): Promise => { + redirectOAuthToMobile: async (options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/oauth/mobile-redirect`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -11211,10 +11804,45 @@ export const OAuthApiAxiosParamCreator = function (configuration?: Configuration }, /** * + * @param {OAuthConfigDto} oAuthConfigDto * @param {*} [options] Override http request option. * @throws {RequiredError} */ - unlink: async (options: AxiosRequestConfig = {}): Promise => { + startOAuth: async (oAuthConfigDto: OAuthConfigDto, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'oAuthConfigDto' is not null or undefined + assertParamExists('startOAuth', 'oAuthConfigDto', oAuthConfigDto) + const localVarPath = `/oauth/authorize`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(oAuthConfigDto, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + unlinkOAuthAccount: async (options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/oauth/unlink`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -11257,24 +11885,14 @@ export const OAuthApiAxiosParamCreator = function (configuration?: Configuration export const OAuthApiFp = function(configuration?: Configuration) { const localVarAxiosParamCreator = OAuthApiAxiosParamCreator(configuration) return { - /** - * - * @param {OAuthConfigDto} oAuthConfigDto - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async authorizeOAuth(oAuthConfigDto: OAuthConfigDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.authorizeOAuth(oAuthConfigDto, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); - }, /** * * @param {OAuthCallbackDto} oAuthCallbackDto * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async callback(oAuthCallbackDto: OAuthCallbackDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.callback(oAuthCallbackDto, options); + async finishOAuth(oAuthCallbackDto: OAuthCallbackDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.finishOAuth(oAuthCallbackDto, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -11284,8 +11902,8 @@ export const OAuthApiFp = function(configuration?: Configuration) { * @deprecated * @throws {RequiredError} */ - async generateConfig(oAuthConfigDto: OAuthConfigDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.generateConfig(oAuthConfigDto, options); + async generateOAuthConfig(oAuthConfigDto: OAuthConfigDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.generateOAuthConfig(oAuthConfigDto, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -11294,8 +11912,8 @@ export const OAuthApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async link(oAuthCallbackDto: OAuthCallbackDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.link(oAuthCallbackDto, options); + async linkOAuthAccount(oAuthCallbackDto: OAuthCallbackDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.linkOAuthAccount(oAuthCallbackDto, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -11303,8 +11921,18 @@ export const OAuthApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async mobileRedirect(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.mobileRedirect(options); + async redirectOAuthToMobile(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.redirectOAuthToMobile(options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + /** + * + * @param {OAuthConfigDto} oAuthConfigDto + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async startOAuth(oAuthConfigDto: OAuthConfigDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.startOAuth(oAuthConfigDto, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -11312,8 +11940,8 @@ export const OAuthApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async unlink(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.unlink(options); + async unlinkOAuthAccount(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.unlinkOAuthAccount(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, } @@ -11328,116 +11956,116 @@ export const OAuthApiFactory = function (configuration?: Configuration, basePath return { /** * - * @param {OAuthApiAuthorizeOAuthRequest} requestParameters Request parameters. + * @param {OAuthApiFinishOAuthRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - authorizeOAuth(requestParameters: OAuthApiAuthorizeOAuthRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.authorizeOAuth(requestParameters.oAuthConfigDto, options).then((request) => request(axios, basePath)); - }, - /** - * - * @param {OAuthApiCallbackRequest} requestParameters Request parameters. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - callback(requestParameters: OAuthApiCallbackRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.callback(requestParameters.oAuthCallbackDto, options).then((request) => request(axios, basePath)); + finishOAuth(requestParameters: OAuthApiFinishOAuthRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.finishOAuth(requestParameters.oAuthCallbackDto, options).then((request) => request(axios, basePath)); }, /** * @deprecated use feature flags and /oauth/authorize - * @param {OAuthApiGenerateConfigRequest} requestParameters Request parameters. + * @param {OAuthApiGenerateOAuthConfigRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @deprecated * @throws {RequiredError} */ - generateConfig(requestParameters: OAuthApiGenerateConfigRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.generateConfig(requestParameters.oAuthConfigDto, options).then((request) => request(axios, basePath)); + generateOAuthConfig(requestParameters: OAuthApiGenerateOAuthConfigRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.generateOAuthConfig(requestParameters.oAuthConfigDto, options).then((request) => request(axios, basePath)); }, /** * - * @param {OAuthApiLinkRequest} requestParameters Request parameters. + * @param {OAuthApiLinkOAuthAccountRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - link(requestParameters: OAuthApiLinkRequest, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.link(requestParameters.oAuthCallbackDto, options).then((request) => request(axios, basePath)); + linkOAuthAccount(requestParameters: OAuthApiLinkOAuthAccountRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.linkOAuthAccount(requestParameters.oAuthCallbackDto, options).then((request) => request(axios, basePath)); }, /** * * @param {*} [options] Override http request option. * @throws {RequiredError} */ - mobileRedirect(options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.mobileRedirect(options).then((request) => request(axios, basePath)); + redirectOAuthToMobile(options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.redirectOAuthToMobile(options).then((request) => request(axios, basePath)); + }, + /** + * + * @param {OAuthApiStartOAuthRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + startOAuth(requestParameters: OAuthApiStartOAuthRequest, options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.startOAuth(requestParameters.oAuthConfigDto, options).then((request) => request(axios, basePath)); }, /** * * @param {*} [options] Override http request option. * @throws {RequiredError} */ - unlink(options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.unlink(options).then((request) => request(axios, basePath)); + unlinkOAuthAccount(options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.unlinkOAuthAccount(options).then((request) => request(axios, basePath)); }, }; }; /** - * Request parameters for authorizeOAuth operation in OAuthApi. + * Request parameters for finishOAuth operation in OAuthApi. * @export - * @interface OAuthApiAuthorizeOAuthRequest + * @interface OAuthApiFinishOAuthRequest */ -export interface OAuthApiAuthorizeOAuthRequest { - /** - * - * @type {OAuthConfigDto} - * @memberof OAuthApiAuthorizeOAuth - */ - readonly oAuthConfigDto: OAuthConfigDto -} - -/** - * Request parameters for callback operation in OAuthApi. - * @export - * @interface OAuthApiCallbackRequest - */ -export interface OAuthApiCallbackRequest { +export interface OAuthApiFinishOAuthRequest { /** * * @type {OAuthCallbackDto} - * @memberof OAuthApiCallback + * @memberof OAuthApiFinishOAuth */ readonly oAuthCallbackDto: OAuthCallbackDto } /** - * Request parameters for generateConfig operation in OAuthApi. + * Request parameters for generateOAuthConfig operation in OAuthApi. * @export - * @interface OAuthApiGenerateConfigRequest + * @interface OAuthApiGenerateOAuthConfigRequest */ -export interface OAuthApiGenerateConfigRequest { +export interface OAuthApiGenerateOAuthConfigRequest { /** * * @type {OAuthConfigDto} - * @memberof OAuthApiGenerateConfig + * @memberof OAuthApiGenerateOAuthConfig */ readonly oAuthConfigDto: OAuthConfigDto } /** - * Request parameters for link operation in OAuthApi. + * Request parameters for linkOAuthAccount operation in OAuthApi. * @export - * @interface OAuthApiLinkRequest + * @interface OAuthApiLinkOAuthAccountRequest */ -export interface OAuthApiLinkRequest { +export interface OAuthApiLinkOAuthAccountRequest { /** * * @type {OAuthCallbackDto} - * @memberof OAuthApiLink + * @memberof OAuthApiLinkOAuthAccount */ readonly oAuthCallbackDto: OAuthCallbackDto } +/** + * Request parameters for startOAuth operation in OAuthApi. + * @export + * @interface OAuthApiStartOAuthRequest + */ +export interface OAuthApiStartOAuthRequest { + /** + * + * @type {OAuthConfigDto} + * @memberof OAuthApiStartOAuth + */ + readonly oAuthConfigDto: OAuthConfigDto +} + /** * OAuthApi - object-oriented interface * @export @@ -11447,47 +12075,36 @@ export interface OAuthApiLinkRequest { export class OAuthApi extends BaseAPI { /** * - * @param {OAuthApiAuthorizeOAuthRequest} requestParameters Request parameters. + * @param {OAuthApiFinishOAuthRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof OAuthApi */ - public authorizeOAuth(requestParameters: OAuthApiAuthorizeOAuthRequest, options?: AxiosRequestConfig) { - return OAuthApiFp(this.configuration).authorizeOAuth(requestParameters.oAuthConfigDto, options).then((request) => request(this.axios, this.basePath)); - } - - /** - * - * @param {OAuthApiCallbackRequest} requestParameters Request parameters. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof OAuthApi - */ - public callback(requestParameters: OAuthApiCallbackRequest, options?: AxiosRequestConfig) { - return OAuthApiFp(this.configuration).callback(requestParameters.oAuthCallbackDto, options).then((request) => request(this.axios, this.basePath)); + public finishOAuth(requestParameters: OAuthApiFinishOAuthRequest, options?: AxiosRequestConfig) { + return OAuthApiFp(this.configuration).finishOAuth(requestParameters.oAuthCallbackDto, options).then((request) => request(this.axios, this.basePath)); } /** * @deprecated use feature flags and /oauth/authorize - * @param {OAuthApiGenerateConfigRequest} requestParameters Request parameters. + * @param {OAuthApiGenerateOAuthConfigRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @deprecated * @throws {RequiredError} * @memberof OAuthApi */ - public generateConfig(requestParameters: OAuthApiGenerateConfigRequest, options?: AxiosRequestConfig) { - return OAuthApiFp(this.configuration).generateConfig(requestParameters.oAuthConfigDto, options).then((request) => request(this.axios, this.basePath)); + public generateOAuthConfig(requestParameters: OAuthApiGenerateOAuthConfigRequest, options?: AxiosRequestConfig) { + return OAuthApiFp(this.configuration).generateOAuthConfig(requestParameters.oAuthConfigDto, options).then((request) => request(this.axios, this.basePath)); } /** * - * @param {OAuthApiLinkRequest} requestParameters Request parameters. + * @param {OAuthApiLinkOAuthAccountRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof OAuthApi */ - public link(requestParameters: OAuthApiLinkRequest, options?: AxiosRequestConfig) { - return OAuthApiFp(this.configuration).link(requestParameters.oAuthCallbackDto, options).then((request) => request(this.axios, this.basePath)); + public linkOAuthAccount(requestParameters: OAuthApiLinkOAuthAccountRequest, options?: AxiosRequestConfig) { + return OAuthApiFp(this.configuration).linkOAuthAccount(requestParameters.oAuthCallbackDto, options).then((request) => request(this.axios, this.basePath)); } /** @@ -11496,8 +12113,19 @@ export class OAuthApi extends BaseAPI { * @throws {RequiredError} * @memberof OAuthApi */ - public mobileRedirect(options?: AxiosRequestConfig) { - return OAuthApiFp(this.configuration).mobileRedirect(options).then((request) => request(this.axios, this.basePath)); + public redirectOAuthToMobile(options?: AxiosRequestConfig) { + return OAuthApiFp(this.configuration).redirectOAuthToMobile(options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @param {OAuthApiStartOAuthRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof OAuthApi + */ + public startOAuth(requestParameters: OAuthApiStartOAuthRequest, options?: AxiosRequestConfig) { + return OAuthApiFp(this.configuration).startOAuth(requestParameters.oAuthConfigDto, options).then((request) => request(this.axios, this.basePath)); } /** @@ -11506,8 +12134,8 @@ export class OAuthApi extends BaseAPI { * @throws {RequiredError} * @memberof OAuthApi */ - public unlink(options?: AxiosRequestConfig) { - return OAuthApiFp(this.configuration).unlink(options).then((request) => request(this.axios, this.basePath)); + public unlinkOAuthAccount(options?: AxiosRequestConfig) { + return OAuthApiFp(this.configuration).unlinkOAuthAccount(options).then((request) => request(this.axios, this.basePath)); } } @@ -13162,37 +13790,8 @@ export const ServerInfoApiAxiosParamCreator = function (configuration?: Configur * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getServerVersion: async (options: AxiosRequestConfig = {}): Promise => { - const localVarPath = `/server-info/version`; - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - /** - * - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - getStats: async (options: AxiosRequestConfig = {}): Promise => { - const localVarPath = `/server-info/stats`; + getServerStatistics: async (options: AxiosRequestConfig = {}): Promise => { + const localVarPath = `/server-info/statistics`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); let baseOptions; @@ -13215,6 +13814,35 @@ export const ServerInfoApiAxiosParamCreator = function (configuration?: Configur + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getServerVersion: async (options: AxiosRequestConfig = {}): Promise => { + const localVarPath = `/server-info/version`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -13353,8 +13981,8 @@ export const ServerInfoApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getServerVersion(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getServerVersion(options); + async getServerStatistics(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getServerStatistics(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -13362,8 +13990,8 @@ export const ServerInfoApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getStats(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getStats(options); + async getServerVersion(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getServerVersion(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -13432,16 +14060,16 @@ export const ServerInfoApiFactory = function (configuration?: Configuration, bas * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getServerVersion(options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.getServerVersion(options).then((request) => request(axios, basePath)); + getServerStatistics(options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.getServerStatistics(options).then((request) => request(axios, basePath)); }, /** * * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getStats(options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.getStats(options).then((request) => request(axios, basePath)); + getServerVersion(options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.getServerVersion(options).then((request) => request(axios, basePath)); }, /** * @@ -13513,8 +14141,8 @@ export class ServerInfoApi extends BaseAPI { * @throws {RequiredError} * @memberof ServerInfoApi */ - public getServerVersion(options?: AxiosRequestConfig) { - return ServerInfoApiFp(this.configuration).getServerVersion(options).then((request) => request(this.axios, this.basePath)); + public getServerStatistics(options?: AxiosRequestConfig) { + return ServerInfoApiFp(this.configuration).getServerStatistics(options).then((request) => request(this.axios, this.basePath)); } /** @@ -13523,8 +14151,8 @@ export class ServerInfoApi extends BaseAPI { * @throws {RequiredError} * @memberof ServerInfoApi */ - public getStats(options?: AxiosRequestConfig) { - return ServerInfoApiFp(this.configuration).getStats(options).then((request) => request(this.axios, this.basePath)); + public getServerVersion(options?: AxiosRequestConfig) { + return ServerInfoApiFp(this.configuration).getServerVersion(options).then((request) => request(this.axios, this.basePath)); } /** @@ -14410,7 +15038,7 @@ export const SystemConfigApiAxiosParamCreator = function (configuration?: Config * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getDefaults: async (options: AxiosRequestConfig = {}): Promise => { + getConfigDefaults: async (options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/system-config/defaults`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -14549,8 +15177,8 @@ export const SystemConfigApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getDefaults(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getDefaults(options); + async getConfigDefaults(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getConfigDefaults(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -14595,8 +15223,8 @@ export const SystemConfigApiFactory = function (configuration?: Configuration, b * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getDefaults(options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.getDefaults(options).then((request) => request(axios, basePath)); + getConfigDefaults(options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.getConfigDefaults(options).then((request) => request(axios, basePath)); }, /** * @@ -14655,8 +15283,8 @@ export class SystemConfigApi extends BaseAPI { * @throws {RequiredError} * @memberof SystemConfigApi */ - public getDefaults(options?: AxiosRequestConfig) { - return SystemConfigApiFp(this.configuration).getDefaults(options).then((request) => request(this.axios, this.basePath)); + public getConfigDefaults(options?: AxiosRequestConfig) { + return SystemConfigApiFp(this.configuration).getConfigDefaults(options).then((request) => request(this.axios, this.basePath)); } /** diff --git a/web/src/api/open-api/base.ts b/web/src/api/open-api/base.ts index 814dc8f92..9a534e7bd 100644 --- a/web/src/api/open-api/base.ts +++ b/web/src/api/open-api/base.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.83.0 + * The version of the OpenAPI document: 1.84.0 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/web/src/api/open-api/common.ts b/web/src/api/open-api/common.ts index 7d762d6ac..8997b2d52 100644 --- a/web/src/api/open-api/common.ts +++ b/web/src/api/open-api/common.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.83.0 + * The version of the OpenAPI document: 1.84.0 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/web/src/api/open-api/configuration.ts b/web/src/api/open-api/configuration.ts index 3ace8a93f..8058881d1 100644 --- a/web/src/api/open-api/configuration.ts +++ b/web/src/api/open-api/configuration.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.83.0 + * The version of the OpenAPI document: 1.84.0 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/web/src/api/open-api/index.ts b/web/src/api/open-api/index.ts index 62d163db6..d0651f28a 100644 --- a/web/src/api/open-api/index.ts +++ b/web/src/api/open-api/index.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.83.0 + * The version of the OpenAPI document: 1.84.0 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/web/src/api/utils.ts b/web/src/api/utils.ts index f82596eef..8dd0fb4ca 100644 --- a/web/src/api/utils.ts +++ b/web/src/api/utils.ts @@ -36,23 +36,19 @@ export const oauth = { authorize: async (location: Location) => { try { const redirectUri = location.href.split('?')[0]; - const { data } = await api.oauthApi.authorizeOAuth({ oAuthConfigDto: { redirectUri } }); + const { data } = await api.oauthApi.startOAuth({ oAuthConfigDto: { redirectUri } }); goto(data.url); } catch (error) { handleError(error, 'Unable to login with OAuth'); } }, - getConfig: (location: Location) => { - const redirectUri = location.href.split('?')[0]; - return api.oauthApi.generateConfig({ oAuthConfigDto: { redirectUri } }); - }, login: (location: Location) => { - return api.oauthApi.callback({ oAuthCallbackDto: { url: location.href } }); + return api.oauthApi.finishOAuth({ oAuthCallbackDto: { url: location.href } }); }, link: (location: Location): AxiosPromise => { - return api.oauthApi.link({ oAuthCallbackDto: { url: location.href } }); + return api.oauthApi.linkOAuthAccount({ oAuthCallbackDto: { url: location.href } }); }, unlink: () => { - return api.oauthApi.unlink(); + return api.oauthApi.unlinkOAuthAccount(); }, }; diff --git a/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte b/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte index 96fceb61e..f22538d94 100644 --- a/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte +++ b/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte @@ -32,7 +32,7 @@ async function getConfigs() { [savedConfig, defaultConfig] = await Promise.all([ api.systemConfigApi.getConfig().then((res) => res.data.ffmpeg), - api.systemConfigApi.getDefaults().then((res) => res.data.ffmpeg), + api.systemConfigApi.getConfigDefaults().then((res) => res.data.ffmpeg), ]); } @@ -76,7 +76,7 @@ } async function resetToDefault() { - const { data: configs } = await api.systemConfigApi.getDefaults(); + const { data: configs } = await api.systemConfigApi.getConfigDefaults(); ffmpegConfig = { ...configs.ffmpeg }; defaultConfig = { ...configs.ffmpeg }; diff --git a/web/src/lib/components/admin-page/settings/job-settings/job-settings.svelte b/web/src/lib/components/admin-page/settings/job-settings/job-settings.svelte index b795db7d3..9098bc33c 100644 --- a/web/src/lib/components/admin-page/settings/job-settings/job-settings.svelte +++ b/web/src/lib/components/admin-page/settings/job-settings/job-settings.svelte @@ -22,7 +22,7 @@ async function getConfigs() { [savedConfig, defaultConfig] = await Promise.all([ api.systemConfigApi.getConfig().then((res) => res.data.job), - api.systemConfigApi.getDefaults().then((res) => res.data.job), + api.systemConfigApi.getConfigDefaults().then((res) => res.data.job), ]); } @@ -59,7 +59,7 @@ } async function resetToDefault() { - const { data: configs } = await api.systemConfigApi.getDefaults(); + const { data: configs } = await api.systemConfigApi.getConfigDefaults(); jobConfig = { ...configs.job }; defaultConfig = { ...configs.job }; diff --git a/web/src/lib/components/admin-page/settings/library-settings/library-settings.svelte b/web/src/lib/components/admin-page/settings/library-settings/library-settings.svelte new file mode 100644 index 000000000..698f2fc35 --- /dev/null +++ b/web/src/lib/components/admin-page/settings/library-settings/library-settings.svelte @@ -0,0 +1,145 @@ + + +

+ {#await getConfigs() then} +
+ +
+
+ + +
+ + +
+ + + +

+ Set the scanning interval using the cron format. For more information please refer to e.g. Crontab Guru +

+
+
+
+ +
+ +
+
+
+
+ {/await} +
diff --git a/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte b/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte index 78c37977d..e09157746 100644 --- a/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte +++ b/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte @@ -22,7 +22,7 @@ async function refreshConfig() { [savedConfig, defaultConfig] = await Promise.all([ api.systemConfigApi.getConfig().then((res) => res.data.machineLearning), - api.systemConfigApi.getDefaults().then((res) => res.data.machineLearning), + api.systemConfigApi.getConfigDefaults().then((res) => res.data.machineLearning), ]); } diff --git a/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte b/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte index df9059fce..0efc839ad 100644 --- a/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte +++ b/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte @@ -22,7 +22,7 @@ async function refreshConfig() { [savedConfig, defaultConfig] = await Promise.all([ api.systemConfigApi.getConfig().then((res) => res.data), - api.systemConfigApi.getDefaults().then((res) => res.data), + api.systemConfigApi.getConfigDefaults().then((res) => res.data), ]); } @@ -65,7 +65,7 @@ } async function resetToDefault() { - const { data: configs } = await api.systemConfigApi.getDefaults(); + const { data: configs } = await api.systemConfigApi.getConfigDefaults(); config = cloneDeep(configs); defaultConfig = cloneDeep(configs); diff --git a/web/src/lib/components/admin-page/settings/new-version-check-settings/new-version-check-settings.svelte b/web/src/lib/components/admin-page/settings/new-version-check-settings/new-version-check-settings.svelte index acb83f0ca..7568ef60a 100644 --- a/web/src/lib/components/admin-page/settings/new-version-check-settings/new-version-check-settings.svelte +++ b/web/src/lib/components/admin-page/settings/new-version-check-settings/new-version-check-settings.svelte @@ -18,7 +18,7 @@ async function getConfigs() { [savedConfig, defaultConfig] = await Promise.all([ api.systemConfigApi.getConfig().then((res) => res.data.newVersionCheck), - api.systemConfigApi.getDefaults().then((res) => res.data.newVersionCheck), + api.systemConfigApi.getConfigDefaults().then((res) => res.data.newVersionCheck), ]); } @@ -55,7 +55,7 @@ } async function resetToDefault() { - const { data: configs } = await api.systemConfigApi.getDefaults(); + const { data: configs } = await api.systemConfigApi.getConfigDefaults(); newVersionCheckConfig = { ...configs.newVersionCheck }; defaultConfig = { ...configs.newVersionCheck }; diff --git a/web/src/lib/components/admin-page/settings/oauth/oauth-settings.svelte b/web/src/lib/components/admin-page/settings/oauth/oauth-settings.svelte index 9e16b44f2..a9f2c2713 100644 --- a/web/src/lib/components/admin-page/settings/oauth/oauth-settings.svelte +++ b/web/src/lib/components/admin-page/settings/oauth/oauth-settings.svelte @@ -29,7 +29,7 @@ async function getConfigs() { [savedConfig, defaultConfig] = await Promise.all([ api.systemConfigApi.getConfig().then((res) => res.data.oauth), - api.systemConfigApi.getDefaults().then((res) => res.data.oauth), + api.systemConfigApi.getConfigDefaults().then((res) => res.data.oauth), ]); } @@ -90,7 +90,7 @@ } async function resetToDefault() { - const { data: defaultConfig } = await api.systemConfigApi.getDefaults(); + const { data: defaultConfig } = await api.systemConfigApi.getConfigDefaults(); oauthConfig = { ...defaultConfig.oauth }; diff --git a/web/src/lib/components/admin-page/settings/password-login/password-login-settings.svelte b/web/src/lib/components/admin-page/settings/password-login/password-login-settings.svelte index 2c11512f5..0b5f7a16c 100644 --- a/web/src/lib/components/admin-page/settings/password-login/password-login-settings.svelte +++ b/web/src/lib/components/admin-page/settings/password-login/password-login-settings.svelte @@ -20,7 +20,7 @@ async function getConfigs() { [savedConfig, defaultConfig] = await Promise.all([ api.systemConfigApi.getConfig().then((res) => res.data.passwordLogin), - api.systemConfigApi.getDefaults().then((res) => res.data.passwordLogin), + api.systemConfigApi.getConfigDefaults().then((res) => res.data.passwordLogin), ]); } @@ -77,7 +77,7 @@ } async function resetToDefault() { - const { data: configs } = await api.systemConfigApi.getDefaults(); + const { data: configs } = await api.systemConfigApi.getConfigDefaults(); passwordLoginConfig = { ...configs.passwordLogin }; defaultConfig = { ...configs.passwordLogin }; diff --git a/web/src/lib/components/admin-page/settings/storage-template/storage-template-settings.svelte b/web/src/lib/components/admin-page/settings/storage-template/storage-template-settings.svelte index fc95e6d7b..5bdef1f5e 100644 --- a/web/src/lib/components/admin-page/settings/storage-template/storage-template-settings.svelte +++ b/web/src/lib/components/admin-page/settings/storage-template/storage-template-settings.svelte @@ -26,7 +26,7 @@ async function getConfigs() { [savedConfig, defaultConfig, templateOptions] = await Promise.all([ api.systemConfigApi.getConfig().then((res) => res.data.storageTemplate), - api.systemConfigApi.getDefaults().then((res) => res.data.storageTemplate), + api.systemConfigApi.getConfigDefaults().then((res) => res.data.storageTemplate), api.systemConfigApi.getStorageTemplateOptions().then((res) => res.data), ]); @@ -119,7 +119,7 @@ } async function resetToDefault() { - const { data: defaultConfig } = await api.systemConfigApi.getDefaults(); + const { data: defaultConfig } = await api.systemConfigApi.getConfigDefaults(); storageConfig.template = defaultConfig.storageTemplate.template; diff --git a/web/src/lib/components/admin-page/settings/theme/theme-settings.svelte b/web/src/lib/components/admin-page/settings/theme/theme-settings.svelte index b28d0106d..7d67c3d95 100644 --- a/web/src/lib/components/admin-page/settings/theme/theme-settings.svelte +++ b/web/src/lib/components/admin-page/settings/theme/theme-settings.svelte @@ -19,7 +19,7 @@ async function getConfigs() { [savedConfig, defaultConfig] = await Promise.all([ api.systemConfigApi.getConfig().then((res) => res.data.theme), - api.systemConfigApi.getDefaults().then((res) => res.data.theme), + api.systemConfigApi.getConfigDefaults().then((res) => res.data.theme), ]); } @@ -56,7 +56,7 @@ } async function resetToDefault() { - const { data: configs } = await api.systemConfigApi.getDefaults(); + const { data: configs } = await api.systemConfigApi.getConfigDefaults(); themeConfig = { ...configs.theme }; defaultConfig = { ...configs.theme }; diff --git a/web/src/lib/components/admin-page/settings/thumbnail/thumbnail-settings.svelte b/web/src/lib/components/admin-page/settings/thumbnail/thumbnail-settings.svelte index d57d7ccff..e1f4f89bf 100644 --- a/web/src/lib/components/admin-page/settings/thumbnail/thumbnail-settings.svelte +++ b/web/src/lib/components/admin-page/settings/thumbnail/thumbnail-settings.svelte @@ -20,7 +20,7 @@ async function getConfigs() { [savedConfig, defaultConfig] = await Promise.all([ api.systemConfigApi.getConfig().then((res) => res.data.thumbnail), - api.systemConfigApi.getDefaults().then((res) => res.data.thumbnail), + api.systemConfigApi.getConfigDefaults().then((res) => res.data.thumbnail), ]); } @@ -37,7 +37,7 @@ } async function resetToDefault() { - const { data: configs } = await api.systemConfigApi.getDefaults(); + const { data: configs } = await api.systemConfigApi.getConfigDefaults(); thumbnailConfig = { ...configs.thumbnail }; defaultConfig = { ...configs.thumbnail }; diff --git a/web/src/lib/components/admin-page/settings/trash-settings/trash-settings.svelte b/web/src/lib/components/admin-page/settings/trash-settings/trash-settings.svelte index 5ebc21a6d..da9e0d779 100644 --- a/web/src/lib/components/admin-page/settings/trash-settings/trash-settings.svelte +++ b/web/src/lib/components/admin-page/settings/trash-settings/trash-settings.svelte @@ -20,7 +20,7 @@ async function getConfigs() { [savedConfig, defaultConfig] = await Promise.all([ api.systemConfigApi.getConfig().then((res) => res.data.trash), - api.systemConfigApi.getDefaults().then((res) => res.data.trash), + api.systemConfigApi.getConfigDefaults().then((res) => res.data.trash), ]); } @@ -53,7 +53,7 @@ } async function resetToDefault() { - const { data: configs } = await api.systemConfigApi.getDefaults(); + const { data: configs } = await api.systemConfigApi.getConfigDefaults(); trashConfig = { ...configs.trash }; defaultConfig = { ...configs.trash }; diff --git a/web/src/lib/components/album-page/album-viewer.svelte b/web/src/lib/components/album-page/album-viewer.svelte index ddc165c18..2333a55f0 100644 --- a/web/src/lib/components/album-page/album-viewer.svelte +++ b/web/src/lib/components/album-page/album-viewer.svelte @@ -5,7 +5,7 @@ import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store'; import { locale } from '$lib/stores/preferences.store'; import { fileUploadHandler, openFileUploadDialog } from '$lib/utils/file-uploader'; - import type { AlbumResponseDto, SharedLinkResponseDto } from '@api'; + import type { AlbumResponseDto, SharedLinkResponseDto, UserResponseDto } from '@api'; import { onDestroy, onMount } from 'svelte'; import { dateFormats } from '../../constants'; import { createAssetInteractionStore } from '../../stores/asset-interaction.store'; @@ -22,6 +22,7 @@ import { mdiFileImagePlusOutline, mdiFolderDownloadOutline } from '@mdi/js'; export let sharedLink: SharedLinkResponseDto; + export let user: UserResponseDto | undefined = undefined; const album = sharedLink.album as AlbumResponseDto; @@ -138,7 +139,7 @@
- +

+ import { createEventDispatcher } from 'svelte'; + import UserAvatar from '../shared-components/user-avatar.svelte'; + import { mdiClose, mdiHeart, mdiSend, mdiDotsVertical } from '@mdi/js'; + import Icon from '$lib/components/elements/icon.svelte'; + import { ActivityResponseDto, api, AssetTypeEnum, ReactionType, type UserResponseDto } from '@api'; + import { handleError } from '$lib/utils/handle-error'; + import { isTenMinutesApart } from '$lib/utils/timesince'; + import { clickOutside } from '$lib/utils/click-outside'; + import CircleIconButton from '../elements/buttons/circle-icon-button.svelte'; + import LoadingSpinner from '../shared-components/loading-spinner.svelte'; + import { NotificationType, notificationController } from '../shared-components/notification/notification'; + import { getAssetType } from '$lib/utils/asset-utils'; + import * as luxon from 'luxon'; + + const units: Intl.RelativeTimeFormatUnit[] = ['year', 'month', 'week', 'day', 'hour', 'minute', 'second']; + + const timeSince = (dateTime: luxon.DateTime) => { + const diff = dateTime.diffNow().shiftTo(...units); + const unit = units.find((unit) => diff.get(unit) !== 0) || 'second'; + + const relativeFormatter = new Intl.RelativeTimeFormat('en', { + numeric: 'auto', + }); + return relativeFormatter.format(Math.trunc(diff.as(unit)), unit); + }; + + export let reactions: ActivityResponseDto[]; + export let user: UserResponseDto; + export let assetId: string; + export let albumId: string; + export let assetType: AssetTypeEnum; + export let albumOwnerId: string; + + let textArea: HTMLTextAreaElement; + let innerHeight: number; + let activityHeight: number; + let chatHeight: number; + let divHeight: number; + let previousAssetId: string | null; + let message = ''; + let isSendingMessage = false; + + const dispatch = createEventDispatcher(); + + $: showDeleteReaction = Array(reactions.length).fill(false); + $: { + if (innerHeight && activityHeight) { + divHeight = innerHeight - activityHeight; + } + } + + $: { + if (previousAssetId != assetId) { + getReactions(); + previousAssetId = assetId; + } + } + + const getReactions = async () => { + try { + const { data } = await api.activityApi.getActivities({ assetId, albumId }); + reactions = data; + } catch (error) { + handleError(error, 'Error when fetching reactions'); + } + }; + + const handleEnter = (event: KeyboardEvent) => { + if (event.key === 'Enter') { + event.preventDefault(); + handleSendComment(); + return; + } + }; + + const autoGrow = () => { + textArea.style.height = '5px'; + textArea.style.height = textArea.scrollHeight + 'px'; + }; + + const timeOptions = { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + hour12: false, + } as Intl.DateTimeFormatOptions; + + const handleDeleteReaction = async (reaction: ActivityResponseDto, index: number) => { + try { + await api.activityApi.deleteActivity({ id: reaction.id }); + reactions.splice(index, 1); + showDeleteReaction.splice(index, 1); + reactions = reactions; + if (reaction.type === 'like' && reaction.user.id === user.id) { + dispatch('deleteLike'); + } else { + dispatch('deleteComment'); + } + notificationController.show({ + message: `${reaction.type} deleted`, + type: NotificationType.Info, + }); + } catch (error) { + handleError(error, `Can't remove ${reaction.type}`); + } + }; + + const handleSendComment = async () => { + if (!message) { + return; + } + const timeout = setTimeout(() => (isSendingMessage = true), 100); + try { + const { data } = await api.activityApi.createActivity({ + activityCreateDto: { albumId, assetId, type: ReactionType.Comment, comment: message }, + }); + reactions.push(data); + textArea.style.height = '18px'; + message = ''; + dispatch('addComment'); + // Re-render the activity feed + reactions = reactions; + } catch (error) { + handleError(error, "Can't add your comment"); + } finally { + clearTimeout(timeout); + } + isSendingMessage = false; + }; + + const showOptionsMenu = (index: number) => { + showDeleteReaction[index] = !showDeleteReaction[index]; + }; + + +

+
+
+
+ + +

Activity

+
+
+ {#if innerHeight} +
+ {#each reactions as reaction, index (reaction.id)} + {#if reaction.type === 'comment'} +
+
+ +
+ +
{reaction.comment}
+ {#if reaction.user.id === user.id || albumOwnerId === user.id} +
+ +
+ {/if} +
+ {#if showDeleteReaction[index]} + + {/if} +
+
+ {#if (index != reactions.length - 1 && isTenMinutesApart(reactions[index].createdAt, reactions[index + 1].createdAt)) || index === reactions.length - 1} +
+ {timeSince(luxon.DateTime.fromISO(reaction.createdAt))} +
+ {/if} + {:else if reaction.type === 'like'} +
+
+
+ +
+ {`${reaction.user.firstName} ${reaction.user.lastName} liked this ${getAssetType( + assetType, + ).toLowerCase()}`} +
+ {#if reaction.user.id === user.id || albumOwnerId === user.id} +
+ +
+ {/if} +
+ {#if showDeleteReaction[index]} + + {/if} +
+
+ {#if (index != reactions.length - 1 && isTenMinutesApart(reactions[index].createdAt, reactions[index + 1].createdAt)) || index === reactions.length - 1} +
+ {timeSince(luxon.DateTime.fromISO(reaction.createdAt))} +
+ {/if} +
+ {/if} + {/each} +
+ {/if} +
+ +
+
+
+
+ +
+
handleSendComment()}> +
+