chore: Merge endpoint-errors into master

Reviewed-on: kherel/selfprivacy.org.app#149
Reviewed-by: Inex Code <inex.code@selfprivacy.org>
pull/151/head
NaiJi ✨ 2022-12-09 16:35:51 +02:00
commit 51ca8bce27
25 changed files with 572 additions and 300 deletions

View File

@ -273,6 +273,7 @@
"place_where_data": "A place where your data and SelfPrivacy services will reside:", "place_where_data": "A place where your data and SelfPrivacy services will reside:",
"how": "How to obtain API token", "how": "How to obtain API token",
"provider_bad_key_error": "Provider API key is invalid", "provider_bad_key_error": "Provider API key is invalid",
"could_not_connect": "Counldn't connect to the provider.",
"choose_location_type": "Choose your server location and type:", "choose_location_type": "Choose your server location and type:",
"back_to_locations": "Go back to available locations!", "back_to_locations": "Go back to available locations!",
"no_locations_found": "No available locations found. Make sure your account is accessible.", "no_locations_found": "No available locations found. Make sure your account is accessible.",

View File

@ -272,6 +272,7 @@
"place_where_data": "Здесь будут жить ваши данные и SelfPrivacy-сервисы:", "place_where_data": "Здесь будут жить ваши данные и SelfPrivacy-сервисы:",
"how": "Как получить API Token", "how": "Как получить API Token",
"provider_bad_key_error": "API ключ провайдера неверен", "provider_bad_key_error": "API ключ провайдера неверен",
"could_not_connect": "Не удалось соединиться с провайдером.",
"choose_location_type": "Выберите локацию и тип вашего сервера:", "choose_location_type": "Выберите локацию и тип вашего сервера:",
"back_to_locations": "Назад к доступным локациям!", "back_to_locations": "Назад к доступным локациям!",
"no_locations_found": "Не найдено локаций. Убедитесь, что ваш аккаунт доступен.", "no_locations_found": "Не найдено локаций. Убедитесь, что ваш аккаунт доступен.",

View File

@ -0,0 +1,15 @@
class APIGenericResult<T> {
APIGenericResult({
required this.success,
required this.data,
this.message,
this.code,
});
/// Whether was a response successfully received,
/// doesn't represent success of the request if `data<T>` is `bool`
final bool success;
final String? message;
final T data;
final int? code;
}

View File

@ -22,13 +22,13 @@ mixin JobsApi on ApiMap {
return jobsList; return jobsList;
} }
Future<GenericMutationResult<bool>> removeApiJob(final String uid) async { Future<APIGenericResult<bool>> removeApiJob(final String uid) async {
try { try {
final GraphQLClient client = await getClient(); final GraphQLClient client = await getClient();
final variables = Variables$Mutation$RemoveJob(jobId: uid); final variables = Variables$Mutation$RemoveJob(jobId: uid);
final mutation = Options$Mutation$RemoveJob(variables: variables); final mutation = Options$Mutation$RemoveJob(variables: variables);
final response = await client.mutate$RemoveJob(mutation); final response = await client.mutate$RemoveJob(mutation);
return GenericMutationResult( return APIGenericResult(
data: response.parsedData?.removeJob.success ?? false, data: response.parsedData?.removeJob.success ?? false,
success: true, success: true,
code: response.parsedData?.removeJob.code ?? 0, code: response.parsedData?.removeJob.code ?? 0,
@ -36,7 +36,7 @@ mixin JobsApi on ApiMap {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return GenericMutationResult( return APIGenericResult(
data: false, data: false,
success: false, success: false,
code: 0, code: 0,

View File

@ -1,5 +1,6 @@
import 'package:graphql/client.dart'; import 'package:graphql/client.dart';
import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/api_map.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/api_map.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/disk_volumes.graphql.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/disk_volumes.graphql.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/schema.graphql.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/schema.graphql.dart';
@ -22,36 +23,14 @@ import 'package:selfprivacy/logic/models/service.dart';
import 'package:selfprivacy/logic/models/ssh_settings.dart'; import 'package:selfprivacy/logic/models/ssh_settings.dart';
import 'package:selfprivacy/logic/models/system_settings.dart'; import 'package:selfprivacy/logic/models/system_settings.dart';
export 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
part 'jobs_api.dart'; part 'jobs_api.dart';
part 'server_actions_api.dart'; part 'server_actions_api.dart';
part 'services_api.dart'; part 'services_api.dart';
part 'users_api.dart'; part 'users_api.dart';
part 'volume_api.dart'; part 'volume_api.dart';
class GenericResult<T> {
GenericResult({
required this.success,
required this.data,
this.message,
});
/// Whether was a response successfully received,
/// doesn't represent success of the request if `data<T>` is `bool`
final bool success;
final String? message;
final T data;
}
class GenericMutationResult<T> extends GenericResult<T> {
GenericMutationResult({
required super.success,
required this.code,
required super.data,
super.message,
});
final int code;
}
class ServerApi extends ApiMap class ServerApi extends ApiMap
with VolumeApi, JobsApi, ServerActionsApi, ServicesApi, UsersApi { with VolumeApi, JobsApi, ServerActionsApi, ServicesApi, UsersApi {
ServerApi({ ServerApi({
@ -206,7 +185,7 @@ class ServerApi extends ApiMap
return settings; return settings;
} }
Future<GenericResult<RecoveryKeyStatus?>> getRecoveryTokenStatus() async { Future<APIGenericResult<RecoveryKeyStatus?>> getRecoveryTokenStatus() async {
RecoveryKeyStatus? key; RecoveryKeyStatus? key;
QueryResult<Query$RecoveryKey> response; QueryResult<Query$RecoveryKey> response;
String? error; String? error;
@ -223,18 +202,18 @@ class ServerApi extends ApiMap
print(e); print(e);
} }
return GenericResult<RecoveryKeyStatus?>( return APIGenericResult<RecoveryKeyStatus?>(
success: error == null, success: error == null,
data: key, data: key,
message: error, message: error,
); );
} }
Future<GenericResult<String>> generateRecoveryToken( Future<APIGenericResult<String>> generateRecoveryToken(
final DateTime? expirationDate, final DateTime? expirationDate,
final int? numberOfUses, final int? numberOfUses,
) async { ) async {
GenericResult<String> key; APIGenericResult<String> key;
QueryResult<Mutation$GetNewRecoveryApiKey> response; QueryResult<Mutation$GetNewRecoveryApiKey> response;
try { try {
@ -255,19 +234,19 @@ class ServerApi extends ApiMap
); );
if (response.hasException) { if (response.hasException) {
print(response.exception.toString()); print(response.exception.toString());
key = GenericResult<String>( key = APIGenericResult<String>(
success: false, success: false,
data: '', data: '',
message: response.exception.toString(), message: response.exception.toString(),
); );
} }
key = GenericResult<String>( key = APIGenericResult<String>(
success: true, success: true,
data: response.parsedData!.getNewRecoveryApiKey.key!, data: response.parsedData!.getNewRecoveryApiKey.key!,
); );
} catch (e) { } catch (e) {
print(e); print(e);
key = GenericResult<String>( key = APIGenericResult<String>(
success: false, success: false,
data: '', data: '',
message: e.toString(), message: e.toString(),
@ -300,8 +279,8 @@ class ServerApi extends ApiMap
return records; return records;
} }
Future<GenericResult<List<ApiToken>>> getApiTokens() async { Future<APIGenericResult<List<ApiToken>>> getApiTokens() async {
GenericResult<List<ApiToken>> tokens; APIGenericResult<List<ApiToken>> tokens;
QueryResult<Query$GetApiTokens> response; QueryResult<Query$GetApiTokens> response;
try { try {
@ -310,7 +289,7 @@ class ServerApi extends ApiMap
if (response.hasException) { if (response.hasException) {
final message = response.exception.toString(); final message = response.exception.toString();
print(message); print(message);
tokens = GenericResult<List<ApiToken>>( tokens = APIGenericResult<List<ApiToken>>(
success: false, success: false,
data: [], data: [],
message: message, message: message,
@ -324,13 +303,13 @@ class ServerApi extends ApiMap
ApiToken.fromGraphQL(device), ApiToken.fromGraphQL(device),
) )
.toList(); .toList();
tokens = GenericResult<List<ApiToken>>( tokens = APIGenericResult<List<ApiToken>>(
success: true, success: true,
data: parsed, data: parsed,
); );
} catch (e) { } catch (e) {
print(e); print(e);
tokens = GenericResult<List<ApiToken>>( tokens = APIGenericResult<List<ApiToken>>(
success: false, success: false,
data: [], data: [],
message: e.toString(), message: e.toString(),
@ -340,8 +319,8 @@ class ServerApi extends ApiMap
return tokens; return tokens;
} }
Future<GenericResult<void>> deleteApiToken(final String name) async { Future<APIGenericResult<void>> deleteApiToken(final String name) async {
GenericResult<void> returnable; APIGenericResult<void> returnable;
QueryResult<Mutation$DeleteDeviceApiToken> response; QueryResult<Mutation$DeleteDeviceApiToken> response;
try { try {
@ -358,19 +337,19 @@ class ServerApi extends ApiMap
); );
if (response.hasException) { if (response.hasException) {
print(response.exception.toString()); print(response.exception.toString());
returnable = GenericResult<void>( returnable = APIGenericResult<void>(
success: false, success: false,
data: null, data: null,
message: response.exception.toString(), message: response.exception.toString(),
); );
} }
returnable = GenericResult<void>( returnable = APIGenericResult<void>(
success: true, success: true,
data: null, data: null,
); );
} catch (e) { } catch (e) {
print(e); print(e);
returnable = GenericResult<void>( returnable = APIGenericResult<void>(
success: false, success: false,
data: null, data: null,
message: e.toString(), message: e.toString(),
@ -380,8 +359,8 @@ class ServerApi extends ApiMap
return returnable; return returnable;
} }
Future<GenericResult<String>> createDeviceToken() async { Future<APIGenericResult<String>> createDeviceToken() async {
GenericResult<String> token; APIGenericResult<String> token;
QueryResult<Mutation$GetNewDeviceApiKey> response; QueryResult<Mutation$GetNewDeviceApiKey> response;
try { try {
@ -393,19 +372,19 @@ class ServerApi extends ApiMap
); );
if (response.hasException) { if (response.hasException) {
print(response.exception.toString()); print(response.exception.toString());
token = GenericResult<String>( token = APIGenericResult<String>(
success: false, success: false,
data: '', data: '',
message: response.exception.toString(), message: response.exception.toString(),
); );
} }
token = GenericResult<String>( token = APIGenericResult<String>(
success: true, success: true,
data: response.parsedData!.getNewDeviceApiKey.key!, data: response.parsedData!.getNewDeviceApiKey.key!,
); );
} catch (e) { } catch (e) {
print(e); print(e);
token = GenericResult<String>( token = APIGenericResult<String>(
success: false, success: false,
data: '', data: '',
message: e.toString(), message: e.toString(),
@ -417,10 +396,10 @@ class ServerApi extends ApiMap
Future<bool> isHttpServerWorking() async => (await getApiVersion()) != null; Future<bool> isHttpServerWorking() async => (await getApiVersion()) != null;
Future<GenericResult<String>> authorizeDevice( Future<APIGenericResult<String>> authorizeDevice(
final DeviceToken deviceToken, final DeviceToken deviceToken,
) async { ) async {
GenericResult<String> token; APIGenericResult<String> token;
QueryResult<Mutation$AuthorizeWithNewDeviceApiKey> response; QueryResult<Mutation$AuthorizeWithNewDeviceApiKey> response;
try { try {
@ -442,19 +421,19 @@ class ServerApi extends ApiMap
); );
if (response.hasException) { if (response.hasException) {
print(response.exception.toString()); print(response.exception.toString());
token = GenericResult<String>( token = APIGenericResult<String>(
success: false, success: false,
data: '', data: '',
message: response.exception.toString(), message: response.exception.toString(),
); );
} }
token = GenericResult<String>( token = APIGenericResult<String>(
success: true, success: true,
data: response.parsedData!.authorizeWithNewDeviceApiKey.token!, data: response.parsedData!.authorizeWithNewDeviceApiKey.token!,
); );
} catch (e) { } catch (e) {
print(e); print(e);
token = GenericResult<String>( token = APIGenericResult<String>(
success: false, success: false,
data: '', data: '',
message: e.toString(), message: e.toString(),
@ -464,10 +443,10 @@ class ServerApi extends ApiMap
return token; return token;
} }
Future<GenericResult<String>> useRecoveryToken( Future<APIGenericResult<String>> useRecoveryToken(
final DeviceToken deviceToken, final DeviceToken deviceToken,
) async { ) async {
GenericResult<String> token; APIGenericResult<String> token;
QueryResult<Mutation$UseRecoveryApiKey> response; QueryResult<Mutation$UseRecoveryApiKey> response;
try { try {
@ -489,19 +468,19 @@ class ServerApi extends ApiMap
); );
if (response.hasException) { if (response.hasException) {
print(response.exception.toString()); print(response.exception.toString());
token = GenericResult<String>( token = APIGenericResult<String>(
success: false, success: false,
data: '', data: '',
message: response.exception.toString(), message: response.exception.toString(),
); );
} }
token = GenericResult<String>( token = APIGenericResult<String>(
success: true, success: true,
data: response.parsedData!.useRecoveryApiKey.token!, data: response.parsedData!.useRecoveryApiKey.token!,
); );
} catch (e) { } catch (e) {
print(e); print(e);
token = GenericResult<String>( token = APIGenericResult<String>(
success: false, success: false,
data: '', data: '',
message: e.toString(), message: e.toString(),

View File

@ -20,7 +20,7 @@ mixin ServicesApi on ApiMap {
return services; return services;
} }
Future<GenericMutationResult<bool>> enableService( Future<APIGenericResult<bool>> enableService(
final String serviceId, final String serviceId,
) async { ) async {
try { try {
@ -28,7 +28,7 @@ mixin ServicesApi on ApiMap {
final variables = Variables$Mutation$EnableService(serviceId: serviceId); final variables = Variables$Mutation$EnableService(serviceId: serviceId);
final mutation = Options$Mutation$EnableService(variables: variables); final mutation = Options$Mutation$EnableService(variables: variables);
final response = await client.mutate$EnableService(mutation); final response = await client.mutate$EnableService(mutation);
return GenericMutationResult( return APIGenericResult(
data: response.parsedData?.enableService.success ?? false, data: response.parsedData?.enableService.success ?? false,
success: true, success: true,
code: response.parsedData?.enableService.code ?? 0, code: response.parsedData?.enableService.code ?? 0,
@ -36,7 +36,7 @@ mixin ServicesApi on ApiMap {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return GenericMutationResult( return APIGenericResult(
data: false, data: false,
success: false, success: false,
code: 0, code: 0,
@ -45,7 +45,7 @@ mixin ServicesApi on ApiMap {
} }
} }
Future<GenericMutationResult<void>> disableService( Future<APIGenericResult<void>> disableService(
final String serviceId, final String serviceId,
) async { ) async {
try { try {
@ -53,7 +53,7 @@ mixin ServicesApi on ApiMap {
final variables = Variables$Mutation$DisableService(serviceId: serviceId); final variables = Variables$Mutation$DisableService(serviceId: serviceId);
final mutation = Options$Mutation$DisableService(variables: variables); final mutation = Options$Mutation$DisableService(variables: variables);
final response = await client.mutate$DisableService(mutation); final response = await client.mutate$DisableService(mutation);
return GenericMutationResult( return APIGenericResult(
data: null, data: null,
success: response.parsedData?.disableService.success ?? false, success: response.parsedData?.disableService.success ?? false,
code: response.parsedData?.disableService.code ?? 0, code: response.parsedData?.disableService.code ?? 0,
@ -61,7 +61,7 @@ mixin ServicesApi on ApiMap {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return GenericMutationResult( return APIGenericResult(
data: null, data: null,
success: false, success: false,
code: 0, code: 0,
@ -70,7 +70,7 @@ mixin ServicesApi on ApiMap {
} }
} }
Future<GenericMutationResult<bool>> stopService( Future<APIGenericResult<bool>> stopService(
final String serviceId, final String serviceId,
) async { ) async {
try { try {
@ -78,7 +78,7 @@ mixin ServicesApi on ApiMap {
final variables = Variables$Mutation$StopService(serviceId: serviceId); final variables = Variables$Mutation$StopService(serviceId: serviceId);
final mutation = Options$Mutation$StopService(variables: variables); final mutation = Options$Mutation$StopService(variables: variables);
final response = await client.mutate$StopService(mutation); final response = await client.mutate$StopService(mutation);
return GenericMutationResult( return APIGenericResult(
data: response.parsedData?.stopService.success ?? false, data: response.parsedData?.stopService.success ?? false,
success: true, success: true,
code: response.parsedData?.stopService.code ?? 0, code: response.parsedData?.stopService.code ?? 0,
@ -86,7 +86,7 @@ mixin ServicesApi on ApiMap {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return GenericMutationResult( return APIGenericResult(
data: false, data: false,
success: false, success: false,
code: 0, code: 0,
@ -95,13 +95,13 @@ mixin ServicesApi on ApiMap {
} }
} }
Future<GenericMutationResult> startService(final String serviceId) async { Future<APIGenericResult> startService(final String serviceId) async {
try { try {
final GraphQLClient client = await getClient(); final GraphQLClient client = await getClient();
final variables = Variables$Mutation$StartService(serviceId: serviceId); final variables = Variables$Mutation$StartService(serviceId: serviceId);
final mutation = Options$Mutation$StartService(variables: variables); final mutation = Options$Mutation$StartService(variables: variables);
final response = await client.mutate$StartService(mutation); final response = await client.mutate$StartService(mutation);
return GenericMutationResult( return APIGenericResult(
data: null, data: null,
success: response.parsedData?.startService.success ?? false, success: response.parsedData?.startService.success ?? false,
code: response.parsedData?.startService.code ?? 0, code: response.parsedData?.startService.code ?? 0,
@ -109,7 +109,7 @@ mixin ServicesApi on ApiMap {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return GenericMutationResult( return APIGenericResult(
data: null, data: null,
success: false, success: false,
code: 0, code: 0,
@ -118,7 +118,7 @@ mixin ServicesApi on ApiMap {
} }
} }
Future<GenericMutationResult<bool>> restartService( Future<APIGenericResult<bool>> restartService(
final String serviceId, final String serviceId,
) async { ) async {
try { try {
@ -126,7 +126,7 @@ mixin ServicesApi on ApiMap {
final variables = Variables$Mutation$RestartService(serviceId: serviceId); final variables = Variables$Mutation$RestartService(serviceId: serviceId);
final mutation = Options$Mutation$RestartService(variables: variables); final mutation = Options$Mutation$RestartService(variables: variables);
final response = await client.mutate$RestartService(mutation); final response = await client.mutate$RestartService(mutation);
return GenericMutationResult( return APIGenericResult(
data: response.parsedData?.restartService.success ?? false, data: response.parsedData?.restartService.success ?? false,
success: true, success: true,
code: response.parsedData?.restartService.code ?? 0, code: response.parsedData?.restartService.code ?? 0,
@ -134,7 +134,7 @@ mixin ServicesApi on ApiMap {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return GenericMutationResult( return APIGenericResult(
data: false, data: false,
success: false, success: false,
code: 0, code: 0,
@ -143,7 +143,7 @@ mixin ServicesApi on ApiMap {
} }
} }
Future<GenericMutationResult<ServerJob?>> moveService( Future<APIGenericResult<ServerJob?>> moveService(
final String serviceId, final String serviceId,
final String destination, final String destination,
) async { ) async {
@ -158,7 +158,7 @@ mixin ServicesApi on ApiMap {
final mutation = Options$Mutation$MoveService(variables: variables); final mutation = Options$Mutation$MoveService(variables: variables);
final response = await client.mutate$MoveService(mutation); final response = await client.mutate$MoveService(mutation);
final jobJson = response.parsedData?.moveService.job?.toJson(); final jobJson = response.parsedData?.moveService.job?.toJson();
return GenericMutationResult( return APIGenericResult(
success: true, success: true,
code: response.parsedData?.moveService.code ?? 0, code: response.parsedData?.moveService.code ?? 0,
message: response.parsedData?.moveService.message, message: response.parsedData?.moveService.message,
@ -166,7 +166,7 @@ mixin ServicesApi on ApiMap {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return GenericMutationResult( return APIGenericResult(
success: false, success: false,
code: 0, code: 0,
message: e.toString(), message: e.toString(),

View File

@ -45,7 +45,7 @@ mixin UsersApi on ApiMap {
return user; return user;
} }
Future<GenericMutationResult<User?>> createUser( Future<APIGenericResult<User?>> createUser(
final String username, final String username,
final String password, final String password,
) async { ) async {
@ -56,7 +56,7 @@ mixin UsersApi on ApiMap {
); );
final mutation = Options$Mutation$CreateUser(variables: variables); final mutation = Options$Mutation$CreateUser(variables: variables);
final response = await client.mutate$CreateUser(mutation); final response = await client.mutate$CreateUser(mutation);
return GenericMutationResult( return APIGenericResult(
success: true, success: true,
code: response.parsedData?.createUser.code ?? 500, code: response.parsedData?.createUser.code ?? 500,
message: response.parsedData?.createUser.message, message: response.parsedData?.createUser.message,
@ -66,7 +66,7 @@ mixin UsersApi on ApiMap {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return GenericMutationResult( return APIGenericResult(
success: false, success: false,
code: 0, code: 0,
message: e.toString(), message: e.toString(),
@ -75,7 +75,7 @@ mixin UsersApi on ApiMap {
} }
} }
Future<GenericMutationResult<bool>> deleteUser( Future<APIGenericResult<bool>> deleteUser(
final String username, final String username,
) async { ) async {
try { try {
@ -83,7 +83,7 @@ mixin UsersApi on ApiMap {
final variables = Variables$Mutation$DeleteUser(username: username); final variables = Variables$Mutation$DeleteUser(username: username);
final mutation = Options$Mutation$DeleteUser(variables: variables); final mutation = Options$Mutation$DeleteUser(variables: variables);
final response = await client.mutate$DeleteUser(mutation); final response = await client.mutate$DeleteUser(mutation);
return GenericMutationResult( return APIGenericResult(
data: response.parsedData?.deleteUser.success ?? false, data: response.parsedData?.deleteUser.success ?? false,
success: true, success: true,
code: response.parsedData?.deleteUser.code ?? 500, code: response.parsedData?.deleteUser.code ?? 500,
@ -91,7 +91,7 @@ mixin UsersApi on ApiMap {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return GenericMutationResult( return APIGenericResult(
data: false, data: false,
success: false, success: false,
code: 500, code: 500,
@ -100,7 +100,7 @@ mixin UsersApi on ApiMap {
} }
} }
Future<GenericMutationResult<User?>> updateUser( Future<APIGenericResult<User?>> updateUser(
final String username, final String username,
final String password, final String password,
) async { ) async {
@ -111,7 +111,7 @@ mixin UsersApi on ApiMap {
); );
final mutation = Options$Mutation$UpdateUser(variables: variables); final mutation = Options$Mutation$UpdateUser(variables: variables);
final response = await client.mutate$UpdateUser(mutation); final response = await client.mutate$UpdateUser(mutation);
return GenericMutationResult( return APIGenericResult(
success: true, success: true,
code: response.parsedData?.updateUser.code ?? 500, code: response.parsedData?.updateUser.code ?? 500,
message: response.parsedData?.updateUser.message, message: response.parsedData?.updateUser.message,
@ -121,7 +121,7 @@ mixin UsersApi on ApiMap {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return GenericMutationResult( return APIGenericResult(
data: null, data: null,
success: false, success: false,
code: 0, code: 0,
@ -130,7 +130,7 @@ mixin UsersApi on ApiMap {
} }
} }
Future<GenericMutationResult<User?>> addSshKey( Future<APIGenericResult<User?>> addSshKey(
final String username, final String username,
final String sshKey, final String sshKey,
) async { ) async {
@ -144,7 +144,7 @@ mixin UsersApi on ApiMap {
); );
final mutation = Options$Mutation$AddSshKey(variables: variables); final mutation = Options$Mutation$AddSshKey(variables: variables);
final response = await client.mutate$AddSshKey(mutation); final response = await client.mutate$AddSshKey(mutation);
return GenericMutationResult( return APIGenericResult(
success: true, success: true,
code: response.parsedData?.addSshKey.code ?? 500, code: response.parsedData?.addSshKey.code ?? 500,
message: response.parsedData?.addSshKey.message, message: response.parsedData?.addSshKey.message,
@ -154,7 +154,7 @@ mixin UsersApi on ApiMap {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return GenericMutationResult( return APIGenericResult(
data: null, data: null,
success: false, success: false,
code: 0, code: 0,
@ -163,7 +163,7 @@ mixin UsersApi on ApiMap {
} }
} }
Future<GenericMutationResult<User?>> removeSshKey( Future<APIGenericResult<User?>> removeSshKey(
final String username, final String username,
final String sshKey, final String sshKey,
) async { ) async {
@ -177,7 +177,7 @@ mixin UsersApi on ApiMap {
); );
final mutation = Options$Mutation$RemoveSshKey(variables: variables); final mutation = Options$Mutation$RemoveSshKey(variables: variables);
final response = await client.mutate$RemoveSshKey(mutation); final response = await client.mutate$RemoveSshKey(mutation);
return GenericMutationResult( return APIGenericResult(
success: response.parsedData?.removeSshKey.success ?? false, success: response.parsedData?.removeSshKey.success ?? false,
code: response.parsedData?.removeSshKey.code ?? 500, code: response.parsedData?.removeSshKey.code ?? 500,
message: response.parsedData?.removeSshKey.message, message: response.parsedData?.removeSshKey.message,
@ -187,7 +187,7 @@ mixin UsersApi on ApiMap {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return GenericMutationResult( return APIGenericResult(
data: null, data: null,
success: false, success: false,
code: 0, code: 0,

View File

@ -57,10 +57,10 @@ mixin VolumeApi on ApiMap {
} }
} }
Future<GenericMutationResult<String?>> migrateToBinds( Future<APIGenericResult<String?>> migrateToBinds(
final Map<String, String> serviceToDisk, final Map<String, String> serviceToDisk,
) async { ) async {
GenericMutationResult<String?>? mutation; APIGenericResult<String?>? mutation;
try { try {
final GraphQLClient client = await getClient(); final GraphQLClient client = await getClient();
@ -78,7 +78,7 @@ mixin VolumeApi on ApiMap {
await client.mutate$MigrateToBinds( await client.mutate$MigrateToBinds(
migrateMutation, migrateMutation,
); );
mutation = mutation = GenericMutationResult( mutation = mutation = APIGenericResult(
success: true, success: true,
code: result.parsedData!.migrateToBinds.code, code: result.parsedData!.migrateToBinds.code,
message: result.parsedData!.migrateToBinds.message, message: result.parsedData!.migrateToBinds.message,
@ -86,7 +86,7 @@ mixin VolumeApi on ApiMap {
); );
} catch (e) { } catch (e) {
print(e); print(e);
mutation = GenericMutationResult( mutation = APIGenericResult(
success: false, success: false,
code: 0, code: 0,
message: e.toString(), message: e.toString(),

View File

@ -2,9 +2,12 @@ import 'dart:io';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/api_map.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/api_map.dart';
import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart'; import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart';
export 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
class BackblazeApiAuth { class BackblazeApiAuth {
BackblazeApiAuth({required this.authorizationToken, required this.apiUrl}); BackblazeApiAuth({required this.authorizationToken, required this.apiUrl});
@ -71,28 +74,43 @@ class BackblazeApi extends ApiMap {
); );
} }
Future<bool> isValid(final String encodedApiKey) async { Future<APIGenericResult<bool>> isApiTokenValid(
final String encodedApiKey,
) async {
final Dio client = await getClient(); final Dio client = await getClient();
bool isTokenValid = false;
try { try {
final Response response = await client.get( final Response response = await client.get(
'b2_authorize_account', 'b2_authorize_account',
options: Options(headers: {'Authorization': 'Basic $encodedApiKey'}), options: Options(
followRedirects: false,
validateStatus: (final status) =>
status != null && (status >= 200 || status == 401),
headers: {'Authorization': 'Basic $encodedApiKey'},
),
); );
if (response.statusCode == HttpStatus.ok) { if (response.statusCode == HttpStatus.ok) {
if (response.data['allowed']['capabilities'].contains('listBuckets')) { isTokenValid = response.data['allowed']['capabilities'].contains('listBuckets');
return true;
}
return false;
} else if (response.statusCode == HttpStatus.unauthorized) { } else if (response.statusCode == HttpStatus.unauthorized) {
return false; isTokenValid = false;
} else { } else {
throw Exception('code: ${response.statusCode}'); throw Exception('code: ${response.statusCode}');
} }
} on DioError { } on DioError catch (e) {
return false; print(e);
return APIGenericResult(
data: false,
success: false,
message: e.toString(),
);
} finally { } finally {
close(client); close(client);
} }
return APIGenericResult(
data: isTokenValid,
success: true,
);
} }
// Create bucket // Create bucket

View File

@ -46,33 +46,50 @@ class CloudflareApi extends DnsProviderApi {
String rootAddress = 'https://api.cloudflare.com/client/v4'; String rootAddress = 'https://api.cloudflare.com/client/v4';
@override @override
Future<bool> isApiTokenValid(final String token) async { Future<APIGenericResult<bool>> isApiTokenValid(final String token) async {
bool isValid = false; bool isValid = false;
Response? response; Response? response;
String message = '';
final Dio client = await getClient(); final Dio client = await getClient();
try { try {
response = await client.get( response = await client.get(
'/user/tokens/verify', '/user/tokens/verify',
options: Options(headers: {'Authorization': 'Bearer $token'}), options: Options(
followRedirects: false,
validateStatus: (final status) =>
status != null && (status >= 200 || status == 401),
headers: {'Authorization': 'Bearer $token'},
),
); );
} catch (e) { } catch (e) {
print(e); print(e);
isValid = false; isValid = false;
message = e.toString();
} finally { } finally {
close(client); close(client);
} }
if (response != null) { if (response == null) {
if (response.statusCode == HttpStatus.ok) { return APIGenericResult(
isValid = true; data: isValid,
} else if (response.statusCode == HttpStatus.unauthorized) { success: false,
isValid = false; message: message,
} else { );
throw Exception('code: ${response.statusCode}');
}
} }
return isValid; if (response.statusCode == HttpStatus.ok) {
isValid = true;
} else if (response.statusCode == HttpStatus.unauthorized) {
isValid = false;
} else {
throw Exception('code: ${response.statusCode}');
}
return APIGenericResult(
data: isValid,
success: true,
message: response.statusMessage,
);
} }
@override @override
@ -96,7 +113,7 @@ class CloudflareApi extends DnsProviderApi {
} }
@override @override
Future<void> removeSimilarRecords({ Future<APIGenericResult<void>> removeSimilarRecords({
required final ServerDomain domain, required final ServerDomain domain,
final String? ip4, final String? ip4,
}) async { }) async {
@ -122,9 +139,16 @@ class CloudflareApi extends DnsProviderApi {
await Future.wait(allDeleteFutures); await Future.wait(allDeleteFutures);
} catch (e) { } catch (e) {
print(e); print(e);
return APIGenericResult(
success: false,
data: null,
message: e.toString(),
);
} finally { } finally {
close(client); close(client);
} }
return APIGenericResult(success: true, data: null);
} }
@override @override
@ -166,7 +190,7 @@ class CloudflareApi extends DnsProviderApi {
} }
@override @override
Future<void> createMultipleDnsRecords({ Future<APIGenericResult<void>> createMultipleDnsRecords({
required final ServerDomain domain, required final ServerDomain domain,
final String? ip4, final String? ip4,
}) async { }) async {
@ -189,9 +213,18 @@ class CloudflareApi extends DnsProviderApi {
} on DioError catch (e) { } on DioError catch (e) {
print(e.message); print(e.message);
rethrow; rethrow;
} catch (e) {
print(e);
return APIGenericResult(
success: false,
data: null,
message: e.toString(),
);
} finally { } finally {
close(client); close(client);
} }
return APIGenericResult(success: true, data: null);
} }
List<DnsRecord> projectDnsRecords( List<DnsRecord> projectDnsRecords(

View File

@ -1,7 +1,10 @@
import 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/api_map.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/api_map.dart';
import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/hive/server_domain.dart';
import 'package:selfprivacy/logic/models/json/dns_records.dart'; import 'package:selfprivacy/logic/models/json/dns_records.dart';
export 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
class DomainNotFoundException implements Exception { class DomainNotFoundException implements Exception {
DomainNotFoundException(this.message); DomainNotFoundException(this.message);
final String message; final String message;
@ -11,11 +14,11 @@ abstract class DnsProviderApi extends ApiMap {
Future<List<DnsRecord>> getDnsRecords({ Future<List<DnsRecord>> getDnsRecords({
required final ServerDomain domain, required final ServerDomain domain,
}); });
Future<void> removeSimilarRecords({ Future<APIGenericResult<void>> removeSimilarRecords({
required final ServerDomain domain, required final ServerDomain domain,
final String? ip4, final String? ip4,
}); });
Future<void> createMultipleDnsRecords({ Future<APIGenericResult<void>> createMultipleDnsRecords({
required final ServerDomain domain, required final ServerDomain domain,
final String? ip4, final String? ip4,
}); });
@ -26,6 +29,6 @@ abstract class DnsProviderApi extends ApiMap {
Future<String?> getZoneId(final String domain); Future<String?> getZoneId(final String domain);
Future<List<String>> domainList(); Future<List<String>> domainList();
Future<bool> isApiTokenValid(final String token); Future<APIGenericResult<bool>> isApiTokenValid(final String token);
RegExp getApiTokenValidation(); RegExp getApiTokenValidation();
} }

View File

@ -59,35 +59,50 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
String get displayProviderName => 'Digital Ocean'; String get displayProviderName => 'Digital Ocean';
@override @override
Future<bool> isApiTokenValid(final String token) async { Future<APIGenericResult<bool>> isApiTokenValid(final String token) async {
bool isValid = false; bool isValid = false;
Response? response; Response? response;
String message = '';
final Dio client = await getClient(); final Dio client = await getClient();
try { try {
response = await client.get( response = await client.get(
'/account', '/account',
options: Options( options: Options(
followRedirects: false,
validateStatus: (final status) =>
status != null && (status >= 200 || status == 401),
headers: {'Authorization': 'Bearer $token'}, headers: {'Authorization': 'Bearer $token'},
), ),
); );
} catch (e) { } catch (e) {
print(e); print(e);
isValid = false; isValid = false;
message = e.toString();
} finally { } finally {
close(client); close(client);
} }
if (response != null) { if (response == null) {
if (response.statusCode == HttpStatus.ok) { return APIGenericResult(
isValid = true; data: isValid,
} else if (response.statusCode == HttpStatus.unauthorized) { success: false,
isValid = false; message: message,
} else { );
throw Exception('code: ${response.statusCode}');
}
} }
return isValid; if (response.statusCode == HttpStatus.ok) {
isValid = true;
} else if (response.statusCode == HttpStatus.unauthorized) {
isValid = false;
} else {
throw Exception('code: ${response.statusCode}');
}
return APIGenericResult(
data: isValid,
success: true,
message: response.statusMessage,
);
} }
/// Hardcoded on their documentation and there is no pricing API at all /// Hardcoded on their documentation and there is no pricing API at all
@ -99,10 +114,10 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
); );
@override @override
Future<ServerVolume?> createVolume() async { Future<APIGenericResult<ServerVolume?>> createVolume() async {
ServerVolume? volume; ServerVolume? volume;
final Response createVolumeResponse; Response? createVolumeResponse;
final Dio client = await getClient(); final Dio client = await getClient();
try { try {
final List<ServerVolume> volumes = await getVolumes(); final List<ServerVolume> volumes = await getVolumes();
@ -131,11 +146,21 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return APIGenericResult(
data: null,
success: false,
message: e.toString(),
);
} finally { } finally {
client.close(); client.close();
} }
return volume; return APIGenericResult(
data: volume,
success: true,
code: createVolumeResponse.statusCode,
message: createVolumeResponse.statusMessage,
);
} }
@override @override
@ -204,13 +229,13 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
} }
@override @override
Future<bool> attachVolume( Future<APIGenericResult<bool>> attachVolume(
final ServerVolume volume, final ServerVolume volume,
final int serverId, final int serverId,
) async { ) async {
bool success = false; bool success = false;
final Response attachVolumeResponse; Response? attachVolumeResponse;
final Dio client = await getClient(); final Dio client = await getClient();
try { try {
attachVolumeResponse = await client.post( attachVolumeResponse = await client.post(
@ -226,11 +251,21 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
attachVolumeResponse.data['action']['status'].toString() != 'error'; attachVolumeResponse.data['action']['status'].toString() != 'error';
} catch (e) { } catch (e) {
print(e); print(e);
return APIGenericResult(
data: false,
success: false,
message: e.toString(),
);
} finally { } finally {
close(client); close(client);
} }
return success; return APIGenericResult(
data: success,
success: true,
code: attachVolumeResponse.statusCode,
message: attachVolumeResponse.statusMessage,
);
} }
@override @override
@ -308,7 +343,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
} }
@override @override
Future<ServerHostingDetails?> createServer({ Future<APIGenericResult<ServerHostingDetails?>> createServer({
required final String dnsApiToken, required final String dnsApiToken,
required final User rootUser, required final User rootUser,
required final String domainName, required final String domainName,
@ -330,6 +365,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
"#cloud-config\nruncmd:\n- curl https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-infect/raw/branch/$infectBranch/nixos-infect | PROVIDER=$infectProviderName STAGING_ACME='$stagingAcme' DOMAIN='$domainName' LUSER='${rootUser.login}' ENCODED_PASSWORD='$base64Password' CF_TOKEN=$dnsApiToken DB_PASSWORD=$dbPassword API_TOKEN=$apiToken HOSTNAME=$formattedHostname bash 2>&1 | tee /tmp/infect.log"; "#cloud-config\nruncmd:\n- curl https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-infect/raw/branch/$infectBranch/nixos-infect | PROVIDER=$infectProviderName STAGING_ACME='$stagingAcme' DOMAIN='$domainName' LUSER='${rootUser.login}' ENCODED_PASSWORD='$base64Password' CF_TOKEN=$dnsApiToken DB_PASSWORD=$dbPassword API_TOKEN=$apiToken HOSTNAME=$formattedHostname bash 2>&1 | tee /tmp/infect.log";
print(userdataString); print(userdataString);
Response? serverCreateResponse;
final Dio client = await getClient(); final Dio client = await getClient();
try { try {
final Map<String, Object> data = { final Map<String, Object> data = {
@ -341,14 +377,15 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
}; };
print('Decoded data: $data'); print('Decoded data: $data');
final Response serverCreateResponse = await client.post( serverCreateResponse = await client.post(
'/droplets', '/droplets',
data: data, data: data,
); );
final int serverId = serverCreateResponse.data['droplet']['id']; final int serverId = serverCreateResponse.data['droplet']['id'];
final ServerVolume? newVolume = await createVolume(); final ServerVolume? newVolume = (await createVolume()).data;
final bool attachedVolume = await attachVolume(newVolume!, serverId); final bool attachedVolume =
(await attachVolume(newVolume!, serverId)).data;
String? ipv4; String? ipv4;
int attempts = 0; int attempts = 0;
@ -376,11 +413,21 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
} }
} catch (e) { } catch (e) {
print(e); print(e);
return APIGenericResult(
success: false,
data: null,
message: e.toString(),
);
} finally { } finally {
close(client); close(client);
} }
return serverDetails; return APIGenericResult(
data: serverDetails,
success: true,
code: serverCreateResponse.statusCode,
message: serverCreateResponse.statusMessage,
);
} }
@override @override
@ -694,7 +741,8 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
} }
@override @override
Future<List<ServerProviderLocation>> getAvailableLocations() async { Future<APIGenericResult<List<ServerProviderLocation>>>
getAvailableLocations() async {
List<ServerProviderLocation> locations = []; List<ServerProviderLocation> locations = [];
final Dio client = await getClient(); final Dio client = await getClient();
@ -715,15 +763,20 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
.toList(); .toList();
} catch (e) { } catch (e) {
print(e); print(e);
return APIGenericResult(
data: [],
success: false,
message: e.toString(),
);
} finally { } finally {
close(client); close(client);
} }
return locations; return APIGenericResult(data: locations, success: true);
} }
@override @override
Future<List<ServerType>> getServerTypesByLocation({ Future<APIGenericResult<List<ServerType>>> getServerTypesByLocation({
required final ServerProviderLocation location, required final ServerProviderLocation location,
}) async { }) async {
final List<ServerType> types = []; final List<ServerType> types = [];
@ -756,19 +809,26 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
} }
} catch (e) { } catch (e) {
print(e); print(e);
return APIGenericResult(
data: [],
success: false,
message: e.toString(),
);
} finally { } finally {
close(client); close(client);
} }
return types; return APIGenericResult(data: types, success: true);
} }
@override @override
Future<void> createReverseDns({ Future<APIGenericResult<void>> createReverseDns({
required final ServerHostingDetails serverDetails, required final ServerHostingDetails serverDetails,
required final ServerDomain domain, required final ServerDomain domain,
}) async { }) async {
/// TODO remove from provider interface /// TODO remove from provider interface
const bool success = true;
return APIGenericResult(success: success, data: null);
} }
@override @override

View File

@ -60,35 +60,50 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
String get displayProviderName => 'Hetzner'; String get displayProviderName => 'Hetzner';
@override @override
Future<bool> isApiTokenValid(final String token) async { Future<APIGenericResult<bool>> isApiTokenValid(final String token) async {
bool isValid = false; bool isValid = false;
Response? response; Response? response;
String message = '';
final Dio client = await getClient(); final Dio client = await getClient();
try { try {
response = await client.get( response = await client.get(
'/servers', '/servers',
options: Options( options: Options(
followRedirects: false,
validateStatus: (final status) =>
status != null && (status >= 200 || status == 401),
headers: {'Authorization': 'Bearer $token'}, headers: {'Authorization': 'Bearer $token'},
), ),
); );
} catch (e) { } catch (e) {
print(e); print(e);
isValid = false; isValid = false;
message = e.toString();
} finally { } finally {
close(client); close(client);
} }
if (response != null) { if (response == null) {
if (response.statusCode == HttpStatus.ok) { return APIGenericResult(
isValid = true; data: isValid,
} else if (response.statusCode == HttpStatus.unauthorized) { success: false,
isValid = false; message: message,
} else { );
throw Exception('code: ${response.statusCode}');
}
} }
return isValid; if (response.statusCode == HttpStatus.ok) {
isValid = true;
} else if (response.statusCode == HttpStatus.unauthorized) {
isValid = false;
} else {
throw Exception('code: ${response.statusCode}');
}
return APIGenericResult(
data: isValid,
success: true,
message: response.statusMessage,
);
} }
@override @override
@ -125,10 +140,10 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
} }
@override @override
Future<ServerVolume?> createVolume() async { Future<APIGenericResult<ServerVolume?>> createVolume() async {
ServerVolume? volume; ServerVolume? volume;
final Response createVolumeResponse; Response? createVolumeResponse;
final Dio client = await getClient(); final Dio client = await getClient();
try { try {
createVolumeResponse = await client.post( createVolumeResponse = await client.post(
@ -156,11 +171,21 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return APIGenericResult(
data: null,
success: false,
message: e.toString(),
);
} finally { } finally {
client.close(); client.close();
} }
return volume; return APIGenericResult(
data: volume,
success: true,
code: createVolumeResponse.statusCode,
message: createVolumeResponse.statusMessage,
);
} }
@override @override
@ -244,13 +269,13 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
} }
@override @override
Future<bool> attachVolume( Future<APIGenericResult<bool>> attachVolume(
final ServerVolume volume, final ServerVolume volume,
final int serverId, final int serverId,
) async { ) async {
bool success = false; bool success = false;
final Response attachVolumeResponse; Response? attachVolumeResponse;
final Dio client = await getClient(); final Dio client = await getClient();
try { try {
attachVolumeResponse = await client.post( attachVolumeResponse = await client.post(
@ -268,7 +293,12 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
client.close(); client.close();
} }
return success; return APIGenericResult(
data: success,
success: true,
code: attachVolumeResponse?.statusCode,
message: attachVolumeResponse?.statusMessage,
);
} }
@override @override
@ -320,31 +350,33 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
} }
@override @override
Future<ServerHostingDetails?> createServer({ Future<APIGenericResult<ServerHostingDetails?>> createServer({
required final String dnsApiToken, required final String dnsApiToken,
required final User rootUser, required final User rootUser,
required final String domainName, required final String domainName,
required final String serverType, required final String serverType,
}) async { }) async {
ServerHostingDetails? details; final APIGenericResult<ServerVolume?> newVolumeResponse =
await createVolume();
final ServerVolume? newVolume = await createVolume(); if (!newVolumeResponse.success || newVolumeResponse.data == null) {
if (newVolume == null) { return APIGenericResult(
return details; data: null,
success: false,
message: newVolumeResponse.message,
code: newVolumeResponse.code,
);
} }
return createServerWithVolume(
details = await createServerWithVolume(
dnsApiToken: dnsApiToken, dnsApiToken: dnsApiToken,
rootUser: rootUser, rootUser: rootUser,
domainName: domainName, domainName: domainName,
volume: newVolume, volume: newVolumeResponse.data!,
serverType: serverType, serverType: serverType,
); );
return details;
} }
Future<ServerHostingDetails?> createServerWithVolume({ Future<APIGenericResult<ServerHostingDetails?>> createServerWithVolume({
required final String dnsApiToken, required final String dnsApiToken,
required final User rootUser, required final User rootUser,
required final String domainName, required final String domainName,
@ -366,6 +398,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
final String userdataString = final String userdataString =
"#cloud-config\nruncmd:\n- curl https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-infect/raw/branch/$infectBranch/nixos-infect | STAGING_ACME='$stagingAcme' PROVIDER=$infectProviderName NIX_CHANNEL=nixos-21.05 DOMAIN='$domainName' LUSER='${rootUser.login}' ENCODED_PASSWORD='$base64Password' CF_TOKEN=$dnsApiToken DB_PASSWORD=$dbPassword API_TOKEN=$apiToken HOSTNAME=$hostname bash 2>&1 | tee /tmp/infect.log"; "#cloud-config\nruncmd:\n- curl https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-infect/raw/branch/$infectBranch/nixos-infect | STAGING_ACME='$stagingAcme' PROVIDER=$infectProviderName NIX_CHANNEL=nixos-21.05 DOMAIN='$domainName' LUSER='${rootUser.login}' ENCODED_PASSWORD='$base64Password' CF_TOKEN=$dnsApiToken DB_PASSWORD=$dbPassword API_TOKEN=$apiToken HOSTNAME=$hostname bash 2>&1 | tee /tmp/infect.log";
Response? serverCreateResponse;
ServerHostingDetails? serverDetails; ServerHostingDetails? serverDetails;
DioError? hetznerError; DioError? hetznerError;
bool success = false; bool success = false;
@ -385,7 +418,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
}; };
print('Decoded data: $data'); print('Decoded data: $data');
final Response serverCreateResponse = await client.post( serverCreateResponse = await client.post(
'/servers', '/servers',
data: data, data: data,
); );
@ -413,11 +446,19 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
await deleteVolume(volume); await deleteVolume(volume);
} }
if (hetznerError != null) { String? apiResultMessage = serverCreateResponse?.statusMessage;
throw hetznerError; if (hetznerError != null &&
hetznerError.response!.data['error']['code'] == 'uniqueness_error') {
apiResultMessage = 'uniqueness_error';
} }
return serverDetails; return APIGenericResult(
data: serverDetails,
success: success && hetznerError == null,
code: serverCreateResponse?.statusCode ??
hetznerError?.response?.statusCode,
message: apiResultMessage,
);
} }
static String getHostnameFromDomain(final String domain) { static String getHostnameFromDomain(final String domain) {
@ -692,7 +733,8 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
} }
@override @override
Future<List<ServerProviderLocation>> getAvailableLocations() async { Future<APIGenericResult<List<ServerProviderLocation>>>
getAvailableLocations() async {
List<ServerProviderLocation> locations = []; List<ServerProviderLocation> locations = [];
final Dio client = await getClient(); final Dio client = await getClient();
@ -713,15 +755,20 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
.toList(); .toList();
} catch (e) { } catch (e) {
print(e); print(e);
return APIGenericResult(
success: false,
data: [],
message: e.toString(),
);
} finally { } finally {
close(client); close(client);
} }
return locations; return APIGenericResult(success: true, data: locations);
} }
@override @override
Future<List<ServerType>> getServerTypesByLocation({ Future<APIGenericResult<List<ServerType>>> getServerTypesByLocation({
required final ServerProviderLocation location, required final ServerProviderLocation location,
}) async { }) async {
final List<ServerType> types = []; final List<ServerType> types = [];
@ -754,15 +801,20 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
} }
} catch (e) { } catch (e) {
print(e); print(e);
return APIGenericResult(
data: [],
success: false,
message: e.toString(),
);
} finally { } finally {
close(client); close(client);
} }
return types; return APIGenericResult(data: types, success: true);
} }
@override @override
Future<void> createReverseDns({ Future<APIGenericResult<void>> createReverseDns({
required final ServerHostingDetails serverDetails, required final ServerHostingDetails serverDetails,
required final ServerDomain domain, required final ServerDomain domain,
}) async { }) async {
@ -777,8 +829,15 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
); );
} catch (e) { } catch (e) {
print(e); print(e);
return APIGenericResult(
success: false,
data: null,
message: e.toString(),
);
} finally { } finally {
close(client); close(client);
} }
return APIGenericResult(success: true, data: null);
} }
} }

View File

@ -1,3 +1,4 @@
import 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/api_map.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/api_map.dart';
import 'package:selfprivacy/logic/models/hive/server_details.dart'; import 'package:selfprivacy/logic/models/hive/server_details.dart';
import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/hive/server_domain.dart';
@ -8,6 +9,8 @@ import 'package:selfprivacy/logic/models/server_metadata.dart';
import 'package:selfprivacy/logic/models/server_provider_location.dart'; import 'package:selfprivacy/logic/models/server_provider_location.dart';
import 'package:selfprivacy/logic/models/server_type.dart'; import 'package:selfprivacy/logic/models/server_type.dart';
export 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
class ProviderApiTokenValidation { class ProviderApiTokenValidation {
ProviderApiTokenValidation({ ProviderApiTokenValidation({
required this.length, required this.length,
@ -19,8 +22,9 @@ class ProviderApiTokenValidation {
abstract class ServerProviderApi extends ApiMap { abstract class ServerProviderApi extends ApiMap {
Future<List<ServerBasicInfo>> getServers(); Future<List<ServerBasicInfo>> getServers();
Future<List<ServerProviderLocation>> getAvailableLocations(); Future<APIGenericResult<List<ServerProviderLocation>>>
Future<List<ServerType>> getServerTypesByLocation({ getAvailableLocations();
Future<APIGenericResult<List<ServerType>>> getServerTypesByLocation({
required final ServerProviderLocation location, required final ServerProviderLocation location,
}); });
@ -28,18 +32,18 @@ abstract class ServerProviderApi extends ApiMap {
Future<ServerHostingDetails> powerOn(); Future<ServerHostingDetails> powerOn();
Future<void> deleteServer({required final String domainName}); Future<void> deleteServer({required final String domainName});
Future<ServerHostingDetails?> createServer({ Future<APIGenericResult<ServerHostingDetails?>> createServer({
required final String dnsApiToken, required final String dnsApiToken,
required final User rootUser, required final User rootUser,
required final String domainName, required final String domainName,
required final String serverType, required final String serverType,
}); });
Future<void> createReverseDns({ Future<APIGenericResult<void>> createReverseDns({
required final ServerHostingDetails serverDetails, required final ServerHostingDetails serverDetails,
required final ServerDomain domain, required final ServerDomain domain,
}); });
Future<bool> isApiTokenValid(final String token); Future<APIGenericResult<bool>> isApiTokenValid(final String token);
ProviderApiTokenValidation getApiTokenValidation(); ProviderApiTokenValidation getApiTokenValidation();
Future<List<ServerMetadataEntity>> getMetadata(final int serverId); Future<List<ServerMetadataEntity>> getMetadata(final int serverId);
Future<ServerMetrics?> getMetrics( Future<ServerMetrics?> getMetrics(

View File

@ -1,12 +1,18 @@
import 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/api_map.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/api_map.dart';
import 'package:selfprivacy/logic/models/disk_size.dart'; import 'package:selfprivacy/logic/models/disk_size.dart';
import 'package:selfprivacy/logic/models/hive/server_details.dart'; import 'package:selfprivacy/logic/models/hive/server_details.dart';
import 'package:selfprivacy/logic/models/price.dart'; import 'package:selfprivacy/logic/models/price.dart';
export 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
mixin VolumeProviderApi on ApiMap { mixin VolumeProviderApi on ApiMap {
Future<ServerVolume?> createVolume(); Future<APIGenericResult<ServerVolume?>> createVolume();
Future<List<ServerVolume>> getVolumes({final String? status}); Future<List<ServerVolume>> getVolumes({final String? status});
Future<bool> attachVolume(final ServerVolume volume, final int serverId); Future<APIGenericResult<bool>> attachVolume(
final ServerVolume volume,
final int serverId,
);
Future<bool> detachVolume(final ServerVolume volume); Future<bool> detachVolume(final ServerVolume volume);
Future<bool> resizeVolume(final ServerVolume volume, final DiskSize size); Future<bool> resizeVolume(final ServerVolume volume, final DiskSize size);
Future<void> deleteVolume(final ServerVolume volume); Future<void> deleteVolume(final ServerVolume volume);

View File

@ -35,7 +35,7 @@ class ApiDevicesCubit
} }
Future<List<ApiToken>?> _getApiTokens() async { Future<List<ApiToken>?> _getApiTokens() async {
final GenericResult<List<ApiToken>> response = await api.getApiTokens(); final APIGenericResult<List<ApiToken>> response = await api.getApiTokens();
if (response.success) { if (response.success) {
return response.data; return response.data;
} else { } else {
@ -44,7 +44,8 @@ class ApiDevicesCubit
} }
Future<void> deleteDevice(final ApiToken device) async { Future<void> deleteDevice(final ApiToken device) async {
final GenericResult<void> response = await api.deleteApiToken(device.name); final APIGenericResult<void> response =
await api.deleteApiToken(device.name);
if (response.success) { if (response.success) {
emit( emit(
ApiDevicesState( ApiDevicesState(
@ -59,7 +60,7 @@ class ApiDevicesCubit
} }
Future<String?> getNewDeviceKey() async { Future<String?> getNewDeviceKey() async {
final GenericResult<String> response = await api.createDeviceToken(); final APIGenericResult<String> response = await api.createDeviceToken();
if (response.success) { if (response.success) {
return response.data; return response.data;
} else { } else {

View File

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:cubit_form/cubit_form.dart'; import 'package:cubit_form/cubit_form.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/backblaze.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/backblaze.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart'; import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart'; import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart';
@ -7,7 +8,6 @@ import 'package:easy_localization/easy_localization.dart';
class BackblazeFormCubit extends FormCubit { class BackblazeFormCubit extends FormCubit {
BackblazeFormCubit(this.serverInstallationCubit) { BackblazeFormCubit(this.serverInstallationCubit) {
//var regExp = RegExp(r"\s+|[-!$%^&*()@+|~=`{}\[\]:<>?,.\/]");
keyId = FieldCubit( keyId = FieldCubit(
initalValue: '', initalValue: '',
validations: [ validations: [
@ -40,7 +40,7 @@ class BackblazeFormCubit extends FormCubit {
@override @override
FutureOr<bool> asyncValidation() async { FutureOr<bool> asyncValidation() async {
late bool isKeyValid; late APIGenericResult<bool> backblazeResponse;
final BackblazeApi apiClient = BackblazeApi(isWithToken: false); final BackblazeApi apiClient = BackblazeApi(isWithToken: false);
try { try {
@ -48,18 +48,30 @@ class BackblazeFormCubit extends FormCubit {
keyId.state.value, keyId.state.value,
applicationKey.state.value, applicationKey.state.value,
); );
isKeyValid = await apiClient.isValid(encodedApiKey); backblazeResponse = await apiClient.isApiTokenValid(encodedApiKey);
} catch (e) { } catch (e) {
addError(e); addError(e);
isKeyValid = false; backblazeResponse = APIGenericResult(
success: false,
data: false,
message: e.toString(),
);
} }
if (!isKeyValid) { if (!backblazeResponse.success) {
keyId.setError('initializing.backblaze_bad_key_error'.tr()); getIt<NavigationService>().showSnackBar(
applicationKey.setError('initializing.backblaze_bad_key_error'.tr()); 'initializing.could_not_connect'.tr(),
);
keyId.setError('');
applicationKey.setError('');
return false; return false;
} }
return true; if (!backblazeResponse.data) {
keyId.setError('initializing.backblaze_bad_key_error'.tr());
applicationKey.setError('initializing.backblaze_bad_key_error'.tr());
}
return backblazeResponse.data;
} }
} }

View File

@ -28,21 +28,24 @@ class DnsProviderFormCubit extends FormCubit {
@override @override
FutureOr<bool> asyncValidation() async { FutureOr<bool> asyncValidation() async {
late bool isKeyValid; bool? isKeyValid;
try { try {
isKeyValid = await initializingCubit isKeyValid = await initializingCubit
.isDnsProviderApiTokenValid(apiKey.state.value); .isDnsProviderApiTokenValid(apiKey.state.value);
} catch (e) { } catch (e) {
addError(e); addError(e);
isKeyValid = false; }
if (isKeyValid == null) {
apiKey.setError('');
return false;
} }
if (!isKeyValid) { if (!isKeyValid) {
apiKey.setError('initializing.cloudflare_bad_key_error'.tr()); apiKey.setError('initializing.cloudflare_bad_key_error'.tr());
return false;
} }
return true; return isKeyValid;
} }
} }

View File

@ -29,21 +29,24 @@ class ProviderFormCubit extends FormCubit {
@override @override
FutureOr<bool> asyncValidation() async { FutureOr<bool> asyncValidation() async {
late bool isKeyValid; bool? isKeyValid;
try { try {
isKeyValid = await serverInstallationCubit isKeyValid = await serverInstallationCubit
.isServerProviderApiTokenValid(apiKey.state.value); .isServerProviderApiTokenValid(apiKey.state.value);
} catch (e) { } catch (e) {
addError(e); addError(e);
isKeyValid = false; }
if (isKeyValid == null) {
apiKey.setError('');
return false;
} }
if (!isKeyValid) { if (!isKeyValid) {
apiKey.setError('initializing.provider_bad_key_error'.tr()); apiKey.setError('initializing.provider_bad_key_error'.tr());
return false;
} }
return true; return isKeyValid;
} }
} }

View File

@ -113,10 +113,11 @@ class ApiProviderVolumeCubit
} }
Future<void> createVolume() async { Future<void> createVolume() async {
final ServerVolume? volume = await ApiController final ServerVolume? volume = (await ApiController
.currentVolumeProviderApiFactory! .currentVolumeProviderApiFactory!
.getVolumeProvider() .getVolumeProvider()
.createVolume(); .createVolume())
.data;
final diskVolume = DiskVolume(providerVolume: volume); final diskVolume = DiskVolume(providerVolume: volume);
await attachVolume(diskVolume); await attachVolume(diskVolume);

View File

@ -32,7 +32,7 @@ class RecoveryKeyCubit
} }
Future<RecoveryKeyStatus?> _getRecoveryKeyStatus() async { Future<RecoveryKeyStatus?> _getRecoveryKeyStatus() async {
final GenericResult<RecoveryKeyStatus?> response = final APIGenericResult<RecoveryKeyStatus?> response =
await api.getRecoveryTokenStatus(); await api.getRecoveryTokenStatus();
if (response.success) { if (response.success) {
return response.data; return response.data;
@ -57,7 +57,7 @@ class RecoveryKeyCubit
final DateTime? expirationDate, final DateTime? expirationDate,
final int? numberOfUses, final int? numberOfUses,
}) async { }) async {
final GenericResult<String> response = final APIGenericResult<String> response =
await api.generateRecoveryToken(expirationDate, numberOfUses); await api.generateRecoveryToken(expirationDate, numberOfUses);
if (response.success) { if (response.success) {
refresh(); refresh();

View File

@ -76,18 +76,29 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
.getDnsProvider() .getDnsProvider()
.getApiTokenValidation(); .getApiTokenValidation();
Future<bool> isServerProviderApiTokenValid( Future<bool?> isServerProviderApiTokenValid(
final String providerToken, final String providerToken,
) async => ) async {
ApiController.currentServerProviderApiFactory! final APIGenericResult<bool> apiResponse =
.getServerProvider( await ApiController.currentServerProviderApiFactory!
settings: const ServerProviderApiSettings( .getServerProvider(
isWithToken: false, settings: const ServerProviderApiSettings(
), isWithToken: false,
) ),
.isApiTokenValid(providerToken); )
.isApiTokenValid(providerToken);
Future<bool> isDnsProviderApiTokenValid( if (!apiResponse.success) {
getIt<NavigationService>().showSnackBar(
'initializing.could_not_connect'.tr(),
);
return null;
}
return apiResponse.data;
}
Future<bool?> isDnsProviderApiTokenValid(
final String providerToken, final String providerToken,
) async { ) async {
if (ApiController.currentDnsProviderApiFactory == null) { if (ApiController.currentDnsProviderApiFactory == null) {
@ -100,11 +111,21 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
); );
} }
return ApiController.currentDnsProviderApiFactory! final APIGenericResult<bool> apiResponse =
.getDnsProvider( await ApiController.currentDnsProviderApiFactory!
settings: const DnsProviderApiSettings(isWithToken: false), .getDnsProvider(
) settings: const DnsProviderApiSettings(isWithToken: false),
.isApiTokenValid(providerToken); )
.isApiTokenValid(providerToken);
if (!apiResponse.success) {
getIt<NavigationService>().showSnackBar(
'initializing.could_not_connect'.tr(),
);
return null;
}
return apiResponse.data;
} }
Future<List<ServerProviderLocation>> fetchAvailableLocations() async { Future<List<ServerProviderLocation>> fetchAvailableLocations() async {
@ -112,9 +133,18 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
return []; return [];
} }
return ApiController.currentServerProviderApiFactory! final APIGenericResult apiResult = await ApiController
.currentServerProviderApiFactory!
.getServerProvider() .getServerProvider()
.getAvailableLocations(); .getAvailableLocations();
if (!apiResult.success) {
getIt<NavigationService>().showSnackBar(
'initializing.could_not_connect'.tr(),
);
}
return apiResult.data;
} }
Future<List<ServerType>> fetchAvailableTypesByLocation( Future<List<ServerType>> fetchAvailableTypesByLocation(
@ -124,9 +154,18 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
return []; return [];
} }
return ApiController.currentServerProviderApiFactory! final APIGenericResult apiResult = await ApiController
.currentServerProviderApiFactory!
.getServerProvider() .getServerProvider()
.getServerTypesByLocation(location: location); .getServerTypesByLocation(location: location);
if (!apiResult.success) {
getIt<NavigationService>().showSnackBar(
'initializing.could_not_connect'.tr(),
);
}
return apiResult.data;
} }
void setServerProviderKey(final String serverProviderKey) async { void setServerProviderKey(final String serverProviderKey) async {

View File

@ -75,13 +75,12 @@ class ServerInstallationRepository {
); );
} }
if (serverDomain != null && serverDomain.provider != DnsProvider.unknown) { // No other DNS provider is supported for now, so it's fine.
ApiController.initDnsProviderApiFactory( ApiController.initDnsProviderApiFactory(
DnsProviderApiFactorySettings( DnsProviderApiFactorySettings(
provider: serverDomain.provider, provider: DnsProvider.cloudflare,
), ),
); );
}
if (box.get(BNames.hasFinalChecked, defaultValue: false)) { if (box.get(BNames.hasFinalChecked, defaultValue: false)) {
return ServerInstallationFinished( return ServerInstallationFinished(
@ -247,22 +246,52 @@ class ServerInstallationRepository {
}) async { }) async {
final ServerProviderApi api = final ServerProviderApi api =
ApiController.currentServerProviderApiFactory!.getServerProvider(); ApiController.currentServerProviderApiFactory!.getServerProvider();
void showInstallationErrorPopUp() {
showPopUpAlert(
alertTitle: 'modals.unexpected_error'.tr(),
description: 'modals.try_again'.tr(),
actionButtonTitle: 'modals.yes'.tr(),
actionButtonOnPressed: () async {
ServerHostingDetails? serverDetails;
try {
final APIGenericResult createResult = await api.createServer(
dnsApiToken: cloudFlareKey,
rootUser: rootUser,
domainName: domainName,
serverType: getIt<ApiConfigModel>().serverType!,
);
serverDetails = createResult.data;
} catch (e) {
print(e);
}
if (serverDetails == null) {
print('Server is not initialized!');
return;
}
await saveServerDetails(serverDetails);
onSuccess(serverDetails);
},
cancelButtonOnPressed: onCancel,
);
}
try { try {
final ServerHostingDetails? serverDetails = await api.createServer( final APIGenericResult<ServerHostingDetails?> createServerResult =
await api.createServer(
dnsApiToken: cloudFlareKey, dnsApiToken: cloudFlareKey,
rootUser: rootUser, rootUser: rootUser,
domainName: domainName, domainName: domainName,
serverType: getIt<ApiConfigModel>().serverType!, serverType: getIt<ApiConfigModel>().serverType!,
); );
if (serverDetails == null) { if (createServerResult.data == null) {
print('Server is not initialized!'); const String e = 'Server is not initialized!';
return; print(e);
} }
saveServerDetails(serverDetails);
onSuccess(serverDetails); if (createServerResult.message == 'uniqueness_error') {
} on DioError catch (e) {
if (e.response!.data['error']['code'] == 'uniqueness_error') {
showPopUpAlert( showPopUpAlert(
alertTitle: 'modals.already_exists'.tr(), alertTitle: 'modals.already_exists'.tr(),
description: 'modals.destroy_server'.tr(), description: 'modals.destroy_server'.tr(),
@ -274,39 +303,13 @@ class ServerInstallationRepository {
ServerHostingDetails? serverDetails; ServerHostingDetails? serverDetails;
try { try {
serverDetails = await api.createServer( final APIGenericResult createResult = await api.createServer(
dnsApiToken: cloudFlareKey,
rootUser: rootUser,
domainName: domainName,
serverType: getIt<ApiConfigModel>().serverType!,
);
} catch (e) {
print(e);
}
if (serverDetails == null) {
print('Server is not initialized!');
return;
}
await saveServerDetails(serverDetails);
onSuccess(serverDetails);
},
cancelButtonOnPressed: onCancel,
);
} else {
showPopUpAlert(
alertTitle: 'modals.unexpected_error'.tr(),
description: 'modals.try_again'.tr(),
actionButtonTitle: 'modals.yes'.tr(),
actionButtonOnPressed: () async {
ServerHostingDetails? serverDetails;
try {
serverDetails = await api.createServer(
dnsApiToken: cloudFlareKey, dnsApiToken: cloudFlareKey,
rootUser: rootUser, rootUser: rootUser,
domainName: domainName, domainName: domainName,
serverType: getIt<ApiConfigModel>().serverType!, serverType: getIt<ApiConfigModel>().serverType!,
); );
serverDetails = createResult.data;
} catch (e) { } catch (e) {
print(e); print(e);
} }
@ -320,7 +323,14 @@ class ServerInstallationRepository {
}, },
cancelButtonOnPressed: onCancel, cancelButtonOnPressed: onCancel,
); );
return;
} }
saveServerDetails(createServerResult.data!);
onSuccess(createServerResult.data!);
} catch (e) {
print(e);
showInstallationErrorPopUp();
} }
} }
@ -334,21 +344,9 @@ class ServerInstallationRepository {
final ServerProviderApi serverApi = final ServerProviderApi serverApi =
ApiController.currentServerProviderApiFactory!.getServerProvider(); ApiController.currentServerProviderApiFactory!.getServerProvider();
await dnsProviderApi.removeSimilarRecords( void showDomainErrorPopUp(final String error) {
ip4: serverDetails.ip4,
domain: domain,
);
try {
await dnsProviderApi.createMultipleDnsRecords(
ip4: serverDetails.ip4,
domain: domain,
);
} on DioError catch (e) {
showPopUpAlert( showPopUpAlert(
alertTitle: e.response!.data['errors'][0]['code'] == 1038 alertTitle: error,
? 'modals.you_cant_use_this_api'.tr()
: 'domain.error'.tr(),
description: 'modals.delete_server_volume'.tr(), description: 'modals.delete_server_volume'.tr(),
cancelButtonOnPressed: onCancel, cancelButtonOnPressed: onCancel,
actionButtonTitle: 'basis.delete'.tr(), actionButtonTitle: 'basis.delete'.tr(),
@ -359,14 +357,50 @@ class ServerInstallationRepository {
onCancel(); onCancel();
}, },
); );
}
final APIGenericResult removingResult =
await dnsProviderApi.removeSimilarRecords(
ip4: serverDetails.ip4,
domain: domain,
);
if (!removingResult.success) {
showDomainErrorPopUp('domain.error'.tr());
return false; return false;
} }
await serverApi.createReverseDns( bool createdSuccessfully = false;
String errorMessage = 'domain.error'.tr();
try {
final APIGenericResult createResult =
await dnsProviderApi.createMultipleDnsRecords(
ip4: serverDetails.ip4,
domain: domain,
);
createdSuccessfully = createResult.success;
} on DioError catch (e) {
if (e.response!.data['errors'][0]['code'] == 1038) {
errorMessage = 'modals.you_cant_use_this_api'.tr();
}
}
if (!createdSuccessfully) {
showDomainErrorPopUp(errorMessage);
return false;
}
final APIGenericResult createReverseResult =
await serverApi.createReverseDns(
serverDetails: serverDetails, serverDetails: serverDetails,
domain: domain, domain: domain,
); );
if (!createReverseResult.success) {
showDomainErrorPopUp(errorMessage);
return false;
}
return true; return true;
} }
@ -479,7 +513,7 @@ class ServerInstallationRepository {
overrideDomain: serverDomain.domainName, overrideDomain: serverDomain.domainName,
); );
final String serverIp = await getServerIpFromDomain(serverDomain); final String serverIp = await getServerIpFromDomain(serverDomain);
final GenericResult<String> result = await serverApi.authorizeDevice( final APIGenericResult<String> result = await serverApi.authorizeDevice(
DeviceToken(device: await getDeviceName(), token: newDeviceKey), DeviceToken(device: await getDeviceName(), token: newDeviceKey),
); );
@ -516,7 +550,7 @@ class ServerInstallationRepository {
overrideDomain: serverDomain.domainName, overrideDomain: serverDomain.domainName,
); );
final String serverIp = await getServerIpFromDomain(serverDomain); final String serverIp = await getServerIpFromDomain(serverDomain);
final GenericResult<String> result = await serverApi.useRecoveryToken( final APIGenericResult<String> result = await serverApi.useRecoveryToken(
DeviceToken(device: await getDeviceName(), token: recoveryKey), DeviceToken(device: await getDeviceName(), token: recoveryKey),
); );
@ -577,9 +611,9 @@ class ServerInstallationRepository {
); );
} }
} }
final GenericResult<String> deviceAuthKey = final APIGenericResult<String> deviceAuthKey =
await serverApi.createDeviceToken(); await serverApi.createDeviceToken();
final GenericResult<String> result = await serverApi.authorizeDevice( final APIGenericResult<String> result = await serverApi.authorizeDevice(
DeviceToken(device: await getDeviceName(), token: deviceAuthKey.data), DeviceToken(device: await getDeviceName(), token: deviceAuthKey.data),
); );

View File

@ -78,7 +78,7 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
return; return;
} }
// If API returned error, do nothing // If API returned error, do nothing
final GenericMutationResult<User?> result = final APIGenericResult<User?> result =
await api.createUser(user.login, password); await api.createUser(user.login, password);
if (result.data == null) { if (result.data == null) {
getIt<NavigationService>() getIt<NavigationService>()
@ -101,7 +101,7 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
return; return;
} }
final List<User> loadedUsers = List<User>.from(state.users); final List<User> loadedUsers = List<User>.from(state.users);
final GenericMutationResult result = await api.deleteUser(user.login); final APIGenericResult result = await api.deleteUser(user.login);
if (result.success && result.data) { if (result.success && result.data) {
loadedUsers.removeWhere((final User u) => u.login == user.login); loadedUsers.removeWhere((final User u) => u.login == user.login);
await box.clear(); await box.clear();
@ -128,7 +128,7 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
.showSnackBar('users.could_not_change_password'.tr()); .showSnackBar('users.could_not_change_password'.tr());
return; return;
} }
final GenericMutationResult<User?> result = final APIGenericResult<User?> result =
await api.updateUser(user.login, newPassword); await api.updateUser(user.login, newPassword);
if (result.data == null) { if (result.data == null) {
getIt<NavigationService>().showSnackBar( getIt<NavigationService>().showSnackBar(
@ -138,7 +138,7 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
} }
Future<void> addSshKey(final User user, final String publicKey) async { Future<void> addSshKey(final User user, final String publicKey) async {
final GenericMutationResult<User?> result = final APIGenericResult<User?> result =
await api.addSshKey(user.login, publicKey); await api.addSshKey(user.login, publicKey);
if (result.data != null) { if (result.data != null) {
final User updatedUser = result.data!; final User updatedUser = result.data!;
@ -157,7 +157,7 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
} }
Future<void> deleteSshKey(final User user, final String publicKey) async { Future<void> deleteSshKey(final User user, final String publicKey) async {
final GenericMutationResult<User?> result = final APIGenericResult<User?> result =
await api.removeSshKey(user.login, publicKey); await api.removeSshKey(user.login, publicKey);
if (result.data != null) { if (result.data != null) {
final User updatedUser = result.data!; final User updatedUser = result.data!;

View File

@ -77,7 +77,7 @@ class InitializingPage extends StatelessWidget {
'Domain', 'Domain',
'User', 'User',
'Server', 'Server',
'Check', 'Installation',
], ],
activeIndex: cubit.state.porgressBar, activeIndex: cubit.state.porgressBar,
), ),