mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-26 18:56:38 +00:00
feat(backups): Update the models
This commit is contained in:
parent
02cb4dbf8b
commit
d2d8add10d
|
@ -21,6 +21,7 @@ class HiveConfig {
|
|||
Hive.registerAdapter(UserTypeAdapter());
|
||||
Hive.registerAdapter(DnsProviderTypeAdapter());
|
||||
Hive.registerAdapter(ServerProviderTypeAdapter());
|
||||
Hive.registerAdapter(BackupsProviderTypeAdapter());
|
||||
|
||||
await Hive.openBox(BNames.appSettingsBox);
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ mutation ForceSnapshotsReload {
|
|||
}
|
||||
}
|
||||
|
||||
mutation StartBackup($serviceId: String = null) {
|
||||
mutation StartBackup($serviceId: String!) {
|
||||
backup {
|
||||
startBackup(serviceId: $serviceId) {
|
||||
...basicMutationReturnFields
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import 'dart:async';
|
||||
import 'disk_volumes.graphql.dart';
|
||||
import 'package:gql/ast.dart';
|
||||
import 'package:graphql/client.dart' as graphql;
|
||||
import 'package:selfprivacy/utils/scalars.dart';
|
||||
import 'schema.graphql.dart';
|
||||
import 'services.graphql.dart';
|
||||
|
||||
class Fragment$genericBackupConfigReturn {
|
||||
Fragment$genericBackupConfigReturn({
|
||||
|
@ -2738,31 +2738,27 @@ class _CopyWithStubImpl$Mutation$ForceSnapshotsReload$backup$forceSnapshotsReloa
|
|||
}
|
||||
|
||||
class Variables$Mutation$StartBackup {
|
||||
factory Variables$Mutation$StartBackup({String? serviceId}) =>
|
||||
factory Variables$Mutation$StartBackup({required String serviceId}) =>
|
||||
Variables$Mutation$StartBackup._({
|
||||
if (serviceId != null) r'serviceId': serviceId,
|
||||
r'serviceId': serviceId,
|
||||
});
|
||||
|
||||
Variables$Mutation$StartBackup._(this._$data);
|
||||
|
||||
factory Variables$Mutation$StartBackup.fromJson(Map<String, dynamic> data) {
|
||||
final result$data = <String, dynamic>{};
|
||||
if (data.containsKey('serviceId')) {
|
||||
final l$serviceId = data['serviceId'];
|
||||
result$data['serviceId'] = (l$serviceId as String?);
|
||||
}
|
||||
final l$serviceId = data['serviceId'];
|
||||
result$data['serviceId'] = (l$serviceId as String);
|
||||
return Variables$Mutation$StartBackup._(result$data);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$data;
|
||||
|
||||
String? get serviceId => (_$data['serviceId'] as String?);
|
||||
String get serviceId => (_$data['serviceId'] as String);
|
||||
Map<String, dynamic> toJson() {
|
||||
final result$data = <String, dynamic>{};
|
||||
if (_$data.containsKey('serviceId')) {
|
||||
final l$serviceId = serviceId;
|
||||
result$data['serviceId'] = l$serviceId;
|
||||
}
|
||||
final l$serviceId = serviceId;
|
||||
result$data['serviceId'] = l$serviceId;
|
||||
return result$data;
|
||||
}
|
||||
|
||||
|
@ -2782,10 +2778,6 @@ class Variables$Mutation$StartBackup {
|
|||
}
|
||||
final l$serviceId = serviceId;
|
||||
final lOther$serviceId = other.serviceId;
|
||||
if (_$data.containsKey('serviceId') !=
|
||||
other._$data.containsKey('serviceId')) {
|
||||
return false;
|
||||
}
|
||||
if (l$serviceId != lOther$serviceId) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2795,8 +2787,7 @@ class Variables$Mutation$StartBackup {
|
|||
@override
|
||||
int get hashCode {
|
||||
final l$serviceId = serviceId;
|
||||
return Object.hashAll(
|
||||
[_$data.containsKey('serviceId') ? l$serviceId : const {}]);
|
||||
return Object.hashAll([l$serviceId]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2828,7 +2819,8 @@ class _CopyWithImpl$Variables$Mutation$StartBackup<TRes>
|
|||
TRes call({Object? serviceId = _undefined}) =>
|
||||
_then(Variables$Mutation$StartBackup._({
|
||||
..._instance._$data,
|
||||
if (serviceId != _undefined) 'serviceId': (serviceId as String?),
|
||||
if (serviceId != _undefined && serviceId != null)
|
||||
'serviceId': (serviceId as String),
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -2982,9 +2974,9 @@ const documentNodeMutationStartBackup = DocumentNode(definitions: [
|
|||
variable: VariableNode(name: NameNode(value: 'serviceId')),
|
||||
type: NamedTypeNode(
|
||||
name: NameNode(value: 'String'),
|
||||
isNonNull: false,
|
||||
isNonNull: true,
|
||||
),
|
||||
defaultValue: DefaultValueNode(value: NullValueNode()),
|
||||
defaultValue: DefaultValueNode(value: null),
|
||||
directives: [],
|
||||
)
|
||||
],
|
||||
|
@ -3052,7 +3044,7 @@ class Options$Mutation$StartBackup
|
|||
extends graphql.MutationOptions<Mutation$StartBackup> {
|
||||
Options$Mutation$StartBackup({
|
||||
String? operationName,
|
||||
Variables$Mutation$StartBackup? variables,
|
||||
required Variables$Mutation$StartBackup variables,
|
||||
graphql.FetchPolicy? fetchPolicy,
|
||||
graphql.ErrorPolicy? errorPolicy,
|
||||
graphql.CacheRereadPolicy? cacheRereadPolicy,
|
||||
|
@ -3064,7 +3056,7 @@ class Options$Mutation$StartBackup
|
|||
graphql.OnError? onError,
|
||||
}) : onCompletedWithParsed = onCompleted,
|
||||
super(
|
||||
variables: variables?.toJson() ?? {},
|
||||
variables: variables.toJson(),
|
||||
operationName: operationName,
|
||||
fetchPolicy: fetchPolicy,
|
||||
errorPolicy: errorPolicy,
|
||||
|
@ -3098,7 +3090,7 @@ class WatchOptions$Mutation$StartBackup
|
|||
extends graphql.WatchQueryOptions<Mutation$StartBackup> {
|
||||
WatchOptions$Mutation$StartBackup({
|
||||
String? operationName,
|
||||
Variables$Mutation$StartBackup? variables,
|
||||
required Variables$Mutation$StartBackup variables,
|
||||
graphql.FetchPolicy? fetchPolicy,
|
||||
graphql.ErrorPolicy? errorPolicy,
|
||||
graphql.CacheRereadPolicy? cacheRereadPolicy,
|
||||
|
@ -3110,7 +3102,7 @@ class WatchOptions$Mutation$StartBackup
|
|||
bool carryForwardDataOnException = true,
|
||||
bool fetchResults = false,
|
||||
}) : super(
|
||||
variables: variables?.toJson() ?? {},
|
||||
variables: variables.toJson(),
|
||||
operationName: operationName,
|
||||
fetchPolicy: fetchPolicy,
|
||||
errorPolicy: errorPolicy,
|
||||
|
@ -3128,11 +3120,11 @@ class WatchOptions$Mutation$StartBackup
|
|||
|
||||
extension ClientExtension$Mutation$StartBackup on graphql.GraphQLClient {
|
||||
Future<graphql.QueryResult<Mutation$StartBackup>> mutate$StartBackup(
|
||||
[Options$Mutation$StartBackup? options]) async =>
|
||||
await this.mutate(options ?? Options$Mutation$StartBackup());
|
||||
Options$Mutation$StartBackup options) async =>
|
||||
await this.mutate(options);
|
||||
graphql.ObservableQuery<Mutation$StartBackup> watchMutation$StartBackup(
|
||||
[WatchOptions$Mutation$StartBackup? options]) =>
|
||||
this.watchMutation(options ?? WatchOptions$Mutation$StartBackup());
|
||||
WatchOptions$Mutation$StartBackup options) =>
|
||||
this.watchMutation(options);
|
||||
}
|
||||
|
||||
class Mutation$StartBackup$backup {
|
||||
|
|
|
@ -3,7 +3,6 @@ import 'package:gql/ast.dart';
|
|||
import 'package:graphql/client.dart' as graphql;
|
||||
import 'package:selfprivacy/utils/scalars.dart';
|
||||
import 'schema.graphql.dart';
|
||||
import 'services.graphql.dart';
|
||||
|
||||
class Fragment$basicMutationReturnFields {
|
||||
Fragment$basicMutationReturnFields({
|
||||
|
|
|
@ -19,6 +19,7 @@ type ApiDevice {
|
|||
|
||||
type ApiJob {
|
||||
uid: String!
|
||||
typeId: String!
|
||||
name: String!
|
||||
description: String!
|
||||
status: String!
|
||||
|
|
|
@ -23,6 +23,7 @@ query GetApiJobs {
|
|||
status
|
||||
statusText
|
||||
uid
|
||||
typeId
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import 'dart:async';
|
||||
import 'disk_volumes.graphql.dart';
|
||||
import 'package:gql/ast.dart';
|
||||
import 'package:graphql/client.dart' as graphql;
|
||||
import 'package:selfprivacy/utils/scalars.dart';
|
||||
import 'schema.graphql.dart';
|
||||
import 'services.graphql.dart';
|
||||
|
||||
class Fragment$basicMutationReturnFields {
|
||||
Fragment$basicMutationReturnFields({
|
||||
|
@ -2914,6 +2914,13 @@ const documentNodeQueryGetApiJobs = DocumentNode(definitions: [
|
|||
directives: [],
|
||||
selectionSet: null,
|
||||
),
|
||||
FieldNode(
|
||||
name: NameNode(value: 'typeId'),
|
||||
alias: null,
|
||||
arguments: [],
|
||||
directives: [],
|
||||
selectionSet: null,
|
||||
),
|
||||
FieldNode(
|
||||
name: NameNode(value: 'updatedAt'),
|
||||
alias: null,
|
||||
|
@ -3229,6 +3236,7 @@ class Query$GetApiJobs$jobs$getJobs {
|
|||
required this.status,
|
||||
this.statusText,
|
||||
required this.uid,
|
||||
required this.typeId,
|
||||
required this.updatedAt,
|
||||
this.$__typename = 'ApiJob',
|
||||
});
|
||||
|
@ -3244,6 +3252,7 @@ class Query$GetApiJobs$jobs$getJobs {
|
|||
final l$status = json['status'];
|
||||
final l$statusText = json['statusText'];
|
||||
final l$uid = json['uid'];
|
||||
final l$typeId = json['typeId'];
|
||||
final l$updatedAt = json['updatedAt'];
|
||||
final l$$__typename = json['__typename'];
|
||||
return Query$GetApiJobs$jobs$getJobs(
|
||||
|
@ -3257,6 +3266,7 @@ class Query$GetApiJobs$jobs$getJobs {
|
|||
status: (l$status as String),
|
||||
statusText: (l$statusText as String?),
|
||||
uid: (l$uid as String),
|
||||
typeId: (l$typeId as String),
|
||||
updatedAt: dateTimeFromJson(l$updatedAt),
|
||||
$__typename: (l$$__typename as String),
|
||||
);
|
||||
|
@ -3282,6 +3292,8 @@ class Query$GetApiJobs$jobs$getJobs {
|
|||
|
||||
final String uid;
|
||||
|
||||
final String typeId;
|
||||
|
||||
final DateTime updatedAt;
|
||||
|
||||
final String $__typename;
|
||||
|
@ -3309,6 +3321,8 @@ class Query$GetApiJobs$jobs$getJobs {
|
|||
_resultData['statusText'] = l$statusText;
|
||||
final l$uid = uid;
|
||||
_resultData['uid'] = l$uid;
|
||||
final l$typeId = typeId;
|
||||
_resultData['typeId'] = l$typeId;
|
||||
final l$updatedAt = updatedAt;
|
||||
_resultData['updatedAt'] = dateTimeToJson(l$updatedAt);
|
||||
final l$$__typename = $__typename;
|
||||
|
@ -3328,6 +3342,7 @@ class Query$GetApiJobs$jobs$getJobs {
|
|||
final l$status = status;
|
||||
final l$statusText = statusText;
|
||||
final l$uid = uid;
|
||||
final l$typeId = typeId;
|
||||
final l$updatedAt = updatedAt;
|
||||
final l$$__typename = $__typename;
|
||||
return Object.hashAll([
|
||||
|
@ -3341,6 +3356,7 @@ class Query$GetApiJobs$jobs$getJobs {
|
|||
l$status,
|
||||
l$statusText,
|
||||
l$uid,
|
||||
l$typeId,
|
||||
l$updatedAt,
|
||||
l$$__typename,
|
||||
]);
|
||||
|
@ -3405,6 +3421,11 @@ class Query$GetApiJobs$jobs$getJobs {
|
|||
if (l$uid != lOther$uid) {
|
||||
return false;
|
||||
}
|
||||
final l$typeId = typeId;
|
||||
final lOther$typeId = other.typeId;
|
||||
if (l$typeId != lOther$typeId) {
|
||||
return false;
|
||||
}
|
||||
final l$updatedAt = updatedAt;
|
||||
final lOther$updatedAt = other.updatedAt;
|
||||
if (l$updatedAt != lOther$updatedAt) {
|
||||
|
@ -3448,6 +3469,7 @@ abstract class CopyWith$Query$GetApiJobs$jobs$getJobs<TRes> {
|
|||
String? status,
|
||||
String? statusText,
|
||||
String? uid,
|
||||
String? typeId,
|
||||
DateTime? updatedAt,
|
||||
String? $__typename,
|
||||
});
|
||||
|
@ -3477,6 +3499,7 @@ class _CopyWithImpl$Query$GetApiJobs$jobs$getJobs<TRes>
|
|||
Object? status = _undefined,
|
||||
Object? statusText = _undefined,
|
||||
Object? uid = _undefined,
|
||||
Object? typeId = _undefined,
|
||||
Object? updatedAt = _undefined,
|
||||
Object? $__typename = _undefined,
|
||||
}) =>
|
||||
|
@ -3504,6 +3527,9 @@ class _CopyWithImpl$Query$GetApiJobs$jobs$getJobs<TRes>
|
|||
? _instance.statusText
|
||||
: (statusText as String?),
|
||||
uid: uid == _undefined || uid == null ? _instance.uid : (uid as String),
|
||||
typeId: typeId == _undefined || typeId == null
|
||||
? _instance.typeId
|
||||
: (typeId as String),
|
||||
updatedAt: updatedAt == _undefined || updatedAt == null
|
||||
? _instance.updatedAt
|
||||
: (updatedAt as DateTime),
|
||||
|
@ -3530,6 +3556,7 @@ class _CopyWithStubImpl$Query$GetApiJobs$jobs$getJobs<TRes>
|
|||
String? status,
|
||||
String? statusText,
|
||||
String? uid,
|
||||
String? typeId,
|
||||
DateTime? updatedAt,
|
||||
String? $__typename,
|
||||
}) =>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'dart:async';
|
||||
import 'disk_volumes.graphql.dart';
|
||||
import 'package:gql/ast.dart';
|
||||
import 'package:graphql/client.dart' as graphql;
|
||||
import 'schema.graphql.dart';
|
||||
import 'services.graphql.dart';
|
||||
|
||||
class Fragment$basicMutationReturnFields {
|
||||
Fragment$basicMutationReturnFields({
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:async';
|
||||
import 'disk_volumes.graphql.dart';
|
||||
import 'package:gql/ast.dart';
|
||||
import 'package:graphql/client.dart' as graphql;
|
||||
import 'package:selfprivacy/utils/scalars.dart';
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'dart:async';
|
||||
import 'disk_volumes.graphql.dart';
|
||||
import 'package:gql/ast.dart';
|
||||
import 'package:graphql/client.dart' as graphql;
|
||||
import 'schema.graphql.dart';
|
||||
import 'services.graphql.dart';
|
||||
|
||||
class Fragment$basicMutationReturnFields {
|
||||
Fragment$basicMutationReturnFields({
|
||||
|
|
207
lib/logic/api_maps/graphql_maps/server_api/backups_api.dart
Normal file
207
lib/logic/api_maps/graphql_maps/server_api/backups_api.dart
Normal file
|
@ -0,0 +1,207 @@
|
|||
part of 'server_api.dart';
|
||||
|
||||
mixin BackupsApi on GraphQLApiMap {
|
||||
Future<List<Backup>> getBackups() async {
|
||||
List<Backup> backups;
|
||||
QueryResult<Query$AllBackupSnapshots> response;
|
||||
|
||||
try {
|
||||
final GraphQLClient client = await getClient();
|
||||
response = await client.query$AllBackupSnapshots();
|
||||
if (response.hasException) {
|
||||
final message = response.exception.toString();
|
||||
print(message);
|
||||
backups = [];
|
||||
}
|
||||
final List<Backup> parsed = response.parsedData!.backup.allSnapshots
|
||||
.map(
|
||||
(
|
||||
final Query$AllBackupSnapshots$backup$allSnapshots snapshot,
|
||||
) =>
|
||||
Backup.fromGraphQL(snapshot),
|
||||
)
|
||||
.toList();
|
||||
backups = parsed;
|
||||
} catch (e) {
|
||||
print(e);
|
||||
backups = [];
|
||||
}
|
||||
|
||||
return backups;
|
||||
}
|
||||
|
||||
Future<BackupConfiguration?> getBackupsConfiguration() async {
|
||||
BackupConfiguration? backupConfiguration;
|
||||
QueryResult<Query$BackupConfiguration> response;
|
||||
try {
|
||||
final GraphQLClient client = await getClient();
|
||||
response = await client.query$BackupConfiguration();
|
||||
if (response.hasException) {
|
||||
final message = response.exception.toString();
|
||||
print(message);
|
||||
backupConfiguration = null;
|
||||
}
|
||||
final BackupConfiguration parsed = BackupConfiguration.fromGraphQL(
|
||||
response.parsedData!.backup.configuration,
|
||||
);
|
||||
backupConfiguration = parsed;
|
||||
} catch (e) {
|
||||
print(e);
|
||||
backupConfiguration = null;
|
||||
}
|
||||
|
||||
return backupConfiguration;
|
||||
}
|
||||
|
||||
Future<GenericResult> forceBackupListReload() async {
|
||||
try {
|
||||
final GraphQLClient client = await getClient();
|
||||
await client.mutate$ForceSnapshotsReload();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
return GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: e.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
return GenericResult(
|
||||
success: true,
|
||||
data: null,
|
||||
);
|
||||
}
|
||||
|
||||
Future<GenericResult> startBackup(final String serviceId) async {
|
||||
QueryResult<Mutation$StartBackup> response;
|
||||
GenericResult? result;
|
||||
|
||||
try {
|
||||
final GraphQLClient client = await getClient();
|
||||
final variables = Variables$Mutation$StartBackup(serviceId: serviceId);
|
||||
final options = Options$Mutation$StartBackup(variables: variables);
|
||||
response = await client.mutate$StartBackup(options);
|
||||
if (response.hasException) {
|
||||
final message = response.exception.toString();
|
||||
print(message);
|
||||
result = GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: message,
|
||||
);
|
||||
}
|
||||
result = GenericResult(
|
||||
success: true,
|
||||
data: null,
|
||||
);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
result = GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: e.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<GenericResult> setAutobackupPeriod({final int? period}) async {
|
||||
QueryResult<Mutation$SetAutobackupPeriod> response;
|
||||
GenericResult? result;
|
||||
|
||||
try {
|
||||
final GraphQLClient client = await getClient();
|
||||
final variables = Variables$Mutation$SetAutobackupPeriod(period: period);
|
||||
final options =
|
||||
Options$Mutation$SetAutobackupPeriod(variables: variables);
|
||||
response = await client.mutate$SetAutobackupPeriod(options);
|
||||
if (response.hasException) {
|
||||
final message = response.exception.toString();
|
||||
print(message);
|
||||
result = GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: message,
|
||||
);
|
||||
}
|
||||
result = GenericResult(
|
||||
success: true,
|
||||
data: null,
|
||||
);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
result = GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: e.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<GenericResult> removeRepository() async {
|
||||
try {
|
||||
final GraphQLClient client = await getClient();
|
||||
await client.mutate$RemoveRepository();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
return GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: e.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
return GenericResult(
|
||||
success: true,
|
||||
data: null,
|
||||
);
|
||||
}
|
||||
|
||||
Future<GenericResult> initializeRepository(
|
||||
final InitializeRepositoryInput input,
|
||||
) async {
|
||||
QueryResult<Mutation$InitializeRepository> response;
|
||||
GenericResult? result;
|
||||
|
||||
try {
|
||||
final GraphQLClient client = await getClient();
|
||||
final variables = Variables$Mutation$InitializeRepository(
|
||||
repository: Input$InitializeRepositoryInput(
|
||||
locationId: input.locationId,
|
||||
locationName: input.locationName,
|
||||
login: input.login,
|
||||
password: input.password,
|
||||
provider: input.provider.toGraphQL(),
|
||||
),
|
||||
);
|
||||
final options =
|
||||
Options$Mutation$InitializeRepository(variables: variables);
|
||||
response = await client.mutate$InitializeRepository(options);
|
||||
if (response.hasException) {
|
||||
final message = response.exception.toString();
|
||||
print(message);
|
||||
result = GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: message,
|
||||
);
|
||||
}
|
||||
result = GenericResult(
|
||||
success: true,
|
||||
data: null,
|
||||
);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
result = GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: e.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
|||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||
import 'package:selfprivacy/logic/models/initialize_repository_input.dart';
|
||||
import 'package:selfprivacy/logic/models/json/api_token.dart';
|
||||
import 'package:selfprivacy/logic/models/json/backup.dart';
|
||||
import 'package:selfprivacy/logic/models/backup.dart';
|
||||
import 'package:selfprivacy/logic/models/json/device_token.dart';
|
||||
import 'package:selfprivacy/logic/models/json/dns_records.dart';
|
||||
import 'package:selfprivacy/logic/models/json/recovery_token_status.dart';
|
||||
|
@ -32,9 +32,10 @@ part 'server_actions_api.dart';
|
|||
part 'services_api.dart';
|
||||
part 'users_api.dart';
|
||||
part 'volume_api.dart';
|
||||
part 'backups_api.dart';
|
||||
|
||||
class ServerApi extends GraphQLApiMap
|
||||
with VolumeApi, JobsApi, ServerActionsApi, ServicesApi, UsersApi {
|
||||
with VolumeApi, JobsApi, ServerActionsApi, ServicesApi, UsersApi, BackupsApi {
|
||||
ServerApi({
|
||||
this.hasLogger = false,
|
||||
this.isWithToken = true,
|
||||
|
@ -512,202 +513,4 @@ class ServerApi extends GraphQLApiMap
|
|||
|
||||
return token;
|
||||
}
|
||||
|
||||
Future<GenericResult<List<Backup>>> getBackups() async {
|
||||
GenericResult<List<Backup>> backups;
|
||||
QueryResult<Query$AllBackupSnapshots> response;
|
||||
|
||||
try {
|
||||
final GraphQLClient client = await getClient();
|
||||
response = await client.query$AllBackupSnapshots();
|
||||
if (response.hasException) {
|
||||
final message = response.exception.toString();
|
||||
print(message);
|
||||
backups = GenericResult<List<Backup>>(
|
||||
success: false,
|
||||
data: [],
|
||||
message: message,
|
||||
);
|
||||
}
|
||||
final List<Backup> parsed = response.parsedData!.backup.allSnapshots
|
||||
.map(
|
||||
(
|
||||
final Query$AllBackupSnapshots$backup$allSnapshots snapshot,
|
||||
) =>
|
||||
Backup.fromGraphQL(snapshot),
|
||||
)
|
||||
.toList();
|
||||
backups = GenericResult<List<Backup>>(
|
||||
success: true,
|
||||
data: parsed,
|
||||
);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
backups = GenericResult<List<Backup>>(
|
||||
success: false,
|
||||
data: [],
|
||||
message: e.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
return backups;
|
||||
}
|
||||
|
||||
Future<GenericResult> forceBackupListReload() async {
|
||||
try {
|
||||
final GraphQLClient client = await getClient();
|
||||
await client.mutate$ForceSnapshotsReload();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
return GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: e.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
return GenericResult(
|
||||
success: true,
|
||||
data: null,
|
||||
);
|
||||
}
|
||||
|
||||
Future<GenericResult> startBackup({final String? serviceId}) async {
|
||||
QueryResult<Mutation$StartBackup> response;
|
||||
GenericResult? result;
|
||||
|
||||
try {
|
||||
final GraphQLClient client = await getClient();
|
||||
final variables = Variables$Mutation$StartBackup(serviceId: serviceId);
|
||||
final options = Options$Mutation$StartBackup(variables: variables);
|
||||
response = await client.mutate$StartBackup(options);
|
||||
if (response.hasException) {
|
||||
final message = response.exception.toString();
|
||||
print(message);
|
||||
result = GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: message,
|
||||
);
|
||||
}
|
||||
result = GenericResult(
|
||||
success: true,
|
||||
data: null,
|
||||
);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
result = GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: e.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<GenericResult> setAutobackupPeriod({final int? period}) async {
|
||||
QueryResult<Mutation$SetAutobackupPeriod> response;
|
||||
GenericResult? result;
|
||||
|
||||
try {
|
||||
final GraphQLClient client = await getClient();
|
||||
final variables = Variables$Mutation$SetAutobackupPeriod(period: period);
|
||||
final options =
|
||||
Options$Mutation$SetAutobackupPeriod(variables: variables);
|
||||
response = await client.mutate$SetAutobackupPeriod(options);
|
||||
if (response.hasException) {
|
||||
final message = response.exception.toString();
|
||||
print(message);
|
||||
result = GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: message,
|
||||
);
|
||||
}
|
||||
result = GenericResult(
|
||||
success: true,
|
||||
data: null,
|
||||
);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
result = GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: e.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<BackupStatus> getBackupStatus() async => BackupStatus(
|
||||
progress: 0.0,
|
||||
status: BackupStatusEnum.error,
|
||||
errorMessage: null,
|
||||
);
|
||||
|
||||
Future<GenericResult> removeRepository() async {
|
||||
try {
|
||||
final GraphQLClient client = await getClient();
|
||||
await client.mutate$RemoveRepository();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
return GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: e.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
return GenericResult(
|
||||
success: true,
|
||||
data: null,
|
||||
);
|
||||
}
|
||||
|
||||
Future<GenericResult> initializeRepository(
|
||||
final InitializeRepositoryInput input,
|
||||
) async {
|
||||
QueryResult<Mutation$InitializeRepository> response;
|
||||
GenericResult? result;
|
||||
|
||||
try {
|
||||
final GraphQLClient client = await getClient();
|
||||
final variables = Variables$Mutation$InitializeRepository(
|
||||
repository: Input$InitializeRepositoryInput(
|
||||
locationId: input.locationId,
|
||||
locationName: input.locationName,
|
||||
login: input.login,
|
||||
password: input.password,
|
||||
provider: input.provider.toGraphQL(),
|
||||
),
|
||||
);
|
||||
final options =
|
||||
Options$Mutation$InitializeRepository(variables: variables);
|
||||
response = await client.mutate$InitializeRepository(options);
|
||||
if (response.hasException) {
|
||||
final message = response.exception.toString();
|
||||
print(message);
|
||||
result = GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: message,
|
||||
);
|
||||
}
|
||||
result = GenericResult(
|
||||
success: true,
|
||||
data: null,
|
||||
);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
result = GenericResult(
|
||||
success: false,
|
||||
data: null,
|
||||
message: e.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,10 @@ import 'package:selfprivacy/logic/api_maps/rest_maps/backblaze.dart';
|
|||
import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.dart';
|
||||
import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
|
||||
import 'package:selfprivacy/logic/models/json/backup.dart';
|
||||
import 'package:selfprivacy/logic/models/backup.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/backups_credential.dart';
|
||||
import 'package:selfprivacy/logic/models/initialize_repository_input.dart';
|
||||
import 'package:selfprivacy/logic/models/service.dart';
|
||||
|
||||
part 'backups_state.dart';
|
||||
|
||||
|
@ -24,107 +27,83 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
|
|||
Future<void> load() async {
|
||||
if (serverInstallationCubit.state is ServerInstallationFinished) {
|
||||
final BackblazeBucket? bucket = getIt<ApiConfigModel>().backblazeBucket;
|
||||
if (bucket == null) {
|
||||
emit(
|
||||
const BackupsState(
|
||||
isInitialized: false,
|
||||
preventActions: false,
|
||||
refreshing: false,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
final BackupStatus status = await api.getBackupStatus();
|
||||
switch (status.status) {
|
||||
case BackupStatusEnum.noKey:
|
||||
case BackupStatusEnum.notInitialized:
|
||||
emit(
|
||||
BackupsState(
|
||||
backups: const [],
|
||||
isInitialized: true,
|
||||
preventActions: false,
|
||||
progress: 0,
|
||||
status: status.status,
|
||||
refreshing: false,
|
||||
),
|
||||
);
|
||||
break;
|
||||
case BackupStatusEnum.initializing:
|
||||
emit(
|
||||
BackupsState(
|
||||
backups: const [],
|
||||
isInitialized: true,
|
||||
preventActions: false,
|
||||
progress: 0,
|
||||
status: status.status,
|
||||
refreshTimer: const Duration(seconds: 10),
|
||||
refreshing: false,
|
||||
),
|
||||
);
|
||||
break;
|
||||
case BackupStatusEnum.initialized:
|
||||
case BackupStatusEnum.error:
|
||||
final result = await api.getBackups();
|
||||
emit(
|
||||
BackupsState(
|
||||
backups: result.data,
|
||||
isInitialized: true,
|
||||
preventActions: false,
|
||||
progress: status.progress,
|
||||
status: status.status,
|
||||
error: status.errorMessage ?? '',
|
||||
refreshing: false,
|
||||
),
|
||||
);
|
||||
break;
|
||||
case BackupStatusEnum.backingUp:
|
||||
case BackupStatusEnum.restoring:
|
||||
final result = await api.getBackups();
|
||||
emit(
|
||||
BackupsState(
|
||||
backups: result.data,
|
||||
isInitialized: true,
|
||||
preventActions: true,
|
||||
progress: status.progress,
|
||||
status: status.status,
|
||||
error: status.errorMessage ?? '',
|
||||
refreshTimer: const Duration(seconds: 5),
|
||||
refreshing: false,
|
||||
),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
emit(const BackupsState());
|
||||
}
|
||||
Timer(state.refreshTimer, () => updateBackups(useTimer: true));
|
||||
}
|
||||
final BackupConfiguration? backupConfig =
|
||||
await api.getBackupsConfiguration();
|
||||
final List<Backup> backups = await api.getBackups();
|
||||
emit(
|
||||
state.copyWith(
|
||||
backblazeBucket: bucket,
|
||||
isInitialized: backupConfig?.isInitialized,
|
||||
autobackupPeriod: backupConfig?.autobackupPeriod,
|
||||
backups: backups,
|
||||
preventActions: false,
|
||||
refreshing: false,
|
||||
),
|
||||
);
|
||||
print(state);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> createBucket() async {
|
||||
Future<void> initializeBackups() async {
|
||||
emit(state.copyWith(preventActions: true));
|
||||
final String domain = serverInstallationCubit.state.serverDomain!.domainName
|
||||
.replaceAll(RegExp(r'[^a-zA-Z0-9]'), '-');
|
||||
final int serverId = serverInstallationCubit.state.serverDetails!.id;
|
||||
String bucketName = 'selfprivacy-$domain-$serverId';
|
||||
// If bucket name is too long, shorten it
|
||||
if (bucketName.length > 49) {
|
||||
bucketName = bucketName.substring(0, 49);
|
||||
final String? encryptionKey =
|
||||
(await api.getBackupsConfiguration())?.encryptionKey;
|
||||
if (encryptionKey == null) {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar("Couldn't get encryption key from your server.");
|
||||
emit(state.copyWith(preventActions: false));
|
||||
return;
|
||||
}
|
||||
final String bucketId = await backblaze.createBucket(bucketName);
|
||||
|
||||
final BackblazeApplicationKey key = await backblaze.createKey(bucketId);
|
||||
final BackblazeBucket bucket = BackblazeBucket(
|
||||
bucketId: bucketId,
|
||||
bucketName: bucketName,
|
||||
applicationKey: key.applicationKey,
|
||||
applicationKeyId: key.applicationKeyId,
|
||||
final BackblazeBucket bucket;
|
||||
|
||||
if (state.backblazeBucket == null) {
|
||||
final String domain = serverInstallationCubit
|
||||
.state.serverDomain!.domainName
|
||||
.replaceAll(RegExp(r'[^a-zA-Z0-9]'), '-');
|
||||
final int serverId = serverInstallationCubit.state.serverDetails!.id;
|
||||
String bucketName = 'selfprivacy-$domain-$serverId';
|
||||
// If bucket name is too long, shorten it
|
||||
if (bucketName.length > 49) {
|
||||
bucketName = bucketName.substring(0, 49);
|
||||
}
|
||||
final String bucketId = await backblaze.createBucket(bucketName);
|
||||
|
||||
final BackblazeApplicationKey key = await backblaze.createKey(bucketId);
|
||||
bucket = BackblazeBucket(
|
||||
bucketId: bucketId,
|
||||
bucketName: bucketName,
|
||||
applicationKey: key.applicationKey,
|
||||
applicationKeyId: key.applicationKeyId,
|
||||
encryptionKey: encryptionKey,
|
||||
);
|
||||
|
||||
await getIt<ApiConfigModel>().storeBackblazeBucket(bucket);
|
||||
emit(state.copyWith(backblazeBucket: bucket));
|
||||
} else {
|
||||
bucket = state.backblazeBucket!;
|
||||
}
|
||||
|
||||
final GenericResult result = await api.initializeRepository(
|
||||
InitializeRepositoryInput(
|
||||
provider: BackupsProviderType.backblaze,
|
||||
locationId: bucket.bucketId,
|
||||
locationName: bucket.bucketName,
|
||||
login: bucket.applicationKeyId,
|
||||
password: bucket.applicationKey,
|
||||
),
|
||||
);
|
||||
|
||||
await getIt<ApiConfigModel>().storeBackblazeBucket(bucket);
|
||||
//await api.uploadBackblazeConfig(bucket);
|
||||
if (result.success == false) {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar(result.message ?? 'Unknown error');
|
||||
emit(state.copyWith(preventActions: false));
|
||||
return;
|
||||
}
|
||||
await updateBackups();
|
||||
getIt<NavigationService>().showSnackBar(
|
||||
'Backups repository is now initializing. It may take a while.');
|
||||
|
||||
emit(state.copyWith(isInitialized: true, preventActions: false));
|
||||
emit(state.copyWith(preventActions: false));
|
||||
}
|
||||
|
||||
Future<void> reuploadKey() async {
|
||||
|
@ -132,42 +111,47 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
|
|||
final BackblazeBucket? bucket = getIt<ApiConfigModel>().backblazeBucket;
|
||||
if (bucket == null) {
|
||||
emit(state.copyWith(isInitialized: false));
|
||||
print('bucket is null');
|
||||
} else {
|
||||
//await api.uploadBackblazeConfig(bucket);
|
||||
emit(state.copyWith(isInitialized: true, preventActions: false));
|
||||
getIt<NavigationService>().showSnackBar('backup.reuploaded_key');
|
||||
print('bucket is not null');
|
||||
final GenericResult result = await api.initializeRepository(
|
||||
InitializeRepositoryInput(
|
||||
provider: BackupsProviderType.backblaze,
|
||||
locationId: bucket.bucketId,
|
||||
locationName: bucket.bucketName,
|
||||
login: bucket.applicationKeyId,
|
||||
password: bucket.applicationKey,
|
||||
),
|
||||
);
|
||||
print('result is $result');
|
||||
if (result.success == false) {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar(result.message ?? 'Unknown error');
|
||||
emit(state.copyWith(preventActions: false));
|
||||
return;
|
||||
} else {
|
||||
emit(state.copyWith(preventActions: false));
|
||||
getIt<NavigationService>().showSnackBar('backup.reuploaded_key');
|
||||
await updateBackups();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Duration refreshTimeFromState(final BackupStatusEnum status) {
|
||||
switch (status) {
|
||||
case BackupStatusEnum.backingUp:
|
||||
case BackupStatusEnum.restoring:
|
||||
return const Duration(seconds: 5);
|
||||
case BackupStatusEnum.initializing:
|
||||
return const Duration(seconds: 10);
|
||||
default:
|
||||
return const Duration(seconds: 60);
|
||||
}
|
||||
}
|
||||
@Deprecated("we don't have states")
|
||||
Duration refreshTimeFromState() => const Duration(seconds: 60);
|
||||
|
||||
Future<void> updateBackups({final bool useTimer = false}) async {
|
||||
emit(state.copyWith(refreshing: true));
|
||||
final result = await api.getBackups();
|
||||
if (!result.success || result.data.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final backups = await api.getBackups();
|
||||
final backupConfig = await api.getBackupsConfiguration();
|
||||
|
||||
final List<Backup> backups = result.data;
|
||||
final BackupStatus status = await api.getBackupStatus();
|
||||
emit(
|
||||
state.copyWith(
|
||||
backups: backups,
|
||||
progress: status.progress,
|
||||
status: status.status,
|
||||
error: status.errorMessage,
|
||||
refreshTimer: refreshTimeFromState(status.status),
|
||||
refreshTimer: refreshTimeFromState(),
|
||||
refreshing: false,
|
||||
isInitialized: backupConfig?.isInitialized ?? false,
|
||||
autobackupPeriod: backupConfig?.autobackupPeriod,
|
||||
),
|
||||
);
|
||||
if (useTimer) {
|
||||
|
@ -182,9 +166,18 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
|
|||
emit(state.copyWith(preventActions: false));
|
||||
}
|
||||
|
||||
Future<void> createBackup() async {
|
||||
Future<void> createMultipleBackups(final List<Service> services) async {
|
||||
emit(state.copyWith(preventActions: true));
|
||||
await api.startBackup();
|
||||
for (final service in services) {
|
||||
await api.startBackup(service.id);
|
||||
}
|
||||
await updateBackups();
|
||||
emit(state.copyWith(preventActions: false));
|
||||
}
|
||||
|
||||
Future<void> createBackup(final String serviceId) async {
|
||||
emit(state.copyWith(preventActions: true));
|
||||
await api.startBackup(serviceId);
|
||||
await updateBackups();
|
||||
emit(state.copyWith(preventActions: false));
|
||||
}
|
||||
|
|
|
@ -4,31 +4,26 @@ class BackupsState extends ServerInstallationDependendState {
|
|||
const BackupsState({
|
||||
this.isInitialized = false,
|
||||
this.backups = const [],
|
||||
this.progress = 0.0,
|
||||
this.status = BackupStatusEnum.noKey,
|
||||
this.preventActions = true,
|
||||
this.error = '',
|
||||
this.refreshTimer = const Duration(seconds: 60),
|
||||
this.refreshing = true,
|
||||
this.autobackupPeriod,
|
||||
this.backblazeBucket,
|
||||
});
|
||||
|
||||
final bool isInitialized;
|
||||
final List<Backup> backups;
|
||||
final double progress;
|
||||
final BackupStatusEnum status;
|
||||
final bool preventActions;
|
||||
final String error;
|
||||
final Duration refreshTimer;
|
||||
final bool refreshing;
|
||||
final Duration? autobackupPeriod;
|
||||
final BackblazeBucket? backblazeBucket;
|
||||
|
||||
@override
|
||||
List<Object> get props => [
|
||||
isInitialized,
|
||||
backups,
|
||||
progress,
|
||||
preventActions,
|
||||
status,
|
||||
error,
|
||||
refreshTimer,
|
||||
refreshing
|
||||
];
|
||||
|
@ -36,21 +31,19 @@ class BackupsState extends ServerInstallationDependendState {
|
|||
BackupsState copyWith({
|
||||
final bool? isInitialized,
|
||||
final List<Backup>? backups,
|
||||
final double? progress,
|
||||
final BackupStatusEnum? status,
|
||||
final bool? preventActions,
|
||||
final String? error,
|
||||
final Duration? refreshTimer,
|
||||
final bool? refreshing,
|
||||
final Duration? autobackupPeriod,
|
||||
final BackblazeBucket? backblazeBucket,
|
||||
}) =>
|
||||
BackupsState(
|
||||
isInitialized: isInitialized ?? this.isInitialized,
|
||||
backups: backups ?? this.backups,
|
||||
progress: progress ?? this.progress,
|
||||
status: status ?? this.status,
|
||||
preventActions: preventActions ?? this.preventActions,
|
||||
error: error ?? this.error,
|
||||
refreshTimer: refreshTimer ?? this.refreshTimer,
|
||||
refreshing: refreshing ?? this.refreshing,
|
||||
autobackupPeriod: autobackupPeriod ?? this.autobackupPeriod,
|
||||
backblazeBucket: backblazeBucket ?? this.backblazeBucket,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -197,7 +197,7 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
|||
final BackupsCredential backblazeCredential = BackupsCredential(
|
||||
keyId: keyId,
|
||||
applicationKey: applicationKey,
|
||||
provider: BackupsProvider.backblaze,
|
||||
provider: BackupsProviderType.backblaze,
|
||||
);
|
||||
await repository.saveBackblazeKey(backblazeCredential);
|
||||
if (state is ServerInstallationRecovery) {
|
||||
|
@ -699,7 +699,7 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
|||
provider: dnsProviderType,
|
||||
),
|
||||
);
|
||||
await repository.setDnsApiToken(token);
|
||||
// await repository.setDnsApiToken(token);
|
||||
emit(
|
||||
dataState.copyWith(
|
||||
serverDomain: ServerDomain(
|
||||
|
|
60
lib/logic/models/backup.dart
Normal file
60
lib/logic/models/backup.dart
Normal file
|
@ -0,0 +1,60 @@
|
|||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/backups.graphql.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/backups_credential.dart';
|
||||
|
||||
class Backup {
|
||||
Backup.fromGraphQL(
|
||||
final Query$AllBackupSnapshots$backup$allSnapshots snapshot,
|
||||
) : this(
|
||||
id: snapshot.id,
|
||||
time: snapshot.createdAt,
|
||||
serviceId: snapshot.service.id,
|
||||
fallbackServiceName: snapshot.service.displayName,
|
||||
);
|
||||
|
||||
Backup({
|
||||
required this.time,
|
||||
required this.id,
|
||||
required this.serviceId,
|
||||
required this.fallbackServiceName,
|
||||
});
|
||||
|
||||
// Time of the backup
|
||||
final DateTime time;
|
||||
@JsonKey(name: 'short_id')
|
||||
final String id;
|
||||
final String serviceId;
|
||||
final String fallbackServiceName;
|
||||
}
|
||||
|
||||
class BackupConfiguration {
|
||||
BackupConfiguration.fromGraphQL(
|
||||
final Query$BackupConfiguration$backup$configuration configuration,
|
||||
) : this(
|
||||
// Provided by API as int of minutes
|
||||
autobackupPeriod: configuration.autobackupPeriod != null
|
||||
? Duration(minutes: configuration.autobackupPeriod!)
|
||||
: null,
|
||||
encryptionKey: configuration.encryptionKey,
|
||||
isInitialized: configuration.isInitialized,
|
||||
locationId: configuration.locationId,
|
||||
locationName: configuration.locationName,
|
||||
provider: BackupsProviderType.fromGraphQL(configuration.provider),
|
||||
);
|
||||
|
||||
BackupConfiguration({
|
||||
required this.autobackupPeriod,
|
||||
required this.encryptionKey,
|
||||
required this.isInitialized,
|
||||
required this.locationId,
|
||||
required this.locationName,
|
||||
required this.provider,
|
||||
});
|
||||
|
||||
final Duration? autobackupPeriod;
|
||||
final String encryptionKey;
|
||||
final bool isInitialized;
|
||||
final String? locationId;
|
||||
final String? locationName;
|
||||
final BackupsProviderType provider;
|
||||
}
|
|
@ -9,6 +9,7 @@ class BackblazeBucket {
|
|||
required this.bucketName,
|
||||
required this.applicationKeyId,
|
||||
required this.applicationKey,
|
||||
required this.encryptionKey,
|
||||
});
|
||||
|
||||
@HiveField(0)
|
||||
|
@ -23,6 +24,9 @@ class BackblazeBucket {
|
|||
@HiveField(3)
|
||||
final String bucketName;
|
||||
|
||||
@HiveField(4)
|
||||
final String encryptionKey;
|
||||
|
||||
@override
|
||||
String toString() => bucketName;
|
||||
}
|
||||
|
|
|
@ -21,13 +21,14 @@ class BackblazeBucketAdapter extends TypeAdapter<BackblazeBucket> {
|
|||
bucketName: fields[3] as String,
|
||||
applicationKeyId: fields[1] as String,
|
||||
applicationKey: fields[2] as String,
|
||||
encryptionKey: fields[4] as String,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, BackblazeBucket obj) {
|
||||
writer
|
||||
..writeByte(4)
|
||||
..writeByte(5)
|
||||
..writeByte(0)
|
||||
..write(obj.bucketId)
|
||||
..writeByte(1)
|
||||
|
@ -35,7 +36,9 @@ class BackblazeBucketAdapter extends TypeAdapter<BackblazeBucket> {
|
|||
..writeByte(2)
|
||||
..write(obj.applicationKey)
|
||||
..writeByte(3)
|
||||
..write(obj.bucketName);
|
||||
..write(obj.bucketName)
|
||||
..writeByte(4)
|
||||
..write(obj.encryptionKey);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -19,8 +19,8 @@ class BackupsCredential {
|
|||
@HiveField(1)
|
||||
final String applicationKey;
|
||||
|
||||
@HiveField(2, defaultValue: BackupsProvider.backblaze)
|
||||
final BackupsProvider provider;
|
||||
@HiveField(2, defaultValue: BackupsProviderType.backblaze)
|
||||
final BackupsProviderType provider;
|
||||
|
||||
String get encodedApiKey => encodedBackblazeKey(keyId, applicationKey);
|
||||
|
||||
|
@ -35,7 +35,7 @@ String encodedBackblazeKey(final String? keyId, final String? applicationKey) {
|
|||
}
|
||||
|
||||
@HiveType(typeId: 103)
|
||||
enum BackupsProvider {
|
||||
enum BackupsProviderType {
|
||||
@HiveField(0)
|
||||
none,
|
||||
@HiveField(1)
|
||||
|
@ -45,7 +45,7 @@ enum BackupsProvider {
|
|||
@HiveField(3)
|
||||
backblaze;
|
||||
|
||||
factory BackupsProvider.fromGraphQL(final Enum$BackupProvider provider) =>
|
||||
factory BackupsProviderType.fromGraphQL(final Enum$BackupProvider provider) =>
|
||||
switch (provider) {
|
||||
Enum$BackupProvider.NONE => none,
|
||||
Enum$BackupProvider.MEMORY => memory,
|
||||
|
|
|
@ -20,8 +20,8 @@ class BackupsCredentialAdapter extends TypeAdapter<BackupsCredential> {
|
|||
keyId: fields[0] as String,
|
||||
applicationKey: fields[1] as String,
|
||||
provider: fields[2] == null
|
||||
? BackupsProvider.backblaze
|
||||
: fields[2] as BackupsProvider,
|
||||
? BackupsProviderType.backblaze
|
||||
: fields[2] as BackupsProviderType,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -48,39 +48,39 @@ class BackupsCredentialAdapter extends TypeAdapter<BackupsCredential> {
|
|||
typeId == other.typeId;
|
||||
}
|
||||
|
||||
class BackupsProviderAdapter extends TypeAdapter<BackupsProvider> {
|
||||
class BackupsProviderTypeAdapter extends TypeAdapter<BackupsProviderType> {
|
||||
@override
|
||||
final int typeId = 103;
|
||||
|
||||
@override
|
||||
BackupsProvider read(BinaryReader reader) {
|
||||
BackupsProviderType read(BinaryReader reader) {
|
||||
switch (reader.readByte()) {
|
||||
case 0:
|
||||
return BackupsProvider.none;
|
||||
return BackupsProviderType.none;
|
||||
case 1:
|
||||
return BackupsProvider.memory;
|
||||
return BackupsProviderType.memory;
|
||||
case 2:
|
||||
return BackupsProvider.file;
|
||||
return BackupsProviderType.file;
|
||||
case 3:
|
||||
return BackupsProvider.backblaze;
|
||||
return BackupsProviderType.backblaze;
|
||||
default:
|
||||
return BackupsProvider.none;
|
||||
return BackupsProviderType.none;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, BackupsProvider obj) {
|
||||
void write(BinaryWriter writer, BackupsProviderType obj) {
|
||||
switch (obj) {
|
||||
case BackupsProvider.none:
|
||||
case BackupsProviderType.none:
|
||||
writer.writeByte(0);
|
||||
break;
|
||||
case BackupsProvider.memory:
|
||||
case BackupsProviderType.memory:
|
||||
writer.writeByte(1);
|
||||
break;
|
||||
case BackupsProvider.file:
|
||||
case BackupsProviderType.file:
|
||||
writer.writeByte(2);
|
||||
break;
|
||||
case BackupsProvider.backblaze:
|
||||
case BackupsProviderType.backblaze:
|
||||
writer.writeByte(3);
|
||||
break;
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ class BackupsProviderAdapter extends TypeAdapter<BackupsProvider> {
|
|||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is BackupsProviderAdapter &&
|
||||
other is BackupsProviderTypeAdapter &&
|
||||
runtimeType == other.runtimeType &&
|
||||
typeId == other.typeId;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ class InitializeRepositoryInput {
|
|||
required this.login,
|
||||
required this.password,
|
||||
});
|
||||
final BackupsProvider provider;
|
||||
final BackupsProviderType provider;
|
||||
final String locationId;
|
||||
final String locationName;
|
||||
final String login;
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/backups.graphql.dart';
|
||||
|
||||
part 'backup.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class Backup {
|
||||
factory Backup.fromJson(final Map<String, dynamic> json) =>
|
||||
_$BackupFromJson(json);
|
||||
Backup.fromGraphQL(
|
||||
final Query$AllBackupSnapshots$backup$allSnapshots snapshot,
|
||||
) : this(
|
||||
id: snapshot.id,
|
||||
time: snapshot.createdAt,
|
||||
serviceId: snapshot.service.id,
|
||||
fallbackServiceName: snapshot.service.displayName,
|
||||
);
|
||||
|
||||
Backup({
|
||||
required this.time,
|
||||
required this.id,
|
||||
required this.serviceId,
|
||||
required this.fallbackServiceName,
|
||||
});
|
||||
|
||||
// Time of the backup
|
||||
final DateTime time;
|
||||
@JsonKey(name: 'short_id')
|
||||
final String id;
|
||||
final String serviceId;
|
||||
final String fallbackServiceName;
|
||||
}
|
||||
|
||||
enum BackupStatusEnum {
|
||||
@JsonValue('NO_KEY')
|
||||
noKey,
|
||||
@JsonValue('NOT_INITIALIZED')
|
||||
notInitialized,
|
||||
@JsonValue('INITIALIZED')
|
||||
initialized,
|
||||
@JsonValue('BACKING_UP')
|
||||
backingUp,
|
||||
@JsonValue('RESTORING')
|
||||
restoring,
|
||||
@JsonValue('ERROR')
|
||||
error,
|
||||
@JsonValue('INITIALIZING')
|
||||
initializing,
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class BackupStatus {
|
||||
factory BackupStatus.fromJson(final Map<String, dynamic> json) =>
|
||||
_$BackupStatusFromJson(json);
|
||||
BackupStatus({
|
||||
required this.status,
|
||||
required this.progress,
|
||||
required this.errorMessage,
|
||||
});
|
||||
|
||||
final BackupStatusEnum status;
|
||||
final double progress;
|
||||
@JsonKey(name: 'error_message')
|
||||
final String? errorMessage;
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'backup.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
Backup _$BackupFromJson(Map<String, dynamic> json) => Backup(
|
||||
time: DateTime.parse(json['time'] as String),
|
||||
id: json['short_id'] as String,
|
||||
serviceId: json['serviceId'] as String,
|
||||
fallbackServiceName: json['fallbackServiceName'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$BackupToJson(Backup instance) => <String, dynamic>{
|
||||
'time': instance.time.toIso8601String(),
|
||||
'short_id': instance.id,
|
||||
'serviceId': instance.serviceId,
|
||||
'fallbackServiceName': instance.fallbackServiceName,
|
||||
};
|
||||
|
||||
BackupStatus _$BackupStatusFromJson(Map<String, dynamic> json) => BackupStatus(
|
||||
status: $enumDecode(_$BackupStatusEnumEnumMap, json['status']),
|
||||
progress: (json['progress'] as num).toDouble(),
|
||||
errorMessage: json['error_message'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$BackupStatusToJson(BackupStatus instance) =>
|
||||
<String, dynamic>{
|
||||
'status': _$BackupStatusEnumEnumMap[instance.status]!,
|
||||
'progress': instance.progress,
|
||||
'error_message': instance.errorMessage,
|
||||
};
|
||||
|
||||
const _$BackupStatusEnumEnumMap = {
|
||||
BackupStatusEnum.noKey: 'NO_KEY',
|
||||
BackupStatusEnum.notInitialized: 'NOT_INITIALIZED',
|
||||
BackupStatusEnum.initialized: 'INITIALIZED',
|
||||
BackupStatusEnum.backingUp: 'BACKING_UP',
|
||||
BackupStatusEnum.restoring: 'RESTORING',
|
||||
BackupStatusEnum.error: 'ERROR',
|
||||
BackupStatusEnum.initializing: 'INITIALIZING',
|
||||
};
|
|
@ -1,9 +1,14 @@
|
|||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
|
||||
import 'package:selfprivacy/logic/models/json/backup.dart';
|
||||
import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_cubit.dart';
|
||||
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
|
||||
import 'package:selfprivacy/logic/models/backup.dart';
|
||||
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
||||
import 'package:selfprivacy/logic/models/service.dart';
|
||||
import 'package:selfprivacy/logic/models/state_types.dart';
|
||||
import 'package:selfprivacy/ui/components/buttons/brand_button.dart';
|
||||
import 'package:selfprivacy/ui/components/cards/outlined_card.dart';
|
||||
|
@ -29,19 +34,15 @@ class _BackupDetailsPageState extends State<BackupDetailsPage>
|
|||
is ServerInstallationFinished;
|
||||
final bool isBackupInitialized =
|
||||
context.watch<BackupsCubit>().state.isInitialized;
|
||||
final BackupStatusEnum backupStatus =
|
||||
context.watch<BackupsCubit>().state.status;
|
||||
final StateType providerState = isReady && isBackupInitialized
|
||||
? (backupStatus == BackupStatusEnum.error
|
||||
? StateType.warning
|
||||
: StateType.stable)
|
||||
? StateType.stable
|
||||
: StateType.uninitialized;
|
||||
final bool preventActions =
|
||||
context.watch<BackupsCubit>().state.preventActions;
|
||||
final double backupProgress = context.watch<BackupsCubit>().state.progress;
|
||||
final String backupError = context.watch<BackupsCubit>().state.error;
|
||||
final List<Backup> backups = context.watch<BackupsCubit>().state.backups;
|
||||
final bool refreshing = context.watch<BackupsCubit>().state.refreshing;
|
||||
final List<Service> services =
|
||||
context.watch<ServicesCubit>().state.services;
|
||||
|
||||
return BrandHeroScreen(
|
||||
heroIcon: BrandIcons.save,
|
||||
|
@ -53,81 +54,45 @@ class _BackupDetailsPageState extends State<BackupDetailsPage>
|
|||
onPressed: preventActions
|
||||
? null
|
||||
: () async {
|
||||
await context.read<BackupsCubit>().createBucket();
|
||||
await context.read<BackupsCubit>().initializeBackups();
|
||||
},
|
||||
text: 'backup.initialize'.tr(),
|
||||
),
|
||||
if (backupStatus == BackupStatusEnum.initializing)
|
||||
Text(
|
||||
'backup.waiting_for_rebuild'.tr(),
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
if (backupStatus != BackupStatusEnum.initializing &&
|
||||
backupStatus != BackupStatusEnum.noKey)
|
||||
OutlinedCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (backupStatus == BackupStatusEnum.initialized)
|
||||
ListTile(
|
||||
onTap: preventActions
|
||||
? null
|
||||
: () async {
|
||||
await context.read<BackupsCubit>().createBackup();
|
||||
},
|
||||
leading: const Icon(
|
||||
Icons.add_circle_outline_rounded,
|
||||
),
|
||||
title: Text(
|
||||
'backup.create_new'.tr(),
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
if (backupStatus == BackupStatusEnum.backingUp)
|
||||
ListTile(
|
||||
title: Text(
|
||||
'backup.creating'.tr(
|
||||
args: [(backupProgress * 100).round().toString()],
|
||||
ListTile(
|
||||
onTap: preventActions
|
||||
? null
|
||||
: () {
|
||||
// await context.read<BackupsCubit>().createBackup();
|
||||
showModalBottomSheet(
|
||||
useRootNavigator: true,
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (final BuildContext context) =>
|
||||
DraggableScrollableSheet(
|
||||
expand: false,
|
||||
maxChildSize: 0.9,
|
||||
minChildSize: 0.4,
|
||||
initialChildSize: 0.6,
|
||||
builder: (context, scrollController) =>
|
||||
CreateBackupsModal(
|
||||
services: services,
|
||||
scrollController: scrollController,
|
||||
),
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
subtitle: LinearProgressIndicator(
|
||||
value: backupProgress,
|
||||
backgroundColor: Colors.grey.withOpacity(0.2),
|
||||
),
|
||||
),
|
||||
if (backupStatus == BackupStatusEnum.restoring)
|
||||
ListTile(
|
||||
title: Text(
|
||||
'backup.restoring'.tr(
|
||||
args: [(backupProgress * 100).round().toString()],
|
||||
),
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
subtitle: LinearProgressIndicator(
|
||||
backgroundColor: Colors.grey.withOpacity(0.2),
|
||||
),
|
||||
),
|
||||
if (backupStatus == BackupStatusEnum.error)
|
||||
ListTile(
|
||||
leading: Icon(
|
||||
Icons.error_outline,
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
title: Text(
|
||||
'backup.error_pending'.tr(),
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
leading: const Icon(
|
||||
Icons.add_circle_outline_rounded,
|
||||
),
|
||||
title: Text(
|
||||
'backup.create_new'.tr(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Card with a list of existing backups
|
||||
// Each list item has a date
|
||||
// When clicked, starts the restore action
|
||||
if (backupStatus != BackupStatusEnum.initializing &&
|
||||
backupStatus != BackupStatusEnum.noKey)
|
||||
if (isBackupInitialized)
|
||||
OutlinedCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
@ -230,11 +195,151 @@ class _BackupDetailsPageState extends State<BackupDetailsPage>
|
|||
],
|
||||
),
|
||||
),
|
||||
if (backupStatus == BackupStatusEnum.error)
|
||||
Text(
|
||||
backupError.toString(),
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CreateBackupsModal extends StatefulWidget {
|
||||
const CreateBackupsModal({
|
||||
super.key,
|
||||
required this.services,
|
||||
required this.scrollController,
|
||||
});
|
||||
|
||||
final List<Service> services;
|
||||
final ScrollController scrollController;
|
||||
|
||||
@override
|
||||
State<CreateBackupsModal> createState() => _CreateBackupsModalState();
|
||||
}
|
||||
|
||||
class _CreateBackupsModalState extends State<CreateBackupsModal> {
|
||||
// Store in state the selected services to backup
|
||||
List<Service> selectedServices = [];
|
||||
|
||||
// Select all services on modal open
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final List<String> busyServices = context
|
||||
.read<ServerJobsCubit>()
|
||||
.state
|
||||
.backupJobList
|
||||
.where((final ServerJob job) =>
|
||||
job.status == JobStatusEnum.running ||
|
||||
job.status == JobStatusEnum.created)
|
||||
.map((final ServerJob job) => job.typeId.split('.')[1])
|
||||
.toList();
|
||||
selectedServices.addAll(widget.services
|
||||
.where((final Service service) => !busyServices.contains(service.id)));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(final BuildContext context) {
|
||||
final List<String> busyServices = context
|
||||
.watch<ServerJobsCubit>()
|
||||
.state
|
||||
.backupJobList
|
||||
.where((final ServerJob job) =>
|
||||
job.status == JobStatusEnum.running ||
|
||||
job.status == JobStatusEnum.created)
|
||||
.map((final ServerJob job) => job.typeId.split('.')[1])
|
||||
.toList();
|
||||
|
||||
return ListView(
|
||||
controller: widget.scrollController,
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'backup.create_new_select_headline'.tr(),
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Select all services tile
|
||||
CheckboxListTile(
|
||||
onChanged: (final bool? value) {
|
||||
setState(() {
|
||||
if (value ?? true) {
|
||||
setState(() {
|
||||
selectedServices.clear();
|
||||
selectedServices.addAll(widget.services.where(
|
||||
(final service) => !busyServices.contains(service.id)));
|
||||
});
|
||||
} else {
|
||||
selectedServices.clear();
|
||||
}
|
||||
});
|
||||
},
|
||||
title: Text(
|
||||
'backup.select_all'.tr(),
|
||||
),
|
||||
secondary: const Icon(
|
||||
Icons.checklist_outlined,
|
||||
),
|
||||
value: selectedServices.length >=
|
||||
widget.services.length - busyServices.length,
|
||||
),
|
||||
const Divider(
|
||||
height: 1.0,
|
||||
),
|
||||
...widget.services.map(
|
||||
(final Service service) {
|
||||
final bool busy = busyServices.contains(service.id);
|
||||
return CheckboxListTile(
|
||||
onChanged: !busy
|
||||
? (final bool? value) {
|
||||
setState(() {
|
||||
if (value ?? true) {
|
||||
setState(() {
|
||||
selectedServices.add(service);
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
selectedServices.remove(service);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
: null,
|
||||
title: Text(
|
||||
service.displayName,
|
||||
),
|
||||
subtitle: Text(
|
||||
busy ? 'backup.service_busy'.tr() : service.description,
|
||||
),
|
||||
secondary: SvgPicture.string(
|
||||
service.svgIcon,
|
||||
height: 24,
|
||||
width: 24,
|
||||
colorFilter: ColorFilter.mode(
|
||||
busy
|
||||
? Theme.of(context).colorScheme.outlineVariant
|
||||
: Theme.of(context).colorScheme.onBackground,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
),
|
||||
value: selectedServices.contains(service),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Create backup button
|
||||
FilledButton(
|
||||
onPressed: selectedServices.isEmpty
|
||||
? null
|
||||
: () {
|
||||
context
|
||||
.read<BackupsCubit>()
|
||||
.createMultipleBackups(selectedServices);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(
|
||||
'backup.create'.tr(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -97,16 +97,15 @@ class _ProvidersPageState extends State<ProvidersPage> {
|
|||
),
|
||||
const SizedBox(height: 16),
|
||||
// TODO: When backups are fixed, show this card
|
||||
if (isBackupInitialized)
|
||||
_Card(
|
||||
state: isBackupInitialized
|
||||
? StateType.stable
|
||||
: StateType.uninitialized,
|
||||
icon: BrandIcons.save,
|
||||
title: 'backup.card_title'.tr(),
|
||||
subtitle: isBackupInitialized ? 'backup.card_subtitle'.tr() : '',
|
||||
onTap: () => context.pushRoute(const BackupDetailsRoute()),
|
||||
),
|
||||
_Card(
|
||||
state: isBackupInitialized
|
||||
? StateType.stable
|
||||
: StateType.uninitialized,
|
||||
icon: BrandIcons.save,
|
||||
title: 'backup.card_title'.tr(),
|
||||
subtitle: isBackupInitialized ? 'backup.card_subtitle'.tr() : '',
|
||||
onTap: () => context.pushRoute(const BackupDetailsRoute()),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue