fix(server): use UserMetadataKey enum instead of string (#20209)

* fix(server): use UserMetadataKey enum instead of string

* fix: mobile
This commit is contained in:
Daimolean 2025-07-25 23:04:28 +08:00 committed by GitHub
parent ed5759fe07
commit 25e2d37490
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 129 additions and 15 deletions

View File

@ -20,8 +20,8 @@ import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart';
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
import 'package:logging/logging.dart';
import 'package:openapi/api.dart' as api show AssetVisibility, AlbumUserRole;
import 'package:openapi/api.dart' hide AssetVisibility, AlbumUserRole;
import 'package:openapi/api.dart' as api show AssetVisibility, AlbumUserRole, UserMetadataKey;
import 'package:openapi/api.dart' hide AssetVisibility, AlbumUserRole, UserMetadataKey;
class SyncStreamRepository extends DriftDatabaseRepository {
final Logger _logger = Logger('DriftSyncStreamRepository');
@ -647,11 +647,11 @@ extension on api.AssetVisibility {
};
}
extension on String {
extension on api.UserMetadataKey {
UserMetadataKey toUserMetadataKey() => switch (this) {
"onboarding" => UserMetadataKey.onboarding,
"preferences" => UserMetadataKey.preferences,
"license" => UserMetadataKey.license,
api.UserMetadataKey.onboarding => UserMetadataKey.onboarding,
api.UserMetadataKey.preferences => UserMetadataKey.preferences,
api.UserMetadataKey.license => UserMetadataKey.license,
_ => throw Exception('Unknown UserMetadataKey value: $this'),
};
}

View File

@ -557,6 +557,7 @@ Class | Method | HTTP request | Description
- [UserAdminUpdateDto](doc//UserAdminUpdateDto.md)
- [UserAvatarColor](doc//UserAvatarColor.md)
- [UserLicense](doc//UserLicense.md)
- [UserMetadataKey](doc//UserMetadataKey.md)
- [UserPreferencesResponseDto](doc//UserPreferencesResponseDto.md)
- [UserPreferencesUpdateDto](doc//UserPreferencesUpdateDto.md)
- [UserResponseDto](doc//UserResponseDto.md)

View File

@ -338,6 +338,7 @@ part 'model/user_admin_response_dto.dart';
part 'model/user_admin_update_dto.dart';
part 'model/user_avatar_color.dart';
part 'model/user_license.dart';
part 'model/user_metadata_key.dart';
part 'model/user_preferences_response_dto.dart';
part 'model/user_preferences_update_dto.dart';
part 'model/user_response_dto.dart';

View File

@ -732,6 +732,8 @@ class ApiClient {
return UserAvatarColorTypeTransformer().decode(value);
case 'UserLicense':
return UserLicense.fromJson(value);
case 'UserMetadataKey':
return UserMetadataKeyTypeTransformer().decode(value);
case 'UserPreferencesResponseDto':
return UserPreferencesResponseDto.fromJson(value);
case 'UserPreferencesUpdateDto':

View File

@ -151,6 +151,9 @@ String parameterToString(dynamic value) {
if (value is UserAvatarColor) {
return UserAvatarColorTypeTransformer().encode(value).toString();
}
if (value is UserMetadataKey) {
return UserMetadataKeyTypeTransformer().encode(value).toString();
}
if (value is UserStatus) {
return UserStatusTypeTransformer().encode(value).toString();
}

View File

@ -17,7 +17,7 @@ class SyncUserMetadataDeleteV1 {
required this.userId,
});
String key;
UserMetadataKey key;
String userId;
@ -51,7 +51,7 @@ class SyncUserMetadataDeleteV1 {
final json = value.cast<String, dynamic>();
return SyncUserMetadataDeleteV1(
key: mapValueOfType<String>(json, r'key')!,
key: UserMetadataKey.fromJson(json[r'key'])!,
userId: mapValueOfType<String>(json, r'userId')!,
);
}

View File

@ -18,7 +18,7 @@ class SyncUserMetadataV1 {
required this.value,
});
String key;
UserMetadataKey key;
String userId;
@ -57,7 +57,7 @@ class SyncUserMetadataV1 {
final json = value.cast<String, dynamic>();
return SyncUserMetadataV1(
key: mapValueOfType<String>(json, r'key')!,
key: UserMetadataKey.fromJson(json[r'key'])!,
userId: mapValueOfType<String>(json, r'userId')!,
value: mapValueOfType<Object>(json, r'value')!,
);

View File

@ -0,0 +1,88 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// 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 UserMetadataKey {
/// Instantiate a new enum with the provided [value].
const UserMetadataKey._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const preferences = UserMetadataKey._(r'preferences');
static const license = UserMetadataKey._(r'license');
static const onboarding = UserMetadataKey._(r'onboarding');
/// List of all possible values in this [enum][UserMetadataKey].
static const values = <UserMetadataKey>[
preferences,
license,
onboarding,
];
static UserMetadataKey? fromJson(dynamic value) => UserMetadataKeyTypeTransformer().decode(value);
static List<UserMetadataKey> listFromJson(dynamic json, {bool growable = false,}) {
final result = <UserMetadataKey>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = UserMetadataKey.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [UserMetadataKey] to String,
/// and [decode] dynamic data back to [UserMetadataKey].
class UserMetadataKeyTypeTransformer {
factory UserMetadataKeyTypeTransformer() => _instance ??= const UserMetadataKeyTypeTransformer._();
const UserMetadataKeyTypeTransformer._();
String encode(UserMetadataKey data) => data.value;
/// Decodes a [dynamic value][data] to a UserMetadataKey.
///
/// 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.
UserMetadataKey? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'preferences': return UserMetadataKey.preferences;
case r'license': return UserMetadataKey.license;
case r'onboarding': return UserMetadataKey.onboarding;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [UserMetadataKeyTypeTransformer] instance.
static UserMetadataKeyTypeTransformer? _instance;
}

View File

@ -14403,7 +14403,11 @@
"SyncUserMetadataDeleteV1": {
"properties": {
"key": {
"type": "string"
"allOf": [
{
"$ref": "#/components/schemas/UserMetadataKey"
}
]
},
"userId": {
"type": "string"
@ -14418,7 +14422,11 @@
"SyncUserMetadataV1": {
"properties": {
"key": {
"type": "string"
"allOf": [
{
"$ref": "#/components/schemas/UserMetadataKey"
}
]
},
"userId": {
"type": "string"
@ -16132,6 +16140,14 @@
],
"type": "object"
},
"UserMetadataKey": {
"enum": [
"preferences",
"license",
"onboarding"
],
"type": "string"
},
"UserPreferencesResponseDto": {
"properties": {
"albums": {

View File

@ -301,14 +301,16 @@ export class SyncAssetFaceDeleteV1 {
@ExtraModel()
export class SyncUserMetadataV1 {
userId!: string;
key!: string;
@ValidateEnum({ enum: UserMetadataKey, name: 'UserMetadataKey' })
key!: UserMetadataKey;
value!: UserMetadata[UserMetadataKey];
}
@ExtraModel()
export class SyncUserMetadataDeleteV1 {
userId!: string;
key!: string;
@ValidateEnum({ enum: UserMetadataKey, name: 'UserMetadataKey' })
key!: UserMetadataKey;
}
@ExtraModel()

View File

@ -1,4 +1,5 @@
import { PrimaryGeneratedUuidV7Column } from 'src/decorators';
import { UserMetadataKey } from 'src/enum';
import { Column, CreateDateColumn, Generated, Table, Timestamp } from 'src/sql-tools';
@Table('user_metadata_audit')
@ -10,7 +11,7 @@ export class UserMetadataAuditTable {
userId!: string;
@Column({ indexName: 'IDX_user_metadata_audit_key' })
key!: string;
key!: UserMetadataKey;
@CreateDateColumn({ default: () => 'clock_timestamp()', indexName: 'IDX_user_metadata_audit_deleted_at' })
deletedAt!: Generated<Timestamp>;