refactor: user entity (#16655)

* refactor: user entity

* fix: add users to album & user profile url

* chore: rebase fixes

* generate files

* fix(mobile): timeline not reset on login

* fix: test stub

* refactor: rename user model (#16813)

* refactor: rename user model

* simplify import

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>

* chore: generate files

* fix: use getAllAccessible instead of getAll

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
shenlong 2025-03-12 19:26:56 +05:30 committed by GitHub
parent a75718ce99
commit d1c8fe5303
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
82 changed files with 1039 additions and 947 deletions

View file

@ -1,4 +1,5 @@
import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
import 'asset.stub.dart';
import 'user.stub.dart';
@ -26,7 +27,7 @@ final class AlbumStub {
shared: true,
activityEnabled: false,
endDate: DateTime(2020),
)..sharedUsers.addAll([UserStub.admin]);
)..sharedUsers.addAll([User.fromDto(UserStub.admin)]);
static final oneAsset = Album(
name: "album-with-single-asset",
@ -53,7 +54,7 @@ final class AlbumStub {
)
..assets.addAll([AssetStub.image1, AssetStub.image2])
..activityEnabled = true
..owner.value = UserStub.admin;
..owner.value = User.fromDto(UserStub.admin);
static final create2020end2020Album = Album(
name: "create2020update2020Album",

View file

@ -1,35 +1,35 @@
import 'package:immich_mobile/entities/user.entity.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
abstract final class UserStub {
const UserStub._();
static final admin = User(
id: "admin",
updatedAt: DateTime(2021),
static final admin = UserDto(
uid: "admin",
email: "admin@test.com",
name: "admin",
isAdmin: true,
profileImagePath: '',
avatarColor: AvatarColorEnum.green,
updatedAt: DateTime(2021),
profileImagePath: null,
avatarColor: AvatarColor.green,
);
static final user1 = User(
id: "user1",
updatedAt: DateTime(2022),
static final user1 = UserDto(
uid: "user1",
email: "user1@test.com",
name: "user1",
isAdmin: false,
profileImagePath: '',
avatarColor: AvatarColorEnum.red,
updatedAt: DateTime(2022),
profileImagePath: null,
avatarColor: AvatarColor.red,
);
static final user2 = User(
id: "user2",
updatedAt: DateTime(2023),
static final user2 = UserDto(
uid: "user2",
email: "user2@test.com",
name: "user2",
isAdmin: false,
profileImagePath: '',
avatarColor: AvatarColorEnum.primary,
updatedAt: DateTime(2023),
profileImagePath: null,
avatarColor: AvatarColor.primary,
);
}

View file

@ -3,7 +3,7 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:immich_mobile/domain/interfaces/store.interface.dart';
import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/entities/user.entity.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/infrastructure/entities/store.entity.dart';
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
import 'package:isar/isar.dart';
@ -86,7 +86,7 @@ void main() {
});
test('converts user', () async {
User? user = await sut.tryGet(StoreKey.currentUser);
UserDto? user = await sut.tryGet(StoreKey.currentUser);
expect(user, isNull);
await sut.insert(StoreKey.currentUser, _kTestUser);
user = await sut.tryGet(StoreKey.currentUser);

View file

@ -9,7 +9,7 @@ import 'package:immich_mobile/domain/services/store.service.dart';
import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/entities/user.entity.dart';
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
import 'package:immich_mobile/models/activities/activity.model.dart';
import 'package:immich_mobile/pages/common/activities.page.dart';
@ -96,7 +96,7 @@ void main() {
await db.writeTxn(() async {
await db.clear();
// Save all assets
await db.users.put(UserStub.admin);
await db.users.put(User.fromDto(UserStub.admin));
await db.assets.putAll([AssetStub.image1, AssetStub.image2]);
await db.albums.put(AlbumStub.twoAsset);
await AlbumStub.twoAsset.owner.save();

View file

@ -1,13 +1,13 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/entities/user.entity.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:mocktail/mocktail.dart';
class MockCurrentUserProvider extends StateNotifier<User?>
class MockCurrentUserProvider extends StateNotifier<UserDto?>
with Mock
implements CurrentUserProvider {
MockCurrentUserProvider() : super(null);
@override
set state(User? user) => super.state = user;
set state(UserDto? user) => super.state = user;
}

View file

@ -1,16 +1,16 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/domain/services/log.service.dart';
import 'package:immich_mobile/domain/services/store.service.dart';
import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/entities/etag.entity.dart';
import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/entities/user.entity.dart';
import 'package:immich_mobile/infrastructure/repositories/log.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
import 'package:immich_mobile/interfaces/asset.interface.dart';
import 'package:immich_mobile/interfaces/user.interface.dart';
import 'package:immich_mobile/services/sync.service.dart';
import 'package:mocktail/mocktail.dart';
@ -56,8 +56,10 @@ void main() {
final MockAlbumMediaRepository albumMediaRepository =
MockAlbumMediaRepository();
final MockAlbumApiRepository albumApiRepository = MockAlbumApiRepository();
final owner = User(
id: "1",
final MockPartnerRepository partnerRepository = MockPartnerRepository();
final owner = UserDto(
uid: "1",
updatedAt: DateTime.now(),
email: "a@b.c",
name: "first last",
@ -92,21 +94,22 @@ void main() {
albumRepository,
assetRepository,
exifInfoRepository,
partnerRepository,
userRepository,
StoreService.I,
eTagRepository,
);
when(() => eTagRepository.get(owner.isarId))
.thenAnswer((_) async => ETag(id: owner.id, time: DateTime.now()));
when(() => eTagRepository.get(owner.id))
.thenAnswer((_) async => ETag(id: owner.uid, time: DateTime.now()));
when(() => eTagRepository.deleteByIds(["1"])).thenAnswer((_) async {});
when(() => eTagRepository.upsertAll(any())).thenAnswer((_) async {});
when(() => userRepository.me()).thenAnswer((_) async => owner);
when(() => userRepository.getAll(sortBy: UserSort.id))
.thenAnswer((_) async => [owner]);
when(() => userRepository.getAllAccessible())
when(() => partnerRepository.getSharedWith()).thenAnswer((_) async => []);
when(() => userRepository.getAll(sortBy: SortUserBy.id))
.thenAnswer((_) async => [owner]);
when(() => userRepository.getAll()).thenAnswer((_) async => [owner]);
when(
() => assetRepository.getAll(
ownerId: owner.isarId,
ownerId: owner.id,
sortBy: AssetSort.checksum,
),
).thenAnswer((_) async => initialAssets);
@ -180,7 +183,7 @@ void main() {
expect(c1, isTrue);
when(
() => assetRepository.getAll(
ownerId: owner.isarId,
ownerId: owner.id,
sortBy: AssetSort.checksum,
),
).thenAnswer((_) async => remoteAssets);
@ -194,7 +197,7 @@ void main() {
final currentState = [...remoteAssets];
when(
() => assetRepository.getAll(
ownerId: owner.isarId,
ownerId: owner.id,
sortBy: AssetSort.checksum,
),
).thenAnswer((_) async => currentState);
@ -252,7 +255,7 @@ void main() {
}
Future<(List<Asset>?, List<String>?)> _failDiff(
List<User> user,
List<UserDto> user,
DateTime time,
) =>
Future.value((null, null));

View file

@ -1,4 +1,5 @@
import 'package:immich_mobile/domain/interfaces/exif.interface.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/interfaces/album.interface.dart';
import 'package:immich_mobile/interfaces/album_api.interface.dart';
import 'package:immich_mobile/interfaces/album_media.interface.dart';
@ -9,7 +10,7 @@ import 'package:immich_mobile/interfaces/auth_api.interface.dart';
import 'package:immich_mobile/interfaces/backup_album.interface.dart';
import 'package:immich_mobile/interfaces/etag.interface.dart';
import 'package:immich_mobile/interfaces/file_media.interface.dart';
import 'package:immich_mobile/interfaces/user.interface.dart';
import 'package:immich_mobile/interfaces/partner.interface.dart';
import 'package:mocktail/mocktail.dart';
class MockAlbumRepository extends Mock implements IAlbumRepository {}
@ -35,3 +36,5 @@ class MockAlbumApiRepository extends Mock implements IAlbumApiRepository {}
class MockAuthApiRepository extends Mock implements IAuthApiRepository {}
class MockAuthRepository extends Mock implements IAuthRepository {}
class MockPartnerRepository extends Mock implements IPartnerRepository {}

View file

@ -146,7 +146,7 @@ void main() {
() => albumApiRepository.create(
"name",
assetIds: [AssetStub.image1.remoteId!],
sharedUserIds: [UserStub.user1.id],
sharedUserIds: [UserStub.user1.uid],
),
).called(1);
verify(
@ -204,7 +204,7 @@ void main() {
when(
() => albumRepository.addUsers(
AlbumStub.emptyAlbum,
AlbumStub.emptyAlbum.sharedUsers.toList(),
AlbumStub.emptyAlbum.sharedUsers.map((u) => u.toDto()).toList(),
),
).thenAnswer((_) async => AlbumStub.emptyAlbum);
@ -214,7 +214,7 @@ void main() {
final result = await sut.addUsers(
AlbumStub.emptyAlbum,
[UserStub.user2.id],
[UserStub.user2.uid],
);
expect(result, true);

View file

@ -1,7 +1,9 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
import 'package:immich_mobile/services/entity.service.dart';
import 'package:mocktail/mocktail.dart';
import '../fixtures/asset.stub.dart';
import '../fixtures/user.stub.dart';
import '../repository.mocks.dart';
@ -33,25 +35,32 @@ void main() {
)
..remoteThumbnailAssetId = AssetStub.image1.remoteId
..assets.addAll([AssetStub.image1, AssetStub.image1])
..owner.value = UserStub.user1
..sharedUsers.addAll([UserStub.admin, UserStub.admin]);
..owner.value = User.fromDto(UserStub.user1)
..sharedUsers.addAll(
[User.fromDto(UserStub.admin), User.fromDto(UserStub.admin)],
);
when(() => userRepository.get(album.ownerId!))
when(() => userRepository.get(any()))
.thenAnswer((_) async => UserStub.admin);
when(() => userRepository.getByUserId(any()))
.thenAnswer((_) async => UserStub.admin);
when(() => assetRepository.getByRemoteId(AssetStub.image1.remoteId!))
.thenAnswer((_) async => AssetStub.image1);
when(() => userRepository.getByIds(any()))
when(() => userRepository.getByUserIds(any()))
.thenAnswer((_) async => [UserStub.user1, UserStub.user2]);
when(() => assetRepository.getAllByRemoteId(any()))
.thenAnswer((_) async => [AssetStub.image1, AssetStub.image2]);
await sut.fillAlbumWithDatabaseEntities(album);
expect(album.owner.value, UserStub.admin);
expect(album.owner.value?.toDto(), UserStub.admin);
expect(album.thumbnail.value, AssetStub.image1);
expect(album.remoteUsers.toSet(), {UserStub.user1, UserStub.user2});
expect(
album.remoteUsers.map((u) => u.toDto()).toSet(),
{UserStub.user1, UserStub.user2},
);
expect(album.remoteAssets.toSet(), {AssetStub.image1, AssetStub.image2});
});

View file

@ -12,10 +12,10 @@ import 'package:immich_mobile/entities/backup_album.entity.dart';
import 'package:immich_mobile/entities/duplicated_asset.entity.dart';
import 'package:immich_mobile/entities/etag.entity.dart';
import 'package:immich_mobile/entities/ios_device_asset.entity.dart';
import 'package:immich_mobile/entities/user.entity.dart';
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart';
import 'package:immich_mobile/infrastructure/entities/log.entity.dart';
import 'package:immich_mobile/infrastructure/entities/store.entity.dart';
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
import 'package:isar/isar.dart';
import 'package:mocktail/mocktail.dart';