mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-01-22 08:46:18 +01:00
Support server albums shared with you in Collections
This commit is contained in:
parent
c8b132d6d7
commit
66a128bf77
17 changed files with 315 additions and 108 deletions
|
@ -64,6 +64,9 @@ class Collection with EquatableMixin {
|
|||
/// See [CollectionContentProvider.isPendingSharedAlbum]
|
||||
bool get isPendingSharedAlbum => contentProvider.isPendingSharedAlbum;
|
||||
|
||||
/// See [CollectionContentProvider.isOwned]
|
||||
bool get isOwned => contentProvider.isOwned;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
name,
|
||||
|
@ -145,4 +148,7 @@ abstract class CollectionContentProvider with EquatableMixin {
|
|||
/// In some implementation, shared album does not immediately get added to the
|
||||
/// collections list
|
||||
bool get isPendingSharedAlbum;
|
||||
|
||||
/// Return if this collection is owned by you
|
||||
bool get isOwned;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:nc_photos/entity/album/provider.dart';
|
|||
import 'package:nc_photos/entity/collection.dart';
|
||||
import 'package:nc_photos/entity/collection/util.dart';
|
||||
import 'package:nc_photos/entity/collection_item/util.dart';
|
||||
import 'package:nc_photos/entity/file.dart';
|
||||
import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util;
|
||||
import 'package:to_string/to_string.dart';
|
||||
|
||||
|
@ -109,6 +110,9 @@ class CollectionAlbumProvider
|
|||
remote_storage_util.getRemotePendingSharedAlbumsDir(account)) ==
|
||||
true;
|
||||
|
||||
@override
|
||||
bool get isOwned => album.albumFile?.isOwned(account.userId) ?? true;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [account, album];
|
||||
|
||||
|
|
|
@ -56,6 +56,9 @@ class CollectionLocationGroupProvider
|
|||
@override
|
||||
bool get isPendingSharedAlbum => false;
|
||||
|
||||
@override
|
||||
bool get isOwned => true;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [account, location];
|
||||
|
||||
|
|
|
@ -64,6 +64,9 @@ class CollectionMemoryProvider
|
|||
@override
|
||||
bool get isPendingSharedAlbum => false;
|
||||
|
||||
@override
|
||||
bool get isOwned => true;
|
||||
|
||||
@override
|
||||
String toString() => _$toString();
|
||||
|
||||
|
|
|
@ -79,6 +79,9 @@ class CollectionNcAlbumProvider
|
|||
@override
|
||||
bool get isPendingSharedAlbum => false;
|
||||
|
||||
@override
|
||||
bool get isOwned => album.isOwned;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [account, album];
|
||||
|
||||
|
|
|
@ -51,6 +51,9 @@ class CollectionPersonProvider
|
|||
@override
|
||||
bool get isPendingSharedAlbum => false;
|
||||
|
||||
@override
|
||||
bool get isOwned => true;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [account, person];
|
||||
|
||||
|
|
|
@ -49,6 +49,9 @@ class CollectionTagProvider
|
|||
@override
|
||||
bool get isPendingSharedAlbum => false;
|
||||
|
||||
@override
|
||||
bool get isOwned => true;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [account, tags];
|
||||
|
||||
|
|
|
@ -68,25 +68,30 @@ class NcAlbum with EquatableMixin {
|
|||
}
|
||||
|
||||
extension NcAlbumExtension on NcAlbum {
|
||||
/// Return if this album is owned by you, or shared with you by other users
|
||||
bool get isOwned {
|
||||
// [albums/sharedalbums]/{strippedPath}
|
||||
final p = _partialStrippedPath;
|
||||
return p.startsWith("albums/");
|
||||
}
|
||||
|
||||
/// Return the path of this file with the DAV part stripped
|
||||
///
|
||||
/// WebDAV file path: remote.php/dav/photos/{userId}/albums/{strippedPath}.
|
||||
/// If this path points to the user's root album path, return "."
|
||||
String get strippedPath {
|
||||
if (!path.startsWith("${api.ApiPhotos.path}/")) {
|
||||
// [albums/sharedalbums]/{strippedPath}
|
||||
final p = _partialStrippedPath;
|
||||
var begin = 0;
|
||||
if (p.startsWith("albums")) {
|
||||
begin += 6;
|
||||
} else if (p.startsWith("sharedalbums")) {
|
||||
begin += 12;
|
||||
} else {
|
||||
throw ArgumentError("Unsupported path: $path");
|
||||
}
|
||||
var begin = "${api.ApiPhotos.path}/".length;
|
||||
begin = path.indexOf("/", begin);
|
||||
if (begin == -1) {
|
||||
throw ArgumentError("Unsupported path: $path");
|
||||
}
|
||||
// /albums/{strippedPath}
|
||||
if (path.slice(begin, begin + 7) != "/albums") {
|
||||
return path;
|
||||
}
|
||||
begin += 8;
|
||||
final stripped = path.slice(begin);
|
||||
// /{strippedPath}
|
||||
final stripped = p.slice(begin + 1);
|
||||
if (stripped.isEmpty) {
|
||||
return ".";
|
||||
} else {
|
||||
|
@ -109,6 +114,19 @@ extension NcAlbumExtension on NcAlbum {
|
|||
}
|
||||
|
||||
int get identityHashCode => path.hashCode;
|
||||
|
||||
/// Return a new path without the part before albums/sharedalbums
|
||||
String get _partialStrippedPath {
|
||||
if (!path.startsWith("${api.ApiPhotos.path}/")) {
|
||||
throw ArgumentError("Unsupported path: $path");
|
||||
}
|
||||
var begin = "${api.ApiPhotos.path}/".length;
|
||||
begin = path.indexOf("/", begin);
|
||||
if (begin == -1) {
|
||||
throw ArgumentError("Unsupported path: $path");
|
||||
}
|
||||
return path.slice(begin + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@toString
|
||||
|
|
|
@ -23,29 +23,11 @@ class NcAlbumRemoteDataSource implements NcAlbumDataSource {
|
|||
@override
|
||||
Future<List<NcAlbum>> getAlbums(Account account) async {
|
||||
_log.info("[getAlbums] account: ${account.userId}");
|
||||
final response = await ApiUtil.fromAccount(account)
|
||||
.photos(account.userId.toString())
|
||||
.albums()
|
||||
.propfind(
|
||||
lastPhoto: 1,
|
||||
nbItems: 1,
|
||||
location: 1,
|
||||
dateRange: 1,
|
||||
collaborators: 1,
|
||||
);
|
||||
if (!response.isGood) {
|
||||
_log.severe("[getAlbums] Failed requesting server: $response");
|
||||
throw ApiException(
|
||||
response: response,
|
||||
message: "Server responed with an error: HTTP ${response.statusCode}",
|
||||
);
|
||||
}
|
||||
|
||||
final apiNcAlbums = await api.NcAlbumParser().parse(response.body);
|
||||
return apiNcAlbums
|
||||
.map(ApiNcAlbumConverter.fromApi)
|
||||
.where((a) => a.strippedPath != ".")
|
||||
.toList();
|
||||
final results = await Future.wait([
|
||||
_getAlbums(account),
|
||||
_getSharedAlbums(account),
|
||||
]);
|
||||
return results.flattened.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -114,6 +96,58 @@ class NcAlbumRemoteDataSource implements NcAlbumDataSource {
|
|||
.map(ApiNcAlbumItemConverter.fromApi)
|
||||
.toList();
|
||||
}
|
||||
|
||||
Future<List<NcAlbum>> _getAlbums(Account account) async {
|
||||
final response = await ApiUtil.fromAccount(account)
|
||||
.photos(account.userId.toString())
|
||||
.albums()
|
||||
.propfind(
|
||||
lastPhoto: 1,
|
||||
nbItems: 1,
|
||||
location: 1,
|
||||
dateRange: 1,
|
||||
collaborators: 1,
|
||||
);
|
||||
if (!response.isGood) {
|
||||
_log.severe("[_getAlbums] Failed requesting server: $response");
|
||||
throw ApiException(
|
||||
response: response,
|
||||
message: "Server responed with an error: HTTP ${response.statusCode}",
|
||||
);
|
||||
}
|
||||
|
||||
final apiNcAlbums = await api.NcAlbumParser().parse(response.body);
|
||||
return apiNcAlbums
|
||||
.map(ApiNcAlbumConverter.fromApi)
|
||||
.where((a) => a.strippedPath != ".")
|
||||
.toList();
|
||||
}
|
||||
|
||||
Future<List<NcAlbum>> _getSharedAlbums(Account account) async {
|
||||
final response = await ApiUtil.fromAccount(account)
|
||||
.photos(account.userId.toString())
|
||||
.sharedalbums()
|
||||
.propfind(
|
||||
lastPhoto: 1,
|
||||
nbItems: 1,
|
||||
location: 1,
|
||||
dateRange: 1,
|
||||
collaborators: 1,
|
||||
);
|
||||
if (!response.isGood) {
|
||||
_log.severe("[_getSharedAlbums] Failed requesting server: $response");
|
||||
throw ApiException(
|
||||
response: response,
|
||||
message: "Server responed with an error: HTTP ${response.statusCode}",
|
||||
);
|
||||
}
|
||||
|
||||
final apiNcAlbums = await api.NcAlbumParser().parse(response.body);
|
||||
return apiNcAlbums
|
||||
.map(ApiNcAlbumConverter.fromApi)
|
||||
.where((a) => a.strippedPath != ".")
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
@npLog
|
||||
|
@ -175,8 +209,8 @@ class NcAlbumSqliteDbDataSource implements NcAlbumCacheDataSource {
|
|||
return dbItems
|
||||
.map((i) {
|
||||
try {
|
||||
return SqliteNcAlbumItemConverter.fromSql(
|
||||
account.userId.toString(), album.strippedPath, i);
|
||||
return SqliteNcAlbumItemConverter.fromSql(account.userId.toString(),
|
||||
album.strippedPath, album.isOwned, i);
|
||||
} catch (e, stackTrace) {
|
||||
_log.severe(
|
||||
"[getItems] Failed while converting DB entry", e, stackTrace);
|
||||
|
@ -239,7 +273,7 @@ class NcAlbumSqliteDbDataSource implements NcAlbumCacheDataSource {
|
|||
final diff = getDiffWith<NcAlbumItem>(
|
||||
existingItems
|
||||
.map((e) => SqliteNcAlbumItemConverter.fromSql(
|
||||
account.userId.raw, album.strippedPath, e))
|
||||
account.userId.raw, album.strippedPath, album.isOwned, e))
|
||||
.sorted(NcAlbumItemExtension.identityComparator),
|
||||
remote.sorted(NcAlbumItemExtension.identityComparator),
|
||||
NcAlbumItemExtension.identityComparator,
|
||||
|
|
|
@ -41,19 +41,17 @@ extension NcAlbumItemExtension on NcAlbumItem {
|
|||
/// WebDAV file path: remote.php/dav/photos/{userId}/albums/{album}/{strippedPath}.
|
||||
/// If this path points to the user's root album path, return "."
|
||||
String get strippedPath {
|
||||
if (!path.startsWith("${api.ApiPhotos.path}/")) {
|
||||
// [albums/sharedalbums]/{album}/{strippedPath}
|
||||
final p = _partialStrippedPath;
|
||||
var begin = 0;
|
||||
if (p.startsWith("albums")) {
|
||||
begin += 6;
|
||||
} else if (p.startsWith("sharedalbums")) {
|
||||
begin += 12;
|
||||
} else {
|
||||
throw ArgumentError("Unsupported path: $path");
|
||||
}
|
||||
var begin = "${api.ApiPhotos.path}/".length;
|
||||
begin = path.indexOf("/", begin);
|
||||
if (begin == -1) {
|
||||
throw ArgumentError("Unsupported path: $path");
|
||||
}
|
||||
// /albums/{album}/{strippedPath}
|
||||
if (path.slice(begin, begin + 7) != "/albums") {
|
||||
throw ArgumentError("Unsupported path: $path");
|
||||
}
|
||||
begin += 8;
|
||||
begin += 1;
|
||||
// {album}/{strippedPath}
|
||||
begin = path.indexOf("/", begin);
|
||||
if (begin == -1) {
|
||||
|
@ -89,4 +87,17 @@ extension NcAlbumItemExtension on NcAlbumItem {
|
|||
metadata: metadata,
|
||||
);
|
||||
}
|
||||
|
||||
/// Return a new path without the part before albums/sharedalbums
|
||||
String get _partialStrippedPath {
|
||||
if (!path.startsWith("${api.ApiPhotos.path}/")) {
|
||||
throw ArgumentError("Unsupported path: $path");
|
||||
}
|
||||
var begin = "${api.ApiPhotos.path}/".length;
|
||||
begin = path.indexOf("/", begin);
|
||||
if (begin == -1) {
|
||||
throw ArgumentError("Unsupported path: $path");
|
||||
}
|
||||
return path.slice(begin + 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ class SqliteDb extends _$SqliteDb {
|
|||
}) : super(executor ?? platform.openSqliteConnection());
|
||||
|
||||
@override
|
||||
get schemaVersion => 6;
|
||||
get schemaVersion => 7;
|
||||
|
||||
@override
|
||||
get migration => MigrationStrategy(
|
||||
|
@ -111,6 +111,15 @@ class SqliteDb extends _$SqliteDb {
|
|||
await m.createTable(recognizeFaces);
|
||||
await m.createTable(recognizeFaceItems);
|
||||
}
|
||||
if (from < 7) {
|
||||
await m.alterTable(TableMigration(
|
||||
ncAlbums,
|
||||
newColumns: [ncAlbums.isOwned],
|
||||
columnTransformer: {
|
||||
ncAlbums.isOwned: const Constant(true),
|
||||
},
|
||||
));
|
||||
}
|
||||
});
|
||||
} catch (e, stackTrace) {
|
||||
_log.shout("[onUpgrade] Failed upgrading sqlite db", e, stackTrace);
|
||||
|
|
|
@ -4271,6 +4271,18 @@ class $NcAlbumsTable extends NcAlbums with TableInfo<$NcAlbumsTable, NcAlbum> {
|
|||
late final GeneratedColumn<String> collaborators = GeneratedColumn<String>(
|
||||
'collaborators', aliasedName, false,
|
||||
type: DriftSqlType.string, requiredDuringInsert: true);
|
||||
static const VerificationMeta _isOwnedMeta =
|
||||
const VerificationMeta('isOwned');
|
||||
@override
|
||||
late final GeneratedColumn<bool> isOwned =
|
||||
GeneratedColumn<bool>('is_owned', aliasedName, false,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: true,
|
||||
defaultConstraints: GeneratedColumn.constraintsDependsOnDialect({
|
||||
SqlDialect.sqlite: 'CHECK ("is_owned" IN (0, 1))',
|
||||
SqlDialect.mysql: '',
|
||||
SqlDialect.postgres: '',
|
||||
}));
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [
|
||||
rowId,
|
||||
|
@ -4281,7 +4293,8 @@ class $NcAlbumsTable extends NcAlbums with TableInfo<$NcAlbumsTable, NcAlbum> {
|
|||
location,
|
||||
dateStart,
|
||||
dateEnd,
|
||||
collaborators
|
||||
collaborators,
|
||||
isOwned
|
||||
];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'nc_albums';
|
||||
|
@ -4334,6 +4347,12 @@ class $NcAlbumsTable extends NcAlbums with TableInfo<$NcAlbumsTable, NcAlbum> {
|
|||
} else if (isInserting) {
|
||||
context.missing(_collaboratorsMeta);
|
||||
}
|
||||
if (data.containsKey('is_owned')) {
|
||||
context.handle(_isOwnedMeta,
|
||||
isOwned.isAcceptableOrUnknown(data['is_owned']!, _isOwnedMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_isOwnedMeta);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
|
@ -4367,6 +4386,8 @@ class $NcAlbumsTable extends NcAlbums with TableInfo<$NcAlbumsTable, NcAlbum> {
|
|||
.read(DriftSqlType.dateTime, data['${effectivePrefix}date_end'])),
|
||||
collaborators: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.string, data['${effectivePrefix}collaborators'])!,
|
||||
isOwned: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.bool, data['${effectivePrefix}is_owned'])!,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4395,6 +4416,7 @@ class NcAlbum extends DataClass implements Insertable<NcAlbum> {
|
|||
final DateTime? dateStart;
|
||||
final DateTime? dateEnd;
|
||||
final String collaborators;
|
||||
final bool isOwned;
|
||||
const NcAlbum(
|
||||
{required this.rowId,
|
||||
required this.account,
|
||||
|
@ -4404,7 +4426,8 @@ class NcAlbum extends DataClass implements Insertable<NcAlbum> {
|
|||
this.location,
|
||||
this.dateStart,
|
||||
this.dateEnd,
|
||||
required this.collaborators});
|
||||
required this.collaborators,
|
||||
required this.isOwned});
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
|
@ -4427,6 +4450,7 @@ class NcAlbum extends DataClass implements Insertable<NcAlbum> {
|
|||
map['date_end'] = Variable<DateTime>(converter.toSql(dateEnd));
|
||||
}
|
||||
map['collaborators'] = Variable<String>(collaborators);
|
||||
map['is_owned'] = Variable<bool>(isOwned);
|
||||
return map;
|
||||
}
|
||||
|
||||
|
@ -4449,6 +4473,7 @@ class NcAlbum extends DataClass implements Insertable<NcAlbum> {
|
|||
? const Value.absent()
|
||||
: Value(dateEnd),
|
||||
collaborators: Value(collaborators),
|
||||
isOwned: Value(isOwned),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4465,6 +4490,7 @@ class NcAlbum extends DataClass implements Insertable<NcAlbum> {
|
|||
dateStart: serializer.fromJson<DateTime?>(json['dateStart']),
|
||||
dateEnd: serializer.fromJson<DateTime?>(json['dateEnd']),
|
||||
collaborators: serializer.fromJson<String>(json['collaborators']),
|
||||
isOwned: serializer.fromJson<bool>(json['isOwned']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
|
@ -4480,6 +4506,7 @@ class NcAlbum extends DataClass implements Insertable<NcAlbum> {
|
|||
'dateStart': serializer.toJson<DateTime?>(dateStart),
|
||||
'dateEnd': serializer.toJson<DateTime?>(dateEnd),
|
||||
'collaborators': serializer.toJson<String>(collaborators),
|
||||
'isOwned': serializer.toJson<bool>(isOwned),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -4492,7 +4519,8 @@ class NcAlbum extends DataClass implements Insertable<NcAlbum> {
|
|||
Value<String?> location = const Value.absent(),
|
||||
Value<DateTime?> dateStart = const Value.absent(),
|
||||
Value<DateTime?> dateEnd = const Value.absent(),
|
||||
String? collaborators}) =>
|
||||
String? collaborators,
|
||||
bool? isOwned}) =>
|
||||
NcAlbum(
|
||||
rowId: rowId ?? this.rowId,
|
||||
account: account ?? this.account,
|
||||
|
@ -4503,6 +4531,7 @@ class NcAlbum extends DataClass implements Insertable<NcAlbum> {
|
|||
dateStart: dateStart.present ? dateStart.value : this.dateStart,
|
||||
dateEnd: dateEnd.present ? dateEnd.value : this.dateEnd,
|
||||
collaborators: collaborators ?? this.collaborators,
|
||||
isOwned: isOwned ?? this.isOwned,
|
||||
);
|
||||
@override
|
||||
String toString() {
|
||||
|
@ -4515,14 +4544,15 @@ class NcAlbum extends DataClass implements Insertable<NcAlbum> {
|
|||
..write('location: $location, ')
|
||||
..write('dateStart: $dateStart, ')
|
||||
..write('dateEnd: $dateEnd, ')
|
||||
..write('collaborators: $collaborators')
|
||||
..write('collaborators: $collaborators, ')
|
||||
..write('isOwned: $isOwned')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(rowId, account, relativePath, lastPhoto,
|
||||
nbItems, location, dateStart, dateEnd, collaborators);
|
||||
nbItems, location, dateStart, dateEnd, collaborators, isOwned);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
|
@ -4535,7 +4565,8 @@ class NcAlbum extends DataClass implements Insertable<NcAlbum> {
|
|||
other.location == this.location &&
|
||||
other.dateStart == this.dateStart &&
|
||||
other.dateEnd == this.dateEnd &&
|
||||
other.collaborators == this.collaborators);
|
||||
other.collaborators == this.collaborators &&
|
||||
other.isOwned == this.isOwned);
|
||||
}
|
||||
|
||||
class NcAlbumsCompanion extends UpdateCompanion<NcAlbum> {
|
||||
|
@ -4548,6 +4579,7 @@ class NcAlbumsCompanion extends UpdateCompanion<NcAlbum> {
|
|||
final Value<DateTime?> dateStart;
|
||||
final Value<DateTime?> dateEnd;
|
||||
final Value<String> collaborators;
|
||||
final Value<bool> isOwned;
|
||||
const NcAlbumsCompanion({
|
||||
this.rowId = const Value.absent(),
|
||||
this.account = const Value.absent(),
|
||||
|
@ -4558,6 +4590,7 @@ class NcAlbumsCompanion extends UpdateCompanion<NcAlbum> {
|
|||
this.dateStart = const Value.absent(),
|
||||
this.dateEnd = const Value.absent(),
|
||||
this.collaborators = const Value.absent(),
|
||||
this.isOwned = const Value.absent(),
|
||||
});
|
||||
NcAlbumsCompanion.insert({
|
||||
this.rowId = const Value.absent(),
|
||||
|
@ -4569,10 +4602,12 @@ class NcAlbumsCompanion extends UpdateCompanion<NcAlbum> {
|
|||
this.dateStart = const Value.absent(),
|
||||
this.dateEnd = const Value.absent(),
|
||||
required String collaborators,
|
||||
required bool isOwned,
|
||||
}) : account = Value(account),
|
||||
relativePath = Value(relativePath),
|
||||
nbItems = Value(nbItems),
|
||||
collaborators = Value(collaborators);
|
||||
collaborators = Value(collaborators),
|
||||
isOwned = Value(isOwned);
|
||||
static Insertable<NcAlbum> custom({
|
||||
Expression<int>? rowId,
|
||||
Expression<int>? account,
|
||||
|
@ -4583,6 +4618,7 @@ class NcAlbumsCompanion extends UpdateCompanion<NcAlbum> {
|
|||
Expression<DateTime>? dateStart,
|
||||
Expression<DateTime>? dateEnd,
|
||||
Expression<String>? collaborators,
|
||||
Expression<bool>? isOwned,
|
||||
}) {
|
||||
return RawValuesInsertable({
|
||||
if (rowId != null) 'row_id': rowId,
|
||||
|
@ -4594,6 +4630,7 @@ class NcAlbumsCompanion extends UpdateCompanion<NcAlbum> {
|
|||
if (dateStart != null) 'date_start': dateStart,
|
||||
if (dateEnd != null) 'date_end': dateEnd,
|
||||
if (collaborators != null) 'collaborators': collaborators,
|
||||
if (isOwned != null) 'is_owned': isOwned,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -4606,7 +4643,8 @@ class NcAlbumsCompanion extends UpdateCompanion<NcAlbum> {
|
|||
Value<String?>? location,
|
||||
Value<DateTime?>? dateStart,
|
||||
Value<DateTime?>? dateEnd,
|
||||
Value<String>? collaborators}) {
|
||||
Value<String>? collaborators,
|
||||
Value<bool>? isOwned}) {
|
||||
return NcAlbumsCompanion(
|
||||
rowId: rowId ?? this.rowId,
|
||||
account: account ?? this.account,
|
||||
|
@ -4617,6 +4655,7 @@ class NcAlbumsCompanion extends UpdateCompanion<NcAlbum> {
|
|||
dateStart: dateStart ?? this.dateStart,
|
||||
dateEnd: dateEnd ?? this.dateEnd,
|
||||
collaborators: collaborators ?? this.collaborators,
|
||||
isOwned: isOwned ?? this.isOwned,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4652,6 +4691,9 @@ class NcAlbumsCompanion extends UpdateCompanion<NcAlbum> {
|
|||
if (collaborators.present) {
|
||||
map['collaborators'] = Variable<String>(collaborators.value);
|
||||
}
|
||||
if (isOwned.present) {
|
||||
map['is_owned'] = Variable<bool>(isOwned.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
@ -4666,7 +4708,8 @@ class NcAlbumsCompanion extends UpdateCompanion<NcAlbum> {
|
|||
..write('location: $location, ')
|
||||
..write('dateStart: $dateStart, ')
|
||||
..write('dateEnd: $dateEnd, ')
|
||||
..write('collaborators: $collaborators')
|
||||
..write('collaborators: $collaborators, ')
|
||||
..write('isOwned: $isOwned')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
|
|
@ -142,6 +142,7 @@ class NcAlbums extends Table {
|
|||
DateTimeColumn get dateEnd =>
|
||||
dateTime().map(const SqliteDateTimeConverter()).nullable()();
|
||||
TextColumn get collaborators => text()();
|
||||
BoolColumn get isOwned => boolean()();
|
||||
|
||||
@override
|
||||
List<Set<Column>>? get uniqueKeys => [
|
||||
|
|
|
@ -282,7 +282,8 @@ class SqliteNcAlbumConverter {
|
|||
final json = ncAlbum.collaborators
|
||||
.run((obj) => (jsonDecode(obj) as List).cast<Map>());
|
||||
return NcAlbum(
|
||||
path: "${api.ApiPhotos.path}/$userId/albums/${ncAlbum.relativePath}",
|
||||
path:
|
||||
"${api.ApiPhotos.path}/$userId/${ncAlbum.isOwned ? "albums" : "sharedalbums"}/${ncAlbum.relativePath}",
|
||||
lastPhoto: ncAlbum.lastPhoto,
|
||||
nbItems: ncAlbum.nbItems,
|
||||
location: ncAlbum.location,
|
||||
|
@ -306,15 +307,16 @@ class SqliteNcAlbumConverter {
|
|||
dateEnd: Value(ncAlbum.dateEnd),
|
||||
collaborators: Value(
|
||||
jsonEncode(ncAlbum.collaborators.map((c) => c.toJson()).toList())),
|
||||
isOwned: Value(ncAlbum.isOwned),
|
||||
);
|
||||
}
|
||||
|
||||
class SqliteNcAlbumItemConverter {
|
||||
static NcAlbumItem fromSql(
|
||||
String userId, String albumRelativePath, sql.NcAlbumItem item) =>
|
||||
static NcAlbumItem fromSql(String userId, String albumRelativePath,
|
||||
bool isAlbumOwned, sql.NcAlbumItem item) =>
|
||||
NcAlbumItem(
|
||||
path:
|
||||
"${api.ApiPhotos.path}/$userId/albums/$albumRelativePath/${item.relativePath}",
|
||||
"${api.ApiPhotos.path}/$userId/${isAlbumOwned ? "albums" : "sharedalbums"}/$albumRelativePath/${item.relativePath}",
|
||||
fileId: item.fileId,
|
||||
contentLength: item.contentLength,
|
||||
contentType: item.contentType,
|
||||
|
|
|
@ -9,7 +9,8 @@ enum _ItemType {
|
|||
|
||||
@npLog
|
||||
class _Item implements SelectableItemMetadata {
|
||||
_Item(this.collection) : isShared = collection.shares.isNotEmpty {
|
||||
_Item(this.collection)
|
||||
: isShared = collection.shares.isNotEmpty || !collection.isOwned {
|
||||
if (collection.count != null) {
|
||||
_subtitle = L10n.global().albumSize(collection.count!);
|
||||
}
|
||||
|
|
|
@ -70,6 +70,13 @@ extension _$ApiPhotosAlbumsNpLog on ApiPhotosAlbums {
|
|||
static final log = Logger("src.api.ApiPhotosAlbums");
|
||||
}
|
||||
|
||||
extension _$ApiPhotosSharedAlbumsNpLog on ApiPhotosSharedAlbums {
|
||||
// ignore: unused_element
|
||||
Logger get _log => log;
|
||||
|
||||
static final log = Logger("src.api.ApiPhotosSharedAlbums");
|
||||
}
|
||||
|
||||
extension _$ApiPhotosAlbumNpLog on ApiPhotosAlbum {
|
||||
// ignore: unused_element
|
||||
Logger get _log => log;
|
||||
|
|
|
@ -4,6 +4,7 @@ class ApiPhotos {
|
|||
const ApiPhotos(this.api, this.userId);
|
||||
|
||||
ApiPhotosAlbums albums() => ApiPhotosAlbums(this);
|
||||
ApiPhotosSharedAlbums sharedalbums() => ApiPhotosSharedAlbums(this);
|
||||
ApiPhotosAlbum album(String name) => ApiPhotosAlbum(this, name);
|
||||
|
||||
static String get path => "remote.php/dav/photos";
|
||||
|
@ -23,51 +24,15 @@ class ApiPhotosAlbums {
|
|||
location,
|
||||
dateRange,
|
||||
collaborators,
|
||||
}) async {
|
||||
final endpoint = "${ApiPhotos.path}/${photos.userId}/albums";
|
||||
}) {
|
||||
try {
|
||||
if (lastPhoto == null &&
|
||||
nbItems == null &&
|
||||
location == null &&
|
||||
dateRange == null &&
|
||||
collaborators == null) {
|
||||
// no body
|
||||
return await api.request("PROPFIND", endpoint);
|
||||
}
|
||||
|
||||
final namespaces = <String, String>{
|
||||
"DAV:": "d",
|
||||
"http://nextcloud.org/ns": "nc",
|
||||
};
|
||||
final builder = XmlBuilder();
|
||||
builder
|
||||
..processing("xml", "version=\"1.0\"")
|
||||
..element("d:propfind", namespaces: namespaces, nest: () {
|
||||
builder.element("d:prop", nest: () {
|
||||
if (lastPhoto != null) {
|
||||
builder.element("nc:last-photo");
|
||||
}
|
||||
if (nbItems != null) {
|
||||
builder.element("nc:nbItems");
|
||||
}
|
||||
if (location != null) {
|
||||
builder.element("nc:location");
|
||||
}
|
||||
if (dateRange != null) {
|
||||
builder.element("nc:dateRange");
|
||||
}
|
||||
if (collaborators != null) {
|
||||
builder.element("nc:collaborators");
|
||||
}
|
||||
});
|
||||
});
|
||||
return await api.request(
|
||||
"PROPFIND",
|
||||
endpoint,
|
||||
header: {
|
||||
"Content-Type": "application/xml",
|
||||
},
|
||||
body: builder.buildDocument().toXmlString(),
|
||||
return _ApiPhotosAlbumsAlike(photos).propfind(
|
||||
endpoint: "${ApiPhotos.path}/${photos.userId}/albums",
|
||||
lastPhoto: lastPhoto,
|
||||
nbItems: nbItems,
|
||||
location: location,
|
||||
dateRange: dateRange,
|
||||
collaborators: collaborators,
|
||||
);
|
||||
} catch (e) {
|
||||
_log.severe("[propfind] Failed while propfind", e);
|
||||
|
@ -75,6 +40,97 @@ class ApiPhotosAlbums {
|
|||
}
|
||||
}
|
||||
|
||||
final ApiPhotos photos;
|
||||
}
|
||||
|
||||
@npLog
|
||||
class ApiPhotosSharedAlbums {
|
||||
const ApiPhotosSharedAlbums(this.photos);
|
||||
|
||||
/// Retrieve all albums associated with a user
|
||||
Future<Response> propfind({
|
||||
lastPhoto,
|
||||
nbItems,
|
||||
location,
|
||||
dateRange,
|
||||
collaborators,
|
||||
}) {
|
||||
try {
|
||||
return _ApiPhotosAlbumsAlike(photos).propfind(
|
||||
endpoint: "${ApiPhotos.path}/${photos.userId}/sharedalbums",
|
||||
lastPhoto: lastPhoto,
|
||||
nbItems: nbItems,
|
||||
location: location,
|
||||
dateRange: dateRange,
|
||||
collaborators: collaborators,
|
||||
);
|
||||
} catch (e) {
|
||||
_log.severe("[propfind] Failed while propfind", e);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Api get api => photos.api;
|
||||
final ApiPhotos photos;
|
||||
}
|
||||
|
||||
class _ApiPhotosAlbumsAlike {
|
||||
const _ApiPhotosAlbumsAlike(this.photos);
|
||||
|
||||
/// Retrieve all albums associated with a user
|
||||
Future<Response> propfind({
|
||||
required String endpoint,
|
||||
lastPhoto,
|
||||
nbItems,
|
||||
location,
|
||||
dateRange,
|
||||
collaborators,
|
||||
}) async {
|
||||
if (lastPhoto == null &&
|
||||
nbItems == null &&
|
||||
location == null &&
|
||||
dateRange == null &&
|
||||
collaborators == null) {
|
||||
// no body
|
||||
return await api.request("PROPFIND", endpoint);
|
||||
}
|
||||
|
||||
final namespaces = <String, String>{
|
||||
"DAV:": "d",
|
||||
"http://nextcloud.org/ns": "nc",
|
||||
};
|
||||
final builder = XmlBuilder();
|
||||
builder
|
||||
..processing("xml", "version=\"1.0\"")
|
||||
..element("d:propfind", namespaces: namespaces, nest: () {
|
||||
builder.element("d:prop", nest: () {
|
||||
if (lastPhoto != null) {
|
||||
builder.element("nc:last-photo");
|
||||
}
|
||||
if (nbItems != null) {
|
||||
builder.element("nc:nbItems");
|
||||
}
|
||||
if (location != null) {
|
||||
builder.element("nc:location");
|
||||
}
|
||||
if (dateRange != null) {
|
||||
builder.element("nc:dateRange");
|
||||
}
|
||||
if (collaborators != null) {
|
||||
builder.element("nc:collaborators");
|
||||
}
|
||||
});
|
||||
});
|
||||
return await api.request(
|
||||
"PROPFIND",
|
||||
endpoint,
|
||||
header: {
|
||||
"Content-Type": "application/xml",
|
||||
},
|
||||
body: builder.buildDocument().toXmlString(),
|
||||
);
|
||||
}
|
||||
|
||||
Api get api => photos.api;
|
||||
final ApiPhotos photos;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue