|
@@ -9,11 +9,11 @@ import 'package:logging/logging.dart';
|
|
|
import 'package:photos/core/configuration.dart';
|
|
|
import 'package:photos/core/event_bus.dart';
|
|
|
import 'package:photos/db/collections_db.dart';
|
|
|
+import 'package:photos/db/files_db.dart';
|
|
|
import 'package:photos/events/collection_updated_event.dart';
|
|
|
import 'package:photos/models/collection.dart';
|
|
|
import 'package:photos/models/collection_file_item.dart';
|
|
|
import 'package:photos/models/file.dart';
|
|
|
-import 'package:photos/models/shared_collection.dart';
|
|
|
import 'package:photos/utils/crypto_util.dart';
|
|
|
import 'package:photos/utils/file_util.dart';
|
|
|
|
|
@@ -23,8 +23,7 @@ class CollectionsService {
|
|
|
CollectionsDB _db;
|
|
|
Configuration _config;
|
|
|
final _localCollections = Map<String, Collection>();
|
|
|
- final _collectionIDToOwnedCollections = Map<int, Collection>();
|
|
|
- final _collectionIDToSharedCollections = Map<int, SharedCollection>();
|
|
|
+ final _collectionIDToCollections = Map<int, Collection>();
|
|
|
final _cachedKeys = Map<int, Uint8List>();
|
|
|
|
|
|
CollectionsService._privateConstructor() {
|
|
@@ -38,33 +37,18 @@ class CollectionsService {
|
|
|
Future<void> init() async {
|
|
|
final collections = await _db.getAllCollections();
|
|
|
for (final collection in collections) {
|
|
|
- _cacheOwnedCollectionAttributes(collection);
|
|
|
- }
|
|
|
- final sharedCollections = await _db.getAllSharedCollections();
|
|
|
- for (final collection in sharedCollections) {
|
|
|
- _collectionIDToSharedCollections[collection.id] = collection;
|
|
|
+ _cacheCollectionAttributes(collection);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Future<void> sync() async {
|
|
|
final lastCollectionCreationTime =
|
|
|
await _db.getLastCollectionCreationTime();
|
|
|
- var collections =
|
|
|
- await _getOwnedCollections(lastCollectionCreationTime ?? 0);
|
|
|
+ var collections = await _fetchCollections(lastCollectionCreationTime ?? 0);
|
|
|
await _db.insert(collections);
|
|
|
collections = await _db.getAllCollections();
|
|
|
for (final collection in collections) {
|
|
|
- _cacheOwnedCollectionAttributes(collection);
|
|
|
- }
|
|
|
-
|
|
|
- final lastSharedCollectionCreationTime =
|
|
|
- await _db.getLastCollectionCreationTime();
|
|
|
- var sharedCollections =
|
|
|
- await getSharedCollections(lastSharedCollectionCreationTime ?? 0);
|
|
|
- await _db.insertSharedCollections(sharedCollections);
|
|
|
- sharedCollections = await _db.getAllSharedCollections();
|
|
|
- for (final collection in sharedCollections) {
|
|
|
- _collectionIDToSharedCollections[collection.id] = collection;
|
|
|
+ _cacheCollectionAttributes(collection);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -72,8 +56,8 @@ class CollectionsService {
|
|
|
return _localCollections[path];
|
|
|
}
|
|
|
|
|
|
- List<Collection> getOwnedCollections() {
|
|
|
- return _collectionIDToOwnedCollections.values.toList();
|
|
|
+ List<Collection> getCollections() {
|
|
|
+ return _collectionIDToCollections.values.toList();
|
|
|
}
|
|
|
|
|
|
Future<List<String>> getSharees(int collectionID) {
|
|
@@ -113,14 +97,13 @@ class CollectionsService {
|
|
|
|
|
|
Uint8List getCollectionKey(int collectionID) {
|
|
|
if (!_cachedKeys.containsKey(collectionID)) {
|
|
|
+ final collection = _collectionIDToCollections[collectionID];
|
|
|
var key;
|
|
|
- if (_collectionIDToOwnedCollections.containsKey(collectionID)) {
|
|
|
- final collection = _collectionIDToOwnedCollections[collectionID];
|
|
|
+ if (collection.ownerID == _config.getUserID()) {
|
|
|
final encryptedKey = Sodium.base642bin(collection.encryptedKey);
|
|
|
key = CryptoUtil.decryptSync(encryptedKey, _config.getKey(),
|
|
|
Sodium.base642bin(collection.keyDecryptionNonce));
|
|
|
} else {
|
|
|
- final collection = _collectionIDToSharedCollections[collectionID];
|
|
|
final encryptedKey = Sodium.base642bin(collection.encryptedKey);
|
|
|
key = CryptoUtil.openSealSync(
|
|
|
encryptedKey,
|
|
@@ -132,10 +115,10 @@ class CollectionsService {
|
|
|
return _cachedKeys[collectionID];
|
|
|
}
|
|
|
|
|
|
- Future<List<Collection>> _getOwnedCollections(int sinceTime) {
|
|
|
+ Future<List<Collection>> _fetchCollections(int sinceTime) {
|
|
|
return Dio()
|
|
|
.get(
|
|
|
- Configuration.instance.getHttpEndpoint() + "/collections/owned",
|
|
|
+ Configuration.instance.getHttpEndpoint() + "/collections/",
|
|
|
queryParameters: {
|
|
|
"sinceTime": sinceTime,
|
|
|
},
|
|
@@ -154,30 +137,8 @@ class CollectionsService {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- Future<List<SharedCollection>> getSharedCollections(int sinceTime) {
|
|
|
- return Dio()
|
|
|
- .get(
|
|
|
- Configuration.instance.getHttpEndpoint() + "/collections/shared",
|
|
|
- queryParameters: {
|
|
|
- "sinceTime": sinceTime,
|
|
|
- },
|
|
|
- options:
|
|
|
- Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
|
|
|
- )
|
|
|
- .then((response) {
|
|
|
- final collections = List<SharedCollection>();
|
|
|
- if (response != null) {
|
|
|
- final c = response.data["collections"];
|
|
|
- for (final collection in c) {
|
|
|
- collections.add(SharedCollection.fromMap(collection));
|
|
|
- }
|
|
|
- }
|
|
|
- return collections;
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- Collection getOwnedCollectionByID(int collectionID) {
|
|
|
- return _collectionIDToOwnedCollections[collectionID];
|
|
|
+ Collection getCollectionByID(int collectionID) {
|
|
|
+ return _collectionIDToCollections[collectionID];
|
|
|
}
|
|
|
|
|
|
Future<Collection> createAlbum(String albumName) async {
|
|
@@ -224,29 +185,32 @@ class CollectionsService {
|
|
|
params["collectionID"] = collectionID;
|
|
|
for (final file in files) {
|
|
|
final key = decryptFileKey(file);
|
|
|
+ file.collectionID = collectionID;
|
|
|
final encryptedKeyData =
|
|
|
CryptoUtil.encryptSync(key, getCollectionKey(collectionID));
|
|
|
+ file.encryptedKey = Sodium.bin2base64(encryptedKeyData.encryptedData);
|
|
|
+ file.keyDecryptionNonce = Sodium.bin2base64(encryptedKeyData.nonce);
|
|
|
if (params["files"] == null) {
|
|
|
params["files"] = [];
|
|
|
}
|
|
|
params["files"].add(CollectionFileItem(
|
|
|
- file.uploadedFileID,
|
|
|
- Sodium.bin2base64(encryptedKeyData.encryptedData),
|
|
|
- Sodium.bin2base64(encryptedKeyData.nonce),
|
|
|
- ).toMap());
|
|
|
+ file.uploadedFileID, file.encryptedKey, file.keyDecryptionNonce)
|
|
|
+ .toMap());
|
|
|
}
|
|
|
return Dio()
|
|
|
.post(
|
|
|
- Configuration.instance.getHttpEndpoint() + "/collections/add-files",
|
|
|
- data: params,
|
|
|
- options: Options(
|
|
|
- headers: {"X-Auth-Token": Configuration.instance.getToken()}),
|
|
|
- )
|
|
|
- .then(
|
|
|
- (value) => Bus.instance.fire(CollectionUpdatedEvent(collectionID)));
|
|
|
+ Configuration.instance.getHttpEndpoint() + "/collections/add-files",
|
|
|
+ data: params,
|
|
|
+ options:
|
|
|
+ Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
|
|
|
+ )
|
|
|
+ .then((value) async {
|
|
|
+ await FilesDB.instance.insertMultiple(files);
|
|
|
+ Bus.instance.fire(CollectionUpdatedEvent(collectionID));
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- Future<void> removeFromCollection(int collectionID, List<File> files) {
|
|
|
+ Future<void> removeFromCollection(int collectionID, List<File> files) async {
|
|
|
final params = Map<String, dynamic>();
|
|
|
params["collectionID"] = collectionID;
|
|
|
for (final file in files) {
|
|
@@ -255,17 +219,15 @@ class CollectionsService {
|
|
|
}
|
|
|
params["fileIDs"].add(file.uploadedFileID);
|
|
|
}
|
|
|
- return Dio()
|
|
|
- .post(
|
|
|
- Configuration.instance.getHttpEndpoint() +
|
|
|
- "/collections/remove-files",
|
|
|
- data: params,
|
|
|
- options: Options(
|
|
|
- headers: {"X-Auth-Token": Configuration.instance.getToken()}),
|
|
|
- )
|
|
|
- .then(
|
|
|
- (value) => Bus.instance.fire(CollectionUpdatedEvent(collectionID)));
|
|
|
- ;
|
|
|
+ await Dio().post(
|
|
|
+ Configuration.instance.getHttpEndpoint() + "/collections/remove-files",
|
|
|
+ data: params,
|
|
|
+ options:
|
|
|
+ Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
|
|
|
+ );
|
|
|
+ await FilesDB.instance
|
|
|
+ .removeFromCollection(collectionID, params["fileIDs"]);
|
|
|
+ Bus.instance.fire(CollectionUpdatedEvent(collectionID));
|
|
|
}
|
|
|
|
|
|
Future<Collection> createAndCacheCollection(Collection collection) async {
|
|
@@ -278,12 +240,12 @@ class CollectionsService {
|
|
|
)
|
|
|
.then((response) {
|
|
|
final collection = Collection.fromMap(response.data["collection"]);
|
|
|
- _cacheOwnedCollectionAttributes(collection);
|
|
|
+ _cacheCollectionAttributes(collection);
|
|
|
return collection;
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- void _cacheOwnedCollectionAttributes(Collection collection) {
|
|
|
+ void _cacheCollectionAttributes(Collection collection) {
|
|
|
if (collection.attributes.encryptedPath != null) {
|
|
|
var path = utf8.decode(CryptoUtil.decryptSync(
|
|
|
Sodium.base642bin(collection.attributes.encryptedPath),
|
|
@@ -291,8 +253,7 @@ class CollectionsService {
|
|
|
Sodium.base642bin(collection.attributes.pathDecryptionNonce)));
|
|
|
_localCollections[path] = collection;
|
|
|
}
|
|
|
- _collectionIDToOwnedCollections[collection.id] = collection;
|
|
|
- getCollectionKey(collection.id);
|
|
|
+ _collectionIDToCollections[collection.id] = collection;
|
|
|
}
|
|
|
}
|
|
|
|