mirror of
https://github.com/immich-app/immich.git
synced 2026-06-12 19:11:52 -07:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 637525fbca | |||
| b9add5973a | |||
| 78a79245b1 |
@@ -159,8 +159,8 @@ class RemoteAlbumService {
|
||||
return updatedAlbum;
|
||||
}
|
||||
|
||||
FutureOr<(DateTime, DateTime)> getDateRange(String albumId) {
|
||||
return _repository.getDateRange(albumId);
|
||||
Stream<(DateTime, DateTime)> watchDateRange(String albumId) {
|
||||
return _repository.watchDateRange(albumId);
|
||||
}
|
||||
|
||||
Future<List<UserDto>> getSharedUsers(String albumId) {
|
||||
|
||||
@@ -213,7 +213,7 @@ class DriftRemoteAlbumRepository extends DriftDatabaseRepository {
|
||||
});
|
||||
}
|
||||
|
||||
FutureOr<(DateTime, DateTime)> getDateRange(String albumId) {
|
||||
Stream<(DateTime, DateTime)> watchDateRange(String albumId) {
|
||||
final query = _db.remoteAlbumAssetEntity.selectOnly()
|
||||
..where(_db.remoteAlbumAssetEntity.albumId.equals(albumId))
|
||||
..addColumns([_db.remoteAssetEntity.createdAt.min(), _db.remoteAssetEntity.createdAt.max()])
|
||||
@@ -225,7 +225,7 @@ class DriftRemoteAlbumRepository extends DriftDatabaseRepository {
|
||||
final minDate = row.read(_db.remoteAssetEntity.createdAt.min());
|
||||
final maxDate = row.read(_db.remoteAssetEntity.createdAt.max());
|
||||
return (minDate ?? DateTime.now(), maxDate ?? DateTime.now());
|
||||
}).getSingle();
|
||||
}).watchSingle();
|
||||
}
|
||||
|
||||
Future<List<UserDto>> getSharedUsers(String albumId) async {
|
||||
|
||||
@@ -313,9 +313,9 @@ class RemoteAlbumNotifier extends Notifier<RemoteAlbumState> {
|
||||
}
|
||||
}
|
||||
|
||||
final remoteAlbumDateRangeProvider = FutureProvider.family<(DateTime, DateTime), String>((ref, albumId) async {
|
||||
final remoteAlbumDateRangeProvider = StreamProvider.autoDispose.family<(DateTime, DateTime), String>((ref, albumId) {
|
||||
final service = ref.watch(remoteAlbumServiceProvider);
|
||||
return service.getDateRange(albumId);
|
||||
return service.watchDateRange(albumId);
|
||||
});
|
||||
|
||||
final remoteAlbumSharedUsersProvider = FutureProvider.autoDispose.family<List<UserDto>, String>((ref, albumId) async {
|
||||
|
||||
@@ -103,6 +103,8 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
||||
socket.on('AssetUploadReadyV2', _handleSyncAssetUploadReadyV2);
|
||||
socket.on('AssetEditReadyV1', _handleSyncAssetEditReadyV1);
|
||||
socket.on('AssetEditReadyV2', _handleSyncAssetEditReadyV2);
|
||||
socket.on('on_album_asset_create', _handleAlbumAssetMutation);
|
||||
socket.on('on_album_asset_delete', _handleAlbumAssetMutation);
|
||||
socket.on('on_config_update', _handleOnConfigUpdate);
|
||||
socket.on('on_new_release', _handleReleaseUpdates);
|
||||
} catch (e) {
|
||||
@@ -184,6 +186,10 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
||||
unawaited(_ref.read(backgroundSyncProvider).syncWebsocketEditV1(data));
|
||||
}
|
||||
|
||||
void _handleAlbumAssetMutation(dynamic _) {
|
||||
unawaited(_ref.read(backgroundSyncProvider).syncRemote());
|
||||
}
|
||||
|
||||
void _handleSyncAssetEditReadyV2(dynamic data) {
|
||||
unawaited(_ref.read(backgroundSyncProvider).syncWebsocketEditV2(data));
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ type EventMap = {
|
||||
// album events
|
||||
AlbumUpdate: [{ id: string; recipientId: string }];
|
||||
AlbumInvite: [{ id: string; userId: string; senderName: string }];
|
||||
AlbumAssetCreate: [{ albumId: string; userIds: string[] }];
|
||||
AlbumAssetDelete: [{ albumId: string; userIds: string[] }];
|
||||
|
||||
// asset events
|
||||
AssetCreate: [{ asset: Asset; file: UploadFile }];
|
||||
|
||||
@@ -37,6 +37,8 @@ export interface ClientEventMap {
|
||||
on_asset_hidden: [string];
|
||||
on_asset_restore: [string[]];
|
||||
on_asset_stack_update: string[];
|
||||
on_album_asset_create: [string];
|
||||
on_album_asset_delete: [string];
|
||||
on_person_thumbnail: [string];
|
||||
on_server_version: [ServerVersionResponseDto];
|
||||
on_config_update: [];
|
||||
|
||||
@@ -195,6 +195,11 @@ export class AlbumService extends BaseService {
|
||||
for (const recipientId of allUsersExceptUs) {
|
||||
await this.eventRepository.emit('AlbumUpdate', { id, recipientId });
|
||||
}
|
||||
|
||||
await this.eventRepository.emit('AlbumAssetCreate', {
|
||||
albumId: id,
|
||||
userIds: album.albumUsers.map(({ user }) => user.id),
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
@@ -223,7 +228,7 @@ export class AlbumService extends BaseService {
|
||||
}
|
||||
|
||||
const albumAssetValues: { albumId: string; assetId: string }[] = [];
|
||||
const events: { id: string; recipients: string[] }[] = [];
|
||||
const events: { id: string; recipients: string[]; allUserIds: string[] }[] = [];
|
||||
for (const albumId of allowedAlbumIds) {
|
||||
const existingAssetIds = await this.albumRepository.getAssetIds(albumId, [...allowedAssetIds]);
|
||||
const notPresentAssetIds = [...allowedAssetIds].filter((id) => !existingAssetIds.has(id));
|
||||
@@ -246,8 +251,9 @@ export class AlbumService extends BaseService {
|
||||
},
|
||||
auth.user.id,
|
||||
);
|
||||
const allUsersExceptUs = album.albumUsers.map(({ user }) => user.id).filter((userId) => userId !== auth.user.id);
|
||||
events.push({ id: albumId, recipients: allUsersExceptUs });
|
||||
const allUserIds = album.albumUsers.map(({ user }) => user.id);
|
||||
const allUsersExceptUs = allUserIds.filter((userId) => userId !== auth.user.id);
|
||||
events.push({ id: albumId, recipients: allUsersExceptUs, allUserIds });
|
||||
}
|
||||
|
||||
await this.albumRepository.addAssetIdsToAlbums(albumAssetValues);
|
||||
@@ -255,6 +261,7 @@ export class AlbumService extends BaseService {
|
||||
for (const recipientId of event.recipients) {
|
||||
await this.eventRepository.emit('AlbumUpdate', { id: event.id, recipientId });
|
||||
}
|
||||
await this.eventRepository.emit('AlbumAssetCreate', { albumId: event.id, userIds: event.allUserIds });
|
||||
}
|
||||
|
||||
return results;
|
||||
@@ -271,8 +278,15 @@ export class AlbumService extends BaseService {
|
||||
);
|
||||
|
||||
const removedIds = results.filter(({ success }) => success).map(({ id }) => id);
|
||||
if (removedIds.length > 0 && album.albumThumbnailAssetId && removedIds.includes(album.albumThumbnailAssetId)) {
|
||||
await this.albumRepository.updateThumbnails();
|
||||
if (removedIds.length > 0) {
|
||||
if (album.albumThumbnailAssetId && removedIds.includes(album.albumThumbnailAssetId)) {
|
||||
await this.albumRepository.updateThumbnails();
|
||||
}
|
||||
|
||||
await this.eventRepository.emit('AlbumAssetDelete', {
|
||||
albumId: id,
|
||||
userIds: album.albumUsers.map(({ user }) => user.id),
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
|
||||
@@ -230,6 +230,20 @@ export class NotificationService extends BaseService {
|
||||
await this.jobRepository.queue({ name: JobName.NotifyAlbumInvite, data: { id, recipientId: userId, senderName } });
|
||||
}
|
||||
|
||||
@OnEvent({ name: 'AlbumAssetCreate' })
|
||||
onAlbumAssetCreate({ albumId, userIds }: ArgOf<'AlbumAssetCreate'>) {
|
||||
for (const userId of userIds) {
|
||||
this.websocketRepository.clientSend('on_album_asset_create', userId, albumId);
|
||||
}
|
||||
}
|
||||
|
||||
@OnEvent({ name: 'AlbumAssetDelete' })
|
||||
onAlbumAssetDelete({ albumId, userIds }: ArgOf<'AlbumAssetDelete'>) {
|
||||
for (const userId of userIds) {
|
||||
this.websocketRepository.clientSend('on_album_asset_delete', userId, albumId);
|
||||
}
|
||||
}
|
||||
|
||||
@OnEvent({ name: 'SessionDelete' })
|
||||
onSessionDelete({ sessionId }: ArgOf<'SessionDelete'>) {
|
||||
// after the response is sent
|
||||
|
||||
@@ -9,6 +9,7 @@ import { AssetRepository } from 'src/repositories/asset.repository';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
import { CryptoRepository } from 'src/repositories/crypto.repository';
|
||||
import { DatabaseRepository } from 'src/repositories/database.repository';
|
||||
import { EventRepository } from 'src/repositories/event.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { PluginRepository } from 'src/repositories/plugin.repository';
|
||||
import { StorageRepository } from 'src/repositories/storage.repository';
|
||||
@@ -39,7 +40,7 @@ class WorkflowTestContext extends MediumTestContext<WorkflowExecutionService> {
|
||||
UserRepository,
|
||||
WorkflowRepository,
|
||||
],
|
||||
mock: [ConfigRepository],
|
||||
mock: [ConfigRepository, EventRepository],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -52,6 +53,7 @@ class WorkflowTestContext extends MediumTestContext<WorkflowExecutionService> {
|
||||
mockData.resourcePaths.corePlugin = '../packages/plugin-core';
|
||||
mockData.plugins.external.allow = false;
|
||||
this.getMock(ConfigRepository).getEnv.mockReturnValue(mockData);
|
||||
this.getMock(EventRepository).emit.mockResolvedValue();
|
||||
this.get(LoggingRepository).setLogLevel(LogLevel.Verbose);
|
||||
|
||||
await this.sut.onPluginSync();
|
||||
|
||||
Reference in New Issue
Block a user