diff --git a/i18n/en.json b/i18n/en.json index 9bfadc8e63..3267ac4007 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -207,7 +207,7 @@ "oauth_storage_quota_claim": "Storage quota claim", "oauth_storage_quota_claim_description": "Automatically set the user's storage quota to the value of this claim.", "oauth_storage_quota_default": "Default storage quota (GiB)", - "oauth_storage_quota_default_description": "Quota in GiB to be used when no claim is provided (Enter 0 for unlimited quota).", + "oauth_storage_quota_default_description": "Quota in GiB to be used when no claim is provided.", "oauth_timeout": "Request Timeout", "oauth_timeout_description": "Timeout for requests in milliseconds", "offline_paths": "Offline Paths", diff --git a/mobile/openapi/lib/model/system_config_o_auth_dto.dart b/mobile/openapi/lib/model/system_config_o_auth_dto.dart index 24384a47b1..05f75a4642 100644 --- a/mobile/openapi/lib/model/system_config_o_auth_dto.dart +++ b/mobile/openapi/lib/model/system_config_o_auth_dto.dart @@ -18,7 +18,7 @@ class SystemConfigOAuthDto { required this.buttonText, required this.clientId, required this.clientSecret, - required this.defaultStorageQuota, + this.defaultStorageQuota, required this.enabled, required this.issuerUrl, required this.mobileOverrideEnabled, @@ -43,7 +43,13 @@ class SystemConfigOAuthDto { String clientSecret; /// Minimum value: 0 - num defaultStorageQuota; + /// + /// 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. + /// + int? defaultStorageQuota; bool enabled; @@ -96,7 +102,7 @@ class SystemConfigOAuthDto { (buttonText.hashCode) + (clientId.hashCode) + (clientSecret.hashCode) + - (defaultStorageQuota.hashCode) + + (defaultStorageQuota == null ? 0 : defaultStorageQuota!.hashCode) + (enabled.hashCode) + (issuerUrl.hashCode) + (mobileOverrideEnabled.hashCode) + @@ -119,7 +125,11 @@ class SystemConfigOAuthDto { json[r'buttonText'] = this.buttonText; json[r'clientId'] = this.clientId; json[r'clientSecret'] = this.clientSecret; + if (this.defaultStorageQuota != null) { json[r'defaultStorageQuota'] = this.defaultStorageQuota; + } else { + // json[r'defaultStorageQuota'] = null; + } json[r'enabled'] = this.enabled; json[r'issuerUrl'] = this.issuerUrl; json[r'mobileOverrideEnabled'] = this.mobileOverrideEnabled; @@ -148,7 +158,7 @@ class SystemConfigOAuthDto { buttonText: mapValueOfType<String>(json, r'buttonText')!, clientId: mapValueOfType<String>(json, r'clientId')!, clientSecret: mapValueOfType<String>(json, r'clientSecret')!, - defaultStorageQuota: num.parse('${json[r'defaultStorageQuota']}'), + defaultStorageQuota: mapValueOfType<int>(json, r'defaultStorageQuota'), enabled: mapValueOfType<bool>(json, r'enabled')!, issuerUrl: mapValueOfType<String>(json, r'issuerUrl')!, mobileOverrideEnabled: mapValueOfType<bool>(json, r'mobileOverrideEnabled')!, @@ -212,7 +222,6 @@ class SystemConfigOAuthDto { 'buttonText', 'clientId', 'clientSecret', - 'defaultStorageQuota', 'enabled', 'issuerUrl', 'mobileOverrideEnabled', diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index 1d6bd3b048..fae29fc095 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -13685,8 +13685,9 @@ "type": "string" }, "defaultStorageQuota": { + "format": "int64", "minimum": 0, - "type": "number" + "type": "integer" }, "enabled": { "type": "boolean" @@ -13734,7 +13735,6 @@ "buttonText", "clientId", "clientSecret", - "defaultStorageQuota", "enabled", "issuerUrl", "mobileOverrideEnabled", diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index 361d5d0b09..1782e8445f 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -1316,7 +1316,7 @@ export type SystemConfigOAuthDto = { buttonText: string; clientId: string; clientSecret: string; - defaultStorageQuota: number; + defaultStorageQuota?: number; enabled: boolean; issuerUrl: string; mobileOverrideEnabled: boolean; diff --git a/server/src/config.ts b/server/src/config.ts index a9fdffbd62..15745eda3e 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -89,7 +89,7 @@ export interface SystemConfig { buttonText: string; clientId: string; clientSecret: string; - defaultStorageQuota: number; + defaultStorageQuota?: number; enabled: boolean; issuerUrl: string; mobileOverrideEnabled: boolean; @@ -253,7 +253,7 @@ export const defaults = Object.freeze<SystemConfig>({ buttonText: 'Login with OAuth', clientId: '', clientSecret: '', - defaultStorageQuota: 0, + defaultStorageQuota: undefined, enabled: false, issuerUrl: '', mobileOverrideEnabled: false, diff --git a/server/src/dtos/system-config.dto.ts b/server/src/dtos/system-config.dto.ts index 6991baf109..0ae3866082 100644 --- a/server/src/dtos/system-config.dto.ts +++ b/server/src/dtos/system-config.dto.ts @@ -360,7 +360,9 @@ class SystemConfigOAuthDto { @IsNumber() @Min(0) - defaultStorageQuota!: number; + @Optional() + @ApiProperty({ type: 'integer', format: 'int64' }) + defaultStorageQuota?: number; @ValidateBoolean() enabled!: boolean; diff --git a/server/src/services/auth.service.spec.ts b/server/src/services/auth.service.spec.ts index 4bc5f1ce0b..ed757e71b7 100644 --- a/server/src/services/auth.service.spec.ts +++ b/server/src/services/auth.service.spec.ts @@ -702,7 +702,7 @@ describe(AuthService.name, () => { expect(mocks.user.create).toHaveBeenCalledWith(expect.objectContaining({ quotaSizeInBytes: 1_073_741_824 })); }); - it('should not set quota for 0 quota', async () => { + it('should set quota for 0 quota', async () => { const user = factory.userAdmin({ oauthId: 'oauth-id' }); mocks.systemMetadata.get.mockResolvedValue(systemConfigStub.oauthWithStorageQuota); @@ -724,7 +724,7 @@ describe(AuthService.name, () => { email: user.email, name: ' ', oauthId: user.oauthId, - quotaSizeInBytes: null, + quotaSizeInBytes: 0, storageLabel: null, }); }); diff --git a/server/src/services/auth.service.ts b/server/src/services/auth.service.ts index e6c541a624..e5aee54117 100644 --- a/server/src/services/auth.service.ts +++ b/server/src/services/auth.service.ts @@ -300,7 +300,7 @@ export class AuthService extends BaseService { name: userName, email: profile.email, oauthId: profile.sub, - quotaSizeInBytes: storageQuota * HumanReadableSize.GiB || null, + quotaSizeInBytes: storageQuota === undefined ? null : storageQuota * HumanReadableSize.GiB, storageLabel: storageLabel || null, }); } diff --git a/server/src/utils/misc.ts b/server/src/utils/misc.ts index 05811350e4..da9e227f23 100644 --- a/server/src/utils/misc.ts +++ b/server/src/utils/misc.ts @@ -59,9 +59,6 @@ export const getKeysDeep = (target: unknown, path: string[] = []) => { const properties: string[] = []; for (const key of Object.keys(obj as object)) { const value = obj[key as keyof object]; - if (value === undefined) { - continue; - } if (_.isObject(value) && !_.isArray(value) && !_.isDate(value)) { properties.push(...getKeysDeep(value, [...path, key])); diff --git a/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte b/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte index d7af26688a..9f0021d59c 100644 --- a/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte +++ b/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte @@ -182,7 +182,7 @@ label={$t('admin.oauth_storage_quota_default').toUpperCase()} description={$t('admin.oauth_storage_quota_default_description')} bind:value={config.oauth.defaultStorageQuota} - required={true} + required={false} disabled={disabled || !config.oauth.enabled} isEdited={!(config.oauth.defaultStorageQuota == savedConfig.oauth.defaultStorageQuota)} /> diff --git a/web/src/lib/components/shared-components/settings/setting-input-field.svelte b/web/src/lib/components/shared-components/settings/setting-input-field.svelte index 2cab6e95eb..6633086566 100644 --- a/web/src/lib/components/shared-components/settings/setting-input-field.svelte +++ b/web/src/lib/components/shared-components/settings/setting-input-field.svelte @@ -56,7 +56,7 @@ if (newValue > max) { newValue = max; } - value = newValue; + value = value === '' ? undefined : newValue; } };