mirror of
https://github.com/immich-app/immich.git
synced 2025-07-31 15:08:44 -04:00
feat: sync auth user (#20067)
This commit is contained in:
parent
ab597155fa
commit
92384c28de
@ -1 +1 @@
|
|||||||
Subproject commit 18736fc27a80c99c68e856cdb4f842bc81ed3445
|
Subproject commit 37f60ea537c0228f5f92e4f42dc42f0bb39a6d7f
|
1
mobile/openapi/README.md
generated
1
mobile/openapi/README.md
generated
@ -479,6 +479,7 @@ Class | Method | HTTP request | Description
|
|||||||
- [SyncAssetFaceDeleteV1](doc//SyncAssetFaceDeleteV1.md)
|
- [SyncAssetFaceDeleteV1](doc//SyncAssetFaceDeleteV1.md)
|
||||||
- [SyncAssetFaceV1](doc//SyncAssetFaceV1.md)
|
- [SyncAssetFaceV1](doc//SyncAssetFaceV1.md)
|
||||||
- [SyncAssetV1](doc//SyncAssetV1.md)
|
- [SyncAssetV1](doc//SyncAssetV1.md)
|
||||||
|
- [SyncAuthUserV1](doc//SyncAuthUserV1.md)
|
||||||
- [SyncEntityType](doc//SyncEntityType.md)
|
- [SyncEntityType](doc//SyncEntityType.md)
|
||||||
- [SyncMemoryAssetDeleteV1](doc//SyncMemoryAssetDeleteV1.md)
|
- [SyncMemoryAssetDeleteV1](doc//SyncMemoryAssetDeleteV1.md)
|
||||||
- [SyncMemoryAssetV1](doc//SyncMemoryAssetV1.md)
|
- [SyncMemoryAssetV1](doc//SyncMemoryAssetV1.md)
|
||||||
|
1
mobile/openapi/lib/api.dart
generated
1
mobile/openapi/lib/api.dart
generated
@ -260,6 +260,7 @@ part 'model/sync_asset_exif_v1.dart';
|
|||||||
part 'model/sync_asset_face_delete_v1.dart';
|
part 'model/sync_asset_face_delete_v1.dart';
|
||||||
part 'model/sync_asset_face_v1.dart';
|
part 'model/sync_asset_face_v1.dart';
|
||||||
part 'model/sync_asset_v1.dart';
|
part 'model/sync_asset_v1.dart';
|
||||||
|
part 'model/sync_auth_user_v1.dart';
|
||||||
part 'model/sync_entity_type.dart';
|
part 'model/sync_entity_type.dart';
|
||||||
part 'model/sync_memory_asset_delete_v1.dart';
|
part 'model/sync_memory_asset_delete_v1.dart';
|
||||||
part 'model/sync_memory_asset_v1.dart';
|
part 'model/sync_memory_asset_v1.dart';
|
||||||
|
2
mobile/openapi/lib/api_client.dart
generated
2
mobile/openapi/lib/api_client.dart
generated
@ -576,6 +576,8 @@ class ApiClient {
|
|||||||
return SyncAssetFaceV1.fromJson(value);
|
return SyncAssetFaceV1.fromJson(value);
|
||||||
case 'SyncAssetV1':
|
case 'SyncAssetV1':
|
||||||
return SyncAssetV1.fromJson(value);
|
return SyncAssetV1.fromJson(value);
|
||||||
|
case 'SyncAuthUserV1':
|
||||||
|
return SyncAuthUserV1.fromJson(value);
|
||||||
case 'SyncEntityType':
|
case 'SyncEntityType':
|
||||||
return SyncEntityTypeTypeTransformer().decode(value);
|
return SyncEntityTypeTypeTransformer().decode(value);
|
||||||
case 'SyncMemoryAssetDeleteV1':
|
case 'SyncMemoryAssetDeleteV1':
|
||||||
|
215
mobile/openapi/lib/model/sync_auth_user_v1.dart
generated
Normal file
215
mobile/openapi/lib/model/sync_auth_user_v1.dart
generated
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
//
|
||||||
|
// 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 SyncAuthUserV1 {
|
||||||
|
/// Returns a new [SyncAuthUserV1] instance.
|
||||||
|
SyncAuthUserV1({
|
||||||
|
required this.avatarColor,
|
||||||
|
required this.deletedAt,
|
||||||
|
required this.email,
|
||||||
|
required this.hasProfileImage,
|
||||||
|
required this.id,
|
||||||
|
required this.isAdmin,
|
||||||
|
required this.name,
|
||||||
|
required this.oauthId,
|
||||||
|
required this.pinCode,
|
||||||
|
required this.profileChangedAt,
|
||||||
|
required this.quotaSizeInBytes,
|
||||||
|
required this.quotaUsageInBytes,
|
||||||
|
required this.storageLabel,
|
||||||
|
});
|
||||||
|
|
||||||
|
UserAvatarColor? avatarColor;
|
||||||
|
|
||||||
|
DateTime? deletedAt;
|
||||||
|
|
||||||
|
String email;
|
||||||
|
|
||||||
|
bool hasProfileImage;
|
||||||
|
|
||||||
|
String id;
|
||||||
|
|
||||||
|
bool isAdmin;
|
||||||
|
|
||||||
|
String name;
|
||||||
|
|
||||||
|
String oauthId;
|
||||||
|
|
||||||
|
String? pinCode;
|
||||||
|
|
||||||
|
DateTime profileChangedAt;
|
||||||
|
|
||||||
|
int? quotaSizeInBytes;
|
||||||
|
|
||||||
|
int quotaUsageInBytes;
|
||||||
|
|
||||||
|
String? storageLabel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) => identical(this, other) || other is SyncAuthUserV1 &&
|
||||||
|
other.avatarColor == avatarColor &&
|
||||||
|
other.deletedAt == deletedAt &&
|
||||||
|
other.email == email &&
|
||||||
|
other.hasProfileImage == hasProfileImage &&
|
||||||
|
other.id == id &&
|
||||||
|
other.isAdmin == isAdmin &&
|
||||||
|
other.name == name &&
|
||||||
|
other.oauthId == oauthId &&
|
||||||
|
other.pinCode == pinCode &&
|
||||||
|
other.profileChangedAt == profileChangedAt &&
|
||||||
|
other.quotaSizeInBytes == quotaSizeInBytes &&
|
||||||
|
other.quotaUsageInBytes == quotaUsageInBytes &&
|
||||||
|
other.storageLabel == storageLabel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
// ignore: unnecessary_parenthesis
|
||||||
|
(avatarColor == null ? 0 : avatarColor!.hashCode) +
|
||||||
|
(deletedAt == null ? 0 : deletedAt!.hashCode) +
|
||||||
|
(email.hashCode) +
|
||||||
|
(hasProfileImage.hashCode) +
|
||||||
|
(id.hashCode) +
|
||||||
|
(isAdmin.hashCode) +
|
||||||
|
(name.hashCode) +
|
||||||
|
(oauthId.hashCode) +
|
||||||
|
(pinCode == null ? 0 : pinCode!.hashCode) +
|
||||||
|
(profileChangedAt.hashCode) +
|
||||||
|
(quotaSizeInBytes == null ? 0 : quotaSizeInBytes!.hashCode) +
|
||||||
|
(quotaUsageInBytes.hashCode) +
|
||||||
|
(storageLabel == null ? 0 : storageLabel!.hashCode);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => 'SyncAuthUserV1[avatarColor=$avatarColor, deletedAt=$deletedAt, email=$email, hasProfileImage=$hasProfileImage, id=$id, isAdmin=$isAdmin, name=$name, oauthId=$oauthId, pinCode=$pinCode, profileChangedAt=$profileChangedAt, quotaSizeInBytes=$quotaSizeInBytes, quotaUsageInBytes=$quotaUsageInBytes, storageLabel=$storageLabel]';
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final json = <String, dynamic>{};
|
||||||
|
if (this.avatarColor != null) {
|
||||||
|
json[r'avatarColor'] = this.avatarColor;
|
||||||
|
} else {
|
||||||
|
// json[r'avatarColor'] = null;
|
||||||
|
}
|
||||||
|
if (this.deletedAt != null) {
|
||||||
|
json[r'deletedAt'] = this.deletedAt!.toUtc().toIso8601String();
|
||||||
|
} else {
|
||||||
|
// json[r'deletedAt'] = null;
|
||||||
|
}
|
||||||
|
json[r'email'] = this.email;
|
||||||
|
json[r'hasProfileImage'] = this.hasProfileImage;
|
||||||
|
json[r'id'] = this.id;
|
||||||
|
json[r'isAdmin'] = this.isAdmin;
|
||||||
|
json[r'name'] = this.name;
|
||||||
|
json[r'oauthId'] = this.oauthId;
|
||||||
|
if (this.pinCode != null) {
|
||||||
|
json[r'pinCode'] = this.pinCode;
|
||||||
|
} else {
|
||||||
|
// json[r'pinCode'] = null;
|
||||||
|
}
|
||||||
|
json[r'profileChangedAt'] = this.profileChangedAt.toUtc().toIso8601String();
|
||||||
|
if (this.quotaSizeInBytes != null) {
|
||||||
|
json[r'quotaSizeInBytes'] = this.quotaSizeInBytes;
|
||||||
|
} else {
|
||||||
|
// json[r'quotaSizeInBytes'] = null;
|
||||||
|
}
|
||||||
|
json[r'quotaUsageInBytes'] = this.quotaUsageInBytes;
|
||||||
|
if (this.storageLabel != null) {
|
||||||
|
json[r'storageLabel'] = this.storageLabel;
|
||||||
|
} else {
|
||||||
|
// json[r'storageLabel'] = null;
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a new [SyncAuthUserV1] instance and imports its values from
|
||||||
|
/// [value] if it's a [Map], null otherwise.
|
||||||
|
// ignore: prefer_constructors_over_static_methods
|
||||||
|
static SyncAuthUserV1? fromJson(dynamic value) {
|
||||||
|
upgradeDto(value, "SyncAuthUserV1");
|
||||||
|
if (value is Map) {
|
||||||
|
final json = value.cast<String, dynamic>();
|
||||||
|
|
||||||
|
return SyncAuthUserV1(
|
||||||
|
avatarColor: UserAvatarColor.fromJson(json[r'avatarColor']),
|
||||||
|
deletedAt: mapDateTime(json, r'deletedAt', r''),
|
||||||
|
email: mapValueOfType<String>(json, r'email')!,
|
||||||
|
hasProfileImage: mapValueOfType<bool>(json, r'hasProfileImage')!,
|
||||||
|
id: mapValueOfType<String>(json, r'id')!,
|
||||||
|
isAdmin: mapValueOfType<bool>(json, r'isAdmin')!,
|
||||||
|
name: mapValueOfType<String>(json, r'name')!,
|
||||||
|
oauthId: mapValueOfType<String>(json, r'oauthId')!,
|
||||||
|
pinCode: mapValueOfType<String>(json, r'pinCode'),
|
||||||
|
profileChangedAt: mapDateTime(json, r'profileChangedAt', r'')!,
|
||||||
|
quotaSizeInBytes: mapValueOfType<int>(json, r'quotaSizeInBytes'),
|
||||||
|
quotaUsageInBytes: mapValueOfType<int>(json, r'quotaUsageInBytes')!,
|
||||||
|
storageLabel: mapValueOfType<String>(json, r'storageLabel'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<SyncAuthUserV1> listFromJson(dynamic json, {bool growable = false,}) {
|
||||||
|
final result = <SyncAuthUserV1>[];
|
||||||
|
if (json is List && json.isNotEmpty) {
|
||||||
|
for (final row in json) {
|
||||||
|
final value = SyncAuthUserV1.fromJson(row);
|
||||||
|
if (value != null) {
|
||||||
|
result.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toList(growable: growable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<String, SyncAuthUserV1> mapFromJson(dynamic json) {
|
||||||
|
final map = <String, SyncAuthUserV1>{};
|
||||||
|
if (json is Map && json.isNotEmpty) {
|
||||||
|
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||||
|
for (final entry in json.entries) {
|
||||||
|
final value = SyncAuthUserV1.fromJson(entry.value);
|
||||||
|
if (value != null) {
|
||||||
|
map[entry.key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// maps a json object with a list of SyncAuthUserV1-objects as value to a dart map
|
||||||
|
static Map<String, List<SyncAuthUserV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||||
|
final map = <String, List<SyncAuthUserV1>>{};
|
||||||
|
if (json is Map && json.isNotEmpty) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
json = json.cast<String, dynamic>();
|
||||||
|
for (final entry in json.entries) {
|
||||||
|
map[entry.key] = SyncAuthUserV1.listFromJson(entry.value, growable: growable,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The list of required keys that must be present in a JSON.
|
||||||
|
static const requiredKeys = <String>{
|
||||||
|
'avatarColor',
|
||||||
|
'deletedAt',
|
||||||
|
'email',
|
||||||
|
'hasProfileImage',
|
||||||
|
'id',
|
||||||
|
'isAdmin',
|
||||||
|
'name',
|
||||||
|
'oauthId',
|
||||||
|
'pinCode',
|
||||||
|
'profileChangedAt',
|
||||||
|
'quotaSizeInBytes',
|
||||||
|
'quotaUsageInBytes',
|
||||||
|
'storageLabel',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
3
mobile/openapi/lib/model/sync_entity_type.dart
generated
3
mobile/openapi/lib/model/sync_entity_type.dart
generated
@ -23,6 +23,7 @@ class SyncEntityType {
|
|||||||
|
|
||||||
String toJson() => value;
|
String toJson() => value;
|
||||||
|
|
||||||
|
static const authUserV1 = SyncEntityType._(r'AuthUserV1');
|
||||||
static const userV1 = SyncEntityType._(r'UserV1');
|
static const userV1 = SyncEntityType._(r'UserV1');
|
||||||
static const userDeleteV1 = SyncEntityType._(r'UserDeleteV1');
|
static const userDeleteV1 = SyncEntityType._(r'UserDeleteV1');
|
||||||
static const assetV1 = SyncEntityType._(r'AssetV1');
|
static const assetV1 = SyncEntityType._(r'AssetV1');
|
||||||
@ -67,6 +68,7 @@ class SyncEntityType {
|
|||||||
|
|
||||||
/// List of all possible values in this [enum][SyncEntityType].
|
/// List of all possible values in this [enum][SyncEntityType].
|
||||||
static const values = <SyncEntityType>[
|
static const values = <SyncEntityType>[
|
||||||
|
authUserV1,
|
||||||
userV1,
|
userV1,
|
||||||
userDeleteV1,
|
userDeleteV1,
|
||||||
assetV1,
|
assetV1,
|
||||||
@ -146,6 +148,7 @@ class SyncEntityTypeTypeTransformer {
|
|||||||
SyncEntityType? decode(dynamic data, {bool allowNull = true}) {
|
SyncEntityType? decode(dynamic data, {bool allowNull = true}) {
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
switch (data) {
|
switch (data) {
|
||||||
|
case r'AuthUserV1': return SyncEntityType.authUserV1;
|
||||||
case r'UserV1': return SyncEntityType.userV1;
|
case r'UserV1': return SyncEntityType.userV1;
|
||||||
case r'UserDeleteV1': return SyncEntityType.userDeleteV1;
|
case r'UserDeleteV1': return SyncEntityType.userDeleteV1;
|
||||||
case r'AssetV1': return SyncEntityType.assetV1;
|
case r'AssetV1': return SyncEntityType.assetV1;
|
||||||
|
3
mobile/openapi/lib/model/sync_request_type.dart
generated
3
mobile/openapi/lib/model/sync_request_type.dart
generated
@ -30,6 +30,7 @@ class SyncRequestType {
|
|||||||
static const albumAssetExifsV1 = SyncRequestType._(r'AlbumAssetExifsV1');
|
static const albumAssetExifsV1 = SyncRequestType._(r'AlbumAssetExifsV1');
|
||||||
static const assetsV1 = SyncRequestType._(r'AssetsV1');
|
static const assetsV1 = SyncRequestType._(r'AssetsV1');
|
||||||
static const assetExifsV1 = SyncRequestType._(r'AssetExifsV1');
|
static const assetExifsV1 = SyncRequestType._(r'AssetExifsV1');
|
||||||
|
static const authUsersV1 = SyncRequestType._(r'AuthUsersV1');
|
||||||
static const memoriesV1 = SyncRequestType._(r'MemoriesV1');
|
static const memoriesV1 = SyncRequestType._(r'MemoriesV1');
|
||||||
static const memoryToAssetsV1 = SyncRequestType._(r'MemoryToAssetsV1');
|
static const memoryToAssetsV1 = SyncRequestType._(r'MemoryToAssetsV1');
|
||||||
static const partnersV1 = SyncRequestType._(r'PartnersV1');
|
static const partnersV1 = SyncRequestType._(r'PartnersV1');
|
||||||
@ -51,6 +52,7 @@ class SyncRequestType {
|
|||||||
albumAssetExifsV1,
|
albumAssetExifsV1,
|
||||||
assetsV1,
|
assetsV1,
|
||||||
assetExifsV1,
|
assetExifsV1,
|
||||||
|
authUsersV1,
|
||||||
memoriesV1,
|
memoriesV1,
|
||||||
memoryToAssetsV1,
|
memoryToAssetsV1,
|
||||||
partnersV1,
|
partnersV1,
|
||||||
@ -107,6 +109,7 @@ class SyncRequestTypeTypeTransformer {
|
|||||||
case r'AlbumAssetExifsV1': return SyncRequestType.albumAssetExifsV1;
|
case r'AlbumAssetExifsV1': return SyncRequestType.albumAssetExifsV1;
|
||||||
case r'AssetsV1': return SyncRequestType.assetsV1;
|
case r'AssetsV1': return SyncRequestType.assetsV1;
|
||||||
case r'AssetExifsV1': return SyncRequestType.assetExifsV1;
|
case r'AssetExifsV1': return SyncRequestType.assetExifsV1;
|
||||||
|
case r'AuthUsersV1': return SyncRequestType.authUsersV1;
|
||||||
case r'MemoriesV1': return SyncRequestType.memoriesV1;
|
case r'MemoriesV1': return SyncRequestType.memoriesV1;
|
||||||
case r'MemoryToAssetsV1': return SyncRequestType.memoryToAssetsV1;
|
case r'MemoryToAssetsV1': return SyncRequestType.memoryToAssetsV1;
|
||||||
case r'PartnersV1': return SyncRequestType.partnersV1;
|
case r'PartnersV1': return SyncRequestType.partnersV1;
|
||||||
|
14
mobile/openapi/lib/model/sync_user_v1.dart
generated
14
mobile/openapi/lib/model/sync_user_v1.dart
generated
@ -13,12 +13,15 @@ part of openapi.api;
|
|||||||
class SyncUserV1 {
|
class SyncUserV1 {
|
||||||
/// Returns a new [SyncUserV1] instance.
|
/// Returns a new [SyncUserV1] instance.
|
||||||
SyncUserV1({
|
SyncUserV1({
|
||||||
|
required this.avatarColor,
|
||||||
required this.deletedAt,
|
required this.deletedAt,
|
||||||
required this.email,
|
required this.email,
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.name,
|
required this.name,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
UserAvatarColor? avatarColor;
|
||||||
|
|
||||||
DateTime? deletedAt;
|
DateTime? deletedAt;
|
||||||
|
|
||||||
String email;
|
String email;
|
||||||
@ -29,6 +32,7 @@ class SyncUserV1 {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => identical(this, other) || other is SyncUserV1 &&
|
bool operator ==(Object other) => identical(this, other) || other is SyncUserV1 &&
|
||||||
|
other.avatarColor == avatarColor &&
|
||||||
other.deletedAt == deletedAt &&
|
other.deletedAt == deletedAt &&
|
||||||
other.email == email &&
|
other.email == email &&
|
||||||
other.id == id &&
|
other.id == id &&
|
||||||
@ -37,16 +41,22 @@ class SyncUserV1 {
|
|||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
// ignore: unnecessary_parenthesis
|
// ignore: unnecessary_parenthesis
|
||||||
|
(avatarColor == null ? 0 : avatarColor!.hashCode) +
|
||||||
(deletedAt == null ? 0 : deletedAt!.hashCode) +
|
(deletedAt == null ? 0 : deletedAt!.hashCode) +
|
||||||
(email.hashCode) +
|
(email.hashCode) +
|
||||||
(id.hashCode) +
|
(id.hashCode) +
|
||||||
(name.hashCode);
|
(name.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'SyncUserV1[deletedAt=$deletedAt, email=$email, id=$id, name=$name]';
|
String toString() => 'SyncUserV1[avatarColor=$avatarColor, deletedAt=$deletedAt, email=$email, id=$id, name=$name]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
|
if (this.avatarColor != null) {
|
||||||
|
json[r'avatarColor'] = this.avatarColor;
|
||||||
|
} else {
|
||||||
|
// json[r'avatarColor'] = null;
|
||||||
|
}
|
||||||
if (this.deletedAt != null) {
|
if (this.deletedAt != null) {
|
||||||
json[r'deletedAt'] = this.deletedAt!.toUtc().toIso8601String();
|
json[r'deletedAt'] = this.deletedAt!.toUtc().toIso8601String();
|
||||||
} else {
|
} else {
|
||||||
@ -67,6 +77,7 @@ class SyncUserV1 {
|
|||||||
final json = value.cast<String, dynamic>();
|
final json = value.cast<String, dynamic>();
|
||||||
|
|
||||||
return SyncUserV1(
|
return SyncUserV1(
|
||||||
|
avatarColor: UserAvatarColor.fromJson(json[r'avatarColor']),
|
||||||
deletedAt: mapDateTime(json, r'deletedAt', r''),
|
deletedAt: mapDateTime(json, r'deletedAt', r''),
|
||||||
email: mapValueOfType<String>(json, r'email')!,
|
email: mapValueOfType<String>(json, r'email')!,
|
||||||
id: mapValueOfType<String>(json, r'id')!,
|
id: mapValueOfType<String>(json, r'id')!,
|
||||||
@ -118,6 +129,7 @@ class SyncUserV1 {
|
|||||||
|
|
||||||
/// The list of required keys that must be present in a JSON.
|
/// The list of required keys that must be present in a JSON.
|
||||||
static const requiredKeys = <String>{
|
static const requiredKeys = <String>{
|
||||||
|
'avatarColor',
|
||||||
'deletedAt',
|
'deletedAt',
|
||||||
'email',
|
'email',
|
||||||
'id',
|
'id',
|
||||||
|
2
mobile/test/fixtures/sync_stream.stub.dart
vendored
2
mobile/test/fixtures/sync_stream.stub.dart
vendored
@ -9,6 +9,7 @@ abstract final class SyncStreamStub {
|
|||||||
email: "admin@admin",
|
email: "admin@admin",
|
||||||
id: "1",
|
id: "1",
|
||||||
name: "Admin",
|
name: "Admin",
|
||||||
|
avatarColor: null,
|
||||||
),
|
),
|
||||||
ack: "1",
|
ack: "1",
|
||||||
);
|
);
|
||||||
@ -19,6 +20,7 @@ abstract final class SyncStreamStub {
|
|||||||
email: "user@user",
|
email: "user@user",
|
||||||
id: "5",
|
id: "5",
|
||||||
name: "User",
|
name: "User",
|
||||||
|
avatarColor: null,
|
||||||
),
|
),
|
||||||
ack: "5",
|
ack: "5",
|
||||||
);
|
);
|
||||||
|
@ -13978,8 +13978,79 @@
|
|||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"SyncAuthUserV1": {
|
||||||
|
"properties": {
|
||||||
|
"avatarColor": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/UserAvatarColor"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"deletedAt": {
|
||||||
|
"format": "date-time",
|
||||||
|
"nullable": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"hasProfileImage": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"isAdmin": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"oauthId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"pinCode": {
|
||||||
|
"nullable": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"profileChangedAt": {
|
||||||
|
"format": "date-time",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"quotaSizeInBytes": {
|
||||||
|
"nullable": true,
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"quotaUsageInBytes": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"storageLabel": {
|
||||||
|
"nullable": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"avatarColor",
|
||||||
|
"deletedAt",
|
||||||
|
"email",
|
||||||
|
"hasProfileImage",
|
||||||
|
"id",
|
||||||
|
"isAdmin",
|
||||||
|
"name",
|
||||||
|
"oauthId",
|
||||||
|
"pinCode",
|
||||||
|
"profileChangedAt",
|
||||||
|
"quotaSizeInBytes",
|
||||||
|
"quotaUsageInBytes",
|
||||||
|
"storageLabel"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"SyncEntityType": {
|
"SyncEntityType": {
|
||||||
"enum": [
|
"enum": [
|
||||||
|
"AuthUserV1",
|
||||||
"UserV1",
|
"UserV1",
|
||||||
"UserDeleteV1",
|
"UserDeleteV1",
|
||||||
"AssetV1",
|
"AssetV1",
|
||||||
@ -14242,6 +14313,7 @@
|
|||||||
"AlbumAssetExifsV1",
|
"AlbumAssetExifsV1",
|
||||||
"AssetsV1",
|
"AssetsV1",
|
||||||
"AssetExifsV1",
|
"AssetExifsV1",
|
||||||
|
"AuthUsersV1",
|
||||||
"MemoriesV1",
|
"MemoriesV1",
|
||||||
"MemoryToAssetsV1",
|
"MemoryToAssetsV1",
|
||||||
"PartnersV1",
|
"PartnersV1",
|
||||||
@ -14364,6 +14436,14 @@
|
|||||||
},
|
},
|
||||||
"SyncUserV1": {
|
"SyncUserV1": {
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"avatarColor": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/UserAvatarColor"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
"deletedAt": {
|
"deletedAt": {
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
@ -14380,6 +14460,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
"avatarColor",
|
||||||
"deletedAt",
|
"deletedAt",
|
||||||
"email",
|
"email",
|
||||||
"id",
|
"id",
|
||||||
|
@ -4099,6 +4099,7 @@ export enum Error2 {
|
|||||||
NotFound = "not_found"
|
NotFound = "not_found"
|
||||||
}
|
}
|
||||||
export enum SyncEntityType {
|
export enum SyncEntityType {
|
||||||
|
AuthUserV1 = "AuthUserV1",
|
||||||
UserV1 = "UserV1",
|
UserV1 = "UserV1",
|
||||||
UserDeleteV1 = "UserDeleteV1",
|
UserDeleteV1 = "UserDeleteV1",
|
||||||
AssetV1 = "AssetV1",
|
AssetV1 = "AssetV1",
|
||||||
@ -4149,6 +4150,7 @@ export enum SyncRequestType {
|
|||||||
AlbumAssetExifsV1 = "AlbumAssetExifsV1",
|
AlbumAssetExifsV1 = "AlbumAssetExifsV1",
|
||||||
AssetsV1 = "AssetsV1",
|
AssetsV1 = "AssetsV1",
|
||||||
AssetExifsV1 = "AssetExifsV1",
|
AssetExifsV1 = "AssetExifsV1",
|
||||||
|
AuthUsersV1 = "AuthUsersV1",
|
||||||
MemoriesV1 = "MemoriesV1",
|
MemoriesV1 = "MemoriesV1",
|
||||||
MemoryToAssetsV1 = "MemoryToAssetsV1",
|
MemoryToAssetsV1 = "MemoryToAssetsV1",
|
||||||
PartnersV1 = "PartnersV1",
|
PartnersV1 = "PartnersV1",
|
||||||
|
@ -356,6 +356,7 @@ export const columns = {
|
|||||||
],
|
],
|
||||||
syncAlbumUser: ['album_user.albumsId as albumId', 'album_user.usersId as userId', 'album_user.role'],
|
syncAlbumUser: ['album_user.albumsId as albumId', 'album_user.usersId as userId', 'album_user.role'],
|
||||||
syncStack: ['stack.id', 'stack.createdAt', 'stack.updatedAt', 'stack.primaryAssetId', 'stack.ownerId'],
|
syncStack: ['stack.id', 'stack.createdAt', 'stack.updatedAt', 'stack.primaryAssetId', 'stack.ownerId'],
|
||||||
|
syncUser: ['id', 'name', 'email', 'avatarColor', 'deletedAt', 'updateId'],
|
||||||
stack: ['stack.id', 'stack.primaryAssetId', 'ownerId'],
|
stack: ['stack.id', 'stack.primaryAssetId', 'ownerId'],
|
||||||
syncAssetExif: [
|
syncAssetExif: [
|
||||||
'asset_exif.assetId',
|
'asset_exif.assetId',
|
||||||
|
@ -10,6 +10,7 @@ import {
|
|||||||
MemoryType,
|
MemoryType,
|
||||||
SyncEntityType,
|
SyncEntityType,
|
||||||
SyncRequestType,
|
SyncRequestType,
|
||||||
|
UserAvatarColor,
|
||||||
UserMetadataKey,
|
UserMetadataKey,
|
||||||
} from 'src/enum';
|
} from 'src/enum';
|
||||||
import { UserMetadata } from 'src/types';
|
import { UserMetadata } from 'src/types';
|
||||||
@ -58,9 +59,25 @@ export class SyncUserV1 {
|
|||||||
id!: string;
|
id!: string;
|
||||||
name!: string;
|
name!: string;
|
||||||
email!: string;
|
email!: string;
|
||||||
|
@ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', nullable: true })
|
||||||
|
avatarColor!: UserAvatarColor | null;
|
||||||
deletedAt!: Date | null;
|
deletedAt!: Date | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExtraModel()
|
||||||
|
export class SyncAuthUserV1 extends SyncUserV1 {
|
||||||
|
isAdmin!: boolean;
|
||||||
|
pinCode!: string | null;
|
||||||
|
oauthId!: string;
|
||||||
|
storageLabel!: string | null;
|
||||||
|
@ApiProperty({ type: 'integer' })
|
||||||
|
quotaSizeInBytes!: number | null;
|
||||||
|
@ApiProperty({ type: 'integer' })
|
||||||
|
quotaUsageInBytes!: number;
|
||||||
|
hasProfileImage!: boolean;
|
||||||
|
profileChangedAt!: Date;
|
||||||
|
}
|
||||||
|
|
||||||
@ExtraModel()
|
@ExtraModel()
|
||||||
export class SyncUserDeleteV1 {
|
export class SyncUserDeleteV1 {
|
||||||
userId!: string;
|
userId!: string;
|
||||||
@ -301,6 +318,7 @@ export class SyncAckV1 {}
|
|||||||
export class SyncResetV1 {}
|
export class SyncResetV1 {}
|
||||||
|
|
||||||
export type SyncItem = {
|
export type SyncItem = {
|
||||||
|
[SyncEntityType.AuthUserV1]: SyncAuthUserV1;
|
||||||
[SyncEntityType.UserV1]: SyncUserV1;
|
[SyncEntityType.UserV1]: SyncUserV1;
|
||||||
[SyncEntityType.UserDeleteV1]: SyncUserDeleteV1;
|
[SyncEntityType.UserDeleteV1]: SyncUserDeleteV1;
|
||||||
[SyncEntityType.PartnerV1]: SyncPartnerV1;
|
[SyncEntityType.PartnerV1]: SyncPartnerV1;
|
||||||
|
@ -559,6 +559,7 @@ export enum SyncRequestType {
|
|||||||
AlbumAssetExifsV1 = 'AlbumAssetExifsV1',
|
AlbumAssetExifsV1 = 'AlbumAssetExifsV1',
|
||||||
AssetsV1 = 'AssetsV1',
|
AssetsV1 = 'AssetsV1',
|
||||||
AssetExifsV1 = 'AssetExifsV1',
|
AssetExifsV1 = 'AssetExifsV1',
|
||||||
|
AuthUsersV1 = 'AuthUsersV1',
|
||||||
MemoriesV1 = 'MemoriesV1',
|
MemoriesV1 = 'MemoriesV1',
|
||||||
MemoryToAssetsV1 = 'MemoryToAssetsV1',
|
MemoryToAssetsV1 = 'MemoryToAssetsV1',
|
||||||
PartnersV1 = 'PartnersV1',
|
PartnersV1 = 'PartnersV1',
|
||||||
@ -573,6 +574,8 @@ export enum SyncRequestType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum SyncEntityType {
|
export enum SyncEntityType {
|
||||||
|
AuthUserV1 = 'AuthUserV1',
|
||||||
|
|
||||||
UserV1 = 'UserV1',
|
UserV1 = 'UserV1',
|
||||||
UserDeleteV1 = 'UserDeleteV1',
|
UserDeleteV1 = 'UserDeleteV1',
|
||||||
|
|
||||||
|
@ -444,6 +444,29 @@ where
|
|||||||
order by
|
order by
|
||||||
"asset_face"."updateId" asc
|
"asset_face"."updateId" asc
|
||||||
|
|
||||||
|
-- SyncRepository.authUser.getUpserts
|
||||||
|
select
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"email",
|
||||||
|
"avatarColor",
|
||||||
|
"deletedAt",
|
||||||
|
"updateId",
|
||||||
|
"isAdmin",
|
||||||
|
"pinCode",
|
||||||
|
"oauthId",
|
||||||
|
"storageLabel",
|
||||||
|
"quotaSizeInBytes",
|
||||||
|
"quotaUsageInBytes",
|
||||||
|
"profileImagePath",
|
||||||
|
"profileChangedAt"
|
||||||
|
from
|
||||||
|
"user"
|
||||||
|
where
|
||||||
|
"updatedAt" < now() - interval '1 millisecond'
|
||||||
|
order by
|
||||||
|
"updateId" asc
|
||||||
|
|
||||||
-- SyncRepository.memory.getDeletes
|
-- SyncRepository.memory.getDeletes
|
||||||
select
|
select
|
||||||
"id",
|
"id",
|
||||||
@ -871,6 +894,7 @@ select
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
|
"avatarColor",
|
||||||
"deletedAt",
|
"deletedAt",
|
||||||
"updateId"
|
"updateId"
|
||||||
from
|
from
|
||||||
|
@ -43,6 +43,7 @@ export class SyncRepository {
|
|||||||
asset: AssetSync;
|
asset: AssetSync;
|
||||||
assetExif: AssetExifSync;
|
assetExif: AssetExifSync;
|
||||||
assetFace: AssetFaceSync;
|
assetFace: AssetFaceSync;
|
||||||
|
authUser: AuthUserSync;
|
||||||
memory: MemorySync;
|
memory: MemorySync;
|
||||||
memoryToAsset: MemoryToAssetSync;
|
memoryToAsset: MemoryToAssetSync;
|
||||||
partner: PartnerSync;
|
partner: PartnerSync;
|
||||||
@ -63,6 +64,7 @@ export class SyncRepository {
|
|||||||
this.asset = new AssetSync(this.db);
|
this.asset = new AssetSync(this.db);
|
||||||
this.assetExif = new AssetExifSync(this.db);
|
this.assetExif = new AssetExifSync(this.db);
|
||||||
this.assetFace = new AssetFaceSync(this.db);
|
this.assetFace = new AssetFaceSync(this.db);
|
||||||
|
this.authUser = new AuthUserSync(this.db);
|
||||||
this.memory = new MemorySync(this.db);
|
this.memory = new MemorySync(this.db);
|
||||||
this.memoryToAsset = new MemoryToAssetSync(this.db);
|
this.memoryToAsset = new MemoryToAssetSync(this.db);
|
||||||
this.partner = new PartnerSync(this.db);
|
this.partner = new PartnerSync(this.db);
|
||||||
@ -367,6 +369,27 @@ class AssetSync extends BaseSync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AuthUserSync extends BaseSync {
|
||||||
|
@GenerateSql({ params: [], stream: true })
|
||||||
|
getUpserts(ack?: SyncAck) {
|
||||||
|
return this.db
|
||||||
|
.selectFrom('user')
|
||||||
|
.select(columns.syncUser)
|
||||||
|
.select([
|
||||||
|
'isAdmin',
|
||||||
|
'pinCode',
|
||||||
|
'oauthId',
|
||||||
|
'storageLabel',
|
||||||
|
'quotaSizeInBytes',
|
||||||
|
'quotaUsageInBytes',
|
||||||
|
'profileImagePath',
|
||||||
|
'profileChangedAt',
|
||||||
|
])
|
||||||
|
.$call(this.upsertTableFilters(ack))
|
||||||
|
.stream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PersonSync extends BaseSync {
|
class PersonSync extends BaseSync {
|
||||||
@GenerateSql({ params: [DummyValue.UUID], stream: true })
|
@GenerateSql({ params: [DummyValue.UUID], stream: true })
|
||||||
getDeletes(userId: string, ack?: SyncAck) {
|
getDeletes(userId: string, ack?: SyncAck) {
|
||||||
@ -693,11 +716,7 @@ class UserSync extends BaseSync {
|
|||||||
|
|
||||||
@GenerateSql({ params: [], stream: true })
|
@GenerateSql({ params: [], stream: true })
|
||||||
getUpserts(ack?: SyncAck) {
|
getUpserts(ack?: SyncAck) {
|
||||||
return this.db
|
return this.db.selectFrom('user').select(columns.syncUser).$call(this.upsertTableFilters(ack)).stream();
|
||||||
.selectFrom('user')
|
|
||||||
.select(['id', 'name', 'email', 'deletedAt', 'updateId'])
|
|
||||||
.$call(this.upsertTableFilters(ack))
|
|
||||||
.stream();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ const sendEntityBackfillCompleteAck = (response: Writable, ackType: SyncEntityTy
|
|||||||
|
|
||||||
const FULL_SYNC = { needsFullSync: true, deleted: [], upserted: [] };
|
const FULL_SYNC = { needsFullSync: true, deleted: [], upserted: [] };
|
||||||
export const SYNC_TYPES_ORDER = [
|
export const SYNC_TYPES_ORDER = [
|
||||||
|
SyncRequestType.AuthUsersV1,
|
||||||
SyncRequestType.UsersV1,
|
SyncRequestType.UsersV1,
|
||||||
SyncRequestType.PartnersV1,
|
SyncRequestType.PartnersV1,
|
||||||
SyncRequestType.AssetsV1,
|
SyncRequestType.AssetsV1,
|
||||||
@ -140,6 +141,7 @@ export class SyncService extends BaseService {
|
|||||||
const checkpointMap: CheckpointMap = Object.fromEntries(checkpoints.map(({ type, ack }) => [type, fromAck(ack)]));
|
const checkpointMap: CheckpointMap = Object.fromEntries(checkpoints.map(({ type, ack }) => [type, fromAck(ack)]));
|
||||||
|
|
||||||
const handlers: Record<SyncRequestType, () => Promise<void>> = {
|
const handlers: Record<SyncRequestType, () => Promise<void>> = {
|
||||||
|
[SyncRequestType.AuthUsersV1]: () => this.syncAuthUsersV1(response, checkpointMap),
|
||||||
[SyncRequestType.UsersV1]: () => this.syncUsersV1(response, checkpointMap),
|
[SyncRequestType.UsersV1]: () => this.syncUsersV1(response, checkpointMap),
|
||||||
[SyncRequestType.PartnersV1]: () => this.syncPartnersV1(response, checkpointMap, auth),
|
[SyncRequestType.PartnersV1]: () => this.syncPartnersV1(response, checkpointMap, auth),
|
||||||
[SyncRequestType.AssetsV1]: () => this.syncAssetsV1(response, checkpointMap, auth),
|
[SyncRequestType.AssetsV1]: () => this.syncAssetsV1(response, checkpointMap, auth),
|
||||||
@ -169,6 +171,14 @@ export class SyncService extends BaseService {
|
|||||||
response.end();
|
response.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async syncAuthUsersV1(response: Writable, checkpointMap: CheckpointMap) {
|
||||||
|
const upsertType = SyncEntityType.AuthUserV1;
|
||||||
|
const upserts = this.syncRepository.authUser.getUpserts(checkpointMap[upsertType]);
|
||||||
|
for await (const { updateId, profileImagePath, ...data } of upserts) {
|
||||||
|
send(response, { type: upsertType, ids: [updateId], data: { ...data, hasProfileImage: !!profileImagePath } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async syncUsersV1(response: Writable, checkpointMap: CheckpointMap) {
|
private async syncUsersV1(response: Writable, checkpointMap: CheckpointMap) {
|
||||||
const deleteType = SyncEntityType.UserDeleteV1;
|
const deleteType = SyncEntityType.UserDeleteV1;
|
||||||
const deletes = this.syncRepository.user.getDeletes(checkpointMap[deleteType]);
|
const deletes = this.syncRepository.user.getDeletes(checkpointMap[deleteType]);
|
||||||
|
@ -507,7 +507,14 @@ const userInsert = (user: Partial<Insertable<UserTable>> = {}) => {
|
|||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
isAdmin: false,
|
isAdmin: false,
|
||||||
profileImagePath: '',
|
profileImagePath: '',
|
||||||
|
profileChangedAt: newDate(),
|
||||||
shouldChangePassword: true,
|
shouldChangePassword: true,
|
||||||
|
storageLabel: null,
|
||||||
|
pinCode: null,
|
||||||
|
oauthId: '',
|
||||||
|
avatarColor: null,
|
||||||
|
quotaSizeInBytes: null,
|
||||||
|
quotaUsageInBytes: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
return { ...defaults, ...user, id };
|
return { ...defaults, ...user, id };
|
||||||
|
87
server/test/medium/specs/sync/sync-auth-user.spec.ts
Normal file
87
server/test/medium/specs/sync/sync-auth-user.spec.ts
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import { Kysely } from 'kysely';
|
||||||
|
import { SyncEntityType, SyncRequestType } from 'src/enum';
|
||||||
|
import { UserRepository } from 'src/repositories/user.repository';
|
||||||
|
import { DB } from 'src/schema';
|
||||||
|
import { SyncTestContext } from 'test/medium.factory';
|
||||||
|
import { getKyselyDB } from 'test/utils';
|
||||||
|
|
||||||
|
let defaultDatabase: Kysely<DB>;
|
||||||
|
|
||||||
|
const setup = async (db?: Kysely<DB>) => {
|
||||||
|
const ctx = new SyncTestContext(db || defaultDatabase);
|
||||||
|
const { auth, user, session } = await ctx.newSyncAuthUser();
|
||||||
|
return { auth, user, session, ctx };
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
defaultDatabase = await getKyselyDB();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(SyncEntityType.AuthUserV1, () => {
|
||||||
|
it('should detect and sync the first user', async () => {
|
||||||
|
const { auth, user, ctx } = await setup(await getKyselyDB());
|
||||||
|
|
||||||
|
const response = await ctx.syncStream(auth, [SyncRequestType.AuthUsersV1]);
|
||||||
|
expect(response).toHaveLength(1);
|
||||||
|
expect(response).toEqual([
|
||||||
|
{
|
||||||
|
ack: expect.any(String),
|
||||||
|
data: {
|
||||||
|
id: user.id,
|
||||||
|
isAdmin: user.isAdmin,
|
||||||
|
deletedAt: user.deletedAt,
|
||||||
|
name: user.name,
|
||||||
|
avatarColor: user.avatarColor,
|
||||||
|
email: user.email,
|
||||||
|
pinCode: user.pinCode,
|
||||||
|
hasProfileImage: false,
|
||||||
|
profileChangedAt: (user.profileChangedAt as Date).toISOString(),
|
||||||
|
oauthId: user.oauthId,
|
||||||
|
quotaSizeInBytes: user.quotaSizeInBytes,
|
||||||
|
quotaUsageInBytes: user.quotaUsageInBytes,
|
||||||
|
storageLabel: user.storageLabel,
|
||||||
|
},
|
||||||
|
type: 'AuthUserV1',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
await ctx.syncAckAll(auth, response);
|
||||||
|
await expect(ctx.syncStream(auth, [SyncRequestType.AuthUsersV1])).resolves.toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sync a change and then another change to that same user', async () => {
|
||||||
|
const { auth, user, ctx } = await setup(await getKyselyDB());
|
||||||
|
|
||||||
|
const userRepo = ctx.get(UserRepository);
|
||||||
|
|
||||||
|
const response = await ctx.syncStream(auth, [SyncRequestType.AuthUsersV1]);
|
||||||
|
expect(response).toHaveLength(1);
|
||||||
|
expect(response).toEqual([
|
||||||
|
{
|
||||||
|
ack: expect.any(String),
|
||||||
|
data: expect.objectContaining({
|
||||||
|
id: user.id,
|
||||||
|
isAdmin: false,
|
||||||
|
}),
|
||||||
|
type: 'AuthUserV1',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
await ctx.syncAckAll(auth, response);
|
||||||
|
|
||||||
|
await userRepo.update(user.id, { isAdmin: true });
|
||||||
|
|
||||||
|
const newResponse = await ctx.syncStream(auth, [SyncRequestType.AuthUsersV1]);
|
||||||
|
expect(newResponse).toHaveLength(1);
|
||||||
|
expect(newResponse).toEqual([
|
||||||
|
{
|
||||||
|
ack: expect.any(String),
|
||||||
|
data: expect.objectContaining({
|
||||||
|
id: user.id,
|
||||||
|
isAdmin: true,
|
||||||
|
}),
|
||||||
|
type: 'AuthUserV1',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
@ -37,6 +37,7 @@ describe(SyncEntityType.UserV1, () => {
|
|||||||
email: user.email,
|
email: user.email,
|
||||||
id: user.id,
|
id: user.id,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
|
avatarColor: user.avatarColor,
|
||||||
},
|
},
|
||||||
type: 'UserV1',
|
type: 'UserV1',
|
||||||
},
|
},
|
||||||
@ -49,8 +50,7 @@ describe(SyncEntityType.UserV1, () => {
|
|||||||
it('should detect and sync a soft deleted user', async () => {
|
it('should detect and sync a soft deleted user', async () => {
|
||||||
const { auth, ctx } = await setup(await getKyselyDB());
|
const { auth, ctx } = await setup(await getKyselyDB());
|
||||||
|
|
||||||
const deletedAt = new Date().toISOString();
|
const { user: deleted } = await ctx.newUser({ deletedAt: new Date().toISOString() });
|
||||||
const { user: deleted } = await ctx.newUser({ deletedAt });
|
|
||||||
|
|
||||||
const response = await ctx.syncStream(auth, [SyncRequestType.UsersV1]);
|
const response = await ctx.syncStream(auth, [SyncRequestType.UsersV1]);
|
||||||
|
|
||||||
@ -59,22 +59,12 @@ describe(SyncEntityType.UserV1, () => {
|
|||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{
|
{
|
||||||
ack: expect.any(String),
|
ack: expect.any(String),
|
||||||
data: {
|
data: expect.objectContaining({ id: auth.user.id }),
|
||||||
deletedAt: null,
|
|
||||||
email: auth.user.email,
|
|
||||||
id: auth.user.id,
|
|
||||||
name: auth.user.name,
|
|
||||||
},
|
|
||||||
type: 'UserV1',
|
type: 'UserV1',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ack: expect.any(String),
|
ack: expect.any(String),
|
||||||
data: {
|
data: expect.objectContaining({ id: deleted.id }),
|
||||||
deletedAt,
|
|
||||||
email: deleted.email,
|
|
||||||
id: deleted.id,
|
|
||||||
name: deleted.name,
|
|
||||||
},
|
|
||||||
type: 'UserV1',
|
type: 'UserV1',
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
@ -85,7 +75,7 @@ describe(SyncEntityType.UserV1, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should detect and sync a deleted user', async () => {
|
it('should detect and sync a deleted user', async () => {
|
||||||
const { auth, ctx } = await setup(await getKyselyDB());
|
const { auth, user: authUser, ctx } = await setup(await getKyselyDB());
|
||||||
|
|
||||||
const userRepo = ctx.get(UserRepository);
|
const userRepo = ctx.get(UserRepository);
|
||||||
|
|
||||||
@ -104,12 +94,7 @@ describe(SyncEntityType.UserV1, () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
ack: expect.any(String),
|
ack: expect.any(String),
|
||||||
data: {
|
data: expect.objectContaining({ id: authUser.id }),
|
||||||
deletedAt: null,
|
|
||||||
email: auth.user.email,
|
|
||||||
id: auth.user.id,
|
|
||||||
name: auth.user.name,
|
|
||||||
},
|
|
||||||
type: 'UserV1',
|
type: 'UserV1',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@ -119,7 +104,7 @@ describe(SyncEntityType.UserV1, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should sync a user and then an update to that same user', async () => {
|
it('should sync a user and then an update to that same user', async () => {
|
||||||
const { auth, ctx } = await setup(await getKyselyDB());
|
const { auth, user, ctx } = await setup(await getKyselyDB());
|
||||||
|
|
||||||
const userRepo = ctx.get(UserRepository);
|
const userRepo = ctx.get(UserRepository);
|
||||||
|
|
||||||
@ -128,12 +113,7 @@ describe(SyncEntityType.UserV1, () => {
|
|||||||
expect(response).toEqual([
|
expect(response).toEqual([
|
||||||
{
|
{
|
||||||
ack: expect.any(String),
|
ack: expect.any(String),
|
||||||
data: {
|
data: expect.objectContaining({ id: user.id }),
|
||||||
deletedAt: null,
|
|
||||||
email: auth.user.email,
|
|
||||||
id: auth.user.id,
|
|
||||||
name: auth.user.name,
|
|
||||||
},
|
|
||||||
type: 'UserV1',
|
type: 'UserV1',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@ -147,12 +127,7 @@ describe(SyncEntityType.UserV1, () => {
|
|||||||
expect(newResponse).toEqual([
|
expect(newResponse).toEqual([
|
||||||
{
|
{
|
||||||
ack: expect.any(String),
|
ack: expect.any(String),
|
||||||
data: {
|
data: expect.objectContaining({ id: user.id, name: updated.name }),
|
||||||
deletedAt: null,
|
|
||||||
email: auth.user.email,
|
|
||||||
id: auth.user.id,
|
|
||||||
name: updated.name,
|
|
||||||
},
|
|
||||||
type: 'UserV1',
|
type: 'UserV1',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user