fix(server): OAuth quota size

This commit is contained in:
wuzihao051119 2025-05-23 23:26:52 +08:00
parent 2d7377a5e9
commit 3b88e3aeef
11 changed files with 28 additions and 20 deletions
i18n
mobile/openapi/lib/model
open-api
server/src
web/src/lib/components
admin-page/settings/auth
shared-components/settings

View file

@ -207,7 +207,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",
"offline_paths": "Offline Paths", "offline_paths": "Offline Paths",

View file

@ -18,7 +18,7 @@ class SystemConfigOAuthDto {
required this.buttonText, required this.buttonText,
required this.clientId, required this.clientId,
required this.clientSecret, required this.clientSecret,
required this.defaultStorageQuota, this.defaultStorageQuota,
required this.enabled, required this.enabled,
required this.issuerUrl, required this.issuerUrl,
required this.mobileOverrideEnabled, required this.mobileOverrideEnabled,
@ -43,7 +43,13 @@ class SystemConfigOAuthDto {
String clientSecret; String clientSecret;
/// Minimum value: 0 /// 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; bool enabled;
@ -96,7 +102,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 +125,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 +158,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')!,
@ -212,7 +222,6 @@ class SystemConfigOAuthDto {
'buttonText', 'buttonText',
'clientId', 'clientId',
'clientSecret', 'clientSecret',
'defaultStorageQuota',
'enabled', 'enabled',
'issuerUrl', 'issuerUrl',
'mobileOverrideEnabled', 'mobileOverrideEnabled',

View file

@ -13685,8 +13685,9 @@
"type": "string" "type": "string"
}, },
"defaultStorageQuota": { "defaultStorageQuota": {
"format": "int64",
"minimum": 0, "minimum": 0,
"type": "number" "type": "integer"
}, },
"enabled": { "enabled": {
"type": "boolean" "type": "boolean"
@ -13734,7 +13735,6 @@
"buttonText", "buttonText",
"clientId", "clientId",
"clientSecret", "clientSecret",
"defaultStorageQuota",
"enabled", "enabled",
"issuerUrl", "issuerUrl",
"mobileOverrideEnabled", "mobileOverrideEnabled",

View file

@ -1316,7 +1316,7 @@ export type SystemConfigOAuthDto = {
buttonText: string; buttonText: string;
clientId: string; clientId: string;
clientSecret: string; clientSecret: string;
defaultStorageQuota: number; defaultStorageQuota?: number;
enabled: boolean; enabled: boolean;
issuerUrl: string; issuerUrl: string;
mobileOverrideEnabled: boolean; mobileOverrideEnabled: boolean;

View file

@ -89,7 +89,7 @@ export interface SystemConfig {
buttonText: string; buttonText: string;
clientId: string; clientId: string;
clientSecret: string; clientSecret: string;
defaultStorageQuota: number; defaultStorageQuota?: number;
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: undefined,
enabled: false, enabled: false,
issuerUrl: '', issuerUrl: '',
mobileOverrideEnabled: false, mobileOverrideEnabled: false,

View file

@ -360,7 +360,9 @@ class SystemConfigOAuthDto {
@IsNumber() @IsNumber()
@Min(0) @Min(0)
defaultStorageQuota!: number; @Optional()
@ApiProperty({ type: 'integer', format: 'int64' })
defaultStorageQuota?: number;
@ValidateBoolean() @ValidateBoolean()
enabled!: boolean; enabled!: boolean;

View file

@ -702,7 +702,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);
@ -724,7 +724,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,
}); });
}); });

View file

@ -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 === undefined ? null : storageQuota * HumanReadableSize.GiB,
storageLabel: storageLabel || null, storageLabel: storageLabel || null,
}); });
} }

View file

@ -59,9 +59,6 @@ export const getKeysDeep = (target: unknown, path: string[] = []) => {
const properties: string[] = []; const properties: string[] = [];
for (const key of Object.keys(obj as object)) { for (const key of Object.keys(obj as object)) {
const value = obj[key as keyof object]; const value = obj[key as keyof object];
if (value === undefined) {
continue;
}
if (_.isObject(value) && !_.isArray(value) && !_.isDate(value)) { if (_.isObject(value) && !_.isArray(value) && !_.isDate(value)) {
properties.push(...getKeysDeep(value, [...path, key])); properties.push(...getKeysDeep(value, [...path, key]));

View file

@ -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)}
/> />

View file

@ -56,7 +56,7 @@
if (newValue > max) { if (newValue > max) {
newValue = max; newValue = max;
} }
value = newValue; value = value === '' ? undefined : newValue;
} }
}; };