Disallow updating album with a newer version

This commit is contained in:
Ming Ming 2021-11-18 18:50:51 +08:00
parent 3527e96f7a
commit 50599f2ba5
6 changed files with 65 additions and 7 deletions

View file

@ -28,6 +28,13 @@ import 'package:tuple/tuple.dart';
/// Immutable object that represents an album
class Album with EquatableMixin {
/// Create a new album
///
/// If [lastUpdated] is null, the current time will be used.
///
/// [savedVersion] should be null when creating a new album, such that it'll
/// be filled with the current version number automatically. You should only
/// pass this argument when reading album from storage
Album({
DateTime? lastUpdated,
required this.name,
@ -36,7 +43,9 @@ class Album with EquatableMixin {
required this.sortProvider,
this.shares,
this.albumFile,
}) : lastUpdated = (lastUpdated ?? DateTime.now()).toUtc();
int? savedVersion,
}) : lastUpdated = (lastUpdated ?? DateTime.now()).toUtc(),
savedVersion = savedVersion ?? version;
static Album? fromJson(
JsonObj json, {
@ -79,6 +88,17 @@ class Album with EquatableMixin {
return null;
}
}
if (jsonVersion < 7) {
result = upgraderFactory?.buildV6()?.call(result);
if (result == null) {
_log.info("[fromJson] Version $jsonVersion not compatible");
return null;
}
}
if (jsonVersion > version) {
_log.warning(
"[fromJson] Reading album with newer version: $jsonVersion > $version");
}
return Album(
lastUpdated: result["lastUpdated"] == null
? null
@ -96,6 +116,7 @@ class Album with EquatableMixin {
albumFile: result["albumFile"] == null
? null
: File.fromJson(result["albumFile"].cast<String, dynamic>()),
savedVersion: result["version"],
);
}
@ -135,6 +156,7 @@ class Album with EquatableMixin {
sortProvider: sortProvider ?? this.sortProvider,
shares: shares == null ? this.shares : shares.obj,
albumFile: albumFile == null ? this.albumFile : albumFile.obj,
savedVersion: savedVersion,
);
}
@ -173,6 +195,7 @@ class Album with EquatableMixin {
sortProvider,
shares,
albumFile,
savedVersion,
];
final DateTime lastUpdated;
@ -188,6 +211,11 @@ class Album with EquatableMixin {
/// This field is typically only meaningful when returned by [AlbumRepo.get]
final File? albumFile;
/// The original version of this class when saved
///
/// This field only exists in runtime and are not persisted
final int savedVersion;
/// versioning of this class, use to upgrade old persisted album
static const version = 7;
}

View file

@ -89,3 +89,15 @@ class JobCanceledException implements Exception {
final dynamic message;
}
/// Trying to downgrade an Album
class AlbumDowngradeException implements Exception {
const AlbumDowngradeException([this.message]);
@override
toString() {
return "AlbumDowngradeException: $message";
}
final dynamic message;
}

View file

@ -21,6 +21,8 @@ String toUserString(dynamic exception) {
return L10n.global().errorDisconnected;
} else if (exception is InvalidBaseUrlException) {
return L10n.global().errorInvalidBaseUrl;
} else if (exception is AlbumDowngradeException) {
return L10n.global().errorAlbumDowngrade;
}
return exception.toString();
}

View file

@ -1099,5 +1099,9 @@
"errorServerError": "Server error. Please make sure the server is setup correctly",
"@errorServerError": {
"description": "HTTP 500"
},
"errorAlbumDowngrade": "Can't modify this album as it was created by a later version of this app. Please update the app and try again",
"@errorAlbumDowngrade": {
"description": "Album files are versioned. Overwriting a newer version is disallowed as it will lead to unexpected data loss"
}
}

View file

@ -48,7 +48,8 @@
"fixAllTooltip",
"missingShareDescription",
"extraShareDescription",
"defaultButtonLabel"
"defaultButtonLabel",
"errorAlbumDowngrade"
],
"de": [
@ -114,7 +115,8 @@
"fixAllTooltip",
"missingShareDescription",
"extraShareDescription",
"defaultButtonLabel"
"defaultButtonLabel",
"errorAlbumDowngrade"
],
"el": [
@ -235,11 +237,13 @@
"fixAllTooltip",
"missingShareDescription",
"extraShareDescription",
"defaultButtonLabel"
"defaultButtonLabel",
"errorAlbumDowngrade"
],
"es": [
"settingsMapProviderTitle"
"settingsMapProviderTitle",
"errorAlbumDowngrade"
],
"fr": [
@ -340,7 +344,8 @@
"fixAllTooltip",
"missingShareDescription",
"extraShareDescription",
"defaultButtonLabel"
"defaultButtonLabel",
"errorAlbumDowngrade"
],
"ru": [
@ -414,6 +419,7 @@
"fixAllTooltip",
"missingShareDescription",
"extraShareDescription",
"defaultButtonLabel"
"defaultButtonLabel",
"errorAlbumDowngrade"
]
}

View file

@ -5,11 +5,17 @@ import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/album/item.dart';
import 'package:nc_photos/entity/album/provider.dart';
import 'package:nc_photos/event/event.dart';
import 'package:nc_photos/exception.dart';
class UpdateAlbum {
UpdateAlbum(this.albumRepo);
Future<void> call(Account account, Album album) async {
if (album.savedVersion > Album.version) {
// the album is created by a newer version of this app
throw AlbumDowngradeException(
"Not allowed to downgrade album '${album.name}'");
}
final provider = album.provider;
if (provider is AlbumStaticProvider) {
await albumRepo.update(