mirror of
https://github.com/immich-app/immich.git
synced 2025-05-24 01:12:58 -04:00
refactor: user avatar color (#17753)
This commit is contained in:
parent
460d594791
commit
ad272333db
@ -215,6 +215,19 @@ describe('/admin/users', () => {
|
|||||||
const user = await getMyUser({ headers: asBearerAuth(token.accessToken) });
|
const user = await getMyUser({ headers: asBearerAuth(token.accessToken) });
|
||||||
expect(user).toMatchObject({ email: nonAdmin.userEmail });
|
expect(user).toMatchObject({ email: nonAdmin.userEmail });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should update the avatar color', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put(`/admin/users/${admin.userId}`)
|
||||||
|
.send({ avatarColor: 'orange' })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toMatchObject({ avatarColor: 'orange' });
|
||||||
|
|
||||||
|
const after = await getUserAdmin({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
|
||||||
|
expect(after).toMatchObject({ avatarColor: 'orange' });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('PUT /admin/users/:id/preferences', () => {
|
describe('PUT /admin/users/:id/preferences', () => {
|
||||||
@ -240,19 +253,6 @@ describe('/admin/users', () => {
|
|||||||
expect(after).toMatchObject({ memories: { enabled: false } });
|
expect(after).toMatchObject({ memories: { enabled: false } });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update the avatar color', async () => {
|
|
||||||
const { status, body } = await request(app)
|
|
||||||
.put(`/admin/users/${admin.userId}/preferences`)
|
|
||||||
.send({ avatar: { color: 'orange' } })
|
|
||||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
|
||||||
|
|
||||||
expect(status).toBe(200);
|
|
||||||
expect(body).toMatchObject({ avatar: { color: 'orange' } });
|
|
||||||
|
|
||||||
const after = await getUserPreferencesAdmin({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
|
|
||||||
expect(after).toMatchObject({ avatar: { color: 'orange' } });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update download archive size', async () => {
|
it('should update download archive size', async () => {
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.put(`/admin/users/${admin.userId}/preferences`)
|
.put(`/admin/users/${admin.userId}/preferences`)
|
||||||
|
@ -139,6 +139,19 @@ describe('/users', () => {
|
|||||||
profileChangedAt: expect.anything(),
|
profileChangedAt: expect.anything(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should update avatar color', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put(`/users/me`)
|
||||||
|
.send({ avatarColor: 'blue' })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toMatchObject({ avatarColor: 'blue' });
|
||||||
|
|
||||||
|
const after = await getMyUser({ headers: asBearerAuth(admin.accessToken) });
|
||||||
|
expect(after).toMatchObject({ avatarColor: 'blue' });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('PUT /users/me/preferences', () => {
|
describe('PUT /users/me/preferences', () => {
|
||||||
@ -158,19 +171,6 @@ describe('/users', () => {
|
|||||||
expect(after).toMatchObject({ memories: { enabled: false } });
|
expect(after).toMatchObject({ memories: { enabled: false } });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update avatar color', async () => {
|
|
||||||
const { status, body } = await request(app)
|
|
||||||
.put(`/users/me/preferences`)
|
|
||||||
.send({ avatar: { color: 'blue' } })
|
|
||||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
|
||||||
|
|
||||||
expect(status).toBe(200);
|
|
||||||
expect(body).toMatchObject({ avatar: { color: 'blue' } });
|
|
||||||
|
|
||||||
const after = await getMyPreferences({ headers: asBearerAuth(admin.accessToken) });
|
|
||||||
expect(after).toMatchObject({ avatar: { color: 'blue' } });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should require an integer for download archive size', async () => {
|
it('should require an integer for download archive size', async () => {
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.put(`/users/me/preferences`)
|
.put(`/users/me/preferences`)
|
||||||
|
1
mobile/openapi/README.md
generated
1
mobile/openapi/README.md
generated
@ -300,7 +300,6 @@ Class | Method | HTTP request | Description
|
|||||||
- [AssetStatsResponseDto](doc//AssetStatsResponseDto.md)
|
- [AssetStatsResponseDto](doc//AssetStatsResponseDto.md)
|
||||||
- [AssetTypeEnum](doc//AssetTypeEnum.md)
|
- [AssetTypeEnum](doc//AssetTypeEnum.md)
|
||||||
- [AudioCodec](doc//AudioCodec.md)
|
- [AudioCodec](doc//AudioCodec.md)
|
||||||
- [AvatarResponse](doc//AvatarResponse.md)
|
|
||||||
- [AvatarUpdate](doc//AvatarUpdate.md)
|
- [AvatarUpdate](doc//AvatarUpdate.md)
|
||||||
- [BulkIdResponseDto](doc//BulkIdResponseDto.md)
|
- [BulkIdResponseDto](doc//BulkIdResponseDto.md)
|
||||||
- [BulkIdsDto](doc//BulkIdsDto.md)
|
- [BulkIdsDto](doc//BulkIdsDto.md)
|
||||||
|
1
mobile/openapi/lib/api.dart
generated
1
mobile/openapi/lib/api.dart
generated
@ -107,7 +107,6 @@ part 'model/asset_stack_response_dto.dart';
|
|||||||
part 'model/asset_stats_response_dto.dart';
|
part 'model/asset_stats_response_dto.dart';
|
||||||
part 'model/asset_type_enum.dart';
|
part 'model/asset_type_enum.dart';
|
||||||
part 'model/audio_codec.dart';
|
part 'model/audio_codec.dart';
|
||||||
part 'model/avatar_response.dart';
|
|
||||||
part 'model/avatar_update.dart';
|
part 'model/avatar_update.dart';
|
||||||
part 'model/bulk_id_response_dto.dart';
|
part 'model/bulk_id_response_dto.dart';
|
||||||
part 'model/bulk_ids_dto.dart';
|
part 'model/bulk_ids_dto.dart';
|
||||||
|
2
mobile/openapi/lib/api_client.dart
generated
2
mobile/openapi/lib/api_client.dart
generated
@ -270,8 +270,6 @@ class ApiClient {
|
|||||||
return AssetTypeEnumTypeTransformer().decode(value);
|
return AssetTypeEnumTypeTransformer().decode(value);
|
||||||
case 'AudioCodec':
|
case 'AudioCodec':
|
||||||
return AudioCodecTypeTransformer().decode(value);
|
return AudioCodecTypeTransformer().decode(value);
|
||||||
case 'AvatarResponse':
|
|
||||||
return AvatarResponse.fromJson(value);
|
|
||||||
case 'AvatarUpdate':
|
case 'AvatarUpdate':
|
||||||
return AvatarUpdate.fromJson(value);
|
return AvatarUpdate.fromJson(value);
|
||||||
case 'BulkIdResponseDto':
|
case 'BulkIdResponseDto':
|
||||||
|
99
mobile/openapi/lib/model/avatar_response.dart
generated
99
mobile/openapi/lib/model/avatar_response.dart
generated
@ -1,99 +0,0 @@
|
|||||||
//
|
|
||||||
// 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 AvatarResponse {
|
|
||||||
/// Returns a new [AvatarResponse] instance.
|
|
||||||
AvatarResponse({
|
|
||||||
required this.color,
|
|
||||||
});
|
|
||||||
|
|
||||||
UserAvatarColor color;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) => identical(this, other) || other is AvatarResponse &&
|
|
||||||
other.color == color;
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode =>
|
|
||||||
// ignore: unnecessary_parenthesis
|
|
||||||
(color.hashCode);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() => 'AvatarResponse[color=$color]';
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
final json = <String, dynamic>{};
|
|
||||||
json[r'color'] = this.color;
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a new [AvatarResponse] instance and imports its values from
|
|
||||||
/// [value] if it's a [Map], null otherwise.
|
|
||||||
// ignore: prefer_constructors_over_static_methods
|
|
||||||
static AvatarResponse? fromJson(dynamic value) {
|
|
||||||
upgradeDto(value, "AvatarResponse");
|
|
||||||
if (value is Map) {
|
|
||||||
final json = value.cast<String, dynamic>();
|
|
||||||
|
|
||||||
return AvatarResponse(
|
|
||||||
color: UserAvatarColor.fromJson(json[r'color'])!,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<AvatarResponse> listFromJson(dynamic json, {bool growable = false,}) {
|
|
||||||
final result = <AvatarResponse>[];
|
|
||||||
if (json is List && json.isNotEmpty) {
|
|
||||||
for (final row in json) {
|
|
||||||
final value = AvatarResponse.fromJson(row);
|
|
||||||
if (value != null) {
|
|
||||||
result.add(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result.toList(growable: growable);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Map<String, AvatarResponse> mapFromJson(dynamic json) {
|
|
||||||
final map = <String, AvatarResponse>{};
|
|
||||||
if (json is Map && json.isNotEmpty) {
|
|
||||||
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
|
||||||
for (final entry in json.entries) {
|
|
||||||
final value = AvatarResponse.fromJson(entry.value);
|
|
||||||
if (value != null) {
|
|
||||||
map[entry.key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
// maps a json object with a list of AvatarResponse-objects as value to a dart map
|
|
||||||
static Map<String, List<AvatarResponse>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
|
||||||
final map = <String, List<AvatarResponse>>{};
|
|
||||||
if (json is Map && json.isNotEmpty) {
|
|
||||||
// ignore: parameter_assignments
|
|
||||||
json = json.cast<String, dynamic>();
|
|
||||||
for (final entry in json.entries) {
|
|
||||||
map[entry.key] = AvatarResponse.listFromJson(entry.value, growable: growable,);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The list of required keys that must be present in a JSON.
|
|
||||||
static const requiredKeys = <String>{
|
|
||||||
'color',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
13
mobile/openapi/lib/model/user_admin_create_dto.dart
generated
13
mobile/openapi/lib/model/user_admin_create_dto.dart
generated
@ -13,6 +13,7 @@ part of openapi.api;
|
|||||||
class UserAdminCreateDto {
|
class UserAdminCreateDto {
|
||||||
/// Returns a new [UserAdminCreateDto] instance.
|
/// Returns a new [UserAdminCreateDto] instance.
|
||||||
UserAdminCreateDto({
|
UserAdminCreateDto({
|
||||||
|
this.avatarColor,
|
||||||
required this.email,
|
required this.email,
|
||||||
required this.name,
|
required this.name,
|
||||||
this.notify,
|
this.notify,
|
||||||
@ -22,6 +23,8 @@ class UserAdminCreateDto {
|
|||||||
this.storageLabel,
|
this.storageLabel,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
UserAvatarColor? avatarColor;
|
||||||
|
|
||||||
String email;
|
String email;
|
||||||
|
|
||||||
String name;
|
String name;
|
||||||
@ -51,6 +54,7 @@ class UserAdminCreateDto {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => identical(this, other) || other is UserAdminCreateDto &&
|
bool operator ==(Object other) => identical(this, other) || other is UserAdminCreateDto &&
|
||||||
|
other.avatarColor == avatarColor &&
|
||||||
other.email == email &&
|
other.email == email &&
|
||||||
other.name == name &&
|
other.name == name &&
|
||||||
other.notify == notify &&
|
other.notify == notify &&
|
||||||
@ -62,6 +66,7 @@ class UserAdminCreateDto {
|
|||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
// ignore: unnecessary_parenthesis
|
// ignore: unnecessary_parenthesis
|
||||||
|
(avatarColor == null ? 0 : avatarColor!.hashCode) +
|
||||||
(email.hashCode) +
|
(email.hashCode) +
|
||||||
(name.hashCode) +
|
(name.hashCode) +
|
||||||
(notify == null ? 0 : notify!.hashCode) +
|
(notify == null ? 0 : notify!.hashCode) +
|
||||||
@ -71,10 +76,15 @@ class UserAdminCreateDto {
|
|||||||
(storageLabel == null ? 0 : storageLabel!.hashCode);
|
(storageLabel == null ? 0 : storageLabel!.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'UserAdminCreateDto[email=$email, name=$name, notify=$notify, password=$password, quotaSizeInBytes=$quotaSizeInBytes, shouldChangePassword=$shouldChangePassword, storageLabel=$storageLabel]';
|
String toString() => 'UserAdminCreateDto[avatarColor=$avatarColor, email=$email, name=$name, notify=$notify, password=$password, quotaSizeInBytes=$quotaSizeInBytes, shouldChangePassword=$shouldChangePassword, storageLabel=$storageLabel]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
|
if (this.avatarColor != null) {
|
||||||
|
json[r'avatarColor'] = this.avatarColor;
|
||||||
|
} else {
|
||||||
|
// json[r'avatarColor'] = null;
|
||||||
|
}
|
||||||
json[r'email'] = this.email;
|
json[r'email'] = this.email;
|
||||||
json[r'name'] = this.name;
|
json[r'name'] = this.name;
|
||||||
if (this.notify != null) {
|
if (this.notify != null) {
|
||||||
@ -110,6 +120,7 @@ class UserAdminCreateDto {
|
|||||||
final json = value.cast<String, dynamic>();
|
final json = value.cast<String, dynamic>();
|
||||||
|
|
||||||
return UserAdminCreateDto(
|
return UserAdminCreateDto(
|
||||||
|
avatarColor: UserAvatarColor.fromJson(json[r'avatarColor']),
|
||||||
email: mapValueOfType<String>(json, r'email')!,
|
email: mapValueOfType<String>(json, r'email')!,
|
||||||
name: mapValueOfType<String>(json, r'name')!,
|
name: mapValueOfType<String>(json, r'name')!,
|
||||||
notify: mapValueOfType<bool>(json, r'notify'),
|
notify: mapValueOfType<bool>(json, r'notify'),
|
||||||
|
13
mobile/openapi/lib/model/user_admin_update_dto.dart
generated
13
mobile/openapi/lib/model/user_admin_update_dto.dart
generated
@ -13,6 +13,7 @@ part of openapi.api;
|
|||||||
class UserAdminUpdateDto {
|
class UserAdminUpdateDto {
|
||||||
/// Returns a new [UserAdminUpdateDto] instance.
|
/// Returns a new [UserAdminUpdateDto] instance.
|
||||||
UserAdminUpdateDto({
|
UserAdminUpdateDto({
|
||||||
|
this.avatarColor,
|
||||||
this.email,
|
this.email,
|
||||||
this.name,
|
this.name,
|
||||||
this.password,
|
this.password,
|
||||||
@ -21,6 +22,8 @@ class UserAdminUpdateDto {
|
|||||||
this.storageLabel,
|
this.storageLabel,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
UserAvatarColor? avatarColor;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Please note: This property should have been non-nullable! Since the specification file
|
/// 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
|
/// does not include a default value (using the "default:" property), however, the generated
|
||||||
@ -60,6 +63,7 @@ class UserAdminUpdateDto {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => identical(this, other) || other is UserAdminUpdateDto &&
|
bool operator ==(Object other) => identical(this, other) || other is UserAdminUpdateDto &&
|
||||||
|
other.avatarColor == avatarColor &&
|
||||||
other.email == email &&
|
other.email == email &&
|
||||||
other.name == name &&
|
other.name == name &&
|
||||||
other.password == password &&
|
other.password == password &&
|
||||||
@ -70,6 +74,7 @@ class UserAdminUpdateDto {
|
|||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
// ignore: unnecessary_parenthesis
|
// ignore: unnecessary_parenthesis
|
||||||
|
(avatarColor == null ? 0 : avatarColor!.hashCode) +
|
||||||
(email == null ? 0 : email!.hashCode) +
|
(email == null ? 0 : email!.hashCode) +
|
||||||
(name == null ? 0 : name!.hashCode) +
|
(name == null ? 0 : name!.hashCode) +
|
||||||
(password == null ? 0 : password!.hashCode) +
|
(password == null ? 0 : password!.hashCode) +
|
||||||
@ -78,10 +83,15 @@ class UserAdminUpdateDto {
|
|||||||
(storageLabel == null ? 0 : storageLabel!.hashCode);
|
(storageLabel == null ? 0 : storageLabel!.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'UserAdminUpdateDto[email=$email, name=$name, password=$password, quotaSizeInBytes=$quotaSizeInBytes, shouldChangePassword=$shouldChangePassword, storageLabel=$storageLabel]';
|
String toString() => 'UserAdminUpdateDto[avatarColor=$avatarColor, email=$email, name=$name, password=$password, quotaSizeInBytes=$quotaSizeInBytes, shouldChangePassword=$shouldChangePassword, storageLabel=$storageLabel]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
|
if (this.avatarColor != null) {
|
||||||
|
json[r'avatarColor'] = this.avatarColor;
|
||||||
|
} else {
|
||||||
|
// json[r'avatarColor'] = null;
|
||||||
|
}
|
||||||
if (this.email != null) {
|
if (this.email != null) {
|
||||||
json[r'email'] = this.email;
|
json[r'email'] = this.email;
|
||||||
} else {
|
} else {
|
||||||
@ -124,6 +134,7 @@ class UserAdminUpdateDto {
|
|||||||
final json = value.cast<String, dynamic>();
|
final json = value.cast<String, dynamic>();
|
||||||
|
|
||||||
return UserAdminUpdateDto(
|
return UserAdminUpdateDto(
|
||||||
|
avatarColor: UserAvatarColor.fromJson(json[r'avatarColor']),
|
||||||
email: mapValueOfType<String>(json, r'email'),
|
email: mapValueOfType<String>(json, r'email'),
|
||||||
name: mapValueOfType<String>(json, r'name'),
|
name: mapValueOfType<String>(json, r'name'),
|
||||||
password: mapValueOfType<String>(json, r'password'),
|
password: mapValueOfType<String>(json, r'password'),
|
||||||
|
@ -13,7 +13,6 @@ part of openapi.api;
|
|||||||
class UserPreferencesResponseDto {
|
class UserPreferencesResponseDto {
|
||||||
/// Returns a new [UserPreferencesResponseDto] instance.
|
/// Returns a new [UserPreferencesResponseDto] instance.
|
||||||
UserPreferencesResponseDto({
|
UserPreferencesResponseDto({
|
||||||
required this.avatar,
|
|
||||||
required this.download,
|
required this.download,
|
||||||
required this.emailNotifications,
|
required this.emailNotifications,
|
||||||
required this.folders,
|
required this.folders,
|
||||||
@ -25,8 +24,6 @@ class UserPreferencesResponseDto {
|
|||||||
required this.tags,
|
required this.tags,
|
||||||
});
|
});
|
||||||
|
|
||||||
AvatarResponse avatar;
|
|
||||||
|
|
||||||
DownloadResponse download;
|
DownloadResponse download;
|
||||||
|
|
||||||
EmailNotificationsResponse emailNotifications;
|
EmailNotificationsResponse emailNotifications;
|
||||||
@ -47,7 +44,6 @@ class UserPreferencesResponseDto {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => identical(this, other) || other is UserPreferencesResponseDto &&
|
bool operator ==(Object other) => identical(this, other) || other is UserPreferencesResponseDto &&
|
||||||
other.avatar == avatar &&
|
|
||||||
other.download == download &&
|
other.download == download &&
|
||||||
other.emailNotifications == emailNotifications &&
|
other.emailNotifications == emailNotifications &&
|
||||||
other.folders == folders &&
|
other.folders == folders &&
|
||||||
@ -61,7 +57,6 @@ class UserPreferencesResponseDto {
|
|||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
// ignore: unnecessary_parenthesis
|
// ignore: unnecessary_parenthesis
|
||||||
(avatar.hashCode) +
|
|
||||||
(download.hashCode) +
|
(download.hashCode) +
|
||||||
(emailNotifications.hashCode) +
|
(emailNotifications.hashCode) +
|
||||||
(folders.hashCode) +
|
(folders.hashCode) +
|
||||||
@ -73,11 +68,10 @@ class UserPreferencesResponseDto {
|
|||||||
(tags.hashCode);
|
(tags.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'UserPreferencesResponseDto[avatar=$avatar, download=$download, emailNotifications=$emailNotifications, folders=$folders, memories=$memories, people=$people, purchase=$purchase, ratings=$ratings, sharedLinks=$sharedLinks, tags=$tags]';
|
String toString() => 'UserPreferencesResponseDto[download=$download, emailNotifications=$emailNotifications, folders=$folders, memories=$memories, people=$people, purchase=$purchase, ratings=$ratings, sharedLinks=$sharedLinks, tags=$tags]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
json[r'avatar'] = this.avatar;
|
|
||||||
json[r'download'] = this.download;
|
json[r'download'] = this.download;
|
||||||
json[r'emailNotifications'] = this.emailNotifications;
|
json[r'emailNotifications'] = this.emailNotifications;
|
||||||
json[r'folders'] = this.folders;
|
json[r'folders'] = this.folders;
|
||||||
@ -99,7 +93,6 @@ class UserPreferencesResponseDto {
|
|||||||
final json = value.cast<String, dynamic>();
|
final json = value.cast<String, dynamic>();
|
||||||
|
|
||||||
return UserPreferencesResponseDto(
|
return UserPreferencesResponseDto(
|
||||||
avatar: AvatarResponse.fromJson(json[r'avatar'])!,
|
|
||||||
download: DownloadResponse.fromJson(json[r'download'])!,
|
download: DownloadResponse.fromJson(json[r'download'])!,
|
||||||
emailNotifications: EmailNotificationsResponse.fromJson(json[r'emailNotifications'])!,
|
emailNotifications: EmailNotificationsResponse.fromJson(json[r'emailNotifications'])!,
|
||||||
folders: FoldersResponse.fromJson(json[r'folders'])!,
|
folders: FoldersResponse.fromJson(json[r'folders'])!,
|
||||||
@ -156,7 +149,6 @@ class UserPreferencesResponseDto {
|
|||||||
|
|
||||||
/// The list of required keys that must be present in a JSON.
|
/// The list of required keys that must be present in a JSON.
|
||||||
static const requiredKeys = <String>{
|
static const requiredKeys = <String>{
|
||||||
'avatar',
|
|
||||||
'download',
|
'download',
|
||||||
'emailNotifications',
|
'emailNotifications',
|
||||||
'folders',
|
'folders',
|
||||||
|
13
mobile/openapi/lib/model/user_update_me_dto.dart
generated
13
mobile/openapi/lib/model/user_update_me_dto.dart
generated
@ -13,11 +13,14 @@ part of openapi.api;
|
|||||||
class UserUpdateMeDto {
|
class UserUpdateMeDto {
|
||||||
/// Returns a new [UserUpdateMeDto] instance.
|
/// Returns a new [UserUpdateMeDto] instance.
|
||||||
UserUpdateMeDto({
|
UserUpdateMeDto({
|
||||||
|
this.avatarColor,
|
||||||
this.email,
|
this.email,
|
||||||
this.name,
|
this.name,
|
||||||
this.password,
|
this.password,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
UserAvatarColor? avatarColor;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Please note: This property should have been non-nullable! Since the specification file
|
/// 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
|
/// does not include a default value (using the "default:" property), however, the generated
|
||||||
@ -44,6 +47,7 @@ class UserUpdateMeDto {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => identical(this, other) || other is UserUpdateMeDto &&
|
bool operator ==(Object other) => identical(this, other) || other is UserUpdateMeDto &&
|
||||||
|
other.avatarColor == avatarColor &&
|
||||||
other.email == email &&
|
other.email == email &&
|
||||||
other.name == name &&
|
other.name == name &&
|
||||||
other.password == password;
|
other.password == password;
|
||||||
@ -51,15 +55,21 @@ class UserUpdateMeDto {
|
|||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
// ignore: unnecessary_parenthesis
|
// ignore: unnecessary_parenthesis
|
||||||
|
(avatarColor == null ? 0 : avatarColor!.hashCode) +
|
||||||
(email == null ? 0 : email!.hashCode) +
|
(email == null ? 0 : email!.hashCode) +
|
||||||
(name == null ? 0 : name!.hashCode) +
|
(name == null ? 0 : name!.hashCode) +
|
||||||
(password == null ? 0 : password!.hashCode);
|
(password == null ? 0 : password!.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'UserUpdateMeDto[email=$email, name=$name, password=$password]';
|
String toString() => 'UserUpdateMeDto[avatarColor=$avatarColor, email=$email, name=$name, password=$password]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
|
if (this.avatarColor != null) {
|
||||||
|
json[r'avatarColor'] = this.avatarColor;
|
||||||
|
} else {
|
||||||
|
// json[r'avatarColor'] = null;
|
||||||
|
}
|
||||||
if (this.email != null) {
|
if (this.email != null) {
|
||||||
json[r'email'] = this.email;
|
json[r'email'] = this.email;
|
||||||
} else {
|
} else {
|
||||||
@ -87,6 +97,7 @@ class UserUpdateMeDto {
|
|||||||
final json = value.cast<String, dynamic>();
|
final json = value.cast<String, dynamic>();
|
||||||
|
|
||||||
return UserUpdateMeDto(
|
return UserUpdateMeDto(
|
||||||
|
avatarColor: UserAvatarColor.fromJson(json[r'avatarColor']),
|
||||||
email: mapValueOfType<String>(json, r'email'),
|
email: mapValueOfType<String>(json, r'email'),
|
||||||
name: mapValueOfType<String>(json, r'name'),
|
name: mapValueOfType<String>(json, r'name'),
|
||||||
password: mapValueOfType<String>(json, r'password'),
|
password: mapValueOfType<String>(json, r'password'),
|
||||||
|
@ -8884,21 +8884,6 @@
|
|||||||
],
|
],
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"AvatarResponse": {
|
|
||||||
"properties": {
|
|
||||||
"color": {
|
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/UserAvatarColor"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"color"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"AvatarUpdate": {
|
"AvatarUpdate": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"color": {
|
"color": {
|
||||||
@ -13621,6 +13606,14 @@
|
|||||||
},
|
},
|
||||||
"UserAdminCreateDto": {
|
"UserAdminCreateDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"avatarColor": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/UserAvatarColor"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
"email": {
|
"email": {
|
||||||
"format": "email",
|
"format": "email",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -13763,6 +13756,14 @@
|
|||||||
},
|
},
|
||||||
"UserAdminUpdateDto": {
|
"UserAdminUpdateDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"avatarColor": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/UserAvatarColor"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
"email": {
|
"email": {
|
||||||
"format": "email",
|
"format": "email",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -13826,9 +13827,6 @@
|
|||||||
},
|
},
|
||||||
"UserPreferencesResponseDto": {
|
"UserPreferencesResponseDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"avatar": {
|
|
||||||
"$ref": "#/components/schemas/AvatarResponse"
|
|
||||||
},
|
|
||||||
"download": {
|
"download": {
|
||||||
"$ref": "#/components/schemas/DownloadResponse"
|
"$ref": "#/components/schemas/DownloadResponse"
|
||||||
},
|
},
|
||||||
@ -13858,7 +13856,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"avatar",
|
|
||||||
"download",
|
"download",
|
||||||
"emailNotifications",
|
"emailNotifications",
|
||||||
"folders",
|
"folders",
|
||||||
@ -13952,6 +13949,14 @@
|
|||||||
},
|
},
|
||||||
"UserUpdateMeDto": {
|
"UserUpdateMeDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"avatarColor": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/UserAvatarColor"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
"email": {
|
"email": {
|
||||||
"format": "email",
|
"format": "email",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -64,6 +64,7 @@ export type UserAdminResponseDto = {
|
|||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
};
|
};
|
||||||
export type UserAdminCreateDto = {
|
export type UserAdminCreateDto = {
|
||||||
|
avatarColor?: (UserAvatarColor) | null;
|
||||||
email: string;
|
email: string;
|
||||||
name: string;
|
name: string;
|
||||||
notify?: boolean;
|
notify?: boolean;
|
||||||
@ -76,6 +77,7 @@ export type UserAdminDeleteDto = {
|
|||||||
force?: boolean;
|
force?: boolean;
|
||||||
};
|
};
|
||||||
export type UserAdminUpdateDto = {
|
export type UserAdminUpdateDto = {
|
||||||
|
avatarColor?: (UserAvatarColor) | null;
|
||||||
email?: string;
|
email?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
password?: string;
|
password?: string;
|
||||||
@ -83,9 +85,6 @@ export type UserAdminUpdateDto = {
|
|||||||
shouldChangePassword?: boolean;
|
shouldChangePassword?: boolean;
|
||||||
storageLabel?: string | null;
|
storageLabel?: string | null;
|
||||||
};
|
};
|
||||||
export type AvatarResponse = {
|
|
||||||
color: UserAvatarColor;
|
|
||||||
};
|
|
||||||
export type DownloadResponse = {
|
export type DownloadResponse = {
|
||||||
archiveSize: number;
|
archiveSize: number;
|
||||||
includeEmbeddedVideos: boolean;
|
includeEmbeddedVideos: boolean;
|
||||||
@ -122,7 +121,6 @@ export type TagsResponse = {
|
|||||||
sidebarWeb: boolean;
|
sidebarWeb: boolean;
|
||||||
};
|
};
|
||||||
export type UserPreferencesResponseDto = {
|
export type UserPreferencesResponseDto = {
|
||||||
avatar: AvatarResponse;
|
|
||||||
download: DownloadResponse;
|
download: DownloadResponse;
|
||||||
emailNotifications: EmailNotificationsResponse;
|
emailNotifications: EmailNotificationsResponse;
|
||||||
folders: FoldersResponse;
|
folders: FoldersResponse;
|
||||||
@ -1388,6 +1386,7 @@ export type TrashResponseDto = {
|
|||||||
count: number;
|
count: number;
|
||||||
};
|
};
|
||||||
export type UserUpdateMeDto = {
|
export type UserUpdateMeDto = {
|
||||||
|
avatarColor?: (UserAvatarColor) | null;
|
||||||
email?: string;
|
email?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
password?: string;
|
password?: string;
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
Permission,
|
Permission,
|
||||||
SharedLinkType,
|
SharedLinkType,
|
||||||
SourceType,
|
SourceType,
|
||||||
|
UserAvatarColor,
|
||||||
UserStatus,
|
UserStatus,
|
||||||
} from 'src/enum';
|
} from 'src/enum';
|
||||||
import { OnThisDayData, UserMetadataItem } from 'src/types';
|
import { OnThisDayData, UserMetadataItem } from 'src/types';
|
||||||
@ -122,6 +123,7 @@ export type User = {
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
avatarColor: UserAvatarColor | null;
|
||||||
profileImagePath: string;
|
profileImagePath: string;
|
||||||
profileChangedAt: Date;
|
profileChangedAt: Date;
|
||||||
};
|
};
|
||||||
@ -264,7 +266,15 @@ export type AssetFace = {
|
|||||||
person?: Person | null;
|
person?: Person | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const userColumns = ['id', 'name', 'email', 'profileImagePath', 'profileChangedAt'] as const;
|
const userColumns = ['id', 'name', 'email', 'avatarColor', 'profileImagePath', 'profileChangedAt'] as const;
|
||||||
|
const userWithPrefixColumns = [
|
||||||
|
'users.id',
|
||||||
|
'users.name',
|
||||||
|
'users.email',
|
||||||
|
'users.avatarColor',
|
||||||
|
'users.profileImagePath',
|
||||||
|
'users.profileChangedAt',
|
||||||
|
] as const;
|
||||||
|
|
||||||
export const columns = {
|
export const columns = {
|
||||||
asset: [
|
asset: [
|
||||||
@ -306,7 +316,7 @@ export const columns = {
|
|||||||
'shared_links.password',
|
'shared_links.password',
|
||||||
],
|
],
|
||||||
user: userColumns,
|
user: userColumns,
|
||||||
userWithPrefix: ['users.id', 'users.name', 'users.email', 'users.profileImagePath', 'users.profileChangedAt'],
|
userWithPrefix: userWithPrefixColumns,
|
||||||
userAdmin: [
|
userAdmin: [
|
||||||
...userColumns,
|
...userColumns,
|
||||||
'createdAt',
|
'createdAt',
|
||||||
|
@ -137,11 +137,6 @@ export class UserPreferencesUpdateDto {
|
|||||||
purchase?: PurchaseUpdate;
|
purchase?: PurchaseUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
class AvatarResponse {
|
|
||||||
@ApiProperty({ enumName: 'UserAvatarColor', enum: UserAvatarColor })
|
|
||||||
color!: UserAvatarColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
class RatingsResponse {
|
class RatingsResponse {
|
||||||
enabled: boolean = false;
|
enabled: boolean = false;
|
||||||
}
|
}
|
||||||
@ -195,7 +190,6 @@ export class UserPreferencesResponseDto implements UserPreferences {
|
|||||||
ratings!: RatingsResponse;
|
ratings!: RatingsResponse;
|
||||||
sharedLinks!: SharedLinksResponse;
|
sharedLinks!: SharedLinksResponse;
|
||||||
tags!: TagsResponse;
|
tags!: TagsResponse;
|
||||||
avatar!: AvatarResponse;
|
|
||||||
emailNotifications!: EmailNotificationsResponse;
|
emailNotifications!: EmailNotificationsResponse;
|
||||||
download!: DownloadResponse;
|
download!: DownloadResponse;
|
||||||
purchase!: PurchaseResponse;
|
purchase!: PurchaseResponse;
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { Transform } from 'class-transformer';
|
import { Transform } from 'class-transformer';
|
||||||
import { IsBoolean, IsEmail, IsNotEmpty, IsNumber, IsString, Min } from 'class-validator';
|
import { IsBoolean, IsEmail, IsEnum, IsNotEmpty, IsNumber, IsString, Min } from 'class-validator';
|
||||||
import { User, UserAdmin } from 'src/database';
|
import { User, UserAdmin } from 'src/database';
|
||||||
import { UserAvatarColor, UserMetadataKey, UserStatus } from 'src/enum';
|
import { UserAvatarColor, UserMetadataKey, UserStatus } from 'src/enum';
|
||||||
import { UserMetadataItem } from 'src/types';
|
import { UserMetadataItem } from 'src/types';
|
||||||
import { getPreferences } from 'src/utils/preferences';
|
|
||||||
import { Optional, ValidateBoolean, toEmail, toSanitized } from 'src/validation';
|
import { Optional, ValidateBoolean, toEmail, toSanitized } from 'src/validation';
|
||||||
|
|
||||||
export class UserUpdateMeDto {
|
export class UserUpdateMeDto {
|
||||||
@ -23,6 +22,11 @@ export class UserUpdateMeDto {
|
|||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|
||||||
|
@Optional({ nullable: true })
|
||||||
|
@IsEnum(UserAvatarColor)
|
||||||
|
@ApiProperty({ enumName: 'UserAvatarColor', enum: UserAvatarColor })
|
||||||
|
avatarColor?: UserAvatarColor | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UserResponseDto {
|
export class UserResponseDto {
|
||||||
@ -41,13 +45,21 @@ export class UserLicense {
|
|||||||
activatedAt!: Date;
|
activatedAt!: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const emailToAvatarColor = (email: string): UserAvatarColor => {
|
||||||
|
const values = Object.values(UserAvatarColor);
|
||||||
|
const randomIndex = Math.floor(
|
||||||
|
[...email].map((letter) => letter.codePointAt(0) ?? 0).reduce((a, b) => a + b, 0) % values.length,
|
||||||
|
);
|
||||||
|
return values[randomIndex];
|
||||||
|
};
|
||||||
|
|
||||||
export const mapUser = (entity: User | UserAdmin): UserResponseDto => {
|
export const mapUser = (entity: User | UserAdmin): UserResponseDto => {
|
||||||
return {
|
return {
|
||||||
id: entity.id,
|
id: entity.id,
|
||||||
email: entity.email,
|
email: entity.email,
|
||||||
name: entity.name,
|
name: entity.name,
|
||||||
profileImagePath: entity.profileImagePath,
|
profileImagePath: entity.profileImagePath,
|
||||||
avatarColor: getPreferences(entity.email, (entity as UserAdmin).metadata || []).avatar.color,
|
avatarColor: entity.avatarColor ?? emailToAvatarColor(entity.email),
|
||||||
profileChangedAt: entity.profileChangedAt,
|
profileChangedAt: entity.profileChangedAt,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -69,6 +81,11 @@ export class UserAdminCreateDto {
|
|||||||
@IsString()
|
@IsString()
|
||||||
name!: string;
|
name!: string;
|
||||||
|
|
||||||
|
@Optional({ nullable: true })
|
||||||
|
@IsEnum(UserAvatarColor)
|
||||||
|
@ApiProperty({ enumName: 'UserAvatarColor', enum: UserAvatarColor })
|
||||||
|
avatarColor?: UserAvatarColor | null;
|
||||||
|
|
||||||
@Optional({ nullable: true })
|
@Optional({ nullable: true })
|
||||||
@IsString()
|
@IsString()
|
||||||
@Transform(toSanitized)
|
@Transform(toSanitized)
|
||||||
@ -104,6 +121,11 @@ export class UserAdminUpdateDto {
|
|||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|
||||||
|
@Optional({ nullable: true })
|
||||||
|
@IsEnum(UserAvatarColor)
|
||||||
|
@ApiProperty({ enumName: 'UserAvatarColor', enum: UserAvatarColor })
|
||||||
|
avatarColor?: UserAvatarColor | null;
|
||||||
|
|
||||||
@Optional({ nullable: true })
|
@Optional({ nullable: true })
|
||||||
@IsString()
|
@IsString()
|
||||||
@Transform(toSanitized)
|
@Transform(toSanitized)
|
||||||
|
@ -13,6 +13,7 @@ from
|
|||||||
"users"."id",
|
"users"."id",
|
||||||
"users"."name",
|
"users"."name",
|
||||||
"users"."email",
|
"users"."email",
|
||||||
|
"users"."avatarColor",
|
||||||
"users"."profileImagePath",
|
"users"."profileImagePath",
|
||||||
"users"."profileChangedAt"
|
"users"."profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -44,6 +45,7 @@ returning
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
|
@ -12,6 +12,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -36,6 +37,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -100,6 +102,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -124,6 +127,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -191,6 +195,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -215,6 +220,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -269,6 +275,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -292,6 +299,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -353,6 +361,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
|
@ -12,6 +12,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -29,6 +30,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -61,6 +63,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -78,6 +81,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -112,6 +116,7 @@ returning
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -129,6 +134,7 @@ returning
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -156,6 +162,7 @@ returning
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
@ -173,6 +180,7 @@ returning
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt"
|
"profileChangedAt"
|
||||||
from
|
from
|
||||||
|
@ -5,6 +5,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt",
|
"profileChangedAt",
|
||||||
"createdAt",
|
"createdAt",
|
||||||
@ -43,6 +44,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt",
|
"profileChangedAt",
|
||||||
"createdAt",
|
"createdAt",
|
||||||
@ -90,6 +92,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt",
|
"profileChangedAt",
|
||||||
"createdAt",
|
"createdAt",
|
||||||
@ -128,6 +131,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt",
|
"profileChangedAt",
|
||||||
"createdAt",
|
"createdAt",
|
||||||
@ -152,6 +156,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt",
|
"profileChangedAt",
|
||||||
"createdAt",
|
"createdAt",
|
||||||
@ -198,6 +203,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt",
|
"profileChangedAt",
|
||||||
"createdAt",
|
"createdAt",
|
||||||
@ -235,6 +241,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"profileImagePath",
|
"profileImagePath",
|
||||||
"profileChangedAt",
|
"profileChangedAt",
|
||||||
"createdAt",
|
"createdAt",
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
import { Kysely, sql } from 'kysely';
|
||||||
|
|
||||||
|
export async function up(db: Kysely<any>): Promise<void> {
|
||||||
|
await sql`ALTER TABLE "users" ADD "avatarColor" character varying;`.execute(db);
|
||||||
|
await sql`
|
||||||
|
UPDATE "users"
|
||||||
|
SET "avatarColor" = "user_metadata"."value"->'avatar'->>'color'
|
||||||
|
FROM "user_metadata"
|
||||||
|
WHERE "users"."id" = "user_metadata"."userId" AND "user_metadata"."key" = 'preferences';`.execute(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(db: Kysely<any>): Promise<void> {
|
||||||
|
await sql`ALTER TABLE "users" DROP COLUMN "avatarColor";`.execute(db);
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { ColumnType } from 'kysely';
|
import { ColumnType } from 'kysely';
|
||||||
import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
|
import { UpdatedAtTrigger, UpdateIdColumn } from 'src/decorators';
|
||||||
import { UserStatus } from 'src/enum';
|
import { UserAvatarColor, UserStatus } from 'src/enum';
|
||||||
import { users_delete_audit } from 'src/schema/functions';
|
import { users_delete_audit } from 'src/schema/functions';
|
||||||
import {
|
import {
|
||||||
AfterDeleteTrigger,
|
AfterDeleteTrigger,
|
||||||
@ -49,6 +49,9 @@ export class UserTable {
|
|||||||
@Column({ type: 'boolean', default: true })
|
@Column({ type: 'boolean', default: true })
|
||||||
shouldChangePassword!: Generated<boolean>;
|
shouldChangePassword!: Generated<boolean>;
|
||||||
|
|
||||||
|
@Column({ default: null })
|
||||||
|
avatarColor!: UserAvatarColor | null;
|
||||||
|
|
||||||
@DeleteDateColumn()
|
@DeleteDateColumn()
|
||||||
deletedAt!: Timestamp | null;
|
deletedAt!: Timestamp | null;
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ export class DownloadService extends BaseService {
|
|||||||
|
|
||||||
const targetSize = dto.archiveSize || HumanReadableSize.GiB * 4;
|
const targetSize = dto.archiveSize || HumanReadableSize.GiB * 4;
|
||||||
const metadata = await this.userRepository.getMetadata(auth.user.id);
|
const metadata = await this.userRepository.getMetadata(auth.user.id);
|
||||||
const preferences = getPreferences(auth.user.email, metadata);
|
const preferences = getPreferences(metadata);
|
||||||
const motionIds = new Set<string>();
|
const motionIds = new Set<string>();
|
||||||
const archives: DownloadArchiveInfo[] = [];
|
const archives: DownloadArchiveInfo[] = [];
|
||||||
let archive: DownloadArchiveInfo = { size: 0, assetIds: [] };
|
let archive: DownloadArchiveInfo = { size: 0, assetIds: [] };
|
||||||
|
@ -271,7 +271,7 @@ export class NotificationService extends BaseService {
|
|||||||
return JobStatus.SKIPPED;
|
return JobStatus.SKIPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { emailNotifications } = getPreferences(recipient.email, recipient.metadata);
|
const { emailNotifications } = getPreferences(recipient.metadata);
|
||||||
|
|
||||||
if (!emailNotifications.enabled || !emailNotifications.albumInvite) {
|
if (!emailNotifications.enabled || !emailNotifications.albumInvite) {
|
||||||
return JobStatus.SKIPPED;
|
return JobStatus.SKIPPED;
|
||||||
@ -333,7 +333,7 @@ export class NotificationService extends BaseService {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { emailNotifications } = getPreferences(user.email, user.metadata);
|
const { emailNotifications } = getPreferences(user.metadata);
|
||||||
|
|
||||||
if (!emailNotifications.enabled || !emailNotifications.albumUpdate) {
|
if (!emailNotifications.enabled || !emailNotifications.albumUpdate) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -106,21 +106,19 @@ export class UserAdminService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getPreferences(auth: AuthDto, id: string): Promise<UserPreferencesResponseDto> {
|
async getPreferences(auth: AuthDto, id: string): Promise<UserPreferencesResponseDto> {
|
||||||
const { email } = await this.findOrFail(id, { withDeleted: true });
|
await this.findOrFail(id, { withDeleted: true });
|
||||||
const metadata = await this.userRepository.getMetadata(id);
|
const metadata = await this.userRepository.getMetadata(id);
|
||||||
const preferences = getPreferences(email, metadata);
|
return mapPreferences(getPreferences(metadata));
|
||||||
return mapPreferences(preferences);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updatePreferences(auth: AuthDto, id: string, dto: UserPreferencesUpdateDto) {
|
async updatePreferences(auth: AuthDto, id: string, dto: UserPreferencesUpdateDto) {
|
||||||
const { email } = await this.findOrFail(id, { withDeleted: false });
|
await this.findOrFail(id, { withDeleted: false });
|
||||||
const metadata = await this.userRepository.getMetadata(id);
|
const metadata = await this.userRepository.getMetadata(id);
|
||||||
const preferences = getPreferences(email, metadata);
|
const newPreferences = mergePreferences(getPreferences(metadata), dto);
|
||||||
const newPreferences = mergePreferences(preferences, dto);
|
|
||||||
|
|
||||||
await this.userRepository.upsertMetadata(id, {
|
await this.userRepository.upsertMetadata(id, {
|
||||||
key: UserMetadataKey.PREFERENCES,
|
key: UserMetadataKey.PREFERENCES,
|
||||||
value: getPreferencesPartial({ email }, newPreferences),
|
value: getPreferencesPartial(newPreferences),
|
||||||
});
|
});
|
||||||
|
|
||||||
return mapPreferences(newPreferences);
|
return mapPreferences(newPreferences);
|
||||||
|
@ -53,6 +53,7 @@ export class UserService extends BaseService {
|
|||||||
const update: Updateable<UserTable> = {
|
const update: Updateable<UserTable> = {
|
||||||
email: dto.email,
|
email: dto.email,
|
||||||
name: dto.name,
|
name: dto.name,
|
||||||
|
avatarColor: dto.avatarColor,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (dto.password) {
|
if (dto.password) {
|
||||||
@ -68,18 +69,16 @@ export class UserService extends BaseService {
|
|||||||
|
|
||||||
async getMyPreferences(auth: AuthDto): Promise<UserPreferencesResponseDto> {
|
async getMyPreferences(auth: AuthDto): Promise<UserPreferencesResponseDto> {
|
||||||
const metadata = await this.userRepository.getMetadata(auth.user.id);
|
const metadata = await this.userRepository.getMetadata(auth.user.id);
|
||||||
const preferences = getPreferences(auth.user.email, metadata);
|
return mapPreferences(getPreferences(metadata));
|
||||||
return mapPreferences(preferences);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateMyPreferences(auth: AuthDto, dto: UserPreferencesUpdateDto) {
|
async updateMyPreferences(auth: AuthDto, dto: UserPreferencesUpdateDto) {
|
||||||
const metadata = await this.userRepository.getMetadata(auth.user.id);
|
const metadata = await this.userRepository.getMetadata(auth.user.id);
|
||||||
const current = getPreferences(auth.user.email, metadata);
|
const updated = mergePreferences(getPreferences(metadata), dto);
|
||||||
const updated = mergePreferences(current, dto);
|
|
||||||
|
|
||||||
await this.userRepository.upsertMetadata(auth.user.id, {
|
await this.userRepository.upsertMetadata(auth.user.id, {
|
||||||
key: UserMetadataKey.PREFERENCES,
|
key: UserMetadataKey.PREFERENCES,
|
||||||
value: getPreferencesPartial(auth.user, updated),
|
value: getPreferencesPartial(updated),
|
||||||
});
|
});
|
||||||
|
|
||||||
return mapPreferences(updated);
|
return mapPreferences(updated);
|
||||||
|
@ -11,7 +11,6 @@ import {
|
|||||||
SyncEntityType,
|
SyncEntityType,
|
||||||
SystemMetadataKey,
|
SystemMetadataKey,
|
||||||
TranscodeTarget,
|
TranscodeTarget,
|
||||||
UserAvatarColor,
|
|
||||||
UserMetadataKey,
|
UserMetadataKey,
|
||||||
VideoCodec,
|
VideoCodec,
|
||||||
} from 'src/enum';
|
} from 'src/enum';
|
||||||
@ -486,9 +485,6 @@ export interface UserPreferences {
|
|||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
sidebarWeb: boolean;
|
sidebarWeb: boolean;
|
||||||
};
|
};
|
||||||
avatar: {
|
|
||||||
color: UserAvatarColor;
|
|
||||||
};
|
|
||||||
emailNotifications: {
|
emailNotifications: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
albumInvite: boolean;
|
albumInvite: boolean;
|
||||||
|
@ -1,16 +1,11 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { UserPreferencesUpdateDto } from 'src/dtos/user-preferences.dto';
|
import { UserPreferencesUpdateDto } from 'src/dtos/user-preferences.dto';
|
||||||
import { UserAvatarColor, UserMetadataKey } from 'src/enum';
|
import { UserMetadataKey } from 'src/enum';
|
||||||
import { DeepPartial, UserMetadataItem, UserPreferences } from 'src/types';
|
import { DeepPartial, UserMetadataItem, UserPreferences } from 'src/types';
|
||||||
import { HumanReadableSize } from 'src/utils/bytes';
|
import { HumanReadableSize } from 'src/utils/bytes';
|
||||||
import { getKeysDeep } from 'src/utils/misc';
|
import { getKeysDeep } from 'src/utils/misc';
|
||||||
|
|
||||||
const getDefaultPreferences = (user: { email: string }): UserPreferences => {
|
const getDefaultPreferences = (): UserPreferences => {
|
||||||
const values = Object.values(UserAvatarColor);
|
|
||||||
const randomIndex = Math.floor(
|
|
||||||
[...user.email].map((letter) => letter.codePointAt(0) ?? 0).reduce((a, b) => a + b, 0) % values.length,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
folders: {
|
folders: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
@ -34,9 +29,6 @@ const getDefaultPreferences = (user: { email: string }): UserPreferences => {
|
|||||||
enabled: false,
|
enabled: false,
|
||||||
sidebarWeb: false,
|
sidebarWeb: false,
|
||||||
},
|
},
|
||||||
avatar: {
|
|
||||||
color: values[randomIndex],
|
|
||||||
},
|
|
||||||
emailNotifications: {
|
emailNotifications: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
albumInvite: true,
|
albumInvite: true,
|
||||||
@ -53,8 +45,8 @@ const getDefaultPreferences = (user: { email: string }): UserPreferences => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getPreferences = (email: string, metadata: UserMetadataItem[]): UserPreferences => {
|
export const getPreferences = (metadata: UserMetadataItem[]): UserPreferences => {
|
||||||
const preferences = getDefaultPreferences({ email });
|
const preferences = getDefaultPreferences();
|
||||||
const item = metadata.find(({ key }) => key === UserMetadataKey.PREFERENCES);
|
const item = metadata.find(({ key }) => key === UserMetadataKey.PREFERENCES);
|
||||||
const partial = item?.value || {};
|
const partial = item?.value || {};
|
||||||
for (const property of getKeysDeep(partial)) {
|
for (const property of getKeysDeep(partial)) {
|
||||||
@ -64,8 +56,8 @@ export const getPreferences = (email: string, metadata: UserMetadataItem[]): Use
|
|||||||
return preferences;
|
return preferences;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getPreferencesPartial = (user: { email: string }, newPreferences: UserPreferences) => {
|
export const getPreferencesPartial = (newPreferences: UserPreferences) => {
|
||||||
const defaultPreferences = getDefaultPreferences(user);
|
const defaultPreferences = getDefaultPreferences();
|
||||||
const partial: DeepPartial<UserPreferences> = {};
|
const partial: DeepPartial<UserPreferences> = {};
|
||||||
for (const property of getKeysDeep(defaultPreferences)) {
|
for (const property of getKeysDeep(defaultPreferences)) {
|
||||||
const newValue = _.get(newPreferences, property);
|
const newValue = _.get(newPreferences, property);
|
||||||
|
12
server/test/fixtures/user.stub.ts
vendored
12
server/test/fixtures/user.stub.ts
vendored
@ -1,5 +1,5 @@
|
|||||||
import { UserAdmin } from 'src/database';
|
import { UserAdmin } from 'src/database';
|
||||||
import { UserAvatarColor, UserMetadataKey, UserStatus } from 'src/enum';
|
import { UserStatus } from 'src/enum';
|
||||||
import { authStub } from 'test/fixtures/auth.stub';
|
import { authStub } from 'test/fixtures/auth.stub';
|
||||||
|
|
||||||
export const userStub = {
|
export const userStub = {
|
||||||
@ -12,6 +12,7 @@ export const userStub = {
|
|||||||
storageLabel: 'admin',
|
storageLabel: 'admin',
|
||||||
oauthId: '',
|
oauthId: '',
|
||||||
shouldChangePassword: false,
|
shouldChangePassword: false,
|
||||||
|
avatarColor: null,
|
||||||
profileImagePath: '',
|
profileImagePath: '',
|
||||||
createdAt: new Date('2021-01-01'),
|
createdAt: new Date('2021-01-01'),
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
@ -28,16 +29,12 @@ export const userStub = {
|
|||||||
storageLabel: null,
|
storageLabel: null,
|
||||||
oauthId: '',
|
oauthId: '',
|
||||||
shouldChangePassword: false,
|
shouldChangePassword: false,
|
||||||
|
avatarColor: null,
|
||||||
profileImagePath: '',
|
profileImagePath: '',
|
||||||
createdAt: new Date('2021-01-01'),
|
createdAt: new Date('2021-01-01'),
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
updatedAt: new Date('2021-01-01'),
|
updatedAt: new Date('2021-01-01'),
|
||||||
metadata: [
|
metadata: [],
|
||||||
{
|
|
||||||
key: UserMetadataKey.PREFERENCES,
|
|
||||||
value: { avatar: { color: UserAvatarColor.PRIMARY } },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
quotaSizeInBytes: null,
|
quotaSizeInBytes: null,
|
||||||
quotaUsageInBytes: 0,
|
quotaUsageInBytes: 0,
|
||||||
},
|
},
|
||||||
@ -50,6 +47,7 @@ export const userStub = {
|
|||||||
storageLabel: null,
|
storageLabel: null,
|
||||||
oauthId: '',
|
oauthId: '',
|
||||||
shouldChangePassword: false,
|
shouldChangePassword: false,
|
||||||
|
avatarColor: null,
|
||||||
profileImagePath: '',
|
profileImagePath: '',
|
||||||
createdAt: new Date('2021-01-01'),
|
createdAt: new Date('2021-01-01'),
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
|
@ -140,6 +140,7 @@ const userFactory = (user: Partial<User> = {}) => ({
|
|||||||
id: newUuid(),
|
id: newUuid(),
|
||||||
name: 'Test User',
|
name: 'Test User',
|
||||||
email: 'test@immich.cloud',
|
email: 'test@immich.cloud',
|
||||||
|
avatarColor: null,
|
||||||
profileImagePath: '',
|
profileImagePath: '',
|
||||||
profileChangedAt: newDate(),
|
profileChangedAt: newDate(),
|
||||||
...user,
|
...user,
|
||||||
@ -155,6 +156,7 @@ const userAdminFactory = (user: Partial<UserAdmin> = {}) => {
|
|||||||
storageLabel = null,
|
storageLabel = null,
|
||||||
shouldChangePassword = false,
|
shouldChangePassword = false,
|
||||||
isAdmin = false,
|
isAdmin = false,
|
||||||
|
avatarColor = null,
|
||||||
createdAt = newDate(),
|
createdAt = newDate(),
|
||||||
updatedAt = newDate(),
|
updatedAt = newDate(),
|
||||||
deletedAt = null,
|
deletedAt = null,
|
||||||
@ -173,6 +175,7 @@ const userAdminFactory = (user: Partial<UserAdmin> = {}) => {
|
|||||||
storageLabel,
|
storageLabel,
|
||||||
shouldChangePassword,
|
shouldChangePassword,
|
||||||
isAdmin,
|
isAdmin,
|
||||||
|
avatarColor,
|
||||||
createdAt,
|
createdAt,
|
||||||
updatedAt,
|
updatedAt,
|
||||||
deletedAt,
|
deletedAt,
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import { preferences, user } from '$lib/stores/user.store';
|
import { user } from '$lib/stores/user.store';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { deleteProfileImage, updateMyPreferences, type UserAvatarColor } from '@immich/sdk';
|
import { deleteProfileImage, updateMyUser, type UserAvatarColor } from '@immich/sdk';
|
||||||
import { mdiCog, mdiLogout, mdiPencil, mdiWrench } from '@mdi/js';
|
import { mdiCog, mdiLogout, mdiPencil, mdiWrench } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
@ -30,8 +30,7 @@
|
|||||||
await deleteProfileImage();
|
await deleteProfileImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
$preferences = await updateMyPreferences({ userPreferencesUpdateDto: { avatar: { color } } });
|
$user = await updateMyUser({ userUpdateMeDto: { avatarColor: color } });
|
||||||
$user = { ...$user, profileImagePath: '', avatarColor: $preferences.avatar.color };
|
|
||||||
isShowSelectAvatar = false;
|
isShowSelectAvatar = false;
|
||||||
|
|
||||||
notificationController.show({
|
notificationController.show({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user