This commit is contained in:
Jason Rasmussen 2024-11-05 09:02:09 -05:00
parent 5edbb93a4d
commit ad9aa9b523
No known key found for this signature in database
GPG Key ID: 2EF24B77EAFA4A41
40 changed files with 6105 additions and 15 deletions

View File

@ -0,0 +1,85 @@
import { LoginResponseDto, login, signUpAdmin } from '@immich/sdk';
import { loginDto, signupDto } from 'src/fixtures';
import { errorDto } from 'src/responses';
import { app, utils } from 'src/utils';
import request from 'supertest';
import { beforeAll, describe, expect, it } from 'vitest';
describe('/sync', () => {
let admin: LoginResponseDto;
beforeAll(async () => {
await utils.resetDatabase();
await signUpAdmin({ signUpDto: signupDto.admin });
admin = await login({ loginCredentialDto: loginDto.admin });
});
describe('GET /sync/acknowledge', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post('/sync/acknowledge');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require a valid timestamp', async () => {
const { status, body } = await request(app)
.post('/sync/acknowledge')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({
type: 'AssetOwner',
timestamp: '2024-10-31 25:25:25',
});
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['timestamp must be a valid ISO 8601 date string']));
});
it('should work', async () => {
const { status } = await request(app)
.post('/sync/acknowledge')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({
type: 'AssetOwner',
timestamp: '2024-10-23T21:01:07.732Z',
});
expect(status).toBe(204);
});
});
describe('GET /sync/stream', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post('/sync/stream');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should reject invalid types', async () => {
const { status, body } = await request(app)
.post('/sync/stream')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ types: ['invalid'] });
expect(status).toBe(400);
expect(body).toEqual(
errorDto.badRequest([expect.stringContaining('each value in types must be one of the following values')]),
);
});
it('should require at least one type', async () => {
const { status, body } = await request(app)
.post('/sync/stream')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ types: [] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest());
});
it('should accept a valid type', async () => {
const response = await request(app)
.post('/sync/stream')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ types: ['AssetOwnerV1'] });
expect(response.status).toBe(200);
expect(response.get('Content-Type')).toBe('application/jsonlines+json; charset=utf-8');
expect(response.body).toEqual('');
});
});
});

View File

