Jelajahi Sumber

Fetch and store shared collections

Vishnu Mohandas 4 tahun lalu
induk
melakukan
0af41fd97b

+ 76 - 6
lib/db/collections_db.dart

@@ -3,13 +3,15 @@ import 'dart:io';
 import 'package:path/path.dart';
 import 'package:path_provider/path_provider.dart';
 import 'package:photos/models/collection.dart';
+import 'package:photos/models/shared_collection.dart';
 import 'package:sqflite/sqflite.dart';
 
 class CollectionsDB {
   static final _databaseName = "ente.collections.db";
   static final _databaseVersion = 1;
 
-  static final table = 'collections';
+  static final collectionsTable = 'collections';
+  static final sharedCollectionsTable = 'shared_collections';
 
   static final columnID = 'collection_id';
   static final columnOwnerID = 'owner_id';
@@ -43,7 +45,7 @@ class CollectionsDB {
 
   Future _onCreate(Database db, int version) async {
     await db.execute('''
-                CREATE TABLE $table (
+                CREATE TABLE $collectionsTable (
                   $columnID INTEGER PRIMARY KEY NOT NULL,
                   $columnOwnerID INTEGER NOT NULL,
                   $columnEncryptedKey TEXT NOT NULL,
@@ -55,21 +57,43 @@ class CollectionsDB {
                   $columnCreationTime TEXT NOT NULL
                 )
                 ''');
+
+    await db.execute('''
+                CREATE TABLE $sharedCollectionsTable (
+                  $columnID INTEGER PRIMARY KEY NOT NULL,
+                  $columnOwnerID INTEGER NOT NULL,
+                  $columnEncryptedKey TEXT NOT NULL,
+                  $columnName TEXT NOT NULL,
+                  $columnType TEXT NOT NULL,
+                  $columnCreationTime TEXT NOT NULL
+                )
+                ''');
   }
 
   Future<List<dynamic>> insert(List<Collection> collections) async {
     final db = await instance.database;
     var batch = db.batch();
     for (final collection in collections) {
-      batch.insert(table, _getRowForCollection(collection),
+      batch.insert(collectionsTable, _getRowForCollection(collection),
+          conflictAlgorithm: ConflictAlgorithm.replace);
+    }
+    return await batch.commit();
+  }
+
+  Future<List<dynamic>> insertSharedCollections(
+      List<SharedCollection> collections) async {
+    final db = await instance.database;
+    var batch = db.batch();
+    for (final collection in collections) {
+      batch.insert(collectionsTable, _getRowForSharedCollection(collection),
           conflictAlgorithm: ConflictAlgorithm.replace);
     }
     return await batch.commit();
   }
 
-  Future<List<Collection>> getAll() async {
+  Future<List<Collection>> getAllCollections() async {
     final db = await instance.database;
-    final rows = await db.query(table);
+    final rows = await db.query(collectionsTable);
     final collections = List<Collection>();
     for (final row in rows) {
       collections.add(_convertToCollection(row));
@@ -77,10 +101,34 @@ class CollectionsDB {
     return collections;
   }
 
+  Future<List<SharedCollection>> getAllSharedCollections() async {
+    final db = await instance.database;
+    final rows = await db.query(collectionsTable);
+    final collections = List<SharedCollection>();
+    for (final row in rows) {
+      collections.add(_convertToSharedCollection(row));
+    }
+    return collections;
+  }
+
   Future<int> getLastCollectionCreationTime() async {
     final db = await instance.database;
     final rows = await db.query(
-      table,
+      collectionsTable,
+      orderBy: '$columnCreationTime DESC',
+      limit: 1,
+    );
+    if (rows.isNotEmpty) {
+      return int.parse(rows[0][columnCreationTime]);
+    } else {
+      return null;
+    }
+  }
+
+  Future<int> getLastSharedCollectionCreationTime() async {
+    final db = await instance.database;
+    final rows = await db.query(
+      sharedCollectionsTable,
       orderBy: '$columnCreationTime DESC',
       limit: 1,
     );
@@ -118,4 +166,26 @@ class CollectionsDB {
       int.parse(row[columnCreationTime]),
     );
   }
+
+  Map<String, dynamic> _getRowForSharedCollection(SharedCollection collection) {
+    var row = new Map<String, dynamic>();
+    row[columnID] = collection.id;
+    row[columnOwnerID] = collection.ownerID;
+    row[columnEncryptedKey] = collection.encryptedKey;
+    row[columnName] = collection.name;
+    row[columnType] = Collection.typeToString(collection.type);
+    row[columnCreationTime] = collection.creationTime;
+    return row;
+  }
+
+  SharedCollection _convertToSharedCollection(Map<String, dynamic> row) {
+    return SharedCollection(
+      row[columnID],
+      row[columnOwnerID],
+      row[columnEncryptedKey],
+      row[columnName],
+      Collection.typeFromString(row[columnType]),
+      int.parse(row[columnCreationTime]),
+    );
+  }
 }

+ 96 - 0
lib/models/shared_collection.dart

@@ -0,0 +1,96 @@
+import 'dart:convert';
+
+import 'package:photos/models/collection.dart';
+
+class SharedCollection {
+  final int id;
+  final int ownerID;
+  final String encryptedKey;
+  final String name;
+  final CollectionType type;
+  final int creationTime;
+
+  SharedCollection(
+    this.id,
+    this.ownerID,
+    this.encryptedKey,
+    this.name,
+    this.type,
+    this.creationTime,
+  );
+
+  SharedCollection copyWith({
+    int id,
+    int ownerID,
+    String encryptedKey,
+    String name,
+    CollectionType type,
+    int creationTime,
+  }) {
+    return SharedCollection(
+      id ?? this.id,
+      ownerID ?? this.ownerID,
+      encryptedKey ?? this.encryptedKey,
+      name ?? this.name,
+      type ?? this.type,
+      creationTime ?? this.creationTime,
+    );
+  }
+
+  Map<String, dynamic> toMap() {
+    return {
+      'id': id,
+      'ownerID': ownerID,
+      'encryptedKey': encryptedKey,
+      'name': name,
+      'type': Collection.typeToString(type),
+      'creationTime': creationTime,
+    };
+  }
+
+  factory SharedCollection.fromMap(Map<String, dynamic> map) {
+    if (map == null) return null;
+
+    return SharedCollection(
+      map['id'],
+      map['ownerID'],
+      map['encryptedKey'],
+      map['name'],
+      Collection.typeFromString(map['type']),
+      map['creationTime'],
+    );
+  }
+
+  String toJson() => json.encode(toMap());
+
+  factory SharedCollection.fromJson(String source) =>
+      SharedCollection.fromMap(json.decode(source));
+
+  @override
+  String toString() {
+    return 'SharedCollection(id: $id, ownerID: $ownerID, encryptedKey: $encryptedKey, name: $name, type: $type, creationTime: $creationTime)';
+  }
+
+  @override
+  bool operator ==(Object o) {
+    if (identical(this, o)) return true;
+
+    return o is SharedCollection &&
+        o.id == id &&
+        o.ownerID == ownerID &&
+        o.encryptedKey == encryptedKey &&
+        o.name == name &&
+        o.type == type &&
+        o.creationTime == creationTime;
+  }
+
+  @override
+  int get hashCode {
+    return id.hashCode ^
+        ownerID.hashCode ^
+        encryptedKey.hashCode ^
+        name.hashCode ^
+        type.hashCode ^
+        creationTime.hashCode;
+  }
+}

+ 30 - 2
lib/services/collections_service.dart

@@ -1,5 +1,4 @@
 import 'dart:convert';
-import 'dart:io';
 import 'dart:typed_data';
 
 import 'package:dio/dio.dart';
@@ -8,6 +7,7 @@ import 'package:logging/logging.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/db/collections_db.dart';
 import 'package:photos/models/collection.dart';
+import 'package:photos/models/shared_collection.dart';
 import 'package:photos/utils/crypto_util.dart';
 
 class CollectionsService {
@@ -33,10 +33,16 @@ class CollectionsService {
     var collections =
         await getOwnedCollections(lastCollectionCreationTime ?? 0);
     await _db.insert(collections);
-    collections = await _db.getAll();
+    collections = await _db.getAllCollections();
     for (final collection in collections) {
       _cacheCollectionAttributes(collection);
     }
+
+    final lastSharedCollectionCreationTime =
+        await _db.getLastCollectionCreationTime();
+    var sharedCollections =
+        await getSharedCollections(lastSharedCollectionCreationTime ?? 0);
+    await _db.insertSharedCollections(sharedCollections);
   }
 
   Collection getCollectionForPath(String path) {
@@ -119,6 +125,28 @@ 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;
+    });
+  }
+
   Future<Collection> getOrCreateForPath(String path) async {
     if (_localCollections.containsKey(path)) {
       return _localCollections[path];