mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-03-14 11:18:54 +01:00
Disallow updating album with a newer version
This commit is contained in:
parent
3527e96f7a
commit
50599f2ba5
6 changed files with 65 additions and 7 deletions
|
@ -28,6 +28,13 @@ import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
/// Immutable object that represents an album
|
/// Immutable object that represents an album
|
||||||
class Album with EquatableMixin {
|
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({
|
Album({
|
||||||
DateTime? lastUpdated,
|
DateTime? lastUpdated,
|
||||||
required this.name,
|
required this.name,
|
||||||
|
@ -36,7 +43,9 @@ class Album with EquatableMixin {
|
||||||
required this.sortProvider,
|
required this.sortProvider,
|
||||||
this.shares,
|
this.shares,
|
||||||
this.albumFile,
|
this.albumFile,
|
||||||
}) : lastUpdated = (lastUpdated ?? DateTime.now()).toUtc();
|
int? savedVersion,
|
||||||
|
}) : lastUpdated = (lastUpdated ?? DateTime.now()).toUtc(),
|
||||||
|
savedVersion = savedVersion ?? version;
|
||||||
|
|
||||||
static Album? fromJson(
|
static Album? fromJson(
|
||||||
JsonObj json, {
|
JsonObj json, {
|
||||||
|
@ -79,6 +88,17 @@ class Album with EquatableMixin {
|
||||||
return null;
|
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(
|
return Album(
|
||||||
lastUpdated: result["lastUpdated"] == null
|
lastUpdated: result["lastUpdated"] == null
|
||||||
? null
|
? null
|
||||||
|
@ -96,6 +116,7 @@ class Album with EquatableMixin {
|
||||||
albumFile: result["albumFile"] == null
|
albumFile: result["albumFile"] == null
|
||||||
? null
|
? null
|
||||||
: File.fromJson(result["albumFile"].cast<String, dynamic>()),
|
: File.fromJson(result["albumFile"].cast<String, dynamic>()),
|
||||||
|
savedVersion: result["version"],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +156,7 @@ class Album with EquatableMixin {
|
||||||
sortProvider: sortProvider ?? this.sortProvider,
|
sortProvider: sortProvider ?? this.sortProvider,
|
||||||
shares: shares == null ? this.shares : shares.obj,
|
shares: shares == null ? this.shares : shares.obj,
|
||||||
albumFile: albumFile == null ? this.albumFile : albumFile.obj,
|
albumFile: albumFile == null ? this.albumFile : albumFile.obj,
|
||||||
|
savedVersion: savedVersion,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,6 +195,7 @@ class Album with EquatableMixin {
|
||||||
sortProvider,
|
sortProvider,
|
||||||
shares,
|
shares,
|
||||||
albumFile,
|
albumFile,
|
||||||
|
savedVersion,
|
||||||
];
|
];
|
||||||
|
|
||||||
final DateTime lastUpdated;
|
final DateTime lastUpdated;
|
||||||
|
@ -188,6 +211,11 @@ class Album with EquatableMixin {
|
||||||
/// This field is typically only meaningful when returned by [AlbumRepo.get]
|
/// This field is typically only meaningful when returned by [AlbumRepo.get]
|
||||||
final File? albumFile;
|
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
|
/// versioning of this class, use to upgrade old persisted album
|
||||||
static const version = 7;
|
static const version = 7;
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,3 +89,15 @@ class JobCanceledException implements Exception {
|
||||||
|
|
||||||
final dynamic message;
|
final dynamic message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trying to downgrade an Album
|
||||||
|
class AlbumDowngradeException implements Exception {
|
||||||
|
const AlbumDowngradeException([this.message]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
toString() {
|
||||||
|
return "AlbumDowngradeException: $message";
|
||||||
|
}
|
||||||
|
|
||||||
|
final dynamic message;
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ String toUserString(dynamic exception) {
|
||||||
return L10n.global().errorDisconnected;
|
return L10n.global().errorDisconnected;
|
||||||
} else if (exception is InvalidBaseUrlException) {
|
} else if (exception is InvalidBaseUrlException) {
|
||||||
return L10n.global().errorInvalidBaseUrl;
|
return L10n.global().errorInvalidBaseUrl;
|
||||||
|
} else if (exception is AlbumDowngradeException) {
|
||||||
|
return L10n.global().errorAlbumDowngrade;
|
||||||
}
|
}
|
||||||
return exception.toString();
|
return exception.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1099,5 +1099,9 @@
|
||||||
"errorServerError": "Server error. Please make sure the server is setup correctly",
|
"errorServerError": "Server error. Please make sure the server is setup correctly",
|
||||||
"@errorServerError": {
|
"@errorServerError": {
|
||||||
"description": "HTTP 500"
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -48,7 +48,8 @@
|
||||||
"fixAllTooltip",
|
"fixAllTooltip",
|
||||||
"missingShareDescription",
|
"missingShareDescription",
|
||||||
"extraShareDescription",
|
"extraShareDescription",
|
||||||
"defaultButtonLabel"
|
"defaultButtonLabel",
|
||||||
|
"errorAlbumDowngrade"
|
||||||
],
|
],
|
||||||
|
|
||||||
"de": [
|
"de": [
|
||||||
|
@ -114,7 +115,8 @@
|
||||||
"fixAllTooltip",
|
"fixAllTooltip",
|
||||||
"missingShareDescription",
|
"missingShareDescription",
|
||||||
"extraShareDescription",
|
"extraShareDescription",
|
||||||
"defaultButtonLabel"
|
"defaultButtonLabel",
|
||||||
|
"errorAlbumDowngrade"
|
||||||
],
|
],
|
||||||
|
|
||||||
"el": [
|
"el": [
|
||||||
|
@ -235,11 +237,13 @@
|
||||||
"fixAllTooltip",
|
"fixAllTooltip",
|
||||||
"missingShareDescription",
|
"missingShareDescription",
|
||||||
"extraShareDescription",
|
"extraShareDescription",
|
||||||
"defaultButtonLabel"
|
"defaultButtonLabel",
|
||||||
|
"errorAlbumDowngrade"
|
||||||
],
|
],
|
||||||
|
|
||||||
"es": [
|
"es": [
|
||||||
"settingsMapProviderTitle"
|
"settingsMapProviderTitle",
|
||||||
|
"errorAlbumDowngrade"
|
||||||
],
|
],
|
||||||
|
|
||||||
"fr": [
|
"fr": [
|
||||||
|
@ -340,7 +344,8 @@
|
||||||
"fixAllTooltip",
|
"fixAllTooltip",
|
||||||
"missingShareDescription",
|
"missingShareDescription",
|
||||||
"extraShareDescription",
|
"extraShareDescription",
|
||||||
"defaultButtonLabel"
|
"defaultButtonLabel",
|
||||||
|
"errorAlbumDowngrade"
|
||||||
],
|
],
|
||||||
|
|
||||||
"ru": [
|
"ru": [
|
||||||
|
@ -414,6 +419,7 @@
|
||||||
"fixAllTooltip",
|
"fixAllTooltip",
|
||||||
"missingShareDescription",
|
"missingShareDescription",
|
||||||
"extraShareDescription",
|
"extraShareDescription",
|
||||||
"defaultButtonLabel"
|
"defaultButtonLabel",
|
||||||
|
"errorAlbumDowngrade"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -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/item.dart';
|
||||||
import 'package:nc_photos/entity/album/provider.dart';
|
import 'package:nc_photos/entity/album/provider.dart';
|
||||||
import 'package:nc_photos/event/event.dart';
|
import 'package:nc_photos/event/event.dart';
|
||||||
|
import 'package:nc_photos/exception.dart';
|
||||||
|
|
||||||
class UpdateAlbum {
|
class UpdateAlbum {
|
||||||
UpdateAlbum(this.albumRepo);
|
UpdateAlbum(this.albumRepo);
|
||||||
|
|
||||||
Future<void> call(Account account, Album album) async {
|
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;
|
final provider = album.provider;
|
||||||
if (provider is AlbumStaticProvider) {
|
if (provider is AlbumStaticProvider) {
|
||||||
await albumRepo.update(
|
await albumRepo.update(
|
||||||
|
|
Loading…
Reference in a new issue