@ -201,8 +201,10 @@ Class | Method | HTTP request | Description
*StacksApi* | [**getStack**](doc//StacksApi.md#getstack) | **GET** /stacks/{id} |
*StacksApi* | [**searchStacks**](doc//StacksApi.md#searchstacks) | **GET** /stacks |
*StacksApi* | [**updateStack**](doc//StacksApi.md#updatestack) | **PUT** /stacks/{id} |
*SyncApi* | [**ackSync**](doc//SyncApi.md#acksync) | **POST** /sync/acknowledge |
*SyncApi* | [**getDeltaSync**](doc//SyncApi.md#getdeltasync) | **POST** /sync/delta-sync |
*SyncApi* | [**getFullSyncForUser**](doc//SyncApi.md#getfullsyncforuser) | **POST** /sync/full-sync |
*SyncApi* | [**getSyncStream**](doc//SyncApi.md#getsyncstream) | **POST** /sync/stream |
*SystemConfigApi* | [**getConfig**](doc//SystemConfigApi.md#getconfig) | **GET** /system-config |
*SystemConfigApi* | [**getConfigDefaults**](doc//SystemConfigApi.md#getconfigdefaults) | **GET** /system-config/defaults |
*SystemConfigApi* | [**getStorageTemplateOptions**](doc//SystemConfigApi.md#getstoragetemplateoptions) | **GET** /system-config/storage-template-options |
@ -414,6 +416,21 @@ Class | Method | HTTP request | Description
- [StackCreateDto](doc//StackCreateDto.md)
- [StackResponseDto](doc//StackResponseDto.md)
- [StackUpdateDto](doc//StackUpdateDto.md)
- [SyncAcknowledgeDto](doc//SyncAcknowledgeDto.md)
- [SyncActivityDeleteDtoV1](doc//SyncActivityDeleteDtoV1.md)
- [SyncAlbumAssetDeleteDtoV1](doc//SyncAlbumAssetDeleteDtoV1.md)
- [SyncAlbumAssetDtoV1](doc//SyncAlbumAssetDtoV1.md)
- [SyncAlbumDeleteV1](doc//SyncAlbumDeleteV1.md)
- [SyncAlbumDtoV1](doc//SyncAlbumDtoV1.md)
- [SyncAssetAlbumDeleteV1](doc//SyncAssetAlbumDeleteV1.md)
- [SyncAssetAlbumDtoV1](doc//SyncAssetAlbumDtoV1.md)
- [SyncAssetOwnerDeleteV1](doc//SyncAssetOwnerDeleteV1.md)
- [SyncAssetOwnerDtoV1](doc//SyncAssetOwnerDtoV1.md)
- [SyncAssetPartnerDeleteV1](doc//SyncAssetPartnerDeleteV1.md)
- [SyncAssetPartnerDtoV1](doc//SyncAssetPartnerDtoV1.md)
- [SyncMemoryDelete](doc//SyncMemoryDelete.md)
- [SyncMemoryDtoV1](doc//SyncMemoryDtoV1.md)
- [SyncStreamDto](doc//SyncStreamDto.md)
- [SystemConfigBackupsDto](doc//SystemConfigBackupsDto.md)
- [SystemConfigDto](doc//SystemConfigDto.md)
- [SystemConfigFFmpegDto](doc//SystemConfigFFmpegDto.md)

View File

@ -228,6 +228,21 @@ part 'model/source_type.dart';
part 'model/stack_create_dto.dart';
part 'model/stack_response_dto.dart';
part 'model/stack_update_dto.dart';
part 'model/sync_acknowledge_dto.dart';
part 'model/sync_activity_delete_dto_v1.dart';
part 'model/sync_album_asset_delete_dto_v1.dart';
part 'model/sync_album_asset_dto_v1.dart';
part 'model/sync_album_delete_v1.dart';
part 'model/sync_album_dto_v1.dart';
part 'model/sync_asset_album_delete_v1.dart';
part 'model/sync_asset_album_dto_v1.dart';
part 'model/sync_asset_owner_delete_v1.dart';
part 'model/sync_asset_owner_dto_v1.dart';
part 'model/sync_asset_partner_delete_v1.dart';
part 'model/sync_asset_partner_dto_v1.dart';
part 'model/sync_memory_delete.dart';
part 'model/sync_memory_dto_v1.dart';
part 'model/sync_stream_dto.dart';
part 'model/system_config_backups_dto.dart';
part 'model/system_config_dto.dart';
part 'model/system_config_f_fmpeg_dto.dart';

View File

@ -16,6 +16,45 @@ class SyncApi {
final ApiClient apiClient;
/// Performs an HTTP 'POST /sync/acknowledge' operation and returns the [Response].
/// Parameters:
///
/// * [SyncAcknowledgeDto] syncAcknowledgeDto (required):
Future<Response> ackSyncWithHttpInfo(SyncAcknowledgeDto syncAcknowledgeDto,) async {
// ignore: prefer_const_declarations
final path = r'/sync/acknowledge';
// ignore: prefer_final_locals
Object? postBody = syncAcknowledgeDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
path,
'POST',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [SyncAcknowledgeDto] syncAcknowledgeDto (required):
Future<void> ackSync(SyncAcknowledgeDto syncAcknowledgeDto,) async {
final response = await ackSyncWithHttpInfo(syncAcknowledgeDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
}
/// Performs an HTTP 'POST /sync/delta-sync' operation and returns the [Response].
/// Parameters:
///
@ -112,4 +151,43 @@ class SyncApi {
}
return null;
}
/// Performs an HTTP 'POST /sync/stream' operation and returns the [Response].
/// Parameters:
///
/// * [SyncStreamDto] syncStreamDto (required):
Future<Response> getSyncStreamWithHttpInfo(SyncStreamDto syncStreamDto,) async {
// ignore: prefer_const_declarations
final path = r'/sync/stream';
// ignore: prefer_final_locals
Object? postBody = syncStreamDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
path,
'POST',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [SyncStreamDto] syncStreamDto (required):
Future<void> getSyncStream(SyncStreamDto syncStreamDto,) async {
final response = await getSyncStreamWithHttpInfo(syncStreamDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
}
}

View File

@ -510,6 +510,36 @@ class ApiClient {
return StackResponseDto.fromJson(value);
case 'StackUpdateDto':
return StackUpdateDto.fromJson(value);
case 'SyncAcknowledgeDto':
return SyncAcknowledgeDto.fromJson(value);
case 'SyncActivityDeleteDtoV1':
return SyncActivityDeleteDtoV1.fromJson(value);
case 'SyncAlbumAssetDeleteDtoV1':
return SyncAlbumAssetDeleteDtoV1.fromJson(value);
case 'SyncAlbumAssetDtoV1':
return SyncAlbumAssetDtoV1.fromJson(value);
case 'SyncAlbumDeleteV1':
return SyncAlbumDeleteV1.fromJson(value);
case 'SyncAlbumDtoV1':
return SyncAlbumDtoV1.fromJson(value);
case 'SyncAssetAlbumDeleteV1':
return SyncAssetAlbumDeleteV1.fromJson(value);
case 'SyncAssetAlbumDtoV1':
return SyncAssetAlbumDtoV1.fromJson(value);
case 'SyncAssetOwnerDeleteV1':
return SyncAssetOwnerDeleteV1.fromJson(value);
case 'SyncAssetOwnerDtoV1':
return SyncAssetOwnerDtoV1.fromJson(value);
case 'SyncAssetPartnerDeleteV1':
return SyncAssetPartnerDeleteV1.fromJson(value);
case 'SyncAssetPartnerDtoV1':
return SyncAssetPartnerDtoV1.fromJson(value);
case 'SyncMemoryDelete':
return SyncMemoryDelete.fromJson(value);
case 'SyncMemoryDtoV1':
return SyncMemoryDtoV1.fromJson(value);
case 'SyncStreamDto':
return SyncStreamDto.fromJson(value);
case 'SystemConfigBackupsDto':
return SystemConfigBackupsDto.fromJson(value);
case 'SystemConfigDto':

View File

@ -0,0 +1,259 @@
//
// 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 SyncAcknowledgeDto {
/// Returns a new [SyncAcknowledgeDto] instance.
SyncAcknowledgeDto({
required this.timestamp,
required this.type,
});
String timestamp;
SyncAcknowledgeDtoTypeEnum type;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncAcknowledgeDto &&
other.timestamp == timestamp &&
other.type == type;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(timestamp.hashCode) +
(type.hashCode);
@override
String toString() => 'SyncAcknowledgeDto[timestamp=$timestamp, type=$type]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'timestamp'] = this.timestamp;
json[r'type'] = this.type;
return json;
}
/// Returns a new [SyncAcknowledgeDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncAcknowledgeDto? fromJson(dynamic value) {
upgradeDto(value, "SyncAcknowledgeDto");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncAcknowledgeDto(
timestamp: mapValueOfType<String>(json, r'timestamp')!,
type: SyncAcknowledgeDtoTypeEnum.fromJson(json[r'type'])!,
);
}
return null;
}
static List<SyncAcknowledgeDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAcknowledgeDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAcknowledgeDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncAcknowledgeDto> mapFromJson(dynamic json) {
final map = <String, SyncAcknowledgeDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncAcknowledgeDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncAcknowledgeDto-objects as value to a dart map
static Map<String, List<SyncAcknowledgeDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncAcknowledgeDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncAcknowledgeDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'timestamp',
'type',
};
}
class SyncAcknowledgeDtoTypeEnum {
/// Instantiate a new enum with the provided [value].
const SyncAcknowledgeDtoTypeEnum._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const activity = SyncAcknowledgeDtoTypeEnum._(r'Activity');
static const activityDelete = SyncAcknowledgeDtoTypeEnum._(r'ActivityDelete');
static const assetOwner = SyncAcknowledgeDtoTypeEnum._(r'AssetOwner');
static const assetOwnerDelete = SyncAcknowledgeDtoTypeEnum._(r'AssetOwnerDelete');
static const assetPartner = SyncAcknowledgeDtoTypeEnum._(r'AssetPartner');
static const assetPartnerDelete = SyncAcknowledgeDtoTypeEnum._(r'AssetPartnerDelete');
static const assetAlbum = SyncAcknowledgeDtoTypeEnum._(r'AssetAlbum');
static const assetAlbumDelete = SyncAcknowledgeDtoTypeEnum._(r'AssetAlbumDelete');
static const album = SyncAcknowledgeDtoTypeEnum._(r'Album');
static const albumDelete = SyncAcknowledgeDtoTypeEnum._(r'AlbumDelete');
static const memory = SyncAcknowledgeDtoTypeEnum._(r'Memory');
static const memoryDelete = SyncAcknowledgeDtoTypeEnum._(r'MemoryDelete');
static const partner = SyncAcknowledgeDtoTypeEnum._(r'Partner');
static const partnerDelete = SyncAcknowledgeDtoTypeEnum._(r'PartnerDelete');
static const person = SyncAcknowledgeDtoTypeEnum._(r'Person');
static const personDelete = SyncAcknowledgeDtoTypeEnum._(r'PersonDelete');
static const sharedLink = SyncAcknowledgeDtoTypeEnum._(r'SharedLink');
static const sharedLinkDelete = SyncAcknowledgeDtoTypeEnum._(r'SharedLinkDelete');
static const stack = SyncAcknowledgeDtoTypeEnum._(r'Stack');
static const stackDelete = SyncAcknowledgeDtoTypeEnum._(r'StackDelete');
static const tag = SyncAcknowledgeDtoTypeEnum._(r'Tag');
static const tagDelete = SyncAcknowledgeDtoTypeEnum._(r'TagDelete');
static const user = SyncAcknowledgeDtoTypeEnum._(r'User');
static const userDelete = SyncAcknowledgeDtoTypeEnum._(r'UserDelete');
static const albumAsset = SyncAcknowledgeDtoTypeEnum._(r'AlbumAsset');
static const albumAssetDelete = SyncAcknowledgeDtoTypeEnum._(r'AlbumAssetDelete');
static const albumUser = SyncAcknowledgeDtoTypeEnum._(r'AlbumUser');
static const albumUserDelete = SyncAcknowledgeDtoTypeEnum._(r'AlbumUserDelete');
/// List of all possible values in this [enum][SyncAcknowledgeDtoTypeEnum].
static const values = <SyncAcknowledgeDtoTypeEnum>[
activity,
activityDelete,
assetOwner,
assetOwnerDelete,
assetPartner,
assetPartnerDelete,
assetAlbum,
assetAlbumDelete,
album,
albumDelete,
memory,
memoryDelete,
partner,
partnerDelete,
person,
personDelete,
sharedLink,
sharedLinkDelete,
stack,
stackDelete,
tag,
tagDelete,
user,
userDelete,
albumAsset,
albumAssetDelete,
albumUser,
albumUserDelete,
];
static SyncAcknowledgeDtoTypeEnum? fromJson(dynamic value) => SyncAcknowledgeDtoTypeEnumTypeTransformer().decode(value);
static List<SyncAcknowledgeDtoTypeEnum> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAcknowledgeDtoTypeEnum>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAcknowledgeDtoTypeEnum.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [SyncAcknowledgeDtoTypeEnum] to String,
/// and [decode] dynamic data back to [SyncAcknowledgeDtoTypeEnum].
class SyncAcknowledgeDtoTypeEnumTypeTransformer {
factory SyncAcknowledgeDtoTypeEnumTypeTransformer() => _instance ??= const SyncAcknowledgeDtoTypeEnumTypeTransformer._();
const SyncAcknowledgeDtoTypeEnumTypeTransformer._();
String encode(SyncAcknowledgeDtoTypeEnum data) => data.value;
/// Decodes a [dynamic value][data] to a SyncAcknowledgeDtoTypeEnum.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
SyncAcknowledgeDtoTypeEnum? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'Activity': return SyncAcknowledgeDtoTypeEnum.activity;
case r'ActivityDelete': return SyncAcknowledgeDtoTypeEnum.activityDelete;
case r'AssetOwner': return SyncAcknowledgeDtoTypeEnum.assetOwner;
case r'AssetOwnerDelete': return SyncAcknowledgeDtoTypeEnum.assetOwnerDelete;
case r'AssetPartner': return SyncAcknowledgeDtoTypeEnum.assetPartner;
case r'AssetPartnerDelete': return SyncAcknowledgeDtoTypeEnum.assetPartnerDelete;
case r'AssetAlbum': return SyncAcknowledgeDtoTypeEnum.assetAlbum;
case r'AssetAlbumDelete': return SyncAcknowledgeDtoTypeEnum.assetAlbumDelete;
case r'Album': return SyncAcknowledgeDtoTypeEnum.album;
case r'AlbumDelete': return SyncAcknowledgeDtoTypeEnum.albumDelete;
case r'Memory': return SyncAcknowledgeDtoTypeEnum.memory;
case r'MemoryDelete': return SyncAcknowledgeDtoTypeEnum.memoryDelete;
case r'Partner': return SyncAcknowledgeDtoTypeEnum.partner;
case r'PartnerDelete': return SyncAcknowledgeDtoTypeEnum.partnerDelete;
case r'Person': return SyncAcknowledgeDtoTypeEnum.person;
case r'PersonDelete': return SyncAcknowledgeDtoTypeEnum.personDelete;
case r'SharedLink': return SyncAcknowledgeDtoTypeEnum.sharedLink;
case r'SharedLinkDelete': return SyncAcknowledgeDtoTypeEnum.sharedLinkDelete;
case r'Stack': return SyncAcknowledgeDtoTypeEnum.stack;
case r'StackDelete': return SyncAcknowledgeDtoTypeEnum.stackDelete;
case r'Tag': return SyncAcknowledgeDtoTypeEnum.tag;
case r'TagDelete': return SyncAcknowledgeDtoTypeEnum.tagDelete;
case r'User': return SyncAcknowledgeDtoTypeEnum.user;
case r'UserDelete': return SyncAcknowledgeDtoTypeEnum.userDelete;
case r'AlbumAsset': return SyncAcknowledgeDtoTypeEnum.albumAsset;
case r'AlbumAssetDelete': return SyncAcknowledgeDtoTypeEnum.albumAssetDelete;
case r'AlbumUser': return SyncAcknowledgeDtoTypeEnum.albumUser;
case r'AlbumUserDelete': return SyncAcknowledgeDtoTypeEnum.albumUserDelete;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [SyncAcknowledgeDtoTypeEnumTypeTransformer] instance.
static SyncAcknowledgeDtoTypeEnumTypeTransformer? _instance;
}

View File

@ -0,0 +1,107 @@
//
// 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 SyncActivityDeleteDtoV1 {
/// Returns a new [SyncActivityDeleteDtoV1] instance.
SyncActivityDeleteDtoV1({
required this.deletedAt,
required this.id,
});
String deletedAt;
String id;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncActivityDeleteDtoV1 &&
other.deletedAt == deletedAt &&
other.id == id;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(deletedAt.hashCode) +
(id.hashCode);
@override
String toString() => 'SyncActivityDeleteDtoV1[deletedAt=$deletedAt, id=$id]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'deletedAt'] = this.deletedAt;
json[r'id'] = this.id;
return json;
}
/// Returns a new [SyncActivityDeleteDtoV1] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncActivityDeleteDtoV1? fromJson(dynamic value) {
upgradeDto(value, "SyncActivityDeleteDtoV1");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncActivityDeleteDtoV1(
deletedAt: mapValueOfType<String>(json, r'deletedAt')!,
id: mapValueOfType<String>(json, r'id')!,
);
}
return null;
}
static List<SyncActivityDeleteDtoV1> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncActivityDeleteDtoV1>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncActivityDeleteDtoV1.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncActivityDeleteDtoV1> mapFromJson(dynamic json) {
final map = <String, SyncActivityDeleteDtoV1>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncActivityDeleteDtoV1.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncActivityDeleteDtoV1-objects as value to a dart map
static Map<String, List<SyncActivityDeleteDtoV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncActivityDeleteDtoV1>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncActivityDeleteDtoV1.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'deletedAt',
'id',
};
}

View File

@ -0,0 +1,115 @@
//
// 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 SyncAlbumAssetDeleteDtoV1 {
/// Returns a new [SyncAlbumAssetDeleteDtoV1] instance.
SyncAlbumAssetDeleteDtoV1({
required this.albumId,
required this.assetId,
required this.deletedAt,
});
String albumId;
String assetId;
String deletedAt;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncAlbumAssetDeleteDtoV1 &&
other.albumId == albumId &&
other.assetId == assetId &&
other.deletedAt == deletedAt;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(albumId.hashCode) +
(assetId.hashCode) +
(deletedAt.hashCode);
@override
String toString() => 'SyncAlbumAssetDeleteDtoV1[albumId=$albumId, assetId=$assetId, deletedAt=$deletedAt]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'albumId'] = this.albumId;
json[r'assetId'] = this.assetId;
json[r'deletedAt'] = this.deletedAt;
return json;
}
/// Returns a new [SyncAlbumAssetDeleteDtoV1] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncAlbumAssetDeleteDtoV1? fromJson(dynamic value) {
upgradeDto(value, "SyncAlbumAssetDeleteDtoV1");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncAlbumAssetDeleteDtoV1(
albumId: mapValueOfType<String>(json, r'albumId')!,
assetId: mapValueOfType<String>(json, r'assetId')!,
deletedAt: mapValueOfType<String>(json, r'deletedAt')!,
);
}
return null;
}
static List<SyncAlbumAssetDeleteDtoV1> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAlbumAssetDeleteDtoV1>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAlbumAssetDeleteDtoV1.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncAlbumAssetDeleteDtoV1> mapFromJson(dynamic json) {
final map = <String, SyncAlbumAssetDeleteDtoV1>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncAlbumAssetDeleteDtoV1.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncAlbumAssetDeleteDtoV1-objects as value to a dart map
static Map<String, List<SyncAlbumAssetDeleteDtoV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncAlbumAssetDeleteDtoV1>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncAlbumAssetDeleteDtoV1.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'albumId',
'assetId',
'deletedAt',
};
}

View File

@ -0,0 +1,115 @@
//
// 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 SyncAlbumAssetDtoV1 {
/// Returns a new [SyncAlbumAssetDtoV1] instance.
SyncAlbumAssetDtoV1({
required this.albumId,
required this.assetId,
required this.createdAt,
});
String albumId;
String assetId;
String createdAt;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncAlbumAssetDtoV1 &&
other.albumId == albumId &&
other.assetId == assetId &&
other.createdAt == createdAt;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(albumId.hashCode) +
(assetId.hashCode) +
(createdAt.hashCode);
@override
String toString() => 'SyncAlbumAssetDtoV1[albumId=$albumId, assetId=$assetId, createdAt=$createdAt]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'albumId'] = this.albumId;
json[r'assetId'] = this.assetId;
json[r'createdAt'] = this.createdAt;
return json;
}
/// Returns a new [SyncAlbumAssetDtoV1] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncAlbumAssetDtoV1? fromJson(dynamic value) {
upgradeDto(value, "SyncAlbumAssetDtoV1");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncAlbumAssetDtoV1(
albumId: mapValueOfType<String>(json, r'albumId')!,
assetId: mapValueOfType<String>(json, r'assetId')!,
createdAt: mapValueOfType<String>(json, r'createdAt')!,
);
}
return null;
}
static List<SyncAlbumAssetDtoV1> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAlbumAssetDtoV1>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAlbumAssetDtoV1.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncAlbumAssetDtoV1> mapFromJson(dynamic json) {
final map = <String, SyncAlbumAssetDtoV1>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncAlbumAssetDtoV1.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncAlbumAssetDtoV1-objects as value to a dart map
static Map<String, List<SyncAlbumAssetDtoV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncAlbumAssetDtoV1>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncAlbumAssetDtoV1.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'albumId',
'assetId',
'createdAt',
};
}

View File

@ -0,0 +1,107 @@
//
// 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 SyncAlbumDeleteV1 {
/// Returns a new [SyncAlbumDeleteV1] instance.
SyncAlbumDeleteV1({
required this.deletedAt,
required this.id,
});
String deletedAt;
String id;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncAlbumDeleteV1 &&
other.deletedAt == deletedAt &&
other.id == id;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(deletedAt.hashCode) +
(id.hashCode);
@override
String toString() => 'SyncAlbumDeleteV1[deletedAt=$deletedAt, id=$id]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'deletedAt'] = this.deletedAt;
json[r'id'] = this.id;
return json;
}
/// Returns a new [SyncAlbumDeleteV1] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncAlbumDeleteV1? fromJson(dynamic value) {
upgradeDto(value, "SyncAlbumDeleteV1");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncAlbumDeleteV1(
deletedAt: mapValueOfType<String>(json, r'deletedAt')!,
id: mapValueOfType<String>(json, r'id')!,
);
}
return null;
}
static List<SyncAlbumDeleteV1> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAlbumDeleteV1>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAlbumDeleteV1.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncAlbumDeleteV1> mapFromJson(dynamic json) {
final map = <String, SyncAlbumDeleteV1>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncAlbumDeleteV1.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncAlbumDeleteV1-objects as value to a dart map
static Map<String, List<SyncAlbumDeleteV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncAlbumDeleteV1>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncAlbumDeleteV1.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'deletedAt',
'id',
};
}

View File

@ -0,0 +1,115 @@
//
// 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 SyncAlbumDtoV1 {
/// Returns a new [SyncAlbumDtoV1] instance.
SyncAlbumDtoV1({
required this.description,
required this.id,
required this.name,
});
String description;
String id;
String name;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncAlbumDtoV1 &&
other.description == description &&
other.id == id &&
other.name == name;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(description.hashCode) +
(id.hashCode) +
(name.hashCode);
@override
String toString() => 'SyncAlbumDtoV1[description=$description, id=$id, name=$name]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'description'] = this.description;
json[r'id'] = this.id;
json[r'name'] = this.name;
return json;
}
/// Returns a new [SyncAlbumDtoV1] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncAlbumDtoV1? fromJson(dynamic value) {
upgradeDto(value, "SyncAlbumDtoV1");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncAlbumDtoV1(
description: mapValueOfType<String>(json, r'description')!,
id: mapValueOfType<String>(json, r'id')!,
name: mapValueOfType<String>(json, r'name')!,
);
}
return null;
}
static List<SyncAlbumDtoV1> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAlbumDtoV1>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAlbumDtoV1.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncAlbumDtoV1> mapFromJson(dynamic json) {
final map = <String, SyncAlbumDtoV1>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncAlbumDtoV1.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncAlbumDtoV1-objects as value to a dart map
static Map<String, List<SyncAlbumDtoV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncAlbumDtoV1>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncAlbumDtoV1.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'description',
'id',
'name',
};
}

View File

@ -0,0 +1,107 @@
//
// 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 SyncAssetAlbumDeleteV1 {
/// Returns a new [SyncAssetAlbumDeleteV1] instance.
SyncAssetAlbumDeleteV1({
required this.deletedAt,
required this.id,
});
String deletedAt;
String id;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncAssetAlbumDeleteV1 &&
other.deletedAt == deletedAt &&
other.id == id;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(deletedAt.hashCode) +
(id.hashCode);
@override
String toString() => 'SyncAssetAlbumDeleteV1[deletedAt=$deletedAt, id=$id]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'deletedAt'] = this.deletedAt;
json[r'id'] = this.id;
return json;
}
/// Returns a new [SyncAssetAlbumDeleteV1] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncAssetAlbumDeleteV1? fromJson(dynamic value) {
upgradeDto(value, "SyncAssetAlbumDeleteV1");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncAssetAlbumDeleteV1(
deletedAt: mapValueOfType<String>(json, r'deletedAt')!,
id: mapValueOfType<String>(json, r'id')!,
);
}
return null;
}
static List<SyncAssetAlbumDeleteV1> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAssetAlbumDeleteV1>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAssetAlbumDeleteV1.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncAssetAlbumDeleteV1> mapFromJson(dynamic json) {
final map = <String, SyncAssetAlbumDeleteV1>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncAssetAlbumDeleteV1.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncAssetAlbumDeleteV1-objects as value to a dart map
static Map<String, List<SyncAssetAlbumDeleteV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncAssetAlbumDeleteV1>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncAssetAlbumDeleteV1.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'deletedAt',
'id',
};
}

View File

@ -0,0 +1,836 @@
//
// 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 SyncAssetAlbumDtoV1 {
/// Returns a new [SyncAssetAlbumDtoV1] instance.
SyncAssetAlbumDtoV1({
this.bitsPerSample,
required this.checksum,
this.city,
this.colorspace,
this.country,
required this.createdAt,
this.dateTimeOriginal,
this.deletedAt,
this.duration,
this.exifImageHeight,
this.exifImageWidth,
this.exposureTime,
this.fNumber,
required this.fileCreatedAt,
required this.fileModifiedAt,
this.fileSizeInByte,
this.fps,
required this.id,
required this.isArchived,
required this.isExternal,
required this.isFavorite,
required this.isOffline,
this.iso,
this.latitude,
this.lensModel,
this.libraryId,
this.livePhotoVideoId,
this.longitude,
this.make,
this.model,
this.modifyDate,
this.orientation,
required this.originalFileName,
required this.originalPath,
required this.ownerId,
this.profileDescription,
this.projectionType,
this.rating,
this.state,
required this.status,
this.thumbhash,
required this.type,
});
///
/// 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.
///
num? bitsPerSample;
String checksum;
///
/// 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.
///
String? city;
///
/// 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.
///
String? colorspace;
///
/// 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.
///
String? country;
String createdAt;
///
/// 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.
///
String? dateTimeOriginal;
///
/// 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.
///
String? deletedAt;
///
/// 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.
///
String? duration;
///
/// 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.
///
num? exifImageHeight;
///
/// 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.
///
num? exifImageWidth;
///
/// 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.
///
String? exposureTime;
///
/// 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.
///
num? fNumber;
String fileCreatedAt;
String fileModifiedAt;
///
/// 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.
///
num? fileSizeInByte;
///
/// 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.
///
num? fps;
String id;
bool isArchived;
bool isExternal;
bool isFavorite;
bool isOffline;
///
/// 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.
///
num? iso;
///
/// 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.
///
num? latitude;
///
/// 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.
///
String? lensModel;
///
/// 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.
///
String? libraryId;
///
/// 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.
///
String? livePhotoVideoId;
///
/// 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.
///
num? longitude;
///
/// 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.
///
String? make;
///
/// 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.
///
String? model;
///
/// 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.
///
String? modifyDate;
///
/// 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.
///
String? orientation;
String originalFileName;
String originalPath;
String ownerId;
///
/// 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.
///
String? profileDescription;
///
/// 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.
///
String? projectionType;
///
/// 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.
///
num? rating;
///
/// 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.
///
String? state;
SyncAssetAlbumDtoV1StatusEnum status;
///
/// 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.
///
String? thumbhash;
SyncAssetAlbumDtoV1TypeEnum type;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncAssetAlbumDtoV1 &&
other.bitsPerSample == bitsPerSample &&
other.checksum == checksum &&
other.city == city &&
other.colorspace == colorspace &&
other.country == country &&
other.createdAt == createdAt &&
other.dateTimeOriginal == dateTimeOriginal &&
other.deletedAt == deletedAt &&
other.duration == duration &&
other.exifImageHeight == exifImageHeight &&
other.exifImageWidth == exifImageWidth &&
other.exposureTime == exposureTime &&
other.fNumber == fNumber &&
other.fileCreatedAt == fileCreatedAt &&
other.fileModifiedAt == fileModifiedAt &&
other.fileSizeInByte == fileSizeInByte &&
other.fps == fps &&
other.id == id &&
other.isArchived == isArchived &&
other.isExternal == isExternal &&
other.isFavorite == isFavorite &&
other.isOffline == isOffline &&
other.iso == iso &&
other.latitude == latitude &&
other.lensModel == lensModel &&
other.libraryId == libraryId &&
other.livePhotoVideoId == livePhotoVideoId &&
other.longitude == longitude &&
other.make == make &&
other.model == model &&
other.modifyDate == modifyDate &&
other.orientation == orientation &&
other.originalFileName == originalFileName &&
other.originalPath == originalPath &&
other.ownerId == ownerId &&
other.profileDescription == profileDescription &&
other.projectionType == projectionType &&
other.rating == rating &&
other.state == state &&
other.status == status &&
other.thumbhash == thumbhash &&
other.type == type;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(bitsPerSample == null ? 0 : bitsPerSample!.hashCode) +
(checksum.hashCode) +
(city == null ? 0 : city!.hashCode) +
(colorspace == null ? 0 : colorspace!.hashCode) +
(country == null ? 0 : country!.hashCode) +
(createdAt.hashCode) +
(dateTimeOriginal == null ? 0 : dateTimeOriginal!.hashCode) +
(deletedAt == null ? 0 : deletedAt!.hashCode) +
(duration == null ? 0 : duration!.hashCode) +
(exifImageHeight == null ? 0 : exifImageHeight!.hashCode) +
(exifImageWidth == null ? 0 : exifImageWidth!.hashCode) +
(exposureTime == null ? 0 : exposureTime!.hashCode) +
(fNumber == null ? 0 : fNumber!.hashCode) +
(fileCreatedAt.hashCode) +
(fileModifiedAt.hashCode) +
(fileSizeInByte == null ? 0 : fileSizeInByte!.hashCode) +
(fps == null ? 0 : fps!.hashCode) +
(id.hashCode) +
(isArchived.hashCode) +
(isExternal.hashCode) +
(isFavorite.hashCode) +
(isOffline.hashCode) +
(iso == null ? 0 : iso!.hashCode) +
(latitude == null ? 0 : latitude!.hashCode) +
(lensModel == null ? 0 : lensModel!.hashCode) +
(libraryId == null ? 0 : libraryId!.hashCode) +
(livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode) +
(longitude == null ? 0 : longitude!.hashCode) +
(make == null ? 0 : make!.hashCode) +
(model == null ? 0 : model!.hashCode) +
(modifyDate == null ? 0 : modifyDate!.hashCode) +
(orientation == null ? 0 : orientation!.hashCode) +
(originalFileName.hashCode) +
(originalPath.hashCode) +
(ownerId.hashCode) +
(profileDescription == null ? 0 : profileDescription!.hashCode) +
(projectionType == null ? 0 : projectionType!.hashCode) +
(rating == null ? 0 : rating!.hashCode) +
(state == null ? 0 : state!.hashCode) +
(status.hashCode) +
(thumbhash == null ? 0 : thumbhash!.hashCode) +
(type.hashCode);
@override
String toString() => 'SyncAssetAlbumDtoV1[bitsPerSample=$bitsPerSample, checksum=$checksum, city=$city, colorspace=$colorspace, country=$country, createdAt=$createdAt, dateTimeOriginal=$dateTimeOriginal, deletedAt=$deletedAt, duration=$duration, exifImageHeight=$exifImageHeight, exifImageWidth=$exifImageWidth, exposureTime=$exposureTime, fNumber=$fNumber, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, fileSizeInByte=$fileSizeInByte, fps=$fps, id=$id, isArchived=$isArchived, isExternal=$isExternal, isFavorite=$isFavorite, isOffline=$isOffline, iso=$iso, latitude=$latitude, lensModel=$lensModel, libraryId=$libraryId, livePhotoVideoId=$livePhotoVideoId, longitude=$longitude, make=$make, model=$model, modifyDate=$modifyDate, orientation=$orientation, originalFileName=$originalFileName, originalPath=$originalPath, ownerId=$ownerId, profileDescription=$profileDescription, projectionType=$projectionType, rating=$rating, state=$state, status=$status, thumbhash=$thumbhash, type=$type]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
if (this.bitsPerSample != null) {
json[r'bitsPerSample'] = this.bitsPerSample;
} else {
// json[r'bitsPerSample'] = null;
}
json[r'checksum'] = this.checksum;
if (this.city != null) {
json[r'city'] = this.city;
} else {
// json[r'city'] = null;
}
if (this.colorspace != null) {
json[r'colorspace'] = this.colorspace;
} else {
// json[r'colorspace'] = null;
}
if (this.country != null) {
json[r'country'] = this.country;
} else {
// json[r'country'] = null;
}
json[r'createdAt'] = this.createdAt;
if (this.dateTimeOriginal != null) {
json[r'dateTimeOriginal'] = this.dateTimeOriginal;
} else {
// json[r'dateTimeOriginal'] = null;
}
if (this.deletedAt != null) {
json[r'deletedAt'] = this.deletedAt;
} else {
// json[r'deletedAt'] = null;
}
if (this.duration != null) {
json[r'duration'] = this.duration;
} else {
// json[r'duration'] = null;
}
if (this.exifImageHeight != null) {
json[r'exifImageHeight'] = this.exifImageHeight;
} else {
// json[r'exifImageHeight'] = null;
}
if (this.exifImageWidth != null) {
json[r'exifImageWidth'] = this.exifImageWidth;
} else {
// json[r'exifImageWidth'] = null;
}
if (this.exposureTime != null) {
json[r'exposureTime'] = this.exposureTime;
} else {
// json[r'exposureTime'] = null;
}
if (this.fNumber != null) {
json[r'fNumber'] = this.fNumber;
} else {
// json[r'fNumber'] = null;
}
json[r'fileCreatedAt'] = this.fileCreatedAt;
json[r'fileModifiedAt'] = this.fileModifiedAt;
if (this.fileSizeInByte != null) {
json[r'fileSizeInByte'] = this.fileSizeInByte;
} else {
// json[r'fileSizeInByte'] = null;
}
if (this.fps != null) {
json[r'fps'] = this.fps;
} else {
// json[r'fps'] = null;
}
json[r'id'] = this.id;
json[r'isArchived'] = this.isArchived;
json[r'isExternal'] = this.isExternal;
json[r'isFavorite'] = this.isFavorite;
json[r'isOffline'] = this.isOffline;
if (this.iso != null) {
json[r'iso'] = this.iso;
} else {
// json[r'iso'] = null;
}
if (this.latitude != null) {
json[r'latitude'] = this.latitude;
} else {
// json[r'latitude'] = null;
}
if (this.lensModel != null) {
json[r'lensModel'] = this.lensModel;
} else {
// json[r'lensModel'] = null;
}
if (this.libraryId != null) {
json[r'libraryId'] = this.libraryId;
} else {
// json[r'libraryId'] = null;
}
if (this.livePhotoVideoId != null) {
json[r'livePhotoVideoId'] = this.livePhotoVideoId;
} else {
// json[r'livePhotoVideoId'] = null;
}
if (this.longitude != null) {
json[r'longitude'] = this.longitude;
} else {
// json[r'longitude'] = null;
}
if (this.make != null) {
json[r'make'] = this.make;
} else {
// json[r'make'] = null;
}
if (this.model != null) {
json[r'model'] = this.model;
} else {
// json[r'model'] = null;
}
if (this.modifyDate != null) {
json[r'modifyDate'] = this.modifyDate;
} else {
// json[r'modifyDate'] = null;
}
if (this.orientation != null) {
json[r'orientation'] = this.orientation;
} else {
// json[r'orientation'] = null;
}
json[r'originalFileName'] = this.originalFileName;
json[r'originalPath'] = this.originalPath;
json[r'ownerId'] = this.ownerId;
if (this.profileDescription != null) {
json[r'profileDescription'] = this.profileDescription;
} else {
// json[r'profileDescription'] = null;
}
if (this.projectionType != null) {
json[r'projectionType'] = this.projectionType;
} else {
// json[r'projectionType'] = null;
}
if (this.rating != null) {
json[r'rating'] = this.rating;
} else {
// json[r'rating'] = null;
}
if (this.state != null) {
json[r'state'] = this.state;
} else {
// json[r'state'] = null;
}
json[r'status'] = this.status;
if (this.thumbhash != null) {
json[r'thumbhash'] = this.thumbhash;
} else {
// json[r'thumbhash'] = null;
}
json[r'type'] = this.type;
return json;
}
/// Returns a new [SyncAssetAlbumDtoV1] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncAssetAlbumDtoV1? fromJson(dynamic value) {
upgradeDto(value, "SyncAssetAlbumDtoV1");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncAssetAlbumDtoV1(
bitsPerSample: num.parse('${json[r'bitsPerSample']}'),
checksum: mapValueOfType<String>(json, r'checksum')!,
city: mapValueOfType<String>(json, r'city'),
colorspace: mapValueOfType<String>(json, r'colorspace'),
country: mapValueOfType<String>(json, r'country'),
createdAt: mapValueOfType<String>(json, r'createdAt')!,
dateTimeOriginal: mapValueOfType<String>(json, r'dateTimeOriginal'),
deletedAt: mapValueOfType<String>(json, r'deletedAt'),
duration: mapValueOfType<String>(json, r'duration'),
exifImageHeight: num.parse('${json[r'exifImageHeight']}'),
exifImageWidth: num.parse('${json[r'exifImageWidth']}'),
exposureTime: mapValueOfType<String>(json, r'exposureTime'),
fNumber: num.parse('${json[r'fNumber']}'),
fileCreatedAt: mapValueOfType<String>(json, r'fileCreatedAt')!,
fileModifiedAt: mapValueOfType<String>(json, r'fileModifiedAt')!,
fileSizeInByte: num.parse('${json[r'fileSizeInByte']}'),
fps: num.parse('${json[r'fps']}'),
id: mapValueOfType<String>(json, r'id')!,
isArchived: mapValueOfType<bool>(json, r'isArchived')!,
isExternal: mapValueOfType<bool>(json, r'isExternal')!,
isFavorite: mapValueOfType<bool>(json, r'isFavorite')!,
isOffline: mapValueOfType<bool>(json, r'isOffline')!,
iso: num.parse('${json[r'iso']}'),
latitude: num.parse('${json[r'latitude']}'),
lensModel: mapValueOfType<String>(json, r'lensModel'),
libraryId: mapValueOfType<String>(json, r'libraryId'),
livePhotoVideoId: mapValueOfType<String>(json, r'livePhotoVideoId'),
longitude: num.parse('${json[r'longitude']}'),
make: mapValueOfType<String>(json, r'make'),
model: mapValueOfType<String>(json, r'model'),
modifyDate: mapValueOfType<String>(json, r'modifyDate'),
orientation: mapValueOfType<String>(json, r'orientation'),
originalFileName: mapValueOfType<String>(json, r'originalFileName')!,
originalPath: mapValueOfType<String>(json, r'originalPath')!,
ownerId: mapValueOfType<String>(json, r'ownerId')!,
profileDescription: mapValueOfType<String>(json, r'profileDescription'),
projectionType: mapValueOfType<String>(json, r'projectionType'),
rating: num.parse('${json[r'rating']}'),
state: mapValueOfType<String>(json, r'state'),
status: SyncAssetAlbumDtoV1StatusEnum.fromJson(json[r'status'])!,
thumbhash: mapValueOfType<String>(json, r'thumbhash'),
type: SyncAssetAlbumDtoV1TypeEnum.fromJson(json[r'type'])!,
);
}
return null;
}
static List<SyncAssetAlbumDtoV1> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAssetAlbumDtoV1>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAssetAlbumDtoV1.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncAssetAlbumDtoV1> mapFromJson(dynamic json) {
final map = <String, SyncAssetAlbumDtoV1>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncAssetAlbumDtoV1.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncAssetAlbumDtoV1-objects as value to a dart map
static Map<String, List<SyncAssetAlbumDtoV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncAssetAlbumDtoV1>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncAssetAlbumDtoV1.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'checksum',
'createdAt',
'fileCreatedAt',
'fileModifiedAt',
'id',
'isArchived',
'isExternal',
'isFavorite',
'isOffline',
'originalFileName',
'originalPath',
'ownerId',
'status',
'type',
};
}
class SyncAssetAlbumDtoV1StatusEnum {
/// Instantiate a new enum with the provided [value].
const SyncAssetAlbumDtoV1StatusEnum._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const active = SyncAssetAlbumDtoV1StatusEnum._(r'active');
static const trashed = SyncAssetAlbumDtoV1StatusEnum._(r'trashed');
static const deleted = SyncAssetAlbumDtoV1StatusEnum._(r'deleted');
/// List of all possible values in this [enum][SyncAssetAlbumDtoV1StatusEnum].
static const values = <SyncAssetAlbumDtoV1StatusEnum>[
active,
trashed,
deleted,
];
static SyncAssetAlbumDtoV1StatusEnum? fromJson(dynamic value) => SyncAssetAlbumDtoV1StatusEnumTypeTransformer().decode(value);
static List<SyncAssetAlbumDtoV1StatusEnum> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAssetAlbumDtoV1StatusEnum>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAssetAlbumDtoV1StatusEnum.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [SyncAssetAlbumDtoV1StatusEnum] to String,
/// and [decode] dynamic data back to [SyncAssetAlbumDtoV1StatusEnum].
class SyncAssetAlbumDtoV1StatusEnumTypeTransformer {
factory SyncAssetAlbumDtoV1StatusEnumTypeTransformer() => _instance ??= const SyncAssetAlbumDtoV1StatusEnumTypeTransformer._();
const SyncAssetAlbumDtoV1StatusEnumTypeTransformer._();
String encode(SyncAssetAlbumDtoV1StatusEnum data) => data.value;
/// Decodes a [dynamic value][data] to a SyncAssetAlbumDtoV1StatusEnum.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
SyncAssetAlbumDtoV1StatusEnum? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'active': return SyncAssetAlbumDtoV1StatusEnum.active;
case r'trashed': return SyncAssetAlbumDtoV1StatusEnum.trashed;
case r'deleted': return SyncAssetAlbumDtoV1StatusEnum.deleted;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [SyncAssetAlbumDtoV1StatusEnumTypeTransformer] instance.
static SyncAssetAlbumDtoV1StatusEnumTypeTransformer? _instance;
}
class SyncAssetAlbumDtoV1TypeEnum {
/// Instantiate a new enum with the provided [value].
const SyncAssetAlbumDtoV1TypeEnum._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const IMAGE = SyncAssetAlbumDtoV1TypeEnum._(r'IMAGE');
static const VIDEO = SyncAssetAlbumDtoV1TypeEnum._(r'VIDEO');
static const AUDIO = SyncAssetAlbumDtoV1TypeEnum._(r'AUDIO');
static const OTHER = SyncAssetAlbumDtoV1TypeEnum._(r'OTHER');
/// List of all possible values in this [enum][SyncAssetAlbumDtoV1TypeEnum].
static const values = <SyncAssetAlbumDtoV1TypeEnum>[
IMAGE,
VIDEO,
AUDIO,
OTHER,
];
static SyncAssetAlbumDtoV1TypeEnum? fromJson(dynamic value) => SyncAssetAlbumDtoV1TypeEnumTypeTransformer().decode(value);
static List<SyncAssetAlbumDtoV1TypeEnum> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAssetAlbumDtoV1TypeEnum>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAssetAlbumDtoV1TypeEnum.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [SyncAssetAlbumDtoV1TypeEnum] to String,
/// and [decode] dynamic data back to [SyncAssetAlbumDtoV1TypeEnum].
class SyncAssetAlbumDtoV1TypeEnumTypeTransformer {
factory SyncAssetAlbumDtoV1TypeEnumTypeTransformer() => _instance ??= const SyncAssetAlbumDtoV1TypeEnumTypeTransformer._();
const SyncAssetAlbumDtoV1TypeEnumTypeTransformer._();
String encode(SyncAssetAlbumDtoV1TypeEnum data) => data.value;
/// Decodes a [dynamic value][data] to a SyncAssetAlbumDtoV1TypeEnum.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
SyncAssetAlbumDtoV1TypeEnum? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'IMAGE': return SyncAssetAlbumDtoV1TypeEnum.IMAGE;
case r'VIDEO': return SyncAssetAlbumDtoV1TypeEnum.VIDEO;
case r'AUDIO': return SyncAssetAlbumDtoV1TypeEnum.AUDIO;
case r'OTHER': return SyncAssetAlbumDtoV1TypeEnum.OTHER;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [SyncAssetAlbumDtoV1TypeEnumTypeTransformer] instance.
static SyncAssetAlbumDtoV1TypeEnumTypeTransformer? _instance;
}

View File

@ -0,0 +1,107 @@
//
// 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 SyncAssetOwnerDeleteV1 {
/// Returns a new [SyncAssetOwnerDeleteV1] instance.
SyncAssetOwnerDeleteV1({
required this.deletedAt,
required this.id,
});
String deletedAt;
String id;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncAssetOwnerDeleteV1 &&
other.deletedAt == deletedAt &&
other.id == id;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(deletedAt.hashCode) +
(id.hashCode);
@override
String toString() => 'SyncAssetOwnerDeleteV1[deletedAt=$deletedAt, id=$id]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'deletedAt'] = this.deletedAt;
json[r'id'] = this.id;
return json;
}
/// Returns a new [SyncAssetOwnerDeleteV1] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncAssetOwnerDeleteV1? fromJson(dynamic value) {
upgradeDto(value, "SyncAssetOwnerDeleteV1");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncAssetOwnerDeleteV1(
deletedAt: mapValueOfType<String>(json, r'deletedAt')!,
id: mapValueOfType<String>(json, r'id')!,
);
}
return null;
}
static List<SyncAssetOwnerDeleteV1> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAssetOwnerDeleteV1>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAssetOwnerDeleteV1.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncAssetOwnerDeleteV1> mapFromJson(dynamic json) {
final map = <String, SyncAssetOwnerDeleteV1>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncAssetOwnerDeleteV1.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncAssetOwnerDeleteV1-objects as value to a dart map
static Map<String, List<SyncAssetOwnerDeleteV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncAssetOwnerDeleteV1>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncAssetOwnerDeleteV1.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'deletedAt',
'id',
};
}

View File

@ -0,0 +1,836 @@
//
// 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 SyncAssetOwnerDtoV1 {
/// Returns a new [SyncAssetOwnerDtoV1] instance.
SyncAssetOwnerDtoV1({
this.bitsPerSample,
required this.checksum,
this.city,
this.colorspace,
this.country,
required this.createdAt,
this.dateTimeOriginal,
this.deletedAt,
this.duration,
this.exifImageHeight,
this.exifImageWidth,
this.exposureTime,
this.fNumber,
required this.fileCreatedAt,
required this.fileModifiedAt,
this.fileSizeInByte,
this.fps,
required this.id,
required this.isArchived,
required this.isExternal,
required this.isFavorite,
required this.isOffline,
this.iso,
this.latitude,
this.lensModel,
this.libraryId,
this.livePhotoVideoId,
this.longitude,
this.make,
this.model,
this.modifyDate,
this.orientation,
required this.originalFileName,
required this.originalPath,
required this.ownerId,
this.profileDescription,
this.projectionType,
this.rating,
this.state,
required this.status,
this.thumbhash,
required this.type,
});
///
/// 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.
///
num? bitsPerSample;
String checksum;
///
/// 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.
///
String? city;
///
/// 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.
///
String? colorspace;
///
/// 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.
///
String? country;
String createdAt;
///
/// 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.
///
String? dateTimeOriginal;
///
/// 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.
///
String? deletedAt;
///
/// 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.
///
String? duration;
///
/// 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.
///
num? exifImageHeight;
///
/// 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.
///
num? exifImageWidth;
///
/// 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.
///
String? exposureTime;
///
/// 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.
///
num? fNumber;
String fileCreatedAt;
String fileModifiedAt;
///
/// 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.
///
num? fileSizeInByte;
///
/// 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.
///
num? fps;
String id;
bool isArchived;
bool isExternal;
bool isFavorite;
bool isOffline;
///
/// 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.
///
num? iso;
///
/// 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.
///
num? latitude;
///
/// 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.
///
String? lensModel;
///
/// 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.
///
String? libraryId;
///
/// 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.
///
String? livePhotoVideoId;
///
/// 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.
///
num? longitude;
///
/// 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.
///
String? make;
///
/// 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.
///
String? model;
///
/// 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.
///
String? modifyDate;
///
/// 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.
///
String? orientation;
String originalFileName;
String originalPath;
String ownerId;
///
/// 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.
///
String? profileDescription;
///
/// 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.
///
String? projectionType;
///
/// 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.
///
num? rating;
///
/// 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.
///
String? state;
SyncAssetOwnerDtoV1StatusEnum status;
///
/// 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.
///
String? thumbhash;
SyncAssetOwnerDtoV1TypeEnum type;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncAssetOwnerDtoV1 &&
other.bitsPerSample == bitsPerSample &&
other.checksum == checksum &&
other.city == city &&
other.colorspace == colorspace &&
other.country == country &&
other.createdAt == createdAt &&
other.dateTimeOriginal == dateTimeOriginal &&
other.deletedAt == deletedAt &&
other.duration == duration &&
other.exifImageHeight == exifImageHeight &&
other.exifImageWidth == exifImageWidth &&
other.exposureTime == exposureTime &&
other.fNumber == fNumber &&
other.fileCreatedAt == fileCreatedAt &&
other.fileModifiedAt == fileModifiedAt &&
other.fileSizeInByte == fileSizeInByte &&
other.fps == fps &&
other.id == id &&
other.isArchived == isArchived &&
other.isExternal == isExternal &&
other.isFavorite == isFavorite &&
other.isOffline == isOffline &&
other.iso == iso &&
other.latitude == latitude &&
other.lensModel == lensModel &&
other.libraryId == libraryId &&
other.livePhotoVideoId == livePhotoVideoId &&
other.longitude == longitude &&
other.make == make &&
other.model == model &&
other.modifyDate == modifyDate &&
other.orientation == orientation &&
other.originalFileName == originalFileName &&
other.originalPath == originalPath &&
other.ownerId == ownerId &&
other.profileDescription == profileDescription &&
other.projectionType == projectionType &&
other.rating == rating &&
other.state == state &&
other.status == status &&
other.thumbhash == thumbhash &&
other.type == type;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(bitsPerSample == null ? 0 : bitsPerSample!.hashCode) +
(checksum.hashCode) +
(city == null ? 0 : city!.hashCode) +
(colorspace == null ? 0 : colorspace!.hashCode) +
(country == null ? 0 : country!.hashCode) +
(createdAt.hashCode) +
(dateTimeOriginal == null ? 0 : dateTimeOriginal!.hashCode) +
(deletedAt == null ? 0 : deletedAt!.hashCode) +
(duration == null ? 0 : duration!.hashCode) +
(exifImageHeight == null ? 0 : exifImageHeight!.hashCode) +
(exifImageWidth == null ? 0 : exifImageWidth!.hashCode) +
(exposureTime == null ? 0 : exposureTime!.hashCode) +
(fNumber == null ? 0 : fNumber!.hashCode) +
(fileCreatedAt.hashCode) +
(fileModifiedAt.hashCode) +
(fileSizeInByte == null ? 0 : fileSizeInByte!.hashCode) +
(fps == null ? 0 : fps!.hashCode) +
(id.hashCode) +
(isArchived.hashCode) +
(isExternal.hashCode) +
(isFavorite.hashCode) +
(isOffline.hashCode) +
(iso == null ? 0 : iso!.hashCode) +
(latitude == null ? 0 : latitude!.hashCode) +
(lensModel == null ? 0 : lensModel!.hashCode) +
(libraryId == null ? 0 : libraryId!.hashCode) +
(livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode) +
(longitude == null ? 0 : longitude!.hashCode) +
(make == null ? 0 : make!.hashCode) +
(model == null ? 0 : model!.hashCode) +
(modifyDate == null ? 0 : modifyDate!.hashCode) +
(orientation == null ? 0 : orientation!.hashCode) +
(originalFileName.hashCode) +
(originalPath.hashCode) +
(ownerId.hashCode) +
(profileDescription == null ? 0 : profileDescription!.hashCode) +
(projectionType == null ? 0 : projectionType!.hashCode) +
(rating == null ? 0 : rating!.hashCode) +
(state == null ? 0 : state!.hashCode) +
(status.hashCode) +
(thumbhash == null ? 0 : thumbhash!.hashCode) +
(type.hashCode);
@override
String toString() => 'SyncAssetOwnerDtoV1[bitsPerSample=$bitsPerSample, checksum=$checksum, city=$city, colorspace=$colorspace, country=$country, createdAt=$createdAt, dateTimeOriginal=$dateTimeOriginal, deletedAt=$deletedAt, duration=$duration, exifImageHeight=$exifImageHeight, exifImageWidth=$exifImageWidth, exposureTime=$exposureTime, fNumber=$fNumber, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, fileSizeInByte=$fileSizeInByte, fps=$fps, id=$id, isArchived=$isArchived, isExternal=$isExternal, isFavorite=$isFavorite, isOffline=$isOffline, iso=$iso, latitude=$latitude, lensModel=$lensModel, libraryId=$libraryId, livePhotoVideoId=$livePhotoVideoId, longitude=$longitude, make=$make, model=$model, modifyDate=$modifyDate, orientation=$orientation, originalFileName=$originalFileName, originalPath=$originalPath, ownerId=$ownerId, profileDescription=$profileDescription, projectionType=$projectionType, rating=$rating, state=$state, status=$status, thumbhash=$thumbhash, type=$type]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
if (this.bitsPerSample != null) {
json[r'bitsPerSample'] = this.bitsPerSample;
} else {
// json[r'bitsPerSample'] = null;
}
json[r'checksum'] = this.checksum;
if (this.city != null) {
json[r'city'] = this.city;
} else {
// json[r'city'] = null;
}
if (this.colorspace != null) {
json[r'colorspace'] = this.colorspace;
} else {
// json[r'colorspace'] = null;
}
if (this.country != null) {
json[r'country'] = this.country;
} else {
// json[r'country'] = null;
}
json[r'createdAt'] = this.createdAt;
if (this.dateTimeOriginal != null) {
json[r'dateTimeOriginal'] = this.dateTimeOriginal;
} else {
// json[r'dateTimeOriginal'] = null;
}
if (this.deletedAt != null) {
json[r'deletedAt'] = this.deletedAt;
} else {
// json[r'deletedAt'] = null;
}
if (this.duration != null) {
json[r'duration'] = this.duration;
} else {
// json[r'duration'] = null;
}
if (this.exifImageHeight != null) {
json[r'exifImageHeight'] = this.exifImageHeight;
} else {
// json[r'exifImageHeight'] = null;
}
if (this.exifImageWidth != null) {
json[r'exifImageWidth'] = this.exifImageWidth;
} else {
// json[r'exifImageWidth'] = null;
}
if (this.exposureTime != null) {
json[r'exposureTime'] = this.exposureTime;
} else {
// json[r'exposureTime'] = null;
}
if (this.fNumber != null) {
json[r'fNumber'] = this.fNumber;
} else {
// json[r'fNumber'] = null;
}
json[r'fileCreatedAt'] = this.fileCreatedAt;
json[r'fileModifiedAt'] = this.fileModifiedAt;
if (this.fileSizeInByte != null) {
json[r'fileSizeInByte'] = this.fileSizeInByte;
} else {
// json[r'fileSizeInByte'] = null;
}
if (this.fps != null) {
json[r'fps'] = this.fps;
} else {
// json[r'fps'] = null;
}
json[r'id'] = this.id;
json[r'isArchived'] = this.isArchived;
json[r'isExternal'] = this.isExternal;
json[r'isFavorite'] = this.isFavorite;
json[r'isOffline'] = this.isOffline;
if (this.iso != null) {
json[r'iso'] = this.iso;
} else {
// json[r'iso'] = null;
}
if (this.latitude != null) {
json[r'latitude'] = this.latitude;
} else {
// json[r'latitude'] = null;
}
if (this.lensModel != null) {
json[r'lensModel'] = this.lensModel;
} else {
// json[r'lensModel'] = null;
}
if (this.libraryId != null) {
json[r'libraryId'] = this.libraryId;
} else {
// json[r'libraryId'] = null;
}
if (this.livePhotoVideoId != null) {
json[r'livePhotoVideoId'] = this.livePhotoVideoId;
} else {
// json[r'livePhotoVideoId'] = null;
}
if (this.longitude != null) {
json[r'longitude'] = this.longitude;
} else {
// json[r'longitude'] = null;
}
if (this.make != null) {
json[r'make'] = this.make;
} else {
// json[r'make'] = null;
}
if (this.model != null) {
json[r'model'] = this.model;
} else {
// json[r'model'] = null;
}
if (this.modifyDate != null) {
json[r'modifyDate'] = this.modifyDate;
} else {
// json[r'modifyDate'] = null;
}
if (this.orientation != null) {
json[r'orientation'] = this.orientation;
} else {
// json[r'orientation'] = null;
}
json[r'originalFileName'] = this.originalFileName;
json[r'originalPath'] = this.originalPath;
json[r'ownerId'] = this.ownerId;
if (this.profileDescription != null) {
json[r'profileDescription'] = this.profileDescription;
} else {
// json[r'profileDescription'] = null;
}
if (this.projectionType != null) {
json[r'projectionType'] = this.projectionType;
} else {
// json[r'projectionType'] = null;
}
if (this.rating != null) {
json[r'rating'] = this.rating;
} else {
// json[r'rating'] = null;
}
if (this.state != null) {
json[r'state'] = this.state;
} else {
// json[r'state'] = null;
}
json[r'status'] = this.status;
if (this.thumbhash != null) {
json[r'thumbhash'] = this.thumbhash;
} else {
// json[r'thumbhash'] = null;
}
json[r'type'] = this.type;
return json;
}
/// Returns a new [SyncAssetOwnerDtoV1] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncAssetOwnerDtoV1? fromJson(dynamic value) {
upgradeDto(value, "SyncAssetOwnerDtoV1");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncAssetOwnerDtoV1(
bitsPerSample: num.parse('${json[r'bitsPerSample']}'),
checksum: mapValueOfType<String>(json, r'checksum')!,
city: mapValueOfType<String>(json, r'city'),
colorspace: mapValueOfType<String>(json, r'colorspace'),
country: mapValueOfType<String>(json, r'country'),
createdAt: mapValueOfType<String>(json, r'createdAt')!,
dateTimeOriginal: mapValueOfType<String>(json, r'dateTimeOriginal'),
deletedAt: mapValueOfType<String>(json, r'deletedAt'),
duration: mapValueOfType<String>(json, r'duration'),
exifImageHeight: num.parse('${json[r'exifImageHeight']}'),
exifImageWidth: num.parse('${json[r'exifImageWidth']}'),
exposureTime: mapValueOfType<String>(json, r'exposureTime'),
fNumber: num.parse('${json[r'fNumber']}'),
fileCreatedAt: mapValueOfType<String>(json, r'fileCreatedAt')!,
fileModifiedAt: mapValueOfType<String>(json, r'fileModifiedAt')!,
fileSizeInByte: num.parse('${json[r'fileSizeInByte']}'),
fps: num.parse('${json[r'fps']}'),
id: mapValueOfType<String>(json, r'id')!,
isArchived: mapValueOfType<bool>(json, r'isArchived')!,
isExternal: mapValueOfType<bool>(json, r'isExternal')!,
isFavorite: mapValueOfType<bool>(json, r'isFavorite')!,
isOffline: mapValueOfType<bool>(json, r'isOffline')!,
iso: num.parse('${json[r'iso']}'),
latitude: num.parse('${json[r'latitude']}'),
lensModel: mapValueOfType<String>(json, r'lensModel'),
libraryId: mapValueOfType<String>(json, r'libraryId'),
livePhotoVideoId: mapValueOfType<String>(json, r'livePhotoVideoId'),
longitude: num.parse('${json[r'longitude']}'),
make: mapValueOfType<String>(json, r'make'),
model: mapValueOfType<String>(json, r'model'),
modifyDate: mapValueOfType<String>(json, r'modifyDate'),
orientation: mapValueOfType<String>(json, r'orientation'),
originalFileName: mapValueOfType<String>(json, r'originalFileName')!,
originalPath: mapValueOfType<String>(json, r'originalPath')!,
ownerId: mapValueOfType<String>(json, r'ownerId')!,
profileDescription: mapValueOfType<String>(json, r'profileDescription'),
projectionType: mapValueOfType<String>(json, r'projectionType'),
rating: num.parse('${json[r'rating']}'),
state: mapValueOfType<String>(json, r'state'),
status: SyncAssetOwnerDtoV1StatusEnum.fromJson(json[r'status'])!,
thumbhash: mapValueOfType<String>(json, r'thumbhash'),
type: SyncAssetOwnerDtoV1TypeEnum.fromJson(json[r'type'])!,
);
}
return null;
}
static List<SyncAssetOwnerDtoV1> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAssetOwnerDtoV1>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAssetOwnerDtoV1.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncAssetOwnerDtoV1> mapFromJson(dynamic json) {
final map = <String, SyncAssetOwnerDtoV1>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncAssetOwnerDtoV1.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncAssetOwnerDtoV1-objects as value to a dart map
static Map<String, List<SyncAssetOwnerDtoV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncAssetOwnerDtoV1>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncAssetOwnerDtoV1.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'checksum',
'createdAt',
'fileCreatedAt',
'fileModifiedAt',
'id',
'isArchived',
'isExternal',
'isFavorite',
'isOffline',
'originalFileName',
'originalPath',
'ownerId',
'status',
'type',
};
}
class SyncAssetOwnerDtoV1StatusEnum {
/// Instantiate a new enum with the provided [value].
const SyncAssetOwnerDtoV1StatusEnum._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const active = SyncAssetOwnerDtoV1StatusEnum._(r'active');
static const trashed = SyncAssetOwnerDtoV1StatusEnum._(r'trashed');
static const deleted = SyncAssetOwnerDtoV1StatusEnum._(r'deleted');
/// List of all possible values in this [enum][SyncAssetOwnerDtoV1StatusEnum].
static const values = <SyncAssetOwnerDtoV1StatusEnum>[
active,
trashed,
deleted,
];
static SyncAssetOwnerDtoV1StatusEnum? fromJson(dynamic value) => SyncAssetOwnerDtoV1StatusEnumTypeTransformer().decode(value);
static List<SyncAssetOwnerDtoV1StatusEnum> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAssetOwnerDtoV1StatusEnum>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAssetOwnerDtoV1StatusEnum.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [SyncAssetOwnerDtoV1StatusEnum] to String,
/// and [decode] dynamic data back to [SyncAssetOwnerDtoV1StatusEnum].
class SyncAssetOwnerDtoV1StatusEnumTypeTransformer {
factory SyncAssetOwnerDtoV1StatusEnumTypeTransformer() => _instance ??= const SyncAssetOwnerDtoV1StatusEnumTypeTransformer._();
const SyncAssetOwnerDtoV1StatusEnumTypeTransformer._();
String encode(SyncAssetOwnerDtoV1StatusEnum data) => data.value;
/// Decodes a [dynamic value][data] to a SyncAssetOwnerDtoV1StatusEnum.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
SyncAssetOwnerDtoV1StatusEnum? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'active': return SyncAssetOwnerDtoV1StatusEnum.active;
case r'trashed': return SyncAssetOwnerDtoV1StatusEnum.trashed;
case r'deleted': return SyncAssetOwnerDtoV1StatusEnum.deleted;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [SyncAssetOwnerDtoV1StatusEnumTypeTransformer] instance.
static SyncAssetOwnerDtoV1StatusEnumTypeTransformer? _instance;
}
class SyncAssetOwnerDtoV1TypeEnum {
/// Instantiate a new enum with the provided [value].
const SyncAssetOwnerDtoV1TypeEnum._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const IMAGE = SyncAssetOwnerDtoV1TypeEnum._(r'IMAGE');
static const VIDEO = SyncAssetOwnerDtoV1TypeEnum._(r'VIDEO');
static const AUDIO = SyncAssetOwnerDtoV1TypeEnum._(r'AUDIO');
static const OTHER = SyncAssetOwnerDtoV1TypeEnum._(r'OTHER');
/// List of all possible values in this [enum][SyncAssetOwnerDtoV1TypeEnum].
static const values = <SyncAssetOwnerDtoV1TypeEnum>[
IMAGE,
VIDEO,
AUDIO,
OTHER,
];
static SyncAssetOwnerDtoV1TypeEnum? fromJson(dynamic value) => SyncAssetOwnerDtoV1TypeEnumTypeTransformer().decode(value);
static List<SyncAssetOwnerDtoV1TypeEnum> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAssetOwnerDtoV1TypeEnum>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAssetOwnerDtoV1TypeEnum.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [SyncAssetOwnerDtoV1TypeEnum] to String,
/// and [decode] dynamic data back to [SyncAssetOwnerDtoV1TypeEnum].
class SyncAssetOwnerDtoV1TypeEnumTypeTransformer {
factory SyncAssetOwnerDtoV1TypeEnumTypeTransformer() => _instance ??= const SyncAssetOwnerDtoV1TypeEnumTypeTransformer._();
const SyncAssetOwnerDtoV1TypeEnumTypeTransformer._();
String encode(SyncAssetOwnerDtoV1TypeEnum data) => data.value;
/// Decodes a [dynamic value][data] to a SyncAssetOwnerDtoV1TypeEnum.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
SyncAssetOwnerDtoV1TypeEnum? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'IMAGE': return SyncAssetOwnerDtoV1TypeEnum.IMAGE;
case r'VIDEO': return SyncAssetOwnerDtoV1TypeEnum.VIDEO;
case r'AUDIO': return SyncAssetOwnerDtoV1TypeEnum.AUDIO;
case r'OTHER': return SyncAssetOwnerDtoV1TypeEnum.OTHER;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [SyncAssetOwnerDtoV1TypeEnumTypeTransformer] instance.
static SyncAssetOwnerDtoV1TypeEnumTypeTransformer? _instance;
}

View File

@ -0,0 +1,107 @@
//
// 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 SyncAssetPartnerDeleteV1 {
/// Returns a new [SyncAssetPartnerDeleteV1] instance.
SyncAssetPartnerDeleteV1({
required this.deletedAt,
required this.id,
});
String deletedAt;
String id;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncAssetPartnerDeleteV1 &&
other.deletedAt == deletedAt &&
other.id == id;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(deletedAt.hashCode) +
(id.hashCode);
@override
String toString() => 'SyncAssetPartnerDeleteV1[deletedAt=$deletedAt, id=$id]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'deletedAt'] = this.deletedAt;
json[r'id'] = this.id;
return json;
}
/// Returns a new [SyncAssetPartnerDeleteV1] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncAssetPartnerDeleteV1? fromJson(dynamic value) {
upgradeDto(value, "SyncAssetPartnerDeleteV1");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncAssetPartnerDeleteV1(
deletedAt: mapValueOfType<String>(json, r'deletedAt')!,
id: mapValueOfType<String>(json, r'id')!,
);
}
return null;
}
static List<SyncAssetPartnerDeleteV1> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAssetPartnerDeleteV1>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAssetPartnerDeleteV1.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncAssetPartnerDeleteV1> mapFromJson(dynamic json) {
final map = <String, SyncAssetPartnerDeleteV1>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncAssetPartnerDeleteV1.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncAssetPartnerDeleteV1-objects as value to a dart map
static Map<String, List<SyncAssetPartnerDeleteV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncAssetPartnerDeleteV1>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncAssetPartnerDeleteV1.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'deletedAt',
'id',
};
}

View File

@ -0,0 +1,836 @@
//
// 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 SyncAssetPartnerDtoV1 {
/// Returns a new [SyncAssetPartnerDtoV1] instance.
SyncAssetPartnerDtoV1({
this.bitsPerSample,
required this.checksum,
this.city,
this.colorspace,
this.country,
required this.createdAt,
this.dateTimeOriginal,
this.deletedAt,
this.duration,
this.exifImageHeight,
this.exifImageWidth,
this.exposureTime,
this.fNumber,
required this.fileCreatedAt,
required this.fileModifiedAt,
this.fileSizeInByte,
this.fps,
required this.id,
required this.isArchived,
required this.isExternal,
required this.isFavorite,
required this.isOffline,
this.iso,
this.latitude,
this.lensModel,
this.libraryId,
this.livePhotoVideoId,
this.longitude,
this.make,
this.model,
this.modifyDate,
this.orientation,
required this.originalFileName,
required this.originalPath,
required this.ownerId,
this.profileDescription,
this.projectionType,
this.rating,
this.state,
required this.status,
this.thumbhash,
required this.type,
});
///
/// 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.
///
num? bitsPerSample;
String checksum;
///
/// 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.
///
String? city;
///
/// 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.
///
String? colorspace;
///
/// 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.
///
String? country;
String createdAt;
///
/// 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.
///
String? dateTimeOriginal;
///
/// 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.
///
String? deletedAt;
///
/// 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.
///
String? duration;
///
/// 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.
///
num? exifImageHeight;
///
/// 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.
///
num? exifImageWidth;
///
/// 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.
///
String? exposureTime;
///
/// 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.
///
num? fNumber;
String fileCreatedAt;
String fileModifiedAt;
///
/// 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.
///
num? fileSizeInByte;
///
/// 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.
///
num? fps;
String id;
bool isArchived;
bool isExternal;
bool isFavorite;
bool isOffline;
///
/// 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.
///
num? iso;
///
/// 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.
///
num? latitude;
///
/// 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.
///
String? lensModel;
///
/// 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.
///
String? libraryId;
///
/// 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.
///
String? livePhotoVideoId;
///
/// 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.
///
num? longitude;
///
/// 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.
///
String? make;
///
/// 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.
///
String? model;
///
/// 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.
///
String? modifyDate;
///
/// 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.
///
String? orientation;
String originalFileName;
String originalPath;
String ownerId;
///
/// 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.
///
String? profileDescription;
///
/// 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.
///
String? projectionType;
///
/// 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.
///
num? rating;
///
/// 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.
///
String? state;
SyncAssetPartnerDtoV1StatusEnum status;
///
/// 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.
///
String? thumbhash;
SyncAssetPartnerDtoV1TypeEnum type;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncAssetPartnerDtoV1 &&
other.bitsPerSample == bitsPerSample &&
other.checksum == checksum &&
other.city == city &&
other.colorspace == colorspace &&
other.country == country &&
other.createdAt == createdAt &&
other.dateTimeOriginal == dateTimeOriginal &&
other.deletedAt == deletedAt &&
other.duration == duration &&
other.exifImageHeight == exifImageHeight &&
other.exifImageWidth == exifImageWidth &&
other.exposureTime == exposureTime &&
other.fNumber == fNumber &&
other.fileCreatedAt == fileCreatedAt &&
other.fileModifiedAt == fileModifiedAt &&
other.fileSizeInByte == fileSizeInByte &&
other.fps == fps &&
other.id == id &&
other.isArchived == isArchived &&
other.isExternal == isExternal &&
other.isFavorite == isFavorite &&
other.isOffline == isOffline &&
other.iso == iso &&
other.latitude == latitude &&
other.lensModel == lensModel &&
other.libraryId == libraryId &&
other.livePhotoVideoId == livePhotoVideoId &&
other.longitude == longitude &&
other.make == make &&
other.model == model &&
other.modifyDate == modifyDate &&
other.orientation == orientation &&
other.originalFileName == originalFileName &&
other.originalPath == originalPath &&
other.ownerId == ownerId &&
other.profileDescription == profileDescription &&
other.projectionType == projectionType &&
other.rating == rating &&
other.state == state &&
other.status == status &&
other.thumbhash == thumbhash &&
other.type == type;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(bitsPerSample == null ? 0 : bitsPerSample!.hashCode) +
(checksum.hashCode) +
(city == null ? 0 : city!.hashCode) +
(colorspace == null ? 0 : colorspace!.hashCode) +
(country == null ? 0 : country!.hashCode) +
(createdAt.hashCode) +
(dateTimeOriginal == null ? 0 : dateTimeOriginal!.hashCode) +
(deletedAt == null ? 0 : deletedAt!.hashCode) +
(duration == null ? 0 : duration!.hashCode) +
(exifImageHeight == null ? 0 : exifImageHeight!.hashCode) +
(exifImageWidth == null ? 0 : exifImageWidth!.hashCode) +
(exposureTime == null ? 0 : exposureTime!.hashCode) +
(fNumber == null ? 0 : fNumber!.hashCode) +
(fileCreatedAt.hashCode) +
(fileModifiedAt.hashCode) +
(fileSizeInByte == null ? 0 : fileSizeInByte!.hashCode) +
(fps == null ? 0 : fps!.hashCode) +
(id.hashCode) +
(isArchived.hashCode) +
(isExternal.hashCode) +
(isFavorite.hashCode) +
(isOffline.hashCode) +
(iso == null ? 0 : iso!.hashCode) +
(latitude == null ? 0 : latitude!.hashCode) +
(lensModel == null ? 0 : lensModel!.hashCode) +
(libraryId == null ? 0 : libraryId!.hashCode) +
(livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode) +
(longitude == null ? 0 : longitude!.hashCode) +
(make == null ? 0 : make!.hashCode) +
(model == null ? 0 : model!.hashCode) +
(modifyDate == null ? 0 : modifyDate!.hashCode) +
(orientation == null ? 0 : orientation!.hashCode) +
(originalFileName.hashCode) +
(originalPath.hashCode) +
(ownerId.hashCode) +
(profileDescription == null ? 0 : profileDescription!.hashCode) +
(projectionType == null ? 0 : projectionType!.hashCode) +
(rating == null ? 0 : rating!.hashCode) +
(state == null ? 0 : state!.hashCode) +
(status.hashCode) +
(thumbhash == null ? 0 : thumbhash!.hashCode) +
(type.hashCode);
@override
String toString() => 'SyncAssetPartnerDtoV1[bitsPerSample=$bitsPerSample, checksum=$checksum, city=$city, colorspace=$colorspace, country=$country, createdAt=$createdAt, dateTimeOriginal=$dateTimeOriginal, deletedAt=$deletedAt, duration=$duration, exifImageHeight=$exifImageHeight, exifImageWidth=$exifImageWidth, exposureTime=$exposureTime, fNumber=$fNumber, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, fileSizeInByte=$fileSizeInByte, fps=$fps, id=$id, isArchived=$isArchived, isExternal=$isExternal, isFavorite=$isFavorite, isOffline=$isOffline, iso=$iso, latitude=$latitude, lensModel=$lensModel, libraryId=$libraryId, livePhotoVideoId=$livePhotoVideoId, longitude=$longitude, make=$make, model=$model, modifyDate=$modifyDate, orientation=$orientation, originalFileName=$originalFileName, originalPath=$originalPath, ownerId=$ownerId, profileDescription=$profileDescription, projectionType=$projectionType, rating=$rating, state=$state, status=$status, thumbhash=$thumbhash, type=$type]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
if (this.bitsPerSample != null) {
json[r'bitsPerSample'] = this.bitsPerSample;
} else {
// json[r'bitsPerSample'] = null;
}
json[r'checksum'] = this.checksum;
if (this.city != null) {
json[r'city'] = this.city;
} else {
// json[r'city'] = null;
}
if (this.colorspace != null) {
json[r'colorspace'] = this.colorspace;
} else {
// json[r'colorspace'] = null;
}
if (this.country != null) {
json[r'country'] = this.country;
} else {
// json[r'country'] = null;
}
json[r'createdAt'] = this.createdAt;
if (this.dateTimeOriginal != null) {
json[r'dateTimeOriginal'] = this.dateTimeOriginal;
} else {
// json[r'dateTimeOriginal'] = null;
}
if (this.deletedAt != null) {
json[r'deletedAt'] = this.deletedAt;
} else {
// json[r'deletedAt'] = null;
}
if (this.duration != null) {
json[r'duration'] = this.duration;
} else {
// json[r'duration'] = null;
}
if (this.exifImageHeight != null) {
json[r'exifImageHeight'] = this.exifImageHeight;
} else {
// json[r'exifImageHeight'] = null;
}
if (this.exifImageWidth != null) {
json[r'exifImageWidth'] = this.exifImageWidth;
} else {
// json[r'exifImageWidth'] = null;
}
if (this.exposureTime != null) {
json[r'exposureTime'] = this.exposureTime;
} else {
// json[r'exposureTime'] = null;
}
if (this.fNumber != null) {
json[r'fNumber'] = this.fNumber;
} else {
// json[r'fNumber'] = null;
}
json[r'fileCreatedAt'] = this.fileCreatedAt;
json[r'fileModifiedAt'] = this.fileModifiedAt;
if (this.fileSizeInByte != null) {
json[r'fileSizeInByte'] = this.fileSizeInByte;
} else {
// json[r'fileSizeInByte'] = null;
}
if (this.fps != null) {
json[r'fps'] = this.fps;
} else {
// json[r'fps'] = null;
}
json[r'id'] = this.id;
json[r'isArchived'] = this.isArchived;
json[r'isExternal'] = this.isExternal;
json[r'isFavorite'] = this.isFavorite;
json[r'isOffline'] = this.isOffline;
if (this.iso != null) {
json[r'iso'] = this.iso;
} else {
// json[r'iso'] = null;
}
if (this.latitude != null) {
json[r'latitude'] = this.latitude;
} else {
// json[r'latitude'] = null;
}
if (this.lensModel != null) {
json[r'lensModel'] = this.lensModel;
} else {
// json[r'lensModel'] = null;
}
if (this.libraryId != null) {
json[r'libraryId'] = this.libraryId;
} else {
// json[r'libraryId'] = null;
}
if (this.livePhotoVideoId != null) {
json[r'livePhotoVideoId'] = this.livePhotoVideoId;
} else {
// json[r'livePhotoVideoId'] = null;
}
if (this.longitude != null) {
json[r'longitude'] = this.longitude;
} else {
// json[r'longitude'] = null;
}
if (this.make != null) {
json[r'make'] = this.make;
} else {
// json[r'make'] = null;
}
if (this.model != null) {
json[r'model'] = this.model;
} else {
// json[r'model'] = null;
}
if (this.modifyDate != null) {
json[r'modifyDate'] = this.modifyDate;
} else {
// json[r'modifyDate'] = null;
}
if (this.orientation != null) {
json[r'orientation'] = this.orientation;
} else {
// json[r'orientation'] = null;
}
json[r'originalFileName'] = this.originalFileName;
json[r'originalPath'] = this.originalPath;
json[r'ownerId'] = this.ownerId;
if (this.profileDescription != null) {
json[r'profileDescription'] = this.profileDescription;
} else {
// json[r'profileDescription'] = null;
}
if (this.projectionType != null) {
json[r'projectionType'] = this.projectionType;
} else {
// json[r'projectionType'] = null;
}
if (this.rating != null) {
json[r'rating'] = this.rating;
} else {
// json[r'rating'] = null;
}
if (this.state != null) {
json[r'state'] = this.state;
} else {
// json[r'state'] = null;
}
json[r'status'] = this.status;
if (this.thumbhash != null) {
json[r'thumbhash'] = this.thumbhash;
} else {
// json[r'thumbhash'] = null;
}
json[r'type'] = this.type;
return json;
}
/// Returns a new [SyncAssetPartnerDtoV1] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncAssetPartnerDtoV1? fromJson(dynamic value) {
upgradeDto(value, "SyncAssetPartnerDtoV1");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncAssetPartnerDtoV1(
bitsPerSample: num.parse('${json[r'bitsPerSample']}'),
checksum: mapValueOfType<String>(json, r'checksum')!,
city: mapValueOfType<String>(json, r'city'),
colorspace: mapValueOfType<String>(json, r'colorspace'),
country: mapValueOfType<String>(json, r'country'),
createdAt: mapValueOfType<String>(json, r'createdAt')!,
dateTimeOriginal: mapValueOfType<String>(json, r'dateTimeOriginal'),
deletedAt: mapValueOfType<String>(json, r'deletedAt'),
duration: mapValueOfType<String>(json, r'duration'),
exifImageHeight: num.parse('${json[r'exifImageHeight']}'),
exifImageWidth: num.parse('${json[r'exifImageWidth']}'),
exposureTime: mapValueOfType<String>(json, r'exposureTime'),
fNumber: num.parse('${json[r'fNumber']}'),
fileCreatedAt: mapValueOfType<String>(json, r'fileCreatedAt')!,
fileModifiedAt: mapValueOfType<String>(json, r'fileModifiedAt')!,
fileSizeInByte: num.parse('${json[r'fileSizeInByte']}'),
fps: num.parse('${json[r'fps']}'),
id: mapValueOfType<String>(json, r'id')!,
isArchived: mapValueOfType<bool>(json, r'isArchived')!,
isExternal: mapValueOfType<bool>(json, r'isExternal')!,
isFavorite: mapValueOfType<bool>(json, r'isFavorite')!,
isOffline: mapValueOfType<bool>(json, r'isOffline')!,
iso: num.parse('${json[r'iso']}'),
latitude: num.parse('${json[r'latitude']}'),
lensModel: mapValueOfType<String>(json, r'lensModel'),
libraryId: mapValueOfType<String>(json, r'libraryId'),
livePhotoVideoId: mapValueOfType<String>(json, r'livePhotoVideoId'),
longitude: num.parse('${json[r'longitude']}'),
make: mapValueOfType<String>(json, r'make'),
model: mapValueOfType<String>(json, r'model'),
modifyDate: mapValueOfType<String>(json, r'modifyDate'),
orientation: mapValueOfType<String>(json, r'orientation'),
originalFileName: mapValueOfType<String>(json, r'originalFileName')!,
originalPath: mapValueOfType<String>(json, r'originalPath')!,
ownerId: mapValueOfType<String>(json, r'ownerId')!,
profileDescription: mapValueOfType<String>(json, r'profileDescription'),
projectionType: mapValueOfType<String>(json, r'projectionType'),
rating: num.parse('${json[r'rating']}'),
state: mapValueOfType<String>(json, r'state'),
status: SyncAssetPartnerDtoV1StatusEnum.fromJson(json[r'status'])!,
thumbhash: mapValueOfType<String>(json, r'thumbhash'),
type: SyncAssetPartnerDtoV1TypeEnum.fromJson(json[r'type'])!,
);
}
return null;
}
static List<SyncAssetPartnerDtoV1> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAssetPartnerDtoV1>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAssetPartnerDtoV1.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncAssetPartnerDtoV1> mapFromJson(dynamic json) {
final map = <String, SyncAssetPartnerDtoV1>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncAssetPartnerDtoV1.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncAssetPartnerDtoV1-objects as value to a dart map
static Map<String, List<SyncAssetPartnerDtoV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncAssetPartnerDtoV1>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncAssetPartnerDtoV1.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'checksum',
'createdAt',
'fileCreatedAt',
'fileModifiedAt',
'id',
'isArchived',
'isExternal',
'isFavorite',
'isOffline',
'originalFileName',
'originalPath',
'ownerId',
'status',
'type',
};
}
class SyncAssetPartnerDtoV1StatusEnum {
/// Instantiate a new enum with the provided [value].
const SyncAssetPartnerDtoV1StatusEnum._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const active = SyncAssetPartnerDtoV1StatusEnum._(r'active');
static const trashed = SyncAssetPartnerDtoV1StatusEnum._(r'trashed');
static const deleted = SyncAssetPartnerDtoV1StatusEnum._(r'deleted');
/// List of all possible values in this [enum][SyncAssetPartnerDtoV1StatusEnum].
static const values = <SyncAssetPartnerDtoV1StatusEnum>[
active,
trashed,
deleted,
];
static SyncAssetPartnerDtoV1StatusEnum? fromJson(dynamic value) => SyncAssetPartnerDtoV1StatusEnumTypeTransformer().decode(value);
static List<SyncAssetPartnerDtoV1StatusEnum> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAssetPartnerDtoV1StatusEnum>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAssetPartnerDtoV1StatusEnum.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [SyncAssetPartnerDtoV1StatusEnum] to String,
/// and [decode] dynamic data back to [SyncAssetPartnerDtoV1StatusEnum].
class SyncAssetPartnerDtoV1StatusEnumTypeTransformer {
factory SyncAssetPartnerDtoV1StatusEnumTypeTransformer() => _instance ??= const SyncAssetPartnerDtoV1StatusEnumTypeTransformer._();
const SyncAssetPartnerDtoV1StatusEnumTypeTransformer._();
String encode(SyncAssetPartnerDtoV1StatusEnum data) => data.value;
/// Decodes a [dynamic value][data] to a SyncAssetPartnerDtoV1StatusEnum.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
SyncAssetPartnerDtoV1StatusEnum? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'active': return SyncAssetPartnerDtoV1StatusEnum.active;
case r'trashed': return SyncAssetPartnerDtoV1StatusEnum.trashed;
case r'deleted': return SyncAssetPartnerDtoV1StatusEnum.deleted;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [SyncAssetPartnerDtoV1StatusEnumTypeTransformer] instance.
static SyncAssetPartnerDtoV1StatusEnumTypeTransformer? _instance;
}
class SyncAssetPartnerDtoV1TypeEnum {
/// Instantiate a new enum with the provided [value].
const SyncAssetPartnerDtoV1TypeEnum._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const IMAGE = SyncAssetPartnerDtoV1TypeEnum._(r'IMAGE');
static const VIDEO = SyncAssetPartnerDtoV1TypeEnum._(r'VIDEO');
static const AUDIO = SyncAssetPartnerDtoV1TypeEnum._(r'AUDIO');
static const OTHER = SyncAssetPartnerDtoV1TypeEnum._(r'OTHER');
/// List of all possible values in this [enum][SyncAssetPartnerDtoV1TypeEnum].
static const values = <SyncAssetPartnerDtoV1TypeEnum>[
IMAGE,
VIDEO,
AUDIO,
OTHER,
];
static SyncAssetPartnerDtoV1TypeEnum? fromJson(dynamic value) => SyncAssetPartnerDtoV1TypeEnumTypeTransformer().decode(value);
static List<SyncAssetPartnerDtoV1TypeEnum> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAssetPartnerDtoV1TypeEnum>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAssetPartnerDtoV1TypeEnum.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [SyncAssetPartnerDtoV1TypeEnum] to String,
/// and [decode] dynamic data back to [SyncAssetPartnerDtoV1TypeEnum].
class SyncAssetPartnerDtoV1TypeEnumTypeTransformer {
factory SyncAssetPartnerDtoV1TypeEnumTypeTransformer() => _instance ??= const SyncAssetPartnerDtoV1TypeEnumTypeTransformer._();
const SyncAssetPartnerDtoV1TypeEnumTypeTransformer._();
String encode(SyncAssetPartnerDtoV1TypeEnum data) => data.value;
/// Decodes a [dynamic value][data] to a SyncAssetPartnerDtoV1TypeEnum.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
SyncAssetPartnerDtoV1TypeEnum? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'IMAGE': return SyncAssetPartnerDtoV1TypeEnum.IMAGE;
case r'VIDEO': return SyncAssetPartnerDtoV1TypeEnum.VIDEO;
case r'AUDIO': return SyncAssetPartnerDtoV1TypeEnum.AUDIO;
case r'OTHER': return SyncAssetPartnerDtoV1TypeEnum.OTHER;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [SyncAssetPartnerDtoV1TypeEnumTypeTransformer] instance.
static SyncAssetPartnerDtoV1TypeEnumTypeTransformer? _instance;
}

View File

@ -0,0 +1,107 @@
//
// 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 SyncMemoryDelete {
/// Returns a new [SyncMemoryDelete] instance.
SyncMemoryDelete({
required this.deletedAt,
required this.id,
});
String deletedAt;
String id;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncMemoryDelete &&
other.deletedAt == deletedAt &&
other.id == id;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(deletedAt.hashCode) +
(id.hashCode);
@override
String toString() => 'SyncMemoryDelete[deletedAt=$deletedAt, id=$id]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'deletedAt'] = this.deletedAt;
json[r'id'] = this.id;
return json;
}
/// Returns a new [SyncMemoryDelete] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncMemoryDelete? fromJson(dynamic value) {
upgradeDto(value, "SyncMemoryDelete");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncMemoryDelete(
deletedAt: mapValueOfType<String>(json, r'deletedAt')!,
id: mapValueOfType<String>(json, r'id')!,
);
}
return null;
}
static List<SyncMemoryDelete> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncMemoryDelete>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncMemoryDelete.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncMemoryDelete> mapFromJson(dynamic json) {
final map = <String, SyncMemoryDelete>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncMemoryDelete.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncMemoryDelete-objects as value to a dart map
static Map<String, List<SyncMemoryDelete>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncMemoryDelete>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncMemoryDelete.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'deletedAt',
'id',
};
}

View File

@ -0,0 +1,115 @@
//
// 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 SyncMemoryDtoV1 {
/// Returns a new [SyncMemoryDtoV1] instance.
SyncMemoryDtoV1({
required this.description,
required this.id,
required this.name,
});
String description;
String id;
String name;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncMemoryDtoV1 &&
other.description == description &&
other.id == id &&
other.name == name;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(description.hashCode) +
(id.hashCode) +
(name.hashCode);
@override
String toString() => 'SyncMemoryDtoV1[description=$description, id=$id, name=$name]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'description'] = this.description;
json[r'id'] = this.id;
json[r'name'] = this.name;
return json;
}
/// Returns a new [SyncMemoryDtoV1] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncMemoryDtoV1? fromJson(dynamic value) {
upgradeDto(value, "SyncMemoryDtoV1");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncMemoryDtoV1(
description: mapValueOfType<String>(json, r'description')!,
id: mapValueOfType<String>(json, r'id')!,
name: mapValueOfType<String>(json, r'name')!,
);
}
return null;
}
static List<SyncMemoryDtoV1> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncMemoryDtoV1>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncMemoryDtoV1.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncMemoryDtoV1> mapFromJson(dynamic json) {
final map = <String, SyncMemoryDtoV1>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncMemoryDtoV1.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncMemoryDtoV1-objects as value to a dart map
static Map<String, List<SyncMemoryDtoV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncMemoryDtoV1>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncMemoryDtoV1.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'description',
'id',
'name',
};
}

View File

@ -0,0 +1,251 @@
//
// 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 SyncStreamDto {
/// Returns a new [SyncStreamDto] instance.
SyncStreamDto({
this.types = const [],
});
List<SyncStreamDtoTypesEnum> types;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncStreamDto &&
_deepEquality.equals(other.types, types);
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(types.hashCode);
@override
String toString() => 'SyncStreamDto[types=$types]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'types'] = this.types;
return json;
}
/// Returns a new [SyncStreamDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncStreamDto? fromJson(dynamic value) {
upgradeDto(value, "SyncStreamDto");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncStreamDto(
types: SyncStreamDtoTypesEnum.listFromJson(json[r'types']),
);
}
return null;
}
static List<SyncStreamDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncStreamDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncStreamDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncStreamDto> mapFromJson(dynamic json) {
final map = <String, SyncStreamDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncStreamDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncStreamDto-objects as value to a dart map
static Map<String, List<SyncStreamDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncStreamDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncStreamDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'types',
};
}
class SyncStreamDtoTypesEnum {
/// Instantiate a new enum with the provided [value].
const SyncStreamDtoTypesEnum._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const activityV1 = SyncStreamDtoTypesEnum._(r'ActivityV1');
static const activityDeleteV1 = SyncStreamDtoTypesEnum._(r'ActivityDeleteV1');
static const assetOwnerV1 = SyncStreamDtoTypesEnum._(r'AssetOwnerV1');
static const assetOwnerDeleteV1 = SyncStreamDtoTypesEnum._(r'AssetOwnerDeleteV1');
static const assetPartnerV1 = SyncStreamDtoTypesEnum._(r'AssetPartnerV1');
static const assetPartnerDeleteV1 = SyncStreamDtoTypesEnum._(r'AssetPartnerDeleteV1');
static const assetAlbumV1 = SyncStreamDtoTypesEnum._(r'AssetAlbumV1');
static const assetAlbumDeleteV1 = SyncStreamDtoTypesEnum._(r'AssetAlbumDeleteV1');
static const albumV1 = SyncStreamDtoTypesEnum._(r'AlbumV1');
static const albumDeleteV1 = SyncStreamDtoTypesEnum._(r'AlbumDeleteV1');
static const memoryV1 = SyncStreamDtoTypesEnum._(r'MemoryV1');
static const memoryDeleteV1 = SyncStreamDtoTypesEnum._(r'MemoryDeleteV1');
static const partnerV1 = SyncStreamDtoTypesEnum._(r'PartnerV1');
static const partnerDeleteV1 = SyncStreamDtoTypesEnum._(r'PartnerDeleteV1');
static const personV1 = SyncStreamDtoTypesEnum._(r'PersonV1');
static const personDeleteV1 = SyncStreamDtoTypesEnum._(r'PersonDeleteV1');
static const sharedLinkV1 = SyncStreamDtoTypesEnum._(r'SharedLinkV1');
static const sharedLinkDeleteV1 = SyncStreamDtoTypesEnum._(r'SharedLinkDeleteV1');
static const stackV1 = SyncStreamDtoTypesEnum._(r'StackV1');
static const stackDeleteV1 = SyncStreamDtoTypesEnum._(r'StackDeleteV1');
static const tagV1 = SyncStreamDtoTypesEnum._(r'TagV1');
static const tagDeleteV1 = SyncStreamDtoTypesEnum._(r'TagDeleteV1');
static const userV1 = SyncStreamDtoTypesEnum._(r'UserV1');
static const userDeleteV1 = SyncStreamDtoTypesEnum._(r'UserDeleteV1');
static const albumAssetV1 = SyncStreamDtoTypesEnum._(r'AlbumAssetV1');
static const albumAssetDeleteV1 = SyncStreamDtoTypesEnum._(r'AlbumAssetDeleteV1');
static const albumUserV1 = SyncStreamDtoTypesEnum._(r'AlbumUserV1');
static const albumDeleteUserV1 = SyncStreamDtoTypesEnum._(r'AlbumDeleteUserV1');
/// List of all possible values in this [enum][SyncStreamDtoTypesEnum].
static const values = <SyncStreamDtoTypesEnum>[
activityV1,
activityDeleteV1,
assetOwnerV1,
assetOwnerDeleteV1,
assetPartnerV1,
assetPartnerDeleteV1,
assetAlbumV1,
assetAlbumDeleteV1,
albumV1,
albumDeleteV1,
memoryV1,
memoryDeleteV1,
partnerV1,
partnerDeleteV1,
personV1,
personDeleteV1,
sharedLinkV1,
sharedLinkDeleteV1,
stackV1,
stackDeleteV1,
tagV1,
tagDeleteV1,
userV1,
userDeleteV1,
albumAssetV1,
albumAssetDeleteV1,
albumUserV1,
albumDeleteUserV1,
];
static SyncStreamDtoTypesEnum? fromJson(dynamic value) => SyncStreamDtoTypesEnumTypeTransformer().decode(value);
static List<SyncStreamDtoTypesEnum> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncStreamDtoTypesEnum>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncStreamDtoTypesEnum.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [SyncStreamDtoTypesEnum] to String,
/// and [decode] dynamic data back to [SyncStreamDtoTypesEnum].
class SyncStreamDtoTypesEnumTypeTransformer {
factory SyncStreamDtoTypesEnumTypeTransformer() => _instance ??= const SyncStreamDtoTypesEnumTypeTransformer._();
const SyncStreamDtoTypesEnumTypeTransformer._();
String encode(SyncStreamDtoTypesEnum data) => data.value;
/// Decodes a [dynamic value][data] to a SyncStreamDtoTypesEnum.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
SyncStreamDtoTypesEnum? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'ActivityV1': return SyncStreamDtoTypesEnum.activityV1;
case r'ActivityDeleteV1': return SyncStreamDtoTypesEnum.activityDeleteV1;
case r'AssetOwnerV1': return SyncStreamDtoTypesEnum.assetOwnerV1;
case r'AssetOwnerDeleteV1': return SyncStreamDtoTypesEnum.assetOwnerDeleteV1;
case r'AssetPartnerV1': return SyncStreamDtoTypesEnum.assetPartnerV1;
case r'AssetPartnerDeleteV1': return SyncStreamDtoTypesEnum.assetPartnerDeleteV1;
case r'AssetAlbumV1': return SyncStreamDtoTypesEnum.assetAlbumV1;
case r'AssetAlbumDeleteV1': return SyncStreamDtoTypesEnum.assetAlbumDeleteV1;
case r'AlbumV1': return SyncStreamDtoTypesEnum.albumV1;
case r'AlbumDeleteV1': return SyncStreamDtoTypesEnum.albumDeleteV1;
case r'MemoryV1': return SyncStreamDtoTypesEnum.memoryV1;
case r'MemoryDeleteV1': return SyncStreamDtoTypesEnum.memoryDeleteV1;
case r'PartnerV1': return SyncStreamDtoTypesEnum.partnerV1;
case r'PartnerDeleteV1': return SyncStreamDtoTypesEnum.partnerDeleteV1;
case r'PersonV1': return SyncStreamDtoTypesEnum.personV1;
case r'PersonDeleteV1': return SyncStreamDtoTypesEnum.personDeleteV1;
case r'SharedLinkV1': return SyncStreamDtoTypesEnum.sharedLinkV1;
case r'SharedLinkDeleteV1': return SyncStreamDtoTypesEnum.sharedLinkDeleteV1;
case r'StackV1': return SyncStreamDtoTypesEnum.stackV1;
case r'StackDeleteV1': return SyncStreamDtoTypesEnum.stackDeleteV1;
case r'TagV1': return SyncStreamDtoTypesEnum.tagV1;
case r'TagDeleteV1': return SyncStreamDtoTypesEnum.tagDeleteV1;
case r'UserV1': return SyncStreamDtoTypesEnum.userV1;
case r'UserDeleteV1': return SyncStreamDtoTypesEnum.userDeleteV1;
case r'AlbumAssetV1': return SyncStreamDtoTypesEnum.albumAssetV1;
case r'AlbumAssetDeleteV1': return SyncStreamDtoTypesEnum.albumAssetDeleteV1;
case r'AlbumUserV1': return SyncStreamDtoTypesEnum.albumUserV1;
case r'AlbumDeleteUserV1': return SyncStreamDtoTypesEnum.albumDeleteUserV1;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [SyncStreamDtoTypesEnumTypeTransformer] instance.
static SyncStreamDtoTypesEnumTypeTransformer? _instance;
}

View File

@ -5778,6 +5778,41 @@
]
}
},
"/sync/acknowledge": {
"post": {
"operationId": "ackSync",
"parameters": [],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SyncAcknowledgeDto"
}
}
},
"required": true
},
"responses": {
"204": {
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"tags": [
"Sync"
]
}
},
"/sync/delta-sync": {
"post": {
"operationId": "getDeltaSync",
@ -5865,6 +5900,41 @@
]
}
},
"/sync/stream": {
"post": {
"operationId": "getSyncStream",
"parameters": [],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SyncStreamDto"
}
}
},
"required": true
},
"responses": {
"200": {
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"tags": [
"Sync"
]
}
},
"/system-config": {
"get": {
"operationId": "getConfig",
@ -11481,6 +11551,743 @@
},
"type": "object"
},
"SyncAcknowledgeDto": {
"properties": {
"timestamp": {
"type": "string"
},
"type": {
"enum": [
"Activity",
"ActivityDelete",
"AssetOwner",
"AssetOwnerDelete",
"AssetPartner",
"AssetPartnerDelete",
"AssetAlbum",
"AssetAlbumDelete",
"Album",
"AlbumDelete",
"Memory",
"MemoryDelete",
"Partner",
"PartnerDelete",
"Person",
"PersonDelete",
"SharedLink",
"SharedLinkDelete",
"Stack",
"StackDelete",
"Tag",
"TagDelete",
"User",
"UserDelete",
"AlbumAsset",
"AlbumAssetDelete",
"AlbumUser",
"AlbumUserDelete"
],
"type": "string"
}
},
"required": [
"timestamp",
"type"
],
"type": "object"
},
"SyncActivityDeleteDtoV1": {
"properties": {
"deletedAt": {
"type": "string"
},
"id": {
"type": "string"
}
},
"required": [
"deletedAt",
"id"
],
"type": "object"
},
"SyncActivityDtoV1": {
"properties": {},
"type": "object"
},
"SyncAlbumAssetDeleteDtoV1": {
"properties": {
"albumId": {
"format": "uuid",
"type": "string"
},
"assetId": {
"format": "uuid",
"type": "string"
},
"deletedAt": {
"type": "string"
}
},
"required": [
"albumId",
"assetId",
"deletedAt"
],
"type": "object"
},
"SyncAlbumAssetDtoV1": {
"properties": {
"albumId": {
"format": "uuid",
"type": "string"
},
"assetId": {
"format": "uuid",
"type": "string"
},
"createdAt": {
"type": "string"
}
},
"required": [
"albumId",
"assetId",
"createdAt"
],
"type": "object"
},
"SyncAlbumDeleteV1": {
"properties": {
"deletedAt": {
"type": "string"
},
"id": {
"type": "string"
}
},
"required": [
"deletedAt",
"id"
],
"type": "object"
},
"SyncAlbumDtoV1": {
"properties": {
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"description",
"id",
"name"
],
"type": "object"
},
"SyncAssetAlbumDeleteV1": {
"properties": {
"deletedAt": {
"type": "string"
},
"id": {
"type": "string"
}
},
"required": [
"deletedAt",
"id"
],
"type": "object"
},
"SyncAssetAlbumDtoV1": {
"properties": {
"bitsPerSample": {
"type": "number"
},
"checksum": {
"type": "string"
},
"city": {
"type": "string"
},
"colorspace": {
"type": "string"
},
"country": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"dateTimeOriginal": {
"type": "string"
},
"deletedAt": {
"type": "string"
},
"duration": {
"type": "string"
},
"exifImageHeight": {
"type": "number"
},
"exifImageWidth": {
"type": "number"
},
"exposureTime": {
"type": "string"
},
"fNumber": {
"type": "number"
},
"fileCreatedAt": {
"type": "string"
},
"fileModifiedAt": {
"type": "string"
},
"fileSizeInByte": {
"type": "number"
},
"fps": {
"type": "number"
},
"id": {
"type": "string"
},
"isArchived": {
"type": "boolean"
},
"isExternal": {
"type": "boolean"
},
"isFavorite": {
"type": "boolean"
},
"isOffline": {
"type": "boolean"
},
"iso": {
"type": "number"
},
"latitude": {
"type": "number"
},
"lensModel": {
"type": "string"
},
"libraryId": {
"type": "string"
},
"livePhotoVideoId": {
"type": "string"
},
"longitude": {
"type": "number"
},
"make": {
"type": "string"
},
"model": {
"type": "string"
},
"modifyDate": {
"type": "string"
},
"orientation": {
"type": "string"
},
"originalFileName": {
"type": "string"
},
"originalPath": {
"type": "string"
},
"ownerId": {
"type": "string"
},
"profileDescription": {
"type": "string"
},
"projectionType": {
"type": "string"
},
"rating": {
"type": "number"
},
"state": {
"type": "string"
},
"status": {
"enum": [
"active",
"trashed",
"deleted"
],
"type": "string"
},
"thumbhash": {
"type": "string"
},
"type": {
"enum": [
"IMAGE",
"VIDEO",
"AUDIO",
"OTHER"
],
"type": "string"
}
},
"required": [
"checksum",
"createdAt",
"fileCreatedAt",
"fileModifiedAt",
"id",
"isArchived",
"isExternal",
"isFavorite",
"isOffline",
"originalFileName",
"originalPath",
"ownerId",
"status",
"type"
],
"type": "object"
},
"SyncAssetOwnerDeleteV1": {
"properties": {
"deletedAt": {
"type": "string"
},
"id": {
"type": "string"
}
},
"required": [
"deletedAt",
"id"
],
"type": "object"
},
"SyncAssetOwnerDtoV1": {
"properties": {
"bitsPerSample": {
"type": "number"
},
"checksum": {
"type": "string"
},
"city": {
"type": "string"
},
"colorspace": {
"type": "string"
},
"country": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"dateTimeOriginal": {
"type": "string"
},
"deletedAt": {
"type": "string"
},
"duration": {
"type": "string"
},
"exifImageHeight": {
"type": "number"
},
"exifImageWidth": {
"type": "number"
},
"exposureTime": {
"type": "string"
},
"fNumber": {
"type": "number"
},
"fileCreatedAt": {
"type": "string"
},
"fileModifiedAt": {
"type": "string"
},
"fileSizeInByte": {
"type": "number"
},
"fps": {
"type": "number"
},
"id": {
"type": "string"
},
"isArchived": {
"type": "boolean"
},
"isExternal": {
"type": "boolean"
},
"isFavorite": {
"type": "boolean"
},
"isOffline": {
"type": "boolean"
},
"iso": {
"type": "number"
},
"latitude": {
"type": "number"
},
"lensModel": {
"type": "string"
},
"libraryId": {
"type": "string"
},
"livePhotoVideoId": {
"type": "string"
},
"longitude": {
"type": "number"
},
"make": {
"type": "string"
},
"model": {
"type": "string"
},
"modifyDate": {
"type": "string"
},
"orientation": {
"type": "string"
},
"originalFileName": {
"type": "string"
},
"originalPath": {
"type": "string"
},
"ownerId": {
"type": "string"
},
"profileDescription": {
"type": "string"
},
"projectionType": {
"type": "string"
},
"rating": {
"type": "number"
},
"state": {
"type": "string"
},
"status": {
"enum": [
"active",
"trashed",
"deleted"
],
"type": "string"
},
"thumbhash": {
"type": "string"
},
"type": {
"enum": [
"IMAGE",
"VIDEO",
"AUDIO",
"OTHER"
],
"type": "string"
}
},
"required": [
"checksum",
"createdAt",
"fileCreatedAt",
"fileModifiedAt",
"id",
"isArchived",
"isExternal",
"isFavorite",
"isOffline",
"originalFileName",
"originalPath",
"ownerId",
"status",
"type"
],
"type": "object"
},
"SyncAssetPartnerDeleteV1": {
"properties": {
"deletedAt": {
"type": "string"
},
"id": {
"type": "string"
}
},
"required": [
"deletedAt",
"id"
],
"type": "object"
},
"SyncAssetPartnerDtoV1": {
"properties": {
"bitsPerSample": {
"type": "number"
},
"checksum": {
"type": "string"
},
"city": {
"type": "string"
},
"colorspace": {
"type": "string"
},
"country": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"dateTimeOriginal": {
"type": "string"
},
"deletedAt": {
"type": "string"
},
"duration": {
"type": "string"
},
"exifImageHeight": {
"type": "number"
},
"exifImageWidth": {
"type": "number"
},
"exposureTime": {
"type": "string"
},
"fNumber": {
"type": "number"
},
"fileCreatedAt": {
"type": "string"
},
"fileModifiedAt": {
"type": "string"
},
"fileSizeInByte": {
"type": "number"
},
"fps": {
"type": "number"
},
"id": {
"type": "string"
},
"isArchived": {
"type": "boolean"
},
"isExternal": {
"type": "boolean"
},
"isFavorite": {
"type": "boolean"
},
"isOffline": {
"type": "boolean"
},
"iso": {
"type": "number"
},
"latitude": {
"type": "number"
},
"lensModel": {
"type": "string"
},
"libraryId": {
"type": "string"
},
"livePhotoVideoId": {
"type": "string"
},
"longitude": {
"type": "number"
},
"make": {
"type": "string"
},
"model": {
"type": "string"
},
"modifyDate": {
"type": "string"
},
"orientation": {
"type": "string"
},
"originalFileName": {
"type": "string"
},
"originalPath": {
"type": "string"
},
"ownerId": {
"type": "string"
},
"profileDescription": {
"type": "string"
},
"projectionType": {
"type": "string"
},
"rating": {
"type": "number"
},
"state": {
"type": "string"
},
"status": {
"enum": [
"active",
"trashed",
"deleted"
],
"type": "string"
},
"thumbhash": {
"type": "string"
},
"type": {
"enum": [
"IMAGE",
"VIDEO",
"AUDIO",
"OTHER"
],
"type": "string"
}
},
"required": [
"checksum",
"createdAt",
"fileCreatedAt",
"fileModifiedAt",
"id",
"isArchived",
"isExternal",
"isFavorite",
"isOffline",
"originalFileName",
"originalPath",
"ownerId",
"status",
"type"
],
"type": "object"
},
"SyncMemoryDelete": {
"properties": {
"deletedAt": {
"type": "string"
},
"id": {
"type": "string"
}
},
"required": [
"deletedAt",
"id"
],
"type": "object"
},
"SyncMemoryDtoV1": {
"properties": {
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"description",
"id",
"name"
],
"type": "object"
},
"SyncStreamDto": {
"properties": {
"types": {
"items": {
"enum": [
"ActivityV1",
"ActivityDeleteV1",
"AssetOwnerV1",
"AssetOwnerDeleteV1",
"AssetPartnerV1",
"AssetPartnerDeleteV1",
"AssetAlbumV1",
"AssetAlbumDeleteV1",
"AlbumV1",
"AlbumDeleteV1",
"MemoryV1",
"MemoryDeleteV1",
"PartnerV1",
"PartnerDeleteV1",
"PersonV1",
"PersonDeleteV1",
"SharedLinkV1",
"SharedLinkDeleteV1",
"StackV1",
"StackDeleteV1",
"TagV1",
"TagDeleteV1",
"UserV1",
"UserDeleteV1",
"AlbumAssetV1",
"AlbumAssetDeleteV1",
"AlbumUserV1",
"AlbumDeleteUserV1"
],
"type": "string"
},
"type": "array"
}
},
"required": [
"types"
],
"type": "object"
},
"SystemConfigBackupsDto": {
"properties": {
"database": {

View File

@ -1070,6 +1070,10 @@ export type StackCreateDto = {
export type StackUpdateDto = {
primaryAssetId?: string;
};
export type SyncAcknowledgeDto = {
timestamp: string;
"type": Type;
};
export type AssetDeltaSyncDto = {
updatedAfter: string;
userIds: string[];
@ -1085,6 +1089,9 @@ export type AssetFullSyncDto = {
updatedUntil: string;
userId?: string;
};
export type SyncStreamDto = {
types: ("ActivityV1" | "ActivityDeleteV1" | "AssetOwnerV1" | "AssetOwnerDeleteV1" | "AssetPartnerV1" | "AssetPartnerDeleteV1" | "AssetAlbumV1" | "AssetAlbumDeleteV1" | "AlbumV1" | "AlbumDeleteV1" | "MemoryV1" | "MemoryDeleteV1" | "PartnerV1" | "PartnerDeleteV1" | "PersonV1" | "PersonDeleteV1" | "SharedLinkV1" | "SharedLinkDeleteV1" | "StackV1" | "StackDeleteV1" | "TagV1" | "TagDeleteV1" | "UserV1" | "UserDeleteV1" | "AlbumAssetV1" | "AlbumAssetDeleteV1" | "AlbumUserV1" | "AlbumDeleteUserV1")[];
};
export type DatabaseBackupConfig = {
cronExpression: string;
enabled: boolean;
@ -2861,6 +2868,15 @@ export function updateStack({ id, stackUpdateDto }: {
body: stackUpdateDto
})));
}
export function ackSync({ syncAcknowledgeDto }: {
syncAcknowledgeDto: SyncAcknowledgeDto;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchText("/sync/acknowledge", oazapfts.json({
...opts,
method: "POST",
body: syncAcknowledgeDto
})));
}
export function getDeltaSync({ assetDeltaSyncDto }: {
assetDeltaSyncDto: AssetDeltaSyncDto;
}, opts?: Oazapfts.RequestOpts) {
@ -2885,6 +2901,15 @@ export function getFullSyncForUser({ assetFullSyncDto }: {
body: assetFullSyncDto
})));
}
export function getSyncStream({ syncStreamDto }: {
syncStreamDto: SyncStreamDto;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchText("/sync/stream", oazapfts.json({
...opts,
method: "POST",
body: syncStreamDto
})));
}
export function getConfig(opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
@ -3501,6 +3526,36 @@ export enum Error2 {
NoPermission = "no_permission",
NotFound = "not_found"
}
export enum Type {
Activity = "Activity",
ActivityDelete = "ActivityDelete",
AssetOwner = "AssetOwner",
AssetOwnerDelete = "AssetOwnerDelete",
AssetPartner = "AssetPartner",
AssetPartnerDelete = "AssetPartnerDelete",
AssetAlbum = "AssetAlbum",
AssetAlbumDelete = "AssetAlbumDelete",
Album = "Album",
AlbumDelete = "AlbumDelete",
Memory = "Memory",
MemoryDelete = "MemoryDelete",
Partner = "Partner",
PartnerDelete = "PartnerDelete",
Person = "Person",
PersonDelete = "PersonDelete",
SharedLink = "SharedLink",
SharedLinkDelete = "SharedLinkDelete",
Stack = "Stack",
StackDelete = "StackDelete",
Tag = "Tag",
TagDelete = "TagDelete",
User = "User",
UserDelete = "UserDelete",
AlbumAsset = "AlbumAsset",
AlbumAssetDelete = "AlbumAssetDelete",
AlbumUser = "AlbumUser",
AlbumUserDelete = "AlbumUserDelete"
}
export enum TranscodeHWAccel {
Nvenc = "nvenc",
Qsv = "qsv",

View File

@ -25,7 +25,7 @@ import { teardownTelemetry } from 'src/repositories/telemetry.repository';
import { services } from 'src/services';
import { DatabaseService } from 'src/services/database.service';
const common = [...services, ...repositories];
const common = [...services, ...repositories, GlobalExceptionFilter];
const middleware = [
FileUploadInterceptor,

View File

@ -1,27 +1,58 @@
import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common';
import { Body, Controller, Header, HttpCode, HttpStatus, Post, Res } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Response } from 'express';
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
import { AuthDto } from 'src/dtos/auth.dto';
import { AssetDeltaSyncDto, AssetDeltaSyncResponseDto, AssetFullSyncDto } from 'src/dtos/sync.dto';
import {
AssetDeltaSyncDto,
AssetDeltaSyncResponseDto,
AssetFullSyncDto,
SyncAcknowledgeDto,
SyncStreamDto,
} from 'src/dtos/sync.dto';
import { Auth, Authenticated } from 'src/middleware/auth.guard';
import { GlobalExceptionFilter } from 'src/middleware/global-exception.filter';
import { SyncService } from 'src/services/sync.service';
@ApiTags('Sync')
@Controller('sync')
export class SyncController {
constructor(private service: SyncService) {}
constructor(
private syncService: SyncService,
private errorService: GlobalExceptionFilter,
) {}
@Post('acknowledge')
@HttpCode(HttpStatus.NO_CONTENT)
@Authenticated()
ackSync(@Auth() auth: AuthDto, @Body() dto: SyncAcknowledgeDto) {
return this.syncService.acknowledge(auth, dto);
}
@Post('stream')
@Header('Content-Type', 'application/jsonlines+json')
@HttpCode(HttpStatus.OK)
@Authenticated()
getSyncStream(@Auth() auth: AuthDto, @Res() res: Response, @Body() dto: SyncStreamDto) {
try {
void this.syncService.stream(auth, res, dto);
} catch (error: Error | any) {
res.setHeader('Content-Type', 'application/json');
this.errorService.handleError(res, error);
}
}
@Post('full-sync')
@HttpCode(HttpStatus.OK)
@Authenticated()
getFullSyncForUser(@Auth() auth: AuthDto, @Body() dto: AssetFullSyncDto): Promise<AssetResponseDto[]> {
return this.service.getFullSync(auth, dto);
return this.syncService.getFullSync(auth, dto);
}
@Post('delta-sync')
@HttpCode(HttpStatus.OK)
@Authenticated()
getDeltaSync(@Auth() auth: AuthDto, @Body() dto: AssetDeltaSyncDto): Promise<AssetDeltaSyncResponseDto> {
return this.service.getDeltaSync(auth, dto);
return this.syncService.getDeltaSync(auth, dto);
}
}

View File

@ -1,8 +1,162 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsInt, IsPositive } from 'class-validator';
import { ApiProperty, getSchemaPath } from '@nestjs/swagger';
import { ArrayNotEmpty, IsDateString, IsEnum, IsInt, IsPositive } from 'class-validator';
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
import { AssetStatus, AssetType, SyncAcknowledgeType, SyncResponseType } from 'src/enum';
import { ValidateDate, ValidateUUID } from 'src/validation';
export class SyncAcknowledgeDto {
@IsEnum(SyncAcknowledgeType)
type!: SyncAcknowledgeType;
@IsDateString({ strict: true })
timestamp!: string;
}
export class SyncCommonDeleteDtoV1 {
id!: string;
deletedAt!: string;
}
export class SyncCommonAssetDtoV1 {
// TODO stop using these
// deviceAssetId!: string;
// deviceId!: string;
id!: string;
ownerId!: string;
libraryId?: string;
livePhotoVideoId?: string;
createdAt!: string;
deletedAt?: string;
fileCreatedAt!: string;
fileModifiedAt!: string;
isFavorite!: boolean;
isArchived!: boolean;
isExternal!: boolean;
isOffline!: boolean;
type!: AssetType;
status!: AssetStatus;
thumbhash?: string;
originalPath!: string;
originalFileName!: string;
checksum!: string;
duration?: string;
exifImageWidth?: number;
exifImageHeight?: number;
fileSizeInByte?: number;
orientation?: string;
dateTimeOriginal?: string;
modifyDate?: string;
latitude?: number;
longitude?: number;
projectionType?: string;
city?: string;
state?: string;
country?: string;
make?: string;
model?: string;
lensModel?: string;
fNumber?: number;
iso?: number;
exposureTime?: string;
profileDescription?: string;
colorspace?: string;
bitsPerSample?: number;
rating?: number;
fps?: number;
}
export class SyncActivityDtoV1 {}
export class SyncActivityDeleteDtoV1 extends SyncCommonDeleteDtoV1 {}
export class SyncAssetOwnerDtoV1 extends SyncCommonAssetDtoV1 {}
export class SyncAssetOwnerDeleteV1 extends SyncCommonDeleteDtoV1 {}
export class SyncAssetPartnerDtoV1 extends SyncCommonAssetDtoV1 {}
export class SyncAssetPartnerDeleteV1 extends SyncCommonDeleteDtoV1 {}
export class SyncAssetAlbumDtoV1 extends SyncCommonAssetDtoV1 {}
export class SyncAssetAlbumDeleteV1 extends SyncCommonDeleteDtoV1 {}
export class SyncAlbumDtoV1 {
id!: string;
name!: string;
description!: string;
}
export class SyncAlbumDeleteV1 extends SyncCommonDeleteDtoV1 {}
export class SyncMemoryDtoV1 {
id!: string;
name!: string;
description!: string;
}
export class SyncMemoryDelete extends SyncCommonDeleteDtoV1 {}
export class SyncAlbumAssetDtoV1 {
@ApiProperty({ format: 'uuid' })
albumId!: string;
@ApiProperty({ format: 'uuid' })
assetId!: string;
createdAt!: string;
}
export class SyncAlbumAssetDeleteDtoV1 {
@ApiProperty({ format: 'uuid' })
albumId!: string;
@ApiProperty({ format: 'uuid' })
assetId!: string;
deletedAt!: string;
}
const responseDtos = [
SyncActivityDtoV1,
SyncActivityDeleteDtoV1,
SyncAssetOwnerDtoV1,
SyncAssetOwnerDeleteV1,
SyncAssetPartnerDtoV1,
SyncAssetPartnerDeleteV1,
SyncAssetAlbumDtoV1,
SyncAssetAlbumDeleteV1,
SyncAlbumDtoV1,
SyncAlbumDeleteV1,
SyncMemoryDtoV1,
SyncMemoryDelete,
SyncAlbumAssetDtoV1,
SyncAlbumAssetDeleteDtoV1,
];
export const extraSyncModels = responseDtos;
export class SyncStreamResponseDto {
@ApiProperty({ enum: SyncResponseType, enumName: 'SyncType' })
type!: SyncResponseType;
@ApiProperty({ anyOf: responseDtos.map((schema) => ({ $ref: getSchemaPath(schema) })) })
data!: SyncCommonAssetDtoV1;
}
export class SyncStreamDto {
@IsEnum(SyncResponseType, { each: true })
@ApiProperty({ enum: SyncResponseType, isArray: true })
@ArrayNotEmpty()
types!: SyncResponseType[];
}
export class AssetFullSyncDto {
@ValidateUUID({ optional: true })
lastId?: string;

View File

@ -21,6 +21,7 @@ import { SharedLinkEntity } from 'src/entities/shared-link.entity';
import { SmartInfoEntity } from 'src/entities/smart-info.entity';
import { SmartSearchEntity } from 'src/entities/smart-search.entity';
import { StackEntity } from 'src/entities/stack.entity';
import { SyncCheckpointEntity } from 'src/entities/sync-checkpoint.entity';
import { SystemMetadataEntity } from 'src/entities/system-metadata.entity';
import { TagEntity } from 'src/entities/tag.entity';
import { UserMetadataEntity } from 'src/entities/user-metadata.entity';
@ -54,6 +55,7 @@ export const entities = [
UserEntity,
UserMetadataEntity,
SessionEntity,
SyncCheckpointEntity,
LibraryEntity,
VersionHistoryEntity,
];

View File

@ -1,5 +1,14 @@
import { SyncCheckpointEntity } from 'src/entities/sync-checkpoint.entity';
import { UserEntity } from 'src/entities/user.entity';
import { Column, CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';
import {
Column,
CreateDateColumn,
Entity,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
@Entity('sessions')
export class SessionEntity {
@ -26,4 +35,7 @@ export class SessionEntity {
@Column({ default: '' })
deviceOS!: string;
@OneToMany(() => SyncCheckpointEntity, (checkpoint) => checkpoint.session)
checkpoints?: SyncCheckpointEntity[];
}

View File

@ -0,0 +1,24 @@
import { SessionEntity } from 'src/entities/session.entity';
import { SyncAcknowledgeType } from 'src/enum';
import { Column, CreateDateColumn, Entity, ManyToOne, PrimaryColumn, UpdateDateColumn } from 'typeorm';
@Entity('session_sync_checkpoints')
export class SyncCheckpointEntity {
@ManyToOne(() => SessionEntity, { onDelete: 'CASCADE', onUpdate: 'CASCADE' })
session?: SessionEntity;
@PrimaryColumn()
sessionId!: string;
@PrimaryColumn({ type: 'varchar' })
type!: SyncAcknowledgeType;
@CreateDateColumn({ type: 'timestamptz' })
createdAt!: Date;
@UpdateDateColumn({ type: 'timestamptz' })
updatedAt!: Date;
@Column({ type: 'timestamptz' })
lastTimestamp!: string;
}

View File

@ -53,6 +53,98 @@ export enum DatabaseAction {
DELETE = 'DELETE',
}
export enum SyncAcknowledgeType {
// base types
Activity = 'Activity',
ActivityDelete = 'ActivityDelete',
AssetOwner = 'AssetOwner',
AssetOwnerDelete = 'AssetOwnerDelete',
AssetPartner = 'AssetPartner',
AssetPartnerDelete = 'AssetPartnerDelete',
AssetAlbum = 'AssetAlbum',
AssetAlbumDelete = 'AssetAlbumDelete',
Album = 'Album',
AlbumDelete = 'AlbumDelete',
Memory = 'Memory',
MemoryDelete = 'MemoryDelete',
Partner = 'Partner',
PartnerDelete = 'PartnerDelete',
Person = 'Person',
PersonDelete = 'PersonDelete',
SharedLink = 'SharedLink',
SharedLinkDelete = 'SharedLinkDelete',
Stack = 'Stack',
StackDelete = 'StackDelete',
Tag = 'Tag',
TagDelete = 'TagDelete',
User = 'User',
UserDelete = 'UserDelete',
// relation types
AlbumAsset = 'AlbumAsset',
AlbumAssetDelete = 'AlbumAssetDelete',
AlbumUser = 'AlbumUser',
AlbumUserDelete = 'AlbumUserDelete',
}
export enum SyncResponseType {
// base types
ActivityV1 = 'ActivityV1',
ActivityDeleteV1 = 'ActivityDeleteV1',
AssetOwnerV1 = 'AssetOwnerV1',
AssetOwnerDeleteV1 = 'AssetOwnerDeleteV1',
AssetPartnerV1 = 'AssetPartnerV1',
AssetPartnerDeleteV1 = 'AssetPartnerDeleteV1',
AssetAlbumV1 = 'AssetAlbumV1',
AssetAlbumDeleteV1 = 'AssetAlbumDeleteV1',
AlbumV1 = 'AlbumV1',
AlbumDeleteV1 = 'AlbumDeleteV1',
MemoryV1 = 'MemoryV1',
MemoryDeleteV1 = 'MemoryDeleteV1',
PartnerV1 = 'PartnerV1',
PartnerDeleteV1 = 'PartnerDeleteV1',
PersonV1 = 'PersonV1',
PersonDeleteV1 = 'PersonDeleteV1',
SharedLinkV1 = 'SharedLinkV1',
SharedLinkDeleteV1 = 'SharedLinkDeleteV1',
StackV1 = 'StackV1',
StackDeleteV1 = 'StackDeleteV1',
TagV1 = 'TagV1',
TagDeleteV1 = 'TagDeleteV1',
UserV1 = 'UserV1',
UserDeleteV1 = 'UserDeleteV1',
// relation types
AlbumAssetV1 = 'AlbumAssetV1',
AlbumAssetDeleteV1 = 'AlbumAssetDeleteV1',
AlbumUserV1 = 'AlbumUserV1',
AlbumUserDeleteV1 = 'AlbumDeleteUserV1',
}
export enum EntityType {
ASSET = 'ASSET',
ALBUM = 'ALBUM',

View File

@ -0,0 +1,44 @@
import { AlbumEntity } from 'src/entities/album.entity';
import { AssetEntity } from 'src/entities/asset.entity';
import { SessionEntity } from 'src/entities/session.entity';
import { SyncCheckpointEntity } from 'src/entities/sync-checkpoint.entity';
import { Paginated, PaginationOptions } from 'src/utils/pagination';
export const ISyncRepository = 'ISyncRepository';
export type SyncOptions = PaginationOptions & {
userId: string;
lastCheckpointTimestamp?: string;
};
export type AssetPartnerSyncOptions = SyncOptions & { partnerIds: string[] };
export type EntityPK = { id: string };
export type DeletedEntity<T = EntityPK> = T & {
deletedAt: Date;
};
export type AlbumAssetPK = {
albumId: string;
assetId: string;
};
export type AlbumAssetEntity = AlbumAssetPK & {
createdAt: Date;
};
export interface ISyncRepository {
get(sessionId: string): Promise<SessionEntity | null>;
upsertCheckpoint(checkpoint: Partial<SyncCheckpointEntity>): Promise<void>;
getAssets(options: SyncOptions): Paginated<AssetEntity>;
getDeletedAssets(options: SyncOptions): Paginated<DeletedEntity>;
getAssetsPartner(options: AssetPartnerSyncOptions): Paginated<AssetEntity>;
getDeletedAssetsPartner(options: AssetPartnerSyncOptions): Paginated<DeletedEntity>;
getAlbums(options: SyncOptions): Paginated<AlbumEntity>;
getDeletedAlbums(options: SyncOptions): Paginated<DeletedEntity>;
getAlbumAssets(options: SyncOptions): Paginated<AlbumAssetEntity>;
getDeletedAlbumAssets(options: SyncOptions): Paginated<DeletedEntity<AlbumAssetPK>>;
}

View File

@ -1,9 +1,10 @@
import { ArgumentsHost, Catch, ExceptionFilter, HttpException, Inject } from '@nestjs/common';
import { ArgumentsHost, Catch, ExceptionFilter, HttpException, Inject, Injectable } from '@nestjs/common';
import { Response } from 'express';
import { ClsService } from 'nestjs-cls';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { logGlobalError } from 'src/utils/logger';
@Injectable()
@Catch()
export class GlobalExceptionFilter implements ExceptionFilter<Error> {
constructor(
@ -15,10 +16,13 @@ export class GlobalExceptionFilter implements ExceptionFilter<Error> {
catch(error: Error, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
this.handleError(ctx.getResponse(), error);
}
handleError(res: Response, error: Error) {
const { status, body } = this.fromError(error);
if (!response.headersSent) {
response.status(status).json({ ...body, statusCode: status, correlationId: this.cls.getId() });
if (!res.headersSent) {
res.status(status).json({ ...body, statusCode: status, correlationId: this.cls.getId() });
}
}

View File

@ -0,0 +1,16 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class AddSyncCheckpointTable1730742937135 implements MigrationInterface {
name = 'AddSyncCheckpointTable1730742937135'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "session_sync_checkpoints" ("sessionId" uuid NOT NULL, "type" character varying NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "lastTimestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_b846ab547a702863ef7cd9412fb" PRIMARY KEY ("sessionId", "type"))`);
await queryRunner.query(`ALTER TABLE "session_sync_checkpoints" ADD CONSTRAINT "FK_d8ddd9d687816cc490432b3d4bc" FOREIGN KEY ("sessionId") REFERENCES "sessions"("id") ON DELETE CASCADE ON UPDATE CASCADE`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "session_sync_checkpoints" DROP CONSTRAINT "FK_d8ddd9d687816cc490432b3d4bc"`);
await queryRunner.query(`DROP TABLE "session_sync_checkpoints"`);
}
}

View File

@ -29,6 +29,7 @@ import { ISessionRepository } from 'src/interfaces/session.interface';
import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface';
import { IStackRepository } from 'src/interfaces/stack.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISyncRepository } from 'src/interfaces/sync.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { ITagRepository } from 'src/interfaces/tag.interface';
import { ITelemetryRepository } from 'src/interfaces/telemetry.interface';
@ -67,6 +68,7 @@ import { SessionRepository } from 'src/repositories/session.repository';
import { SharedLinkRepository } from 'src/repositories/shared-link.repository';
import { StackRepository } from 'src/repositories/stack.repository';
import { StorageRepository } from 'src/repositories/storage.repository';
import { SyncRepository } from 'src/repositories/sync.repository';
import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository';
import { TagRepository } from 'src/repositories/tag.repository';
import { TelemetryRepository } from 'src/repositories/telemetry.repository';
@ -107,6 +109,7 @@ export const repositories = [
{ provide: ISharedLinkRepository, useClass: SharedLinkRepository },
{ provide: IStackRepository, useClass: StackRepository },
{ provide: IStorageRepository, useClass: StorageRepository },
{ provide: ISyncRepository, useClass: SyncRepository },
{ provide: ISystemMetadataRepository, useClass: SystemMetadataRepository },
{ provide: ITagRepository, useClass: TagRepository },
{ provide: ITelemetryRepository, useClass: TelemetryRepository },

View File

@ -0,0 +1,115 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { AlbumEntity } from 'src/entities/album.entity';
import { AssetEntity } from 'src/entities/asset.entity';
import { SessionEntity } from 'src/entities/session.entity';
import { SyncCheckpointEntity } from 'src/entities/sync-checkpoint.entity';
import {
AlbumAssetEntity,
AlbumAssetPK,
AssetPartnerSyncOptions,
DeletedEntity,
EntityPK,
ISyncRepository,
SyncOptions,
} from 'src/interfaces/sync.interface';
import { paginate, Paginated } from 'src/utils/pagination';
import { DataSource, FindOptionsWhere, In, MoreThan, Repository } from 'typeorm';
const withCheckpoint = <T>(where: FindOptionsWhere<T>, key: keyof T, lastCheckpointTimestamp?: string) => {
return lastCheckpointTimestamp ? { ...where, [key]: MoreThan(lastCheckpointTimestamp) } : where;
};
@Injectable()
export class SyncRepository implements ISyncRepository {
constructor(
private dataSource: DataSource,
@InjectRepository(AssetEntity) private assetRepository: Repository<AssetEntity>,
@InjectRepository(AlbumEntity) private albumRepository: Repository<AlbumEntity>,
@InjectRepository(SyncCheckpointEntity) private checkpointRepository: Repository<SyncCheckpointEntity>,
@InjectRepository(SessionEntity) private sessionRepository: Repository<SessionEntity>,
) {}
get(sessionId: string): Promise<SessionEntity | null> {
return this.sessionRepository.findOne({
where: {
id: sessionId,
},
relations: {
checkpoints: true,
},
});
}
async upsertCheckpoint(checkpoint: Partial<SyncCheckpointEntity>): Promise<void> {
await this.checkpointRepository.upsert(checkpoint, { conflictPaths: ['sessionId', 'type'] });
}
getAssets({
lastCheckpointTimestamp: checkpoint,
userId,
...options
}: AssetPartnerSyncOptions): Paginated<AssetEntity> {
return paginate(this.assetRepository, options, {
where: withCheckpoint<AssetEntity>(
{
ownerId: userId,
isVisible: true,
},
'updatedAt',
checkpoint,
),
relations: {
exifInfo: true,
},
order: {
updatedAt: 'ASC',
id: 'ASC',
},
});
}
getDeletedAssets(): Paginated<DeletedEntity<EntityPK>> {
return Promise.resolve({ items: [], hasNextPage: false });
}
getAssetsPartner({
lastCheckpointTimestamp: checkpoint,
partnerIds,
...options
}: AssetPartnerSyncOptions): Paginated<AssetEntity> {
return paginate(this.assetRepository, options, {
where: withCheckpoint<AssetEntity>({ ownerId: In(partnerIds) }, 'updatedAt', checkpoint),
order: {
updatedAt: 'ASC',
id: 'ASC',
},
});
}
getDeletedAssetsPartner(): Paginated<DeletedEntity<EntityPK>> {
return Promise.resolve({ items: [], hasNextPage: false });
}
getAlbums({ lastCheckpointTimestamp: checkpoint, userId, ...options }: SyncOptions): Paginated<AlbumEntity> {
return paginate(this.albumRepository, options, {
where: withCheckpoint<AlbumEntity>({ ownerId: userId }, 'updatedAt', checkpoint),
order: {
updatedAt: 'ASC',
id: 'ASC',
},
});
}
getDeletedAlbums(): Paginated<DeletedEntity<EntityPK>> {
return Promise.resolve({ items: [], hasNextPage: false });
}
getAlbumAssets(): Paginated<AlbumAssetEntity> {
return Promise.resolve({ items: [], hasNextPage: false });
}
getDeletedAlbumAssets(): Paginated<DeletedEntity<AlbumAssetPK>> {
return Promise.resolve({ items: [], hasNextPage: false });
}
}

View File

@ -35,6 +35,7 @@ import { ISessionRepository } from 'src/interfaces/session.interface';
import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface';
import { IStackRepository } from 'src/interfaces/stack.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISyncRepository } from 'src/interfaces/sync.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { ITagRepository } from 'src/interfaces/tag.interface';
import { ITelemetryRepository } from 'src/interfaces/telemetry.interface';
@ -80,6 +81,7 @@ export class BaseService {
@Inject(ISharedLinkRepository) protected sharedLinkRepository: ISharedLinkRepository,
@Inject(IStackRepository) protected stackRepository: IStackRepository,
@Inject(IStorageRepository) protected storageRepository: IStorageRepository,
@Inject(ISyncRepository) protected syncRepository: ISyncRepository,
@Inject(ISystemMetadataRepository) protected systemMetadataRepository: ISystemMetadataRepository,
@Inject(ITagRepository) protected tagRepository: ITagRepository,
@Inject(ITelemetryRepository) protected telemetryRepository: ITelemetryRepository,

View File

@ -1,16 +1,337 @@
import { ForbiddenException } from '@nestjs/common';
import { DateTime } from 'luxon';
import { Writable } from 'node:stream';
import { AUDIT_LOG_MAX_DURATION } from 'src/constants';
import { AlbumResponseDto, mapAlbumWithoutAssets } from 'src/dtos/album.dto';
import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto';
import { AuthDto } from 'src/dtos/auth.dto';
import { AssetDeltaSyncDto, AssetDeltaSyncResponseDto, AssetFullSyncDto } from 'src/dtos/sync.dto';
import { DatabaseAction, EntityType, Permission } from 'src/enum';
import {
AssetDeltaSyncDto,
AssetDeltaSyncResponseDto,
AssetFullSyncDto,
SyncAcknowledgeDto,
SyncAlbumAssetDeleteDtoV1,
SyncAlbumAssetDtoV1,
SyncAlbumDeleteV1,
SyncAssetOwnerDeleteV1,
SyncAssetOwnerDtoV1,
SyncAssetPartnerDeleteV1,
SyncCommonAssetDtoV1,
SyncCommonDeleteDtoV1,
SyncStreamDto,
} from 'src/dtos/sync.dto';
import { AlbumEntity } from 'src/entities/album.entity';
import { AssetEntity } from 'src/entities/asset.entity';
import { SyncCheckpointEntity } from 'src/entities/sync-checkpoint.entity';
import { DatabaseAction, EntityType, Permission, SyncAcknowledgeType, SyncResponseType } from 'src/enum';
import { AlbumAssetEntity, AlbumAssetPK, DeletedEntity, SyncOptions } from 'src/interfaces/sync.interface';
import { BaseService } from 'src/services/base.service';
import { getMyPartnerIds } from 'src/utils/asset.util';
import { Paginated, usePagination } from 'src/utils/pagination';
import { setIsEqual } from 'src/utils/set';
const FULL_SYNC = { needsFullSync: true, deleted: [], upserted: [] };
const SYNC_PAGE_SIZE = 5000;
const createdAt = (item: { createdAt: Date }) => item.createdAt.toISOString();
const updatedAt = (item: { updatedAt: Date }) => item.updatedAt.toISOString();
const deletedAt = (item: { deletedAt: Date }) => item.deletedAt.toISOString();
const mapJsonLine = (item: unknown) => JSON.stringify(item) + '\n';
const v1 = {
mapDeletedDto: (item: DeletedEntity): SyncCommonDeleteDtoV1 => ({
id: item.id,
deletedAt: item.deletedAt.toISOString(),
}),
mapAsset: (item: AssetEntity): SyncCommonAssetDtoV1 => ({
id: item.id,
ownerId: item.ownerId,
libraryId: item.libraryId ?? undefined,
livePhotoVideoId: item.livePhotoVideoId ?? undefined,
createdAt: item.createdAt.toISOString(),
deletedAt: item.deletedAt?.toISOString(),
fileCreatedAt: item.fileCreatedAt.toISOString(),
fileModifiedAt: item.fileModifiedAt.toISOString(),
isFavorite: item.isFavorite,
isArchived: item.isArchived,
isExternal: item.isExternal,
isOffline: item.isOffline,
type: item.type,
status: item.status,
thumbhash: item.thumbhash?.toString('base64'),
originalPath: item.originalPath,
originalFileName: item.originalFileName,
checksum: item.checksum.toString('base64'),
duration: item.duration ?? '0:00:00.00000',
exifImageWidth: item.exifInfo?.exifImageWidth ?? undefined,
exifImageHeight: item.exifInfo?.exifImageHeight ?? undefined,
fileSizeInByte: item.exifInfo?.fileSizeInByte ?? undefined,
orientation: item.exifInfo?.orientation ?? undefined,
dateTimeOriginal: item.exifInfo?.dateTimeOriginal?.toISOString(),
modifyDate: item.exifInfo?.modifyDate?.toISOString(),
latitude: item.exifInfo?.latitude ?? undefined,
longitude: item.exifInfo?.longitude ?? undefined,
projectionType: item.exifInfo?.projectionType ?? undefined,
city: item.exifInfo?.city ?? undefined,
state: item.exifInfo?.state ?? undefined,
country: item.exifInfo?.country ?? undefined,
make: item.exifInfo?.make ?? undefined,
model: item.exifInfo?.model ?? undefined,
lensModel: item.exifInfo?.lensModel ?? undefined,
fNumber: item.exifInfo?.fNumber ?? undefined,
iso: item.exifInfo?.iso ?? undefined,
exposureTime: item.exifInfo?.exposureTime ?? undefined,
profileDescription: item.exifInfo?.profileDescription ?? undefined,
colorspace: item.exifInfo?.colorspace ?? undefined,
bitsPerSample: item.exifInfo?.bitsPerSample ?? undefined,
rating: item.exifInfo?.rating ?? undefined,
fps: item.exifInfo?.fps ?? undefined,
}),
mapAlbumAsset: (item: AlbumAssetEntity) => ({
assetId: item.assetId,
albumId: item.albumId,
createdAt: createdAt(item),
}),
mapAlbumAssetDeleted: (item: DeletedEntity<AlbumAssetPK>) => ({
assetId: item.assetId,
albumId: item.albumId,
deletedAt: deletedAt(item),
}),
};
type CheckpointMap = Partial<Record<SyncAcknowledgeType, SyncCheckpointEntity>>;
type Loader<T> = (options: SyncOptions) => Paginated<T>;
type Mapper<T, R> = (item: T) => R;
type SyncResponseWriteArgs<T, R> = {
type: SyncResponseType;
load: Loader<T>;
map: Mapper<T, R>;
timestamp: Mapper<T, string>;
};
const ackTypes: Record<SyncResponseType, SyncAcknowledgeType> = {
[SyncResponseType.ActivityV1]: SyncAcknowledgeType.Activity,
[SyncResponseType.ActivityDeleteV1]: SyncAcknowledgeType.ActivityDelete,
[SyncResponseType.AssetOwnerV1]: SyncAcknowledgeType.AssetOwner,
[SyncResponseType.AssetOwnerDeleteV1]: SyncAcknowledgeType.AssetOwnerDelete,
[SyncResponseType.AssetPartnerV1]: SyncAcknowledgeType.AssetPartner,
[SyncResponseType.AssetPartnerDeleteV1]: SyncAcknowledgeType.AssetPartnerDelete,
[SyncResponseType.AssetAlbumV1]: SyncAcknowledgeType.AssetAlbum,
[SyncResponseType.AssetAlbumDeleteV1]: SyncAcknowledgeType.AssetAlbumDelete,
[SyncResponseType.AlbumV1]: SyncAcknowledgeType.Album,
[SyncResponseType.AlbumDeleteV1]: SyncAcknowledgeType.AlbumDelete,
[SyncResponseType.MemoryV1]: SyncAcknowledgeType.Memory,
[SyncResponseType.MemoryDeleteV1]: SyncAcknowledgeType.MemoryDelete,
[SyncResponseType.PartnerV1]: SyncAcknowledgeType.Partner,
[SyncResponseType.PartnerDeleteV1]: SyncAcknowledgeType.PartnerDelete,
[SyncResponseType.PersonV1]: SyncAcknowledgeType.Person,
[SyncResponseType.PersonDeleteV1]: SyncAcknowledgeType.PersonDelete,
[SyncResponseType.SharedLinkV1]: SyncAcknowledgeType.SharedLink,
[SyncResponseType.SharedLinkDeleteV1]: SyncAcknowledgeType.SharedLinkDelete,
[SyncResponseType.StackV1]: SyncAcknowledgeType.Stack,
[SyncResponseType.StackDeleteV1]: SyncAcknowledgeType.StackDelete,
[SyncResponseType.TagV1]: SyncAcknowledgeType.Tag,
[SyncResponseType.TagDeleteV1]: SyncAcknowledgeType.TagDelete,
[SyncResponseType.UserV1]: SyncAcknowledgeType.User,
[SyncResponseType.UserDeleteV1]: SyncAcknowledgeType.UserDelete,
// relation types
[SyncResponseType.AlbumAssetV1]: SyncAcknowledgeType.AlbumAsset,
[SyncResponseType.AlbumAssetDeleteV1]: SyncAcknowledgeType.AlbumAssetDelete,
[SyncResponseType.AlbumUserV1]: SyncAcknowledgeType.AlbumUser,
[SyncResponseType.AlbumUserDeleteV1]: SyncAcknowledgeType.AlbumUserDelete,
};
const asAcknowledgeType = (type: SyncResponseType) => ackTypes[type];
class SyncResponseWriter<T = any, R = any> {
private checkpoints?: CheckpointMap;
constructor(private args: SyncResponseWriteArgs<T, R>) {}
async write({ stream, userId }: { stream: Writable; userId: string }) {
const { type: responseType, load, map, timestamp: getTimestamp } = this.args;
const acknowledgeType = asAcknowledgeType(responseType);
let lastCheckpointTimestamp = this.getLastTimestamp(acknowledgeType);
const pagination = usePagination(SYNC_PAGE_SIZE, (options) =>
load({ ...options, userId, lastCheckpointTimestamp }),
);
for await (const items of pagination) {
for (const item of items) {
const timestamp = getTimestamp(item);
const ack = timestamp === lastCheckpointTimestamp ? undefined : { timestamp, type: responseType };
stream.write(mapJsonLine({ type: responseType, data: map(item) || (item as unknown as R), ack }));
lastCheckpointTimestamp = timestamp;
}
}
}
withCheckpoints(checkpoints: CheckpointMap) {
this.checkpoints = checkpoints;
return this;
}
private getLastTimestamp(type: SyncAcknowledgeType) {
if (!this.checkpoints) {
throw new Error('checkpoints not set');
}
return this.checkpoints[type]?.lastTimestamp;
}
}
export class SyncService extends BaseService {
async acknowledge(auth: AuthDto, dto: SyncAcknowledgeDto) {
const { id: sessionId } = this.assertSession(auth);
await this.syncRepository.upsertCheckpoint({
sessionId,
type: dto.type,
lastTimestamp: dto.timestamp,
});
}
async stream(auth: AuthDto, stream: Writable, dto: SyncStreamDto) {
const { id: sessionId, userId } = this.assertSession(auth);
const session = await this.syncRepository.get(sessionId);
const checkpoints: CheckpointMap = Object.fromEntries(
(session?.checkpoints ?? []).map((item) => [item.type, item]),
);
const streamers: SyncResponseWriter[] = [];
for (const type of dto.types) {
switch (type) {
case SyncResponseType.AssetOwnerV1: {
streamers.push(
new SyncResponseWriter<AssetEntity, SyncAssetOwnerDtoV1>({
type: SyncResponseType.AssetOwnerV1,
load: (options) => this.syncRepository.getAssets(options),
map: (item) => v1.mapAsset(item),
timestamp: updatedAt,
}),
);
break;
}
case SyncResponseType.AssetOwnerDeleteV1: {
streamers.push(
new SyncResponseWriter<DeletedEntity, SyncAssetOwnerDeleteV1>({
type: SyncResponseType.AssetOwnerDeleteV1,
load: (options) => this.syncRepository.getDeletedAssets(options),
map: v1.mapDeletedDto,
timestamp: deletedAt,
}),
);
break;
}
case SyncResponseType.AssetPartnerV1: {
const partnerIds = await getMyPartnerIds({ userId, repository: this.partnerRepository });
streamers.push(
new SyncResponseWriter<DeletedEntity, SyncAssetPartnerDeleteV1>({
type: SyncResponseType.AssetPartnerV1,
load: (options) => this.syncRepository.getDeletedAssetsPartner({ ...options, partnerIds }),
map: v1.mapDeletedDto,
timestamp: deletedAt,
}),
);
break;
}
case SyncResponseType.AssetPartnerDeleteV1: {
const partnerIds = await getMyPartnerIds({ userId, repository: this.partnerRepository });
streamers.push(
new SyncResponseWriter<AssetEntity, AssetResponseDto>({
type: SyncResponseType.AssetPartnerDeleteV1,
load: (options) => this.syncRepository.getAssetsPartner({ ...options, partnerIds }),
map: (item) => mapAsset(item, { auth, stripMetadata: false }),
timestamp: updatedAt,
}),
);
break;
}
case SyncResponseType.AlbumV1: {
streamers.push(
new SyncResponseWriter<AlbumEntity, AlbumResponseDto>({
type: SyncResponseType.AlbumV1,
load: (options) => this.syncRepository.getAlbums(options),
map: (item) => mapAlbumWithoutAssets(item),
timestamp: updatedAt,
}),
);
break;
}
case SyncResponseType.AlbumDeleteV1: {
streamers.push(
new SyncResponseWriter<DeletedEntity, SyncAlbumDeleteV1>({
type: SyncResponseType.AlbumDeleteV1,
load: (options) => this.syncRepository.getDeletedAlbums(options),
map: v1.mapDeletedDto,
timestamp: deletedAt,
}),
);
break;
}
case SyncResponseType.AlbumAssetV1: {
streamers.push(
new SyncResponseWriter<AlbumAssetEntity, SyncAlbumAssetDtoV1>({
type: SyncResponseType.AlbumAssetV1,
load: (options) => this.syncRepository.getAlbumAssets(options),
map: v1.mapAlbumAsset,
timestamp: createdAt,
}),
);
}
case SyncResponseType.AlbumAssetDeleteV1: {
streamers.push(
new SyncResponseWriter<DeletedEntity<AlbumAssetPK>, SyncAlbumAssetDeleteDtoV1>({
type: SyncResponseType.AlbumAssetDeleteV1,
load: (options) => this.syncRepository.getDeletedAlbumAssets(options),
map: v1.mapAlbumAssetDeleted,
timestamp: deletedAt,
}),
);
}
default: {
this.logger.warn(`Unsupported sync type: ${type}`);
break;
}
}
}
for (const streamer of streamers) {
await streamer.withCheckpoints(checkpoints).write({ stream, userId });
}
stream.end();
}
async getFullSync(auth: AuthDto, dto: AssetFullSyncDto): Promise<AssetResponseDto[]> {
// mobile implementation is faster if this is a single id
const userId = dto.userId || auth.user.id;
@ -71,4 +392,12 @@ export class SyncService extends BaseService {
};
return result;
}
private assertSession(auth: AuthDto) {
if (!auth.session?.id) {
throw new ForbiddenException('This endpoint requires session-based authentication');
}
return auth.session;
}
}

View File

@ -12,6 +12,7 @@ import { writeFileSync } from 'node:fs';
import path from 'node:path';
import { SystemConfig } from 'src/config';
import { CLIP_MODEL_INFO, serverVersion } from 'src/constants';
import { extraSyncModels } from 'src/dtos/sync.dto';
import { ImmichCookie, ImmichHeader, MetadataKey } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
@ -245,6 +246,7 @@ export const useSwagger = (app: INestApplication, { write }: { write: boolean })
const options: SwaggerDocumentOptions = {
operationIdFactory: (controllerKey: string, methodKey: string) => methodKey,
extraModels: [...extraSyncModels],
};
const specification = SwaggerModule.createDocument(app, config, options);

View File

@ -0,0 +1,21 @@
import { ISyncRepository } from 'src/interfaces/sync.interface';
import { Mocked, vitest } from 'vitest';
export const newSyncRepositoryMock = (): Mocked<ISyncRepository> => {
return {
get: vitest.fn(),
upsertCheckpoint: vitest.fn(),
getAssets: vitest.fn(),
getDeletedAssets: vitest.fn(),
getAssetsPartner: vitest.fn(),
getDeletedAssetsPartner: vitest.fn(),
getAlbums: vitest.fn(),
getDeletedAlbums: vitest.fn(),
getAlbumAssets: vitest.fn(),
getDeletedAlbumAssets: vitest.fn(),
};
};

View File

@ -35,6 +35,7 @@ import { newSessionRepositoryMock } from 'test/repositories/session.repository.m
import { newSharedLinkRepositoryMock } from 'test/repositories/shared-link.repository.mock';
import { newStackRepositoryMock } from 'test/repositories/stack.repository.mock';
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
import { newSyncRepositoryMock } from 'test/repositories/sync.repository.mock';
import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock';
import { newTagRepositoryMock } from 'test/repositories/tag.repository.mock';
import { newTelemetryRepositoryMock } from 'test/repositories/telemetry.repository.mock';
@ -91,6 +92,7 @@ export const newTestService = <T extends BaseService>(
const sharedLinkMock = newSharedLinkRepositoryMock();
const stackMock = newStackRepositoryMock();
const storageMock = newStorageRepositoryMock();
const syncMock = newSyncRepositoryMock();
const systemMock = newSystemMetadataRepositoryMock();
const tagMock = newTagRepositoryMock();
const telemetryMock = newTelemetryRepositoryMock();
@ -131,6 +133,7 @@ export const newTestService = <T extends BaseService>(
sharedLinkMock,
stackMock,
storageMock,
syncMock,
systemMock,
tagMock,
telemetryMock,
@ -173,6 +176,7 @@ export const newTestService = <T extends BaseService>(
sharedLinkMock,
stackMock,
storageMock,
syncMock,
systemMock,
tagMock,
telemetryMock,

View File

@ -29,6 +29,34 @@
$: if ($user) {
openWebsocketConnection();
void fetch('/api/sync/stream', {
method: 'POST',
body: JSON.stringify({ types: ['AssetOwnerV1'] }),
headers: { 'Content-Type': 'application/json' },
}).then(async (response) => {
if (response.body) {
const reader = response.body.getReader();
const decoder = new TextDecoder();
let done = false;
while (!done) {
const chunk = await reader.read();
done = chunk.done;
const data = chunk.value;
if (data) {
const parts = decoder.decode(data).split('\n');
for (const part of parts) {
if (!part.trim()) {
continue;
}
console.log(JSON.parse(part));
}
}
}
}
});
} else {
closeWebsocketConnection();
}