mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 20:07:41 +09:00 
			
		
		
		
	fix(web): OAuth quota size (#18526)
	
		
			
	
		
	
	
		
	
		
			Some checks are pending
		
		
	
	
		
			
				
	
				CodeQL / Analyze (javascript) (push) Waiting to run
				
			
		
			
				
	
				CodeQL / Analyze (python) (push) Waiting to run
				
			
		
			
				
	
				Docker / pre-job (push) Waiting to run
				
			
		
			
				
	
				Docker / Re-Tag ML () (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Re-Tag ML (-armnn) (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Re-Tag ML (-cuda) (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Re-Tag ML (-openvino) (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Re-Tag ML (-rknn) (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Re-Tag ML (-rocm) (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Re-Tag Server () (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Build and Push ML (armnn, linux/arm64, -armnn) (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Build and Push ML (cpu, ) (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Build and Push ML (cuda, linux/amd64, -cuda) (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Build and Push ML (openvino, linux/amd64, -openvino) (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Build and Push ML (rknn, linux/arm64, -rknn) (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Build and Push ML (rocm, linux/amd64, {"linux/amd64": "mich"}, -rocm) (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Build and Push Server (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Docker Build & Push Server Success (push) Blocked by required conditions
				
			
		
			
				
	
				Docker / Docker Build & Push ML Success (push) Blocked by required conditions
				
			
		
			
				
	
				Docs build / pre-job (push) Waiting to run
				
			
		
			
				
	
				Docs build / Docs Build (push) Blocked by required conditions
				
			
		
			
				
	
				Static Code Analysis / pre-job (push) Waiting to run
				
			
		
			
				
	
				Static Code Analysis / Run Dart Code Analysis (push) Blocked by required conditions
				
			
		
			
				
	
				Static Code Analysis / zizmor (push) Waiting to run
				
			
		
			
				
	
				Test / pre-job (push) Waiting to run
				
			
		
			
				
	
				Test / Test & Lint Server (push) Blocked by required conditions
				
			
		
			
				
	
				Test / Unit Test CLI (push) Blocked by required conditions
				
			
		
			
				
	
				Test / Unit Test CLI (Windows) (push) Blocked by required conditions
				
			
		
			
				
	
				Test / Lint Web (push) Blocked by required conditions
				
			
		
			
				
	
				Test / Test Web (push) Blocked by required conditions
				
			
		
			
				
	
				Test / Test i18n (push) Blocked by required conditions
				
			
		
			
				
	
				Test / End-to-End Lint (push) Blocked by required conditions
				
			
		
			
				
	
				Test / Medium Tests (Server) (push) Blocked by required conditions
				
			
		
			
				
	
				Test / End-to-End Tests (Server & CLI) (ubuntu-24.04-arm) (push) Blocked by required conditions
				
			
		
			
				
	
				Test / End-to-End Tests (Server & CLI) (ubuntu-latest) (push) Blocked by required conditions
				
			
		
			
				
	
				Test / End-to-End Tests (Web) (ubuntu-24.04-arm) (push) Blocked by required conditions
				
			
		
			
				
	
				Test / End-to-End Tests (Web) (ubuntu-latest) (push) Blocked by required conditions
				
			
		
			
				
	
				Test / End-to-End Tests Success (push) Blocked by required conditions
				
			
		
			
				
	
				Test / Unit Test Mobile (push) Blocked by required conditions
				
			
		
			
				
	
				Test / Unit Test ML (push) Blocked by required conditions
				
			
		
			
				
	
				Test / .github Files Formatting (push) Blocked by required conditions
				
			
		
			
				
	
				Test / ShellCheck (push) Waiting to run
				
			
		
			
				
	
				Test / OpenAPI Clients (push) Waiting to run
				
			
		
			
				
	
				Test / SQL Schema Checks (push) Waiting to run
				
			
		
		
	
	
				
					
				
			
		
			Some checks are pending
		
		
	
	CodeQL / Analyze (javascript) (push) Waiting to run
				
			CodeQL / Analyze (python) (push) Waiting to run
				
			Docker / pre-job (push) Waiting to run
				
			Docker / Re-Tag ML () (push) Blocked by required conditions
				
			Docker / Re-Tag ML (-armnn) (push) Blocked by required conditions
				
			Docker / Re-Tag ML (-cuda) (push) Blocked by required conditions
				
			Docker / Re-Tag ML (-openvino) (push) Blocked by required conditions
				
			Docker / Re-Tag ML (-rknn) (push) Blocked by required conditions
				
			Docker / Re-Tag ML (-rocm) (push) Blocked by required conditions
				
			Docker / Re-Tag Server () (push) Blocked by required conditions
				
			Docker / Build and Push ML (armnn, linux/arm64, -armnn) (push) Blocked by required conditions
				
			Docker / Build and Push ML (cpu, ) (push) Blocked by required conditions
				
			Docker / Build and Push ML (cuda, linux/amd64, -cuda) (push) Blocked by required conditions
				
			Docker / Build and Push ML (openvino, linux/amd64, -openvino) (push) Blocked by required conditions
				
			Docker / Build and Push ML (rknn, linux/arm64, -rknn) (push) Blocked by required conditions
				
			Docker / Build and Push ML (rocm, linux/amd64, {"linux/amd64": "mich"}, -rocm) (push) Blocked by required conditions
				
			Docker / Build and Push Server (push) Blocked by required conditions
				
			Docker / Docker Build & Push Server Success (push) Blocked by required conditions
				
			Docker / Docker Build & Push ML Success (push) Blocked by required conditions
				
			Docs build / pre-job (push) Waiting to run
				
			Docs build / Docs Build (push) Blocked by required conditions
				
			Static Code Analysis / pre-job (push) Waiting to run
				
			Static Code Analysis / Run Dart Code Analysis (push) Blocked by required conditions
				
			Static Code Analysis / zizmor (push) Waiting to run
				
			Test / pre-job (push) Waiting to run
				
			Test / Test & Lint Server (push) Blocked by required conditions
				
			Test / Unit Test CLI (push) Blocked by required conditions
				
			Test / Unit Test CLI (Windows) (push) Blocked by required conditions
				
			Test / Lint Web (push) Blocked by required conditions
				
			Test / Test Web (push) Blocked by required conditions
				
			Test / Test i18n (push) Blocked by required conditions
				
			Test / End-to-End Lint (push) Blocked by required conditions
				
			Test / Medium Tests (Server) (push) Blocked by required conditions
				
			Test / End-to-End Tests (Server & CLI) (ubuntu-24.04-arm) (push) Blocked by required conditions
				
			Test / End-to-End Tests (Server & CLI) (ubuntu-latest) (push) Blocked by required conditions
				
			Test / End-to-End Tests (Web) (ubuntu-24.04-arm) (push) Blocked by required conditions
				
			Test / End-to-End Tests (Web) (ubuntu-latest) (push) Blocked by required conditions
				
			Test / End-to-End Tests Success (push) Blocked by required conditions
				
			Test / Unit Test Mobile (push) Blocked by required conditions
				
			Test / Unit Test ML (push) Blocked by required conditions
				
			Test / .github Files Formatting (push) Blocked by required conditions
				
			Test / ShellCheck (push) Waiting to run
				
			Test / OpenAPI Clients (push) Waiting to run
				
			Test / SQL Schema Checks (push) Waiting to run
				
			fix(server): oauth quota size
This commit is contained in:
		| @@ -123,7 +123,7 @@ The default configuration looks like this: | |||||||
|     "buttonText": "Login with OAuth", |     "buttonText": "Login with OAuth", | ||||||
|     "clientId": "", |     "clientId": "", | ||||||
|     "clientSecret": "", |     "clientSecret": "", | ||||||
|     "defaultStorageQuota": 0, |     "defaultStorageQuota": null, | ||||||
|     "enabled": false, |     "enabled": false, | ||||||
|     "issuerUrl": "", |     "issuerUrl": "", | ||||||
|     "mobileOverrideEnabled": false, |     "mobileOverrideEnabled": false, | ||||||
|   | |||||||
| @@ -204,7 +204,7 @@ | |||||||
|     "oauth_storage_quota_claim": "Storage quota claim", |     "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_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": "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": "Request Timeout", | ||||||
|     "oauth_timeout_description": "Timeout for requests in milliseconds", |     "oauth_timeout_description": "Timeout for requests in milliseconds", | ||||||
|     "password_enable_description": "Login with email and password", |     "password_enable_description": "Login with email and password", | ||||||
|   | |||||||
| @@ -43,7 +43,7 @@ class SystemConfigOAuthDto { | |||||||
|   String clientSecret; |   String clientSecret; | ||||||
| 
 | 
 | ||||||
|   /// Minimum value: 0 |   /// Minimum value: 0 | ||||||
|   num defaultStorageQuota; |   int? defaultStorageQuota; | ||||||
| 
 | 
 | ||||||
|   bool enabled; |   bool enabled; | ||||||
| 
 | 
 | ||||||
| @@ -96,7 +96,7 @@ class SystemConfigOAuthDto { | |||||||
|     (buttonText.hashCode) + |     (buttonText.hashCode) + | ||||||
|     (clientId.hashCode) + |     (clientId.hashCode) + | ||||||
|     (clientSecret.hashCode) + |     (clientSecret.hashCode) + | ||||||
|     (defaultStorageQuota.hashCode) + |     (defaultStorageQuota == null ? 0 : defaultStorageQuota!.hashCode) + | ||||||
|     (enabled.hashCode) + |     (enabled.hashCode) + | ||||||
|     (issuerUrl.hashCode) + |     (issuerUrl.hashCode) + | ||||||
|     (mobileOverrideEnabled.hashCode) + |     (mobileOverrideEnabled.hashCode) + | ||||||
| @@ -119,7 +119,11 @@ class SystemConfigOAuthDto { | |||||||
|       json[r'buttonText'] = this.buttonText; |       json[r'buttonText'] = this.buttonText; | ||||||
|       json[r'clientId'] = this.clientId; |       json[r'clientId'] = this.clientId; | ||||||
|       json[r'clientSecret'] = this.clientSecret; |       json[r'clientSecret'] = this.clientSecret; | ||||||
|  |     if (this.defaultStorageQuota != null) { | ||||||
|       json[r'defaultStorageQuota'] = this.defaultStorageQuota; |       json[r'defaultStorageQuota'] = this.defaultStorageQuota; | ||||||
|  |     } else { | ||||||
|  |     //  json[r'defaultStorageQuota'] = null; | ||||||
|  |     } | ||||||
|       json[r'enabled'] = this.enabled; |       json[r'enabled'] = this.enabled; | ||||||
|       json[r'issuerUrl'] = this.issuerUrl; |       json[r'issuerUrl'] = this.issuerUrl; | ||||||
|       json[r'mobileOverrideEnabled'] = this.mobileOverrideEnabled; |       json[r'mobileOverrideEnabled'] = this.mobileOverrideEnabled; | ||||||
| @@ -148,7 +152,7 @@ class SystemConfigOAuthDto { | |||||||
|         buttonText: mapValueOfType<String>(json, r'buttonText')!, |         buttonText: mapValueOfType<String>(json, r'buttonText')!, | ||||||
|         clientId: mapValueOfType<String>(json, r'clientId')!, |         clientId: mapValueOfType<String>(json, r'clientId')!, | ||||||
|         clientSecret: mapValueOfType<String>(json, r'clientSecret')!, |         clientSecret: mapValueOfType<String>(json, r'clientSecret')!, | ||||||
|         defaultStorageQuota: num.parse('${json[r'defaultStorageQuota']}'), |         defaultStorageQuota: mapValueOfType<int>(json, r'defaultStorageQuota'), | ||||||
|         enabled: mapValueOfType<bool>(json, r'enabled')!, |         enabled: mapValueOfType<bool>(json, r'enabled')!, | ||||||
|         issuerUrl: mapValueOfType<String>(json, r'issuerUrl')!, |         issuerUrl: mapValueOfType<String>(json, r'issuerUrl')!, | ||||||
|         mobileOverrideEnabled: mapValueOfType<bool>(json, r'mobileOverrideEnabled')!, |         mobileOverrideEnabled: mapValueOfType<bool>(json, r'mobileOverrideEnabled')!, | ||||||
|   | |||||||
| @@ -14344,8 +14344,10 @@ | |||||||
|             "type": "string" |             "type": "string" | ||||||
|           }, |           }, | ||||||
|           "defaultStorageQuota": { |           "defaultStorageQuota": { | ||||||
|  |             "format": "int64", | ||||||
|             "minimum": 0, |             "minimum": 0, | ||||||
|             "type": "number" |             "nullable": true, | ||||||
|  |             "type": "integer" | ||||||
|           }, |           }, | ||||||
|           "enabled": { |           "enabled": { | ||||||
|             "type": "boolean" |             "type": "boolean" | ||||||
|   | |||||||
| @@ -1392,7 +1392,7 @@ export type SystemConfigOAuthDto = { | |||||||
|     buttonText: string; |     buttonText: string; | ||||||
|     clientId: string; |     clientId: string; | ||||||
|     clientSecret: string; |     clientSecret: string; | ||||||
|     defaultStorageQuota: number; |     defaultStorageQuota: number | null; | ||||||
|     enabled: boolean; |     enabled: boolean; | ||||||
|     issuerUrl: string; |     issuerUrl: string; | ||||||
|     mobileOverrideEnabled: boolean; |     mobileOverrideEnabled: boolean; | ||||||
|   | |||||||
| @@ -89,7 +89,7 @@ export interface SystemConfig { | |||||||
|     buttonText: string; |     buttonText: string; | ||||||
|     clientId: string; |     clientId: string; | ||||||
|     clientSecret: string; |     clientSecret: string; | ||||||
|     defaultStorageQuota: number; |     defaultStorageQuota: number | null; | ||||||
|     enabled: boolean; |     enabled: boolean; | ||||||
|     issuerUrl: string; |     issuerUrl: string; | ||||||
|     mobileOverrideEnabled: boolean; |     mobileOverrideEnabled: boolean; | ||||||
| @@ -253,7 +253,7 @@ export const defaults = Object.freeze<SystemConfig>({ | |||||||
|     buttonText: 'Login with OAuth', |     buttonText: 'Login with OAuth', | ||||||
|     clientId: '', |     clientId: '', | ||||||
|     clientSecret: '', |     clientSecret: '', | ||||||
|     defaultStorageQuota: 0, |     defaultStorageQuota: null, | ||||||
|     enabled: false, |     enabled: false, | ||||||
|     issuerUrl: '', |     issuerUrl: '', | ||||||
|     mobileOverrideEnabled: false, |     mobileOverrideEnabled: false, | ||||||
|   | |||||||
| @@ -360,7 +360,9 @@ class SystemConfigOAuthDto { | |||||||
|  |  | ||||||
|   @IsNumber() |   @IsNumber() | ||||||
|   @Min(0) |   @Min(0) | ||||||
|   defaultStorageQuota!: number; |   @Optional({ nullable: true }) | ||||||
|  |   @ApiProperty({ type: 'integer', format: 'int64' }) | ||||||
|  |   defaultStorageQuota!: number | null; | ||||||
|  |  | ||||||
|   @ValidateBoolean() |   @ValidateBoolean() | ||||||
|   enabled!: boolean; |   enabled!: boolean; | ||||||
|   | |||||||
| @@ -704,7 +704,7 @@ describe(AuthService.name, () => { | |||||||
|       expect(mocks.user.create).toHaveBeenCalledWith(expect.objectContaining({ quotaSizeInBytes: 1_073_741_824 })); |       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' }); |       const user = factory.userAdmin({ oauthId: 'oauth-id' }); | ||||||
|  |  | ||||||
|       mocks.systemMetadata.get.mockResolvedValue(systemConfigStub.oauthWithStorageQuota); |       mocks.systemMetadata.get.mockResolvedValue(systemConfigStub.oauthWithStorageQuota); | ||||||
| @@ -726,7 +726,7 @@ describe(AuthService.name, () => { | |||||||
|         email: user.email, |         email: user.email, | ||||||
|         name: ' ', |         name: ' ', | ||||||
|         oauthId: user.oauthId, |         oauthId: user.oauthId, | ||||||
|         quotaSizeInBytes: null, |         quotaSizeInBytes: 0, | ||||||
|         storageLabel: null, |         storageLabel: null, | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
|   | |||||||
| @@ -300,7 +300,7 @@ export class AuthService extends BaseService { | |||||||
|         name: userName, |         name: userName, | ||||||
|         email: profile.email, |         email: profile.email, | ||||||
|         oauthId: profile.sub, |         oauthId: profile.sub, | ||||||
|         quotaSizeInBytes: storageQuota * HumanReadableSize.GiB || null, |         quotaSizeInBytes: storageQuota === null ? null : storageQuota * HumanReadableSize.GiB, | ||||||
|         storageLabel: storageLabel || null, |         storageLabel: storageLabel || null, | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -112,7 +112,7 @@ const updatedConfig = Object.freeze<SystemConfig>({ | |||||||
|     buttonText: 'Login with OAuth', |     buttonText: 'Login with OAuth', | ||||||
|     clientId: '', |     clientId: '', | ||||||
|     clientSecret: '', |     clientSecret: '', | ||||||
|     defaultStorageQuota: 0, |     defaultStorageQuota: null, | ||||||
|     enabled: false, |     enabled: false, | ||||||
|     issuerUrl: '', |     issuerUrl: '', | ||||||
|     mobileOverrideEnabled: false, |     mobileOverrideEnabled: false, | ||||||
|   | |||||||
| @@ -182,7 +182,7 @@ | |||||||
|                 label={$t('admin.oauth_storage_quota_default').toUpperCase()} |                 label={$t('admin.oauth_storage_quota_default').toUpperCase()} | ||||||
|                 description={$t('admin.oauth_storage_quota_default_description')} |                 description={$t('admin.oauth_storage_quota_default_description')} | ||||||
|                 bind:value={config.oauth.defaultStorageQuota} |                 bind:value={config.oauth.defaultStorageQuota} | ||||||
|                 required={true} |                 required={false} | ||||||
|                 disabled={disabled || !config.oauth.enabled} |                 disabled={disabled || !config.oauth.enabled} | ||||||
|                 isEdited={!(config.oauth.defaultStorageQuota == savedConfig.oauth.defaultStorageQuota)} |                 isEdited={!(config.oauth.defaultStorageQuota == savedConfig.oauth.defaultStorageQuota)} | ||||||
|               /> |               /> | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ | |||||||
|  |  | ||||||
|   interface Props { |   interface Props { | ||||||
|     inputType: SettingInputFieldType; |     inputType: SettingInputFieldType; | ||||||
|     value: string | number | undefined; |     value: string | number | undefined | null; | ||||||
|     min?: number; |     min?: number; | ||||||
|     max?: number; |     max?: number; | ||||||
|     step?: string; |     step?: string; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user