Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LA 1352 new files appear in offline mode #967

Merged
merged 3 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions data/lib/src/datasource/received_share_datasource.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,8 @@ abstract class ReceivedShareDataSource {
Future<List<ReceivedShare>> getAllReceivedShareOffline();

Future<bool> disableOffline(ShareId shareId, String localPath);

Future<List<ReceivedShare>> getAllReceivedSharesForRecipient(
String recipient);

}
12 changes: 12 additions & 0 deletions data/lib/src/datasource_impl/local_received_share_datasource.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,16 @@ class LocalReceivedShareDataSource extends ReceivedShareDataSource {
throw LocalUnknownError(error);
});
}

@override
Future<List<ReceivedShare>> getAllReceivedSharesForRecipient(
String recipient) {
return Future.sync(() async {
return await _receivedShareDatabaseManager
.getListDataForRecipient(recipient);
}).catchError((error) {
throw LocalUnknownError(error);
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -217,4 +217,10 @@ class ReceivedShareDataSourceImpl extends ReceivedShareDataSource {
Future<bool> disableOffline(ShareId shareId, String localPath) {
throw UnimplementedError();
}

@override
Future<List<ReceivedShare>> getAllReceivedSharesForRecipient(String recipient) {
// TODO: implement getAllReceivedSharesForRecipient
throw UnimplementedError();
}
}
6 changes: 6 additions & 0 deletions data/lib/src/extensions/user_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,10 @@ extension UserExtension on User {
secondFARequired
);
}

GenericUser toGenericUser() {
return GenericUser(
mail,
);
}
}
22 changes: 20 additions & 2 deletions data/lib/src/local/received_share_database_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ import 'package:domain/domain.dart';

import 'model/received_share_cache.dart';

class ReceivedShareDatabaseManager extends LinShareDatabaseManager<ReceivedShare> {
class ReceivedShareDatabaseManager
extends LinShareDatabaseManager<ReceivedShare> {
final DatabaseClient _databaseClient;

ReceivedShareDatabaseManager(this._databaseClient);
Expand Down Expand Up @@ -98,4 +99,21 @@ class ReceivedShareDatabaseManager extends LinShareDatabaseManager<ReceivedShare
return res > 0 ? true : false;
}

}
Future<List<ReceivedShare>> getListDataForRecipient(String mail) async {
final now = DateTime.now();
final todayDate =
DateTime(now.year, now.month, now.day, now.hour, now.minute).toIso8601String();
final queryCondition =
'${ReceivedShareTable.MAIL_RECIPIENT} !="" AND ${ReceivedShareTable.MAIL_RECIPIENT} = ? AND ${ReceivedShareTable.EXPIRATION_DATE} >= ?';
final res = await _databaseClient.getListDataWithCondition(
ReceivedShareTable.TABLE_NAME,
queryCondition,
[mail, todayDate]);
return res.isNotEmpty
? res
.map((mapObject) =>
ReceivedShareCache.fromJson(mapObject).toReceivedShare())
.toList()
: [];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,9 @@ class ReceivedShareRepositoryImpl extends ReceivedShareRepository {
Future<bool> disableOffline(ShareId shareId, String localPath) {
return _receivedShareDataSources[DataSourceType.local]!.disableOffline(shareId, localPath);
}

@override
Future<List<ReceivedShare>> getAllReceivedShareOfflineByRecipient(String recipient) {
return _receivedShareDataSources[DataSourceType.local]!.getAllReceivedSharesForRecipient(recipient);
}
}
66 changes: 66 additions & 0 deletions data/test/local/received_share_database_manager_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import 'package:data/data.dart';
import 'package:data/src/local/config/received_share_table.dart';
import 'package:data/src/local/model/received_share_cache.dart';
import 'package:domain/domain.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:mockito/annotations.dart';
import 'package:testshared/fixture/received_share_fixture.dart';
import 'document_database_manager_test.mocks.dart';

@GenerateMocks([DatabaseClient])
void main() {
late MockDatabaseClient mockDatabaseClient;
late ReceivedShareDatabaseManager receivedShareDatabaseManager;
late DateTime now;
late String todayDate;
setUp(() {
mockDatabaseClient = MockDatabaseClient();
receivedShareDatabaseManager =
ReceivedShareDatabaseManager(mockDatabaseClient);
now = DateTime.now();
todayDate = DateTime(now.year, now.month, now.day, now.hour, now.minute)
.toIso8601String();
});

group('getListDataForRecipient', () {
test(
'getListDataForRecipient returns filtered and mapped data for a specific recipient',
() async {
when(mockDatabaseClient.getListDataWithCondition(
ReceivedShareTable.TABLE_NAME,
'${ReceivedShareTable.MAIL_RECIPIENT} !="" AND ${ReceivedShareTable.MAIL_RECIPIENT} = ? AND ${ReceivedShareTable.EXPIRATION_DATE} >= ?',
[RECIPIENT_1.mail, todayDate],
)).thenAnswer((_) async => [
receivedShare1.toReceivedShareCache().toJson(),
]);

final result = await receivedShareDatabaseManager
.getListDataForRecipient(RECIPIENT_1.mail);

expect(result, isA<List<ReceivedShare>>());
expect(result.length, 1);
expect(result.first.shareId, receivedShare1.shareId);
});
test(
'getListDataForRecipient returns an empty list when no data matches the recipient',
() async {
when(mockDatabaseClient.getListDataWithCondition(
ReceivedShareTable.TABLE_NAME,
'${ReceivedShareTable.MAIL_RECIPIENT} !="" AND ${ReceivedShareTable.MAIL_RECIPIENT} = ? AND ${ReceivedShareTable.EXPIRATION_DATE} >= ?',
[RECIPIENT_1.mail, todayDate],
)).thenAnswer((_) async => []);

final result = await receivedShareDatabaseManager
.getListDataForRecipient(RECIPIENT_1.mail);
expect(result, isA<List<ReceivedShare>>());
expect(result.isEmpty, true);
verify(mockDatabaseClient.getListDataWithCondition(
ReceivedShareTable.TABLE_NAME,
'${ReceivedShareTable.MAIL_RECIPIENT} !="" AND ${ReceivedShareTable.MAIL_RECIPIENT} = ? AND ${ReceivedShareTable.EXPIRATION_DATE} >= ?',
[RECIPIENT_1.mail, todayDate],
)).called(1);
},
);
});
}
1 change: 1 addition & 0 deletions domain/lib/domain.dart
Original file line number Diff line number Diff line change
Expand Up @@ -512,3 +512,4 @@ export 'src/usecases/workgroup/get_all_workgroups_interactor.dart';
export 'src/usecases/workgroup/get_all_workgroups_offline_interactor.dart';
export 'src/usecases/workgroup/workgroup_exception.dart';
export 'src/usecases/workgroup/workgroup_view_state.dart';
export 'src/usecases/received/remove_deleted_received_share_from_local_database.dart';
18 changes: 18 additions & 0 deletions domain/lib/src/extension/received_share_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,22 @@ extension ReceivedShareExtensions on ReceivedShare {
localPath: localPath,
syncOfflineState: SyncOfflineState.completed);
}

ReceivedShare withRecipient(GenericUser recipient) {
return ReceivedShare(
shareId,
name,
creationDate,
modificationDate,
expirationDate,
description,
recipient,
mediaType,
sender,
downloaded,
size,
hasThumbnail,
localPath: localPath,
syncOfflineState: syncOfflineState);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,8 @@ abstract class ReceivedShareRepository {

Future<List<ReceivedShare>> getAllReceivedShareOffline();

Future<List<ReceivedShare>> getAllReceivedShareOfflineByRecipient(
String recipient);

Future<bool> disableOffline(ShareId shareId, String localPath);
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,27 @@ import 'package:domain/src/repository/received/received_share_repository.dart';
import 'package:domain/src/state/failure.dart';
import 'package:domain/src/state/success.dart';
import 'package:domain/src/usecases/received/received_share_view_state.dart';
import 'package:collection/collection.dart';
import 'package:domain/src/usecases/received/remove_deleted_received_share_from_local_database.dart';

class GetAllReceivedSharesInteractor {
final ReceivedShareRepository _receivedShareRepository;
final RemoveDeletedReceivedShareFromLocalDatabaseInteractor
_removeDeletedReceivedShareFromLocalDatabase;

GetAllReceivedSharesInteractor(this._receivedShareRepository);
GetAllReceivedSharesInteractor(this._receivedShareRepository,
this._removeDeletedReceivedShareFromLocalDatabase);

Future<Either<Failure, Success>> execute() async {
Future<Either<Failure, Success>> execute(String recipient) async {
try {
final receivedShares = await _receivedShareRepository.getAllReceivedShares()
.onError((error, stackTrace) => _receivedShareRepository.getAllReceivedShareOffline());
.onError((error, stackTrace) => _receivedShareRepository
.getAllReceivedShareOfflineByRecipient(recipient));
final combinedReceivedShares = List<ReceivedShare>.empty(growable: true);

_removeDeletedReceivedShareFromLocalDatabase.execute(
receivedShares, recipient);
hoangdat marked this conversation as resolved.
Show resolved Hide resolved

if (receivedShares.isNotEmpty) {
for (final received in receivedShares) {
final localReceivedShare = await _receivedShareRepository
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class MakeReceivedShareOfflineInteractor {
this._credentialRepository
);

Future<Either<Failure, Success>> execute(ReceivedShare receivedShare) async {
Future<Either<Failure, Success>> execute(
ReceivedShare receivedShare, GenericUser recipient) async {
try {
final downloadPreviewType = receivedShare.mediaType.isImageFile()
? DownloadPreviewType.image
Expand All @@ -69,7 +70,10 @@ class MakeReceivedShareOfflineInteractor {
});

if (filePath.isNotEmpty) {
final result = await _receivedShareRepository.makeAvailableOffline(receivedShare, filePath);
ReceivedShare receivedShareWithRecipient =
receivedShare.withRecipient(recipient);
final result = await _receivedShareRepository.makeAvailableOffline(
receivedShareWithRecipient, filePath);
if (result) {
return Right<Failure, Success>(MakeAvailableOfflineReceivedShareViewState(OfflineModeActionResult.successful, filePath));
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'dart:developer';
import 'package:domain/domain.dart';

class RemoveDeletedReceivedShareFromLocalDatabaseInteractor {
final ReceivedShareRepository _receivedShareRepository;

RemoveDeletedReceivedShareFromLocalDatabaseInteractor(
this._receivedShareRepository);

Future<void> execute(
List<ReceivedShare> receivedShares, String recipient) async {
try {
var localReceivedShares = await _receivedShareRepository
.getAllReceivedShareOfflineByRecipient(recipient);
final receivedShareIds =
receivedShares.map((received) => received.shareId).toSet();
for (final local in localReceivedShares) {
if (!receivedShareIds.contains(local.shareId)) {
await _receivedShareRepository.disableOffline(
local.shareId, local.localPath ?? '');
}
}
} catch (exception) {
log('RemoveDeletedReceivedShareFromLocalDatabaseInteractor: $exception');
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@

import 'package:dartz/dartz.dart';
import 'package:domain/domain.dart';
import 'package:domain/src/usecases/received/received_share_view_state.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
Expand All @@ -46,19 +45,30 @@ void main() {
group('get_all_received_interactor', () {
late MockReceivedShareRepository receivedShareRepository;
late GetAllReceivedSharesInteractor getAllReceivedSharesInteractor;
late RemoveDeletedReceivedShareFromLocalDatabaseInteractor
removeDeletedReceivedShareFromLocalDatabaseInteractor;


setUp(() {
receivedShareRepository = MockReceivedShareRepository();
getAllReceivedSharesInteractor = GetAllReceivedSharesInteractor(receivedShareRepository);
removeDeletedReceivedShareFromLocalDatabaseInteractor =
RemoveDeletedReceivedShareFromLocalDatabaseInteractor(
receivedShareRepository);
getAllReceivedSharesInteractor = GetAllReceivedSharesInteractor(
receivedShareRepository,
removeDeletedReceivedShareFromLocalDatabaseInteractor);
});

test('get all receives interactor should return success with receive list', () async {
when(receivedShareRepository.getAllReceivedShares()).thenAnswer((_) async => [receivedShare1, receivedShare2]);
when(receivedShareRepository.getAllReceivedShareOffline()).thenAnswer((_) async => []);
when(receivedShareRepository.getReceivedShareOffline(receivedShare1.shareId)).thenAnswer((_) async => null);
when(receivedShareRepository.getReceivedShareOffline(receivedShare2.shareId)).thenAnswer((_) async => null);
when(receivedShareRepository
.getAllReceivedShareOfflineByRecipient(RECIPIENT_1.mail))
.thenAnswer((_) async => [receivedShare1]);

final result = await getAllReceivedSharesInteractor.execute();
final result = await getAllReceivedSharesInteractor.execute(RECIPIENT_1.mail);

result.map((success) => (success as GetAllReceivedShareSuccess).receivedShares)
.fold(
Expand All @@ -71,7 +81,8 @@ void main() {
final exception = Exception();
when(receivedShareRepository.getAllReceivedShares()).thenThrow(exception);

final result = await getAllReceivedSharesInteractor.execute();
final result =
await getAllReceivedSharesInteractor.execute(RECIPIENT_1.mail);

result.fold(
(failure) => expect(failure, isA<GetAllReceivedShareFailure>()),
Expand Down
7 changes: 6 additions & 1 deletion lib/presentation/di/module/app_module.dart
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,12 @@ class AppModule {
getIt.registerFactory(() => GetSharedSpacesRootNodeInfoInteractor(getIt<SharedSpaceDocumentRepository>()));
getIt.registerFactory(() => DownloadMultipleFileIOSInteractor(getIt<DownloadFileIOSInteractor>()));
getIt.registerFactory(() => GetAuthorizedInteractor(getIt<AuthenticationRepository>(), getIt<CredentialRepository>()));
getIt.registerFactory(() => GetAllReceivedSharesInteractor(getIt<ReceivedShareRepository>()));
getIt.registerFactory(() =>
RemoveDeletedReceivedShareFromLocalDatabaseInteractor(
getIt<ReceivedShareRepository>()));
getIt.registerFactory(() => GetAllReceivedSharesInteractor(
getIt<ReceivedShareRepository>(),
getIt<RemoveDeletedReceivedShareFromLocalDatabaseInteractor>()));
getIt.registerFactory(() => CopyToMySpaceInteractor(getIt<DocumentRepository>()));
getIt.registerFactory(() => CopyMultipleFilesToMySpaceInteractor(getIt<CopyToMySpaceInteractor>()));
getIt.registerFactory(() => SearchDocumentInteractor());
Expand Down
11 changes: 8 additions & 3 deletions lib/presentation/widget/received/received_share_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,10 @@ class ReceivedShareViewModel extends BaseViewModel {
ThunkAction<AppState> _getAllReceivedShareAction() {
return (Store<AppState> store) async {
store.dispatch(StartReceivedShareLoadingAction());
await _getAllReceivedInteractor.execute().then((result) => result.fold(
final currentUser = store.state.account.user;
await _getAllReceivedInteractor
.execute(currentUser?.mail ?? '')
.then((result) => result.fold(
(failure) {
store.dispatch(ReceivedShareGetAllReceivedSharesAction(Left(failure)));
_receivedSharesList = [];
Expand Down Expand Up @@ -369,9 +372,10 @@ class ReceivedShareViewModel extends BaseViewModel {
return (Store<AppState> store) async {
store.dispatch(StartReceivedShareLoadingAction());

final currentUser = store.state.account.user;
await Future.wait([
_getSorterInteractor.execute(OrderScreen.receivedShares),
_getAllReceivedInteractor.execute()
_getAllReceivedInteractor.execute(currentUser?.mail ?? '')
]).then((response) async {
response[0].fold((failure) {
store.dispatch(ReceivedShareGetSorterAction(Sorter.fromOrderScreen(OrderScreen.receivedShares)));
Expand Down Expand Up @@ -614,7 +618,8 @@ class ReceivedShareViewModel extends BaseViewModel {

OnlineThunkAction _makeAvailableOfflineAction(ReceivedShare receivedShare, int position) {
return OnlineThunkAction((Store<AppState> store) async {
await _makeReceivedShareOfflineInteractor.execute(receivedShare)
final recipient = GenericUser(store.state.account.user?.mail ?? '');
await _makeReceivedShareOfflineInteractor.execute(receivedShare, recipient)
.then((result) => result.fold(
(failure) {
_receivedSharesList[position] = receivedShare.toSyncOffline(syncOfflineState: SyncOfflineState.none);
Expand Down
Loading