mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 19:17:11 -05:00 
			
		
		
		
	feat(web): email notification preference settings (#9934)
* feat(web): email notification preference settings * Update * remove failed api generation file * fix handle album invite return value * Update web/src/lib/components/user-settings-page/notifications-settings.svelte Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com> * wording * test --------- Co-authored-by: Daniel Dietzler <mail@ddietzler.dev> Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									15474e81b2
								
							
						
					
					
						commit
						b3ee394fdc
					
				@ -250,10 +250,18 @@ describe('/admin/users', () => {
 | 
				
			|||||||
        .set('Authorization', `Bearer ${admin.accessToken}`);
 | 
					        .set('Authorization', `Bearer ${admin.accessToken}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(status).toBe(200);
 | 
					      expect(status).toBe(200);
 | 
				
			||||||
      expect(body).toEqual({ avatar: { color: 'orange' }, memories: { enabled: false } });
 | 
					      expect(body).toEqual({
 | 
				
			||||||
 | 
					        avatar: { color: 'orange' },
 | 
				
			||||||
 | 
					        memories: { enabled: false },
 | 
				
			||||||
 | 
					        emailNotifications: { enabled: true, albumInvite: true, albumUpdate: true },
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const after = await getUserPreferencesAdmin({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
 | 
					      const after = await getUserPreferencesAdmin({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
 | 
				
			||||||
      expect(after).toEqual({ avatar: { color: 'orange' }, memories: { enabled: false } });
 | 
					      expect(after).toEqual({
 | 
				
			||||||
 | 
					        avatar: { color: 'orange' },
 | 
				
			||||||
 | 
					        memories: { enabled: false },
 | 
				
			||||||
 | 
					        emailNotifications: { enabled: true, albumInvite: true, albumUpdate: true },
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								mobile/openapi/README.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								mobile/openapi/README.md
									
									
									
										generated
									
									
									
								
							@ -294,6 +294,8 @@ Class | Method | HTTP request | Description
 | 
				
			|||||||
 - [DownloadResponseDto](doc//DownloadResponseDto.md)
 | 
					 - [DownloadResponseDto](doc//DownloadResponseDto.md)
 | 
				
			||||||
 - [DuplicateDetectionConfig](doc//DuplicateDetectionConfig.md)
 | 
					 - [DuplicateDetectionConfig](doc//DuplicateDetectionConfig.md)
 | 
				
			||||||
 - [DuplicateResponseDto](doc//DuplicateResponseDto.md)
 | 
					 - [DuplicateResponseDto](doc//DuplicateResponseDto.md)
 | 
				
			||||||
 | 
					 - [EmailNotificationsResponse](doc//EmailNotificationsResponse.md)
 | 
				
			||||||
 | 
					 - [EmailNotificationsUpdate](doc//EmailNotificationsUpdate.md)
 | 
				
			||||||
 - [EntityType](doc//EntityType.md)
 | 
					 - [EntityType](doc//EntityType.md)
 | 
				
			||||||
 - [ExifResponseDto](doc//ExifResponseDto.md)
 | 
					 - [ExifResponseDto](doc//ExifResponseDto.md)
 | 
				
			||||||
 - [FaceDto](doc//FaceDto.md)
 | 
					 - [FaceDto](doc//FaceDto.md)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								mobile/openapi/lib/api.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								mobile/openapi/lib/api.dart
									
									
									
										generated
									
									
									
								
							@ -121,6 +121,8 @@ part 'model/download_info_dto.dart';
 | 
				
			|||||||
part 'model/download_response_dto.dart';
 | 
					part 'model/download_response_dto.dart';
 | 
				
			||||||
part 'model/duplicate_detection_config.dart';
 | 
					part 'model/duplicate_detection_config.dart';
 | 
				
			||||||
part 'model/duplicate_response_dto.dart';
 | 
					part 'model/duplicate_response_dto.dart';
 | 
				
			||||||
 | 
					part 'model/email_notifications_response.dart';
 | 
				
			||||||
 | 
					part 'model/email_notifications_update.dart';
 | 
				
			||||||
part 'model/entity_type.dart';
 | 
					part 'model/entity_type.dart';
 | 
				
			||||||
part 'model/exif_response_dto.dart';
 | 
					part 'model/exif_response_dto.dart';
 | 
				
			||||||
part 'model/face_dto.dart';
 | 
					part 'model/face_dto.dart';
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								mobile/openapi/lib/api_client.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								mobile/openapi/lib/api_client.dart
									
									
									
										generated
									
									
									
								
							@ -306,6 +306,10 @@ class ApiClient {
 | 
				
			|||||||
          return DuplicateDetectionConfig.fromJson(value);
 | 
					          return DuplicateDetectionConfig.fromJson(value);
 | 
				
			||||||
        case 'DuplicateResponseDto':
 | 
					        case 'DuplicateResponseDto':
 | 
				
			||||||
          return DuplicateResponseDto.fromJson(value);
 | 
					          return DuplicateResponseDto.fromJson(value);
 | 
				
			||||||
 | 
					        case 'EmailNotificationsResponse':
 | 
				
			||||||
 | 
					          return EmailNotificationsResponse.fromJson(value);
 | 
				
			||||||
 | 
					        case 'EmailNotificationsUpdate':
 | 
				
			||||||
 | 
					          return EmailNotificationsUpdate.fromJson(value);
 | 
				
			||||||
        case 'EntityType':
 | 
					        case 'EntityType':
 | 
				
			||||||
          return EntityTypeTypeTransformer().decode(value);
 | 
					          return EntityTypeTypeTransformer().decode(value);
 | 
				
			||||||
        case 'ExifResponseDto':
 | 
					        case 'ExifResponseDto':
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										114
									
								
								mobile/openapi/lib/model/email_notifications_response.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								mobile/openapi/lib/model/email_notifications_response.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							@ -0,0 +1,114 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// 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 EmailNotificationsResponse {
 | 
				
			||||||
 | 
					  /// Returns a new [EmailNotificationsResponse] instance.
 | 
				
			||||||
 | 
					  EmailNotificationsResponse({
 | 
				
			||||||
 | 
					    required this.albumInvite,
 | 
				
			||||||
 | 
					    required this.albumUpdate,
 | 
				
			||||||
 | 
					    required this.enabled,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool albumInvite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool albumUpdate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool enabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  bool operator ==(Object other) => identical(this, other) || other is EmailNotificationsResponse &&
 | 
				
			||||||
 | 
					    other.albumInvite == albumInvite &&
 | 
				
			||||||
 | 
					    other.albumUpdate == albumUpdate &&
 | 
				
			||||||
 | 
					    other.enabled == enabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  int get hashCode =>
 | 
				
			||||||
 | 
					    // ignore: unnecessary_parenthesis
 | 
				
			||||||
 | 
					    (albumInvite.hashCode) +
 | 
				
			||||||
 | 
					    (albumUpdate.hashCode) +
 | 
				
			||||||
 | 
					    (enabled.hashCode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String toString() => 'EmailNotificationsResponse[albumInvite=$albumInvite, albumUpdate=$albumUpdate, enabled=$enabled]';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Map<String, dynamic> toJson() {
 | 
				
			||||||
 | 
					    final json = <String, dynamic>{};
 | 
				
			||||||
 | 
					      json[r'albumInvite'] = this.albumInvite;
 | 
				
			||||||
 | 
					      json[r'albumUpdate'] = this.albumUpdate;
 | 
				
			||||||
 | 
					      json[r'enabled'] = this.enabled;
 | 
				
			||||||
 | 
					    return json;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Returns a new [EmailNotificationsResponse] instance and imports its values from
 | 
				
			||||||
 | 
					  /// [value] if it's a [Map], null otherwise.
 | 
				
			||||||
 | 
					  // ignore: prefer_constructors_over_static_methods
 | 
				
			||||||
 | 
					  static EmailNotificationsResponse? fromJson(dynamic value) {
 | 
				
			||||||
 | 
					    if (value is Map) {
 | 
				
			||||||
 | 
					      final json = value.cast<String, dynamic>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return EmailNotificationsResponse(
 | 
				
			||||||
 | 
					        albumInvite: mapValueOfType<bool>(json, r'albumInvite')!,
 | 
				
			||||||
 | 
					        albumUpdate: mapValueOfType<bool>(json, r'albumUpdate')!,
 | 
				
			||||||
 | 
					        enabled: mapValueOfType<bool>(json, r'enabled')!,
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static List<EmailNotificationsResponse> listFromJson(dynamic json, {bool growable = false,}) {
 | 
				
			||||||
 | 
					    final result = <EmailNotificationsResponse>[];
 | 
				
			||||||
 | 
					    if (json is List && json.isNotEmpty) {
 | 
				
			||||||
 | 
					      for (final row in json) {
 | 
				
			||||||
 | 
					        final value = EmailNotificationsResponse.fromJson(row);
 | 
				
			||||||
 | 
					        if (value != null) {
 | 
				
			||||||
 | 
					          result.add(value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result.toList(growable: growable);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static Map<String, EmailNotificationsResponse> mapFromJson(dynamic json) {
 | 
				
			||||||
 | 
					    final map = <String, EmailNotificationsResponse>{};
 | 
				
			||||||
 | 
					    if (json is Map && json.isNotEmpty) {
 | 
				
			||||||
 | 
					      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
				
			||||||
 | 
					      for (final entry in json.entries) {
 | 
				
			||||||
 | 
					        final value = EmailNotificationsResponse.fromJson(entry.value);
 | 
				
			||||||
 | 
					        if (value != null) {
 | 
				
			||||||
 | 
					          map[entry.key] = value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return map;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // maps a json object with a list of EmailNotificationsResponse-objects as value to a dart map
 | 
				
			||||||
 | 
					  static Map<String, List<EmailNotificationsResponse>> mapListFromJson(dynamic json, {bool growable = false,}) {
 | 
				
			||||||
 | 
					    final map = <String, List<EmailNotificationsResponse>>{};
 | 
				
			||||||
 | 
					    if (json is Map && json.isNotEmpty) {
 | 
				
			||||||
 | 
					      // ignore: parameter_assignments
 | 
				
			||||||
 | 
					      json = json.cast<String, dynamic>();
 | 
				
			||||||
 | 
					      for (final entry in json.entries) {
 | 
				
			||||||
 | 
					        map[entry.key] = EmailNotificationsResponse.listFromJson(entry.value, growable: growable,);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return map;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// The list of required keys that must be present in a JSON.
 | 
				
			||||||
 | 
					  static const requiredKeys = <String>{
 | 
				
			||||||
 | 
					    'albumInvite',
 | 
				
			||||||
 | 
					    'albumUpdate',
 | 
				
			||||||
 | 
					    'enabled',
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										141
									
								
								mobile/openapi/lib/model/email_notifications_update.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								mobile/openapi/lib/model/email_notifications_update.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							@ -0,0 +1,141 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// 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 EmailNotificationsUpdate {
 | 
				
			||||||
 | 
					  /// Returns a new [EmailNotificationsUpdate] instance.
 | 
				
			||||||
 | 
					  EmailNotificationsUpdate({
 | 
				
			||||||
 | 
					    this.albumInvite,
 | 
				
			||||||
 | 
					    this.albumUpdate,
 | 
				
			||||||
 | 
					    this.enabled,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ///
 | 
				
			||||||
 | 
					  /// 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.
 | 
				
			||||||
 | 
					  ///
 | 
				
			||||||
 | 
					  bool? albumInvite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ///
 | 
				
			||||||
 | 
					  /// 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.
 | 
				
			||||||
 | 
					  ///
 | 
				
			||||||
 | 
					  bool? albumUpdate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ///
 | 
				
			||||||
 | 
					  /// 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.
 | 
				
			||||||
 | 
					  ///
 | 
				
			||||||
 | 
					  bool? enabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  bool operator ==(Object other) => identical(this, other) || other is EmailNotificationsUpdate &&
 | 
				
			||||||
 | 
					    other.albumInvite == albumInvite &&
 | 
				
			||||||
 | 
					    other.albumUpdate == albumUpdate &&
 | 
				
			||||||
 | 
					    other.enabled == enabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  int get hashCode =>
 | 
				
			||||||
 | 
					    // ignore: unnecessary_parenthesis
 | 
				
			||||||
 | 
					    (albumInvite == null ? 0 : albumInvite!.hashCode) +
 | 
				
			||||||
 | 
					    (albumUpdate == null ? 0 : albumUpdate!.hashCode) +
 | 
				
			||||||
 | 
					    (enabled == null ? 0 : enabled!.hashCode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String toString() => 'EmailNotificationsUpdate[albumInvite=$albumInvite, albumUpdate=$albumUpdate, enabled=$enabled]';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Map<String, dynamic> toJson() {
 | 
				
			||||||
 | 
					    final json = <String, dynamic>{};
 | 
				
			||||||
 | 
					    if (this.albumInvite != null) {
 | 
				
			||||||
 | 
					      json[r'albumInvite'] = this.albumInvite;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					    //  json[r'albumInvite'] = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (this.albumUpdate != null) {
 | 
				
			||||||
 | 
					      json[r'albumUpdate'] = this.albumUpdate;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					    //  json[r'albumUpdate'] = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (this.enabled != null) {
 | 
				
			||||||
 | 
					      json[r'enabled'] = this.enabled;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					    //  json[r'enabled'] = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return json;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Returns a new [EmailNotificationsUpdate] instance and imports its values from
 | 
				
			||||||
 | 
					  /// [value] if it's a [Map], null otherwise.
 | 
				
			||||||
 | 
					  // ignore: prefer_constructors_over_static_methods
 | 
				
			||||||
 | 
					  static EmailNotificationsUpdate? fromJson(dynamic value) {
 | 
				
			||||||
 | 
					    if (value is Map) {
 | 
				
			||||||
 | 
					      final json = value.cast<String, dynamic>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return EmailNotificationsUpdate(
 | 
				
			||||||
 | 
					        albumInvite: mapValueOfType<bool>(json, r'albumInvite'),
 | 
				
			||||||
 | 
					        albumUpdate: mapValueOfType<bool>(json, r'albumUpdate'),
 | 
				
			||||||
 | 
					        enabled: mapValueOfType<bool>(json, r'enabled'),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static List<EmailNotificationsUpdate> listFromJson(dynamic json, {bool growable = false,}) {
 | 
				
			||||||
 | 
					    final result = <EmailNotificationsUpdate>[];
 | 
				
			||||||
 | 
					    if (json is List && json.isNotEmpty) {
 | 
				
			||||||
 | 
					      for (final row in json) {
 | 
				
			||||||
 | 
					        final value = EmailNotificationsUpdate.fromJson(row);
 | 
				
			||||||
 | 
					        if (value != null) {
 | 
				
			||||||
 | 
					          result.add(value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result.toList(growable: growable);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static Map<String, EmailNotificationsUpdate> mapFromJson(dynamic json) {
 | 
				
			||||||
 | 
					    final map = <String, EmailNotificationsUpdate>{};
 | 
				
			||||||
 | 
					    if (json is Map && json.isNotEmpty) {
 | 
				
			||||||
 | 
					      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
				
			||||||
 | 
					      for (final entry in json.entries) {
 | 
				
			||||||
 | 
					        final value = EmailNotificationsUpdate.fromJson(entry.value);
 | 
				
			||||||
 | 
					        if (value != null) {
 | 
				
			||||||
 | 
					          map[entry.key] = value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return map;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // maps a json object with a list of EmailNotificationsUpdate-objects as value to a dart map
 | 
				
			||||||
 | 
					  static Map<String, List<EmailNotificationsUpdate>> mapListFromJson(dynamic json, {bool growable = false,}) {
 | 
				
			||||||
 | 
					    final map = <String, List<EmailNotificationsUpdate>>{};
 | 
				
			||||||
 | 
					    if (json is Map && json.isNotEmpty) {
 | 
				
			||||||
 | 
					      // ignore: parameter_assignments
 | 
				
			||||||
 | 
					      json = json.cast<String, dynamic>();
 | 
				
			||||||
 | 
					      for (final entry in json.entries) {
 | 
				
			||||||
 | 
					        map[entry.key] = EmailNotificationsUpdate.listFromJson(entry.value, growable: growable,);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return map;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// The list of required keys that must be present in a JSON.
 | 
				
			||||||
 | 
					  static const requiredKeys = <String>{
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -14,30 +14,36 @@ class UserPreferencesResponseDto {
 | 
				
			|||||||
  /// Returns a new [UserPreferencesResponseDto] instance.
 | 
					  /// Returns a new [UserPreferencesResponseDto] instance.
 | 
				
			||||||
  UserPreferencesResponseDto({
 | 
					  UserPreferencesResponseDto({
 | 
				
			||||||
    required this.avatar,
 | 
					    required this.avatar,
 | 
				
			||||||
 | 
					    required this.emailNotifications,
 | 
				
			||||||
    required this.memories,
 | 
					    required this.memories,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  AvatarResponse avatar;
 | 
					  AvatarResponse avatar;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EmailNotificationsResponse emailNotifications;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  MemoryResponse memories;
 | 
					  MemoryResponse memories;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @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.avatar == avatar &&
 | 
				
			||||||
 | 
					    other.emailNotifications == emailNotifications &&
 | 
				
			||||||
    other.memories == memories;
 | 
					    other.memories == memories;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  int get hashCode =>
 | 
					  int get hashCode =>
 | 
				
			||||||
    // ignore: unnecessary_parenthesis
 | 
					    // ignore: unnecessary_parenthesis
 | 
				
			||||||
    (avatar.hashCode) +
 | 
					    (avatar.hashCode) +
 | 
				
			||||||
 | 
					    (emailNotifications.hashCode) +
 | 
				
			||||||
    (memories.hashCode);
 | 
					    (memories.hashCode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String toString() => 'UserPreferencesResponseDto[avatar=$avatar, memories=$memories]';
 | 
					  String toString() => 'UserPreferencesResponseDto[avatar=$avatar, emailNotifications=$emailNotifications, memories=$memories]';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Map<String, dynamic> toJson() {
 | 
					  Map<String, dynamic> toJson() {
 | 
				
			||||||
    final json = <String, dynamic>{};
 | 
					    final json = <String, dynamic>{};
 | 
				
			||||||
      json[r'avatar'] = this.avatar;
 | 
					      json[r'avatar'] = this.avatar;
 | 
				
			||||||
 | 
					      json[r'emailNotifications'] = this.emailNotifications;
 | 
				
			||||||
      json[r'memories'] = this.memories;
 | 
					      json[r'memories'] = this.memories;
 | 
				
			||||||
    return json;
 | 
					    return json;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -51,6 +57,7 @@ class UserPreferencesResponseDto {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      return UserPreferencesResponseDto(
 | 
					      return UserPreferencesResponseDto(
 | 
				
			||||||
        avatar: AvatarResponse.fromJson(json[r'avatar'])!,
 | 
					        avatar: AvatarResponse.fromJson(json[r'avatar'])!,
 | 
				
			||||||
 | 
					        emailNotifications: EmailNotificationsResponse.fromJson(json[r'emailNotifications'])!,
 | 
				
			||||||
        memories: MemoryResponse.fromJson(json[r'memories'])!,
 | 
					        memories: MemoryResponse.fromJson(json[r'memories'])!,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -100,6 +107,7 @@ 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',
 | 
					    'avatar',
 | 
				
			||||||
 | 
					    'emailNotifications',
 | 
				
			||||||
    'memories',
 | 
					    'memories',
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,7 @@ class UserPreferencesUpdateDto {
 | 
				
			|||||||
  /// Returns a new [UserPreferencesUpdateDto] instance.
 | 
					  /// Returns a new [UserPreferencesUpdateDto] instance.
 | 
				
			||||||
  UserPreferencesUpdateDto({
 | 
					  UserPreferencesUpdateDto({
 | 
				
			||||||
    this.avatar,
 | 
					    this.avatar,
 | 
				
			||||||
 | 
					    this.emailNotifications,
 | 
				
			||||||
    this.memories,
 | 
					    this.memories,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -25,6 +26,14 @@ class UserPreferencesUpdateDto {
 | 
				
			|||||||
  ///
 | 
					  ///
 | 
				
			||||||
  AvatarUpdate? avatar;
 | 
					  AvatarUpdate? avatar;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ///
 | 
				
			||||||
 | 
					  /// 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.
 | 
				
			||||||
 | 
					  ///
 | 
				
			||||||
 | 
					  EmailNotificationsUpdate? emailNotifications;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ///
 | 
					  ///
 | 
				
			||||||
  /// 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
 | 
				
			||||||
@ -36,16 +45,18 @@ class UserPreferencesUpdateDto {
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  bool operator ==(Object other) => identical(this, other) || other is UserPreferencesUpdateDto &&
 | 
					  bool operator ==(Object other) => identical(this, other) || other is UserPreferencesUpdateDto &&
 | 
				
			||||||
    other.avatar == avatar &&
 | 
					    other.avatar == avatar &&
 | 
				
			||||||
 | 
					    other.emailNotifications == emailNotifications &&
 | 
				
			||||||
    other.memories == memories;
 | 
					    other.memories == memories;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  int get hashCode =>
 | 
					  int get hashCode =>
 | 
				
			||||||
    // ignore: unnecessary_parenthesis
 | 
					    // ignore: unnecessary_parenthesis
 | 
				
			||||||
    (avatar == null ? 0 : avatar!.hashCode) +
 | 
					    (avatar == null ? 0 : avatar!.hashCode) +
 | 
				
			||||||
 | 
					    (emailNotifications == null ? 0 : emailNotifications!.hashCode) +
 | 
				
			||||||
    (memories == null ? 0 : memories!.hashCode);
 | 
					    (memories == null ? 0 : memories!.hashCode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String toString() => 'UserPreferencesUpdateDto[avatar=$avatar, memories=$memories]';
 | 
					  String toString() => 'UserPreferencesUpdateDto[avatar=$avatar, emailNotifications=$emailNotifications, memories=$memories]';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Map<String, dynamic> toJson() {
 | 
					  Map<String, dynamic> toJson() {
 | 
				
			||||||
    final json = <String, dynamic>{};
 | 
					    final json = <String, dynamic>{};
 | 
				
			||||||
@ -54,6 +65,11 @@ class UserPreferencesUpdateDto {
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
    //  json[r'avatar'] = null;
 | 
					    //  json[r'avatar'] = null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (this.emailNotifications != null) {
 | 
				
			||||||
 | 
					      json[r'emailNotifications'] = this.emailNotifications;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					    //  json[r'emailNotifications'] = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (this.memories != null) {
 | 
					    if (this.memories != null) {
 | 
				
			||||||
      json[r'memories'] = this.memories;
 | 
					      json[r'memories'] = this.memories;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
@ -71,6 +87,7 @@ class UserPreferencesUpdateDto {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      return UserPreferencesUpdateDto(
 | 
					      return UserPreferencesUpdateDto(
 | 
				
			||||||
        avatar: AvatarUpdate.fromJson(json[r'avatar']),
 | 
					        avatar: AvatarUpdate.fromJson(json[r'avatar']),
 | 
				
			||||||
 | 
					        emailNotifications: EmailNotificationsUpdate.fromJson(json[r'emailNotifications']),
 | 
				
			||||||
        memories: MemoryUpdate.fromJson(json[r'memories']),
 | 
					        memories: MemoryUpdate.fromJson(json[r'memories']),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -8152,6 +8152,39 @@
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "type": "object"
 | 
					        "type": "object"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					      "EmailNotificationsResponse": {
 | 
				
			||||||
 | 
					        "properties": {
 | 
				
			||||||
 | 
					          "albumInvite": {
 | 
				
			||||||
 | 
					            "type": "boolean"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "albumUpdate": {
 | 
				
			||||||
 | 
					            "type": "boolean"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "enabled": {
 | 
				
			||||||
 | 
					            "type": "boolean"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "required": [
 | 
				
			||||||
 | 
					          "albumInvite",
 | 
				
			||||||
 | 
					          "albumUpdate",
 | 
				
			||||||
 | 
					          "enabled"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "type": "object"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "EmailNotificationsUpdate": {
 | 
				
			||||||
 | 
					        "properties": {
 | 
				
			||||||
 | 
					          "albumInvite": {
 | 
				
			||||||
 | 
					            "type": "boolean"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "albumUpdate": {
 | 
				
			||||||
 | 
					            "type": "boolean"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "enabled": {
 | 
				
			||||||
 | 
					            "type": "boolean"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "type": "object"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      "EntityType": {
 | 
					      "EntityType": {
 | 
				
			||||||
        "enum": [
 | 
					        "enum": [
 | 
				
			||||||
          "ASSET",
 | 
					          "ASSET",
 | 
				
			||||||
@ -11205,12 +11238,16 @@
 | 
				
			|||||||
          "avatar": {
 | 
					          "avatar": {
 | 
				
			||||||
            "$ref": "#/components/schemas/AvatarResponse"
 | 
					            "$ref": "#/components/schemas/AvatarResponse"
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
 | 
					          "emailNotifications": {
 | 
				
			||||||
 | 
					            "$ref": "#/components/schemas/EmailNotificationsResponse"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
          "memories": {
 | 
					          "memories": {
 | 
				
			||||||
            "$ref": "#/components/schemas/MemoryResponse"
 | 
					            "$ref": "#/components/schemas/MemoryResponse"
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "required": [
 | 
					        "required": [
 | 
				
			||||||
          "avatar",
 | 
					          "avatar",
 | 
				
			||||||
 | 
					          "emailNotifications",
 | 
				
			||||||
          "memories"
 | 
					          "memories"
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "type": "object"
 | 
					        "type": "object"
 | 
				
			||||||
@ -11220,6 +11257,9 @@
 | 
				
			|||||||
          "avatar": {
 | 
					          "avatar": {
 | 
				
			||||||
            "$ref": "#/components/schemas/AvatarUpdate"
 | 
					            "$ref": "#/components/schemas/AvatarUpdate"
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
 | 
					          "emailNotifications": {
 | 
				
			||||||
 | 
					            "$ref": "#/components/schemas/EmailNotificationsUpdate"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
          "memories": {
 | 
					          "memories": {
 | 
				
			||||||
            "$ref": "#/components/schemas/MemoryUpdate"
 | 
					            "$ref": "#/components/schemas/MemoryUpdate"
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
				
			|||||||
@ -78,21 +78,33 @@ export type UserAdminUpdateDto = {
 | 
				
			|||||||
export type AvatarResponse = {
 | 
					export type AvatarResponse = {
 | 
				
			||||||
    color: UserAvatarColor;
 | 
					    color: UserAvatarColor;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					export type EmailNotificationsResponse = {
 | 
				
			||||||
 | 
					    albumInvite: boolean;
 | 
				
			||||||
 | 
					    albumUpdate: boolean;
 | 
				
			||||||
 | 
					    enabled: boolean;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
export type MemoryResponse = {
 | 
					export type MemoryResponse = {
 | 
				
			||||||
    enabled: boolean;
 | 
					    enabled: boolean;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export type UserPreferencesResponseDto = {
 | 
					export type UserPreferencesResponseDto = {
 | 
				
			||||||
    avatar: AvatarResponse;
 | 
					    avatar: AvatarResponse;
 | 
				
			||||||
 | 
					    emailNotifications: EmailNotificationsResponse;
 | 
				
			||||||
    memories: MemoryResponse;
 | 
					    memories: MemoryResponse;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export type AvatarUpdate = {
 | 
					export type AvatarUpdate = {
 | 
				
			||||||
    color?: UserAvatarColor;
 | 
					    color?: UserAvatarColor;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					export type EmailNotificationsUpdate = {
 | 
				
			||||||
 | 
					    albumInvite?: boolean;
 | 
				
			||||||
 | 
					    albumUpdate?: boolean;
 | 
				
			||||||
 | 
					    enabled?: boolean;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
export type MemoryUpdate = {
 | 
					export type MemoryUpdate = {
 | 
				
			||||||
    enabled?: boolean;
 | 
					    enabled?: boolean;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export type UserPreferencesUpdateDto = {
 | 
					export type UserPreferencesUpdateDto = {
 | 
				
			||||||
    avatar?: AvatarUpdate;
 | 
					    avatar?: AvatarUpdate;
 | 
				
			||||||
 | 
					    emailNotifications?: EmailNotificationsUpdate;
 | 
				
			||||||
    memories?: MemoryUpdate;
 | 
					    memories?: MemoryUpdate;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export type AlbumUserResponseDto = {
 | 
					export type AlbumUserResponseDto = {
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,17 @@ class MemoryUpdate {
 | 
				
			|||||||
  enabled?: boolean;
 | 
					  enabled?: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EmailNotificationsUpdate {
 | 
				
			||||||
 | 
					  @ValidateBoolean({ optional: true })
 | 
				
			||||||
 | 
					  enabled?: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @ValidateBoolean({ optional: true })
 | 
				
			||||||
 | 
					  albumInvite?: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @ValidateBoolean({ optional: true })
 | 
				
			||||||
 | 
					  albumUpdate?: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class UserPreferencesUpdateDto {
 | 
					export class UserPreferencesUpdateDto {
 | 
				
			||||||
  @Optional()
 | 
					  @Optional()
 | 
				
			||||||
  @ValidateNested()
 | 
					  @ValidateNested()
 | 
				
			||||||
@ -26,6 +37,11 @@ export class UserPreferencesUpdateDto {
 | 
				
			|||||||
  @ValidateNested()
 | 
					  @ValidateNested()
 | 
				
			||||||
  @Type(() => MemoryUpdate)
 | 
					  @Type(() => MemoryUpdate)
 | 
				
			||||||
  memories?: MemoryUpdate;
 | 
					  memories?: MemoryUpdate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Optional()
 | 
				
			||||||
 | 
					  @ValidateNested()
 | 
				
			||||||
 | 
					  @Type(() => EmailNotificationsUpdate)
 | 
				
			||||||
 | 
					  emailNotifications?: EmailNotificationsUpdate;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AvatarResponse {
 | 
					class AvatarResponse {
 | 
				
			||||||
@ -37,9 +53,16 @@ class MemoryResponse {
 | 
				
			|||||||
  enabled!: boolean;
 | 
					  enabled!: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EmailNotificationsResponse {
 | 
				
			||||||
 | 
					  enabled!: boolean;
 | 
				
			||||||
 | 
					  albumInvite!: boolean;
 | 
				
			||||||
 | 
					  albumUpdate!: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class UserPreferencesResponseDto implements UserPreferences {
 | 
					export class UserPreferencesResponseDto implements UserPreferences {
 | 
				
			||||||
  memories!: MemoryResponse;
 | 
					  memories!: MemoryResponse;
 | 
				
			||||||
  avatar!: AvatarResponse;
 | 
					  avatar!: AvatarResponse;
 | 
				
			||||||
 | 
					  emailNotifications!: EmailNotificationsResponse;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const mapPreferences = (preferences: UserPreferences): UserPreferencesResponseDto => {
 | 
					export const mapPreferences = (preferences: UserPreferences): UserPreferencesResponseDto => {
 | 
				
			||||||
 | 
				
			|||||||
@ -36,6 +36,11 @@ export interface UserPreferences {
 | 
				
			|||||||
  avatar: {
 | 
					  avatar: {
 | 
				
			||||||
    color: UserAvatarColor;
 | 
					    color: UserAvatarColor;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					  emailNotifications: {
 | 
				
			||||||
 | 
					    enabled: boolean;
 | 
				
			||||||
 | 
					    albumInvite: boolean;
 | 
				
			||||||
 | 
					    albumUpdate: boolean;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getDefaultPreferences = (user: { email: string }): UserPreferences => {
 | 
					export const getDefaultPreferences = (user: { email: string }): UserPreferences => {
 | 
				
			||||||
@ -51,6 +56,11 @@ export const getDefaultPreferences = (user: { email: string }): UserPreferences
 | 
				
			|||||||
    avatar: {
 | 
					    avatar: {
 | 
				
			||||||
      color: values[randomIndex],
 | 
					      color: values[randomIndex],
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    emailNotifications: {
 | 
				
			||||||
 | 
					      enabled: true,
 | 
				
			||||||
 | 
					      albumInvite: true,
 | 
				
			||||||
 | 
					      albumUpdate: true,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -19,6 +19,7 @@ import { ILoggerRepository } from 'src/interfaces/logger.interface';
 | 
				
			|||||||
import { EmailImageAttachment, EmailTemplate, INotificationRepository } from 'src/interfaces/notification.interface';
 | 
					import { EmailImageAttachment, EmailTemplate, INotificationRepository } from 'src/interfaces/notification.interface';
 | 
				
			||||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
 | 
					import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
 | 
				
			||||||
import { IUserRepository } from 'src/interfaces/user.interface';
 | 
					import { IUserRepository } from 'src/interfaces/user.interface';
 | 
				
			||||||
 | 
					import { getPreferences } from 'src/utils/preferences';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Injectable()
 | 
					@Injectable()
 | 
				
			||||||
export class NotificationService {
 | 
					export class NotificationService {
 | 
				
			||||||
@ -95,6 +96,12 @@ export class NotificationService {
 | 
				
			|||||||
      return JobStatus.SKIPPED;
 | 
					      return JobStatus.SKIPPED;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { emailNotifications } = getPreferences(recipient);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!emailNotifications.enabled || !emailNotifications.albumInvite) {
 | 
				
			||||||
 | 
					      return JobStatus.SKIPPED;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const attachment = await this.getAlbumThumbnailAttachment(album);
 | 
					    const attachment = await this.getAlbumThumbnailAttachment(album);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { server } = await this.configCore.getConfig();
 | 
					    const { server } = await this.configCore.getConfig();
 | 
				
			||||||
@ -142,6 +149,12 @@ export class NotificationService {
 | 
				
			|||||||
    const { server } = await this.configCore.getConfig();
 | 
					    const { server } = await this.configCore.getConfig();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (const recipient of recipients) {
 | 
					    for (const recipient of recipients) {
 | 
				
			||||||
 | 
					      const { emailNotifications } = getPreferences(recipient);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!emailNotifications.enabled || !emailNotifications.albumUpdate) {
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const { html, text } = this.notificationRepository.renderEmail({
 | 
					      const { html, text } = this.notificationRepository.renderEmail({
 | 
				
			||||||
        template: EmailTemplate.ALBUM_UPDATE,
 | 
					        template: EmailTemplate.ALBUM_UPDATE,
 | 
				
			||||||
        data: {
 | 
					        data: {
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,75 @@
 | 
				
			|||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					  import {
 | 
				
			||||||
 | 
					    notificationController,
 | 
				
			||||||
 | 
					    NotificationType,
 | 
				
			||||||
 | 
					  } from '$lib/components/shared-components/notification/notification';
 | 
				
			||||||
 | 
					  import { updateMyPreferences } from '@immich/sdk';
 | 
				
			||||||
 | 
					  import { fade } from 'svelte/transition';
 | 
				
			||||||
 | 
					  import { handleError } from '../../utils/handle-error';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
 | 
				
			||||||
 | 
					  import { preferences } from '$lib/stores/user.store';
 | 
				
			||||||
 | 
					  import Button from '../elements/buttons/button.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let emailNotificationsEnabled = $preferences?.emailNotifications?.enabled ?? true;
 | 
				
			||||||
 | 
					  let albumInviteNotificationEnabled = $preferences?.emailNotifications?.albumInvite ?? true;
 | 
				
			||||||
 | 
					  let albumUpdateNotificationEnabled = $preferences?.emailNotifications?.albumUpdate ?? true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleSave = async () => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const data = await updateMyPreferences({
 | 
				
			||||||
 | 
					        userPreferencesUpdateDto: {
 | 
				
			||||||
 | 
					          emailNotifications: {
 | 
				
			||||||
 | 
					            enabled: emailNotificationsEnabled,
 | 
				
			||||||
 | 
					            albumInvite: emailNotificationsEnabled && albumInviteNotificationEnabled,
 | 
				
			||||||
 | 
					            albumUpdate: emailNotificationsEnabled && albumUpdateNotificationEnabled,
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $preferences.emailNotifications.enabled = data.emailNotifications.enabled;
 | 
				
			||||||
 | 
					      $preferences.emailNotifications.albumInvite = data.emailNotifications.albumInvite;
 | 
				
			||||||
 | 
					      $preferences.emailNotifications.albumUpdate = data.emailNotifications.albumUpdate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      notificationController.show({ message: 'Saved settings', type: NotificationType.Info });
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      handleError(error, 'Unable to update settings');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<section class="my-4">
 | 
				
			||||||
 | 
					  <div in:fade={{ duration: 500 }}>
 | 
				
			||||||
 | 
					    <form autocomplete="off" on:submit|preventDefault>
 | 
				
			||||||
 | 
					      <div class="ml-4 mt-4 flex flex-col gap-4">
 | 
				
			||||||
 | 
					        <div class="ml-4">
 | 
				
			||||||
 | 
					          <SettingSwitch
 | 
				
			||||||
 | 
					            title="Enable"
 | 
				
			||||||
 | 
					            subtitle="Toggle email notifications"
 | 
				
			||||||
 | 
					            bind:checked={emailNotificationsEnabled}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="ml-4">
 | 
				
			||||||
 | 
					          <SettingSwitch
 | 
				
			||||||
 | 
					            title="Album Added"
 | 
				
			||||||
 | 
					            subtitle="Receive an email notification when you are added to a shared album"
 | 
				
			||||||
 | 
					            bind:checked={albumInviteNotificationEnabled}
 | 
				
			||||||
 | 
					            disabled={!emailNotificationsEnabled}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="ml-4">
 | 
				
			||||||
 | 
					          <SettingSwitch
 | 
				
			||||||
 | 
					            title="Album Updated"
 | 
				
			||||||
 | 
					            subtitle="Receive an email notification when a shared album has new assets"
 | 
				
			||||||
 | 
					            bind:checked={albumUpdateNotificationEnabled}
 | 
				
			||||||
 | 
					            disabled={!emailNotificationsEnabled}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div class="flex justify-end">
 | 
				
			||||||
 | 
					          <Button type="submit" size="sm" on:click={() => handleSave()}>Save</Button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </form>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</section>
 | 
				
			||||||
@ -15,6 +15,7 @@
 | 
				
			|||||||
  import PartnerSettings from './partner-settings.svelte';
 | 
					  import PartnerSettings from './partner-settings.svelte';
 | 
				
			||||||
  import UserAPIKeyList from './user-api-key-list.svelte';
 | 
					  import UserAPIKeyList from './user-api-key-list.svelte';
 | 
				
			||||||
  import UserProfileSettings from './user-profile-settings.svelte';
 | 
					  import UserProfileSettings from './user-profile-settings.svelte';
 | 
				
			||||||
 | 
					  import NotificationsSettings from '$lib/components/user-settings-page/notifications-settings.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let keys: ApiKeyResponseDto[] = [];
 | 
					  export let keys: ApiKeyResponseDto[] = [];
 | 
				
			||||||
  export let sessions: SessionResponseDto[] = [];
 | 
					  export let sessions: SessionResponseDto[] = [];
 | 
				
			||||||
@ -45,6 +46,10 @@
 | 
				
			|||||||
    <MemoriesSettings />
 | 
					    <MemoriesSettings />
 | 
				
			||||||
  </SettingAccordion>
 | 
					  </SettingAccordion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <SettingAccordion key="notifications" title="Notifications" subtitle="Manage notifications">
 | 
				
			||||||
 | 
					    <NotificationsSettings />
 | 
				
			||||||
 | 
					  </SettingAccordion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  {#if $featureFlags.loaded && $featureFlags.oauth}
 | 
					  {#if $featureFlags.loaded && $featureFlags.oauth}
 | 
				
			||||||
    <SettingAccordion key="oauth" title="OAuth" subtitle="Manage your OAuth connection" isOpen={oauthOpen || undefined}>
 | 
					    <SettingAccordion key="oauth" title="OAuth" subtitle="Manage your OAuth connection" isOpen={oauthOpen || undefined}>
 | 
				
			||||||
      <OAuthSettings user={$user} />
 | 
					      <OAuthSettings user={$user} />
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user