mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-24 09:46:42 +00:00
chore: Merge deletion-error into master
Reviewed-on: https://git.selfprivacy.org/kherel/selfprivacy.org.app/pulls/155 Reviewed-by: Inex Code <inex.code@selfprivacy.org>
This commit is contained in:
commit
86cd12803a
|
@ -392,6 +392,8 @@
|
||||||
"generation_error": "Couldn't generate a recovery key. {}"
|
"generation_error": "Couldn't generate a recovery key. {}"
|
||||||
},
|
},
|
||||||
"modals": {
|
"modals": {
|
||||||
|
"dns_removal_error": "Couldn't remove DNS records.",
|
||||||
|
"server_deletion_error": "Couldn't delete active server.",
|
||||||
"server_validators_error": "Couldn't fetch available servers.",
|
"server_validators_error": "Couldn't fetch available servers.",
|
||||||
"already_exists": "Such server already exists.",
|
"already_exists": "Such server already exists.",
|
||||||
"unexpected_error": "Unexpected error during placement from the provider side.",
|
"unexpected_error": "Unexpected error during placement from the provider side.",
|
||||||
|
|
|
@ -392,6 +392,8 @@
|
||||||
"generation_error": "Не удалось сгенерировать ключ. {}"
|
"generation_error": "Не удалось сгенерировать ключ. {}"
|
||||||
},
|
},
|
||||||
"modals": {
|
"modals": {
|
||||||
|
"dns_removal_error": "Невозможно удалить DNS записи.",
|
||||||
|
"server_deletion_error": "Невозможно удалить сервер.",
|
||||||
"server_validators_error": "Не удалось получить список серверов.",
|
"server_validators_error": "Не удалось получить список серверов.",
|
||||||
"already_exists": "Такой сервер уже существует.",
|
"already_exists": "Такой сервер уже существует.",
|
||||||
"unexpected_error": "Непредвиденная ошибка со стороны провайдера.",
|
"unexpected_error": "Непредвиденная ошибка со стороны провайдера.",
|
||||||
|
|
|
@ -18,6 +18,7 @@ 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';
|
||||||
import 'package:selfprivacy/utils/extensions/string_extensions.dart';
|
import 'package:selfprivacy/utils/extensions/string_extensions.dart';
|
||||||
|
import 'package:selfprivacy/utils/network_utils.dart';
|
||||||
import 'package:selfprivacy/utils/password_generator.dart';
|
import 'package:selfprivacy/utils/password_generator.dart';
|
||||||
|
|
||||||
class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
|
class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
|
@ -325,23 +326,6 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
static String getHostnameFromDomain(final String domain) {
|
|
||||||
// Replace all non-alphanumeric characters with an underscore
|
|
||||||
String hostname =
|
|
||||||
domain.split('.')[0].replaceAll(RegExp(r'[^a-zA-Z0-9]'), '-');
|
|
||||||
if (hostname.endsWith('-')) {
|
|
||||||
hostname = hostname.substring(0, hostname.length - 1);
|
|
||||||
}
|
|
||||||
if (hostname.startsWith('-')) {
|
|
||||||
hostname = hostname.substring(1);
|
|
||||||
}
|
|
||||||
if (hostname.isEmpty) {
|
|
||||||
hostname = 'selfprivacy-server';
|
|
||||||
}
|
|
||||||
|
|
||||||
return hostname;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<APIGenericResult<ServerHostingDetails?>> createServer({
|
Future<APIGenericResult<ServerHostingDetails?>> createServer({
|
||||||
required final String dnsApiToken,
|
required final String dnsApiToken,
|
||||||
|
@ -431,17 +415,42 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> deleteServer({
|
Future<APIGenericResult<bool>> deleteServer({
|
||||||
required final String domainName,
|
required final String domainName,
|
||||||
}) async {
|
}) async {
|
||||||
final Dio client = await getClient();
|
final Dio client = await getClient();
|
||||||
|
|
||||||
final ServerBasicInfo serverToRemove = (await getServers()).firstWhere(
|
final String hostname = getHostnameFromDomain(domainName);
|
||||||
(final el) => el.name == domainName,
|
final servers = await getServers();
|
||||||
);
|
final ServerBasicInfo serverToRemove;
|
||||||
final ServerVolume volumeToRemove = (await getVolumes()).firstWhere(
|
try {
|
||||||
(final el) => el.serverId == serverToRemove.id,
|
serverToRemove = servers.firstWhere(
|
||||||
);
|
(final el) => el.name == hostname,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
return APIGenericResult(
|
||||||
|
data: false,
|
||||||
|
success: false,
|
||||||
|
message: e.toString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final volumes = await getVolumes();
|
||||||
|
final ServerVolume volumeToRemove;
|
||||||
|
try {
|
||||||
|
volumeToRemove = volumes.firstWhere(
|
||||||
|
(final el) => el.serverId == serverToRemove.id,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
return APIGenericResult(
|
||||||
|
data: false,
|
||||||
|
success: false,
|
||||||
|
message: e.toString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final List<Future> laterFutures = <Future>[];
|
final List<Future> laterFutures = <Future>[];
|
||||||
|
|
||||||
await detachVolume(volumeToRemove);
|
await detachVolume(volumeToRemove);
|
||||||
|
@ -449,13 +458,23 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
laterFutures.add(deleteVolume(volumeToRemove));
|
laterFutures.add(deleteVolume(volumeToRemove));
|
||||||
laterFutures.add(client.delete('/droplets/$serverToRemove.id'));
|
laterFutures.add(client.delete('/droplets/${serverToRemove.id}'));
|
||||||
await Future.wait(laterFutures);
|
await Future.wait(laterFutures);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
|
return APIGenericResult(
|
||||||
|
success: false,
|
||||||
|
data: false,
|
||||||
|
message: e.toString(),
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
close(client);
|
close(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return APIGenericResult(
|
||||||
|
success: true,
|
||||||
|
data: true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -19,6 +19,7 @@ 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';
|
||||||
import 'package:selfprivacy/utils/extensions/string_extensions.dart';
|
import 'package:selfprivacy/utils/extensions/string_extensions.dart';
|
||||||
|
import 'package:selfprivacy/utils/network_utils.dart';
|
||||||
import 'package:selfprivacy/utils/password_generator.dart';
|
import 'package:selfprivacy/utils/password_generator.dart';
|
||||||
|
|
||||||
class HetznerApi extends ServerProviderApi with VolumeProviderApi {
|
class HetznerApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
|
@ -461,49 +462,47 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static String getHostnameFromDomain(final String domain) {
|
|
||||||
// Replace all non-alphanumeric characters with an underscore
|
|
||||||
String hostname =
|
|
||||||
domain.split('.')[0].replaceAll(RegExp(r'[^a-zA-Z0-9]'), '-');
|
|
||||||
if (hostname.endsWith('-')) {
|
|
||||||
hostname = hostname.substring(0, hostname.length - 1);
|
|
||||||
}
|
|
||||||
if (hostname.startsWith('-')) {
|
|
||||||
hostname = hostname.substring(1);
|
|
||||||
}
|
|
||||||
if (hostname.isEmpty) {
|
|
||||||
hostname = 'selfprivacy-server';
|
|
||||||
}
|
|
||||||
|
|
||||||
return hostname;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> deleteServer({
|
Future<APIGenericResult<bool>> deleteServer({
|
||||||
required final String domainName,
|
required final String domainName,
|
||||||
}) async {
|
}) async {
|
||||||
final Dio client = await getClient();
|
final Dio client = await getClient();
|
||||||
|
try {
|
||||||
|
final String hostname = getHostnameFromDomain(domainName);
|
||||||
|
|
||||||
final String hostname = getHostnameFromDomain(domainName);
|
final Response serversReponse = await client.get('/servers');
|
||||||
|
final List servers = serversReponse.data['servers'];
|
||||||
|
final Map server =
|
||||||
|
servers.firstWhere((final el) => el['name'] == hostname);
|
||||||
|
final List volumes = server['volumes'];
|
||||||
|
final List<Future> laterFutures = <Future>[];
|
||||||
|
|
||||||
final Response serversReponse = await client.get('/servers');
|
for (final volumeId in volumes) {
|
||||||
final List servers = serversReponse.data['servers'];
|
await client.post('/volumes/$volumeId/actions/detach');
|
||||||
final Map server = servers.firstWhere((final el) => el['name'] == hostname);
|
}
|
||||||
final List volumes = server['volumes'];
|
await Future.delayed(const Duration(seconds: 10));
|
||||||
final List<Future> laterFutures = <Future>[];
|
|
||||||
|
|
||||||
for (final volumeId in volumes) {
|
for (final volumeId in volumes) {
|
||||||
await client.post('/volumes/$volumeId/actions/detach');
|
laterFutures.add(client.delete('/volumes/$volumeId'));
|
||||||
|
}
|
||||||
|
laterFutures.add(client.delete('/servers/${server['id']}'));
|
||||||
|
|
||||||
|
await Future.wait(laterFutures);
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
return APIGenericResult(
|
||||||
|
success: false,
|
||||||
|
data: false,
|
||||||
|
message: e.toString(),
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
close(client);
|
||||||
}
|
}
|
||||||
await Future.delayed(const Duration(seconds: 10));
|
|
||||||
|
|
||||||
for (final volumeId in volumes) {
|
return APIGenericResult(
|
||||||
laterFutures.add(client.delete('/volumes/$volumeId'));
|
success: true,
|
||||||
}
|
data: true,
|
||||||
laterFutures.add(client.delete('/servers/${server['id']}'));
|
);
|
||||||
|
|
||||||
await Future.wait(laterFutures);
|
|
||||||
close(client);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -31,7 +31,9 @@ abstract class ServerProviderApi extends ApiMap {
|
||||||
Future<ServerHostingDetails> restart();
|
Future<ServerHostingDetails> restart();
|
||||||
Future<ServerHostingDetails> powerOn();
|
Future<ServerHostingDetails> powerOn();
|
||||||
|
|
||||||
Future<void> deleteServer({required final String domainName});
|
Future<APIGenericResult<bool>> deleteServer({
|
||||||
|
required final String domainName,
|
||||||
|
});
|
||||||
Future<APIGenericResult<ServerHostingDetails?>> createServer({
|
Future<APIGenericResult<ServerHostingDetails?>> createServer({
|
||||||
required final String dnsApiToken,
|
required final String dnsApiToken,
|
||||||
required final User rootUser,
|
required final User rootUser,
|
||||||
|
|
|
@ -756,7 +756,11 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
||||||
closeTimer();
|
closeTimer();
|
||||||
|
|
||||||
if (state.serverDetails != null) {
|
if (state.serverDetails != null) {
|
||||||
await repository.deleteServer(state.serverDomain!);
|
final bool deletionResult =
|
||||||
|
await repository.deleteServer(state.serverDomain!);
|
||||||
|
if (!deletionResult) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
await repository.deleteServerRelatedRecords();
|
await repository.deleteServerRelatedRecords();
|
||||||
emit(
|
emit(
|
||||||
|
|
|
@ -759,13 +759,26 @@ class ServerInstallationRepository {
|
||||||
await box.put(BNames.hasFinalChecked, value);
|
await box.put(BNames.hasFinalChecked, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteServer(final ServerDomain serverDomain) async {
|
Future<bool> deleteServer(final ServerDomain serverDomain) async {
|
||||||
await ApiController.currentServerProviderApiFactory!
|
final APIGenericResult<bool> deletionResult = await ApiController
|
||||||
|
.currentServerProviderApiFactory!
|
||||||
.getServerProvider()
|
.getServerProvider()
|
||||||
.deleteServer(
|
.deleteServer(
|
||||||
domainName: serverDomain.domainName,
|
domainName: serverDomain.domainName,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!deletionResult.success) {
|
||||||
|
getIt<NavigationService>()
|
||||||
|
.showSnackBar('modals.server_validators_error'.tr());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!deletionResult.data) {
|
||||||
|
getIt<NavigationService>()
|
||||||
|
.showSnackBar('modals.server_deletion_error'.tr());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
await box.put(BNames.hasFinalChecked, false);
|
await box.put(BNames.hasFinalChecked, false);
|
||||||
await box.put(BNames.isServerStarted, false);
|
await box.put(BNames.isServerStarted, false);
|
||||||
await box.put(BNames.isServerResetedFirstTime, false);
|
await box.put(BNames.isServerResetedFirstTime, false);
|
||||||
|
@ -773,9 +786,15 @@ class ServerInstallationRepository {
|
||||||
await box.put(BNames.isLoading, false);
|
await box.put(BNames.isLoading, false);
|
||||||
await box.put(BNames.serverDetails, null);
|
await box.put(BNames.serverDetails, null);
|
||||||
|
|
||||||
await ApiController.currentDnsProviderApiFactory!
|
final APIGenericResult<void> removalResult = await ApiController
|
||||||
|
.currentDnsProviderApiFactory!
|
||||||
.getDnsProvider()
|
.getDnsProvider()
|
||||||
.removeSimilarRecords(domain: serverDomain);
|
.removeSimilarRecords(domain: serverDomain);
|
||||||
|
|
||||||
|
if (!removalResult.success) {
|
||||||
|
getIt<NavigationService>().showSnackBar('modals.dns_removal_error'.tr());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteServerRelatedRecords() async {
|
Future<void> deleteServerRelatedRecords() async {
|
||||||
|
|
|
@ -133,3 +133,20 @@ DnsRecord? extractDkimRecord(final List<DnsRecord> records) {
|
||||||
|
|
||||||
return dkimRecord;
|
return dkimRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getHostnameFromDomain(final String domain) {
|
||||||
|
// Replace all non-alphanumeric characters with an underscore
|
||||||
|
String hostname =
|
||||||
|
domain.split('.')[0].replaceAll(RegExp(r'[^a-zA-Z0-9]'), '-');
|
||||||
|
if (hostname.endsWith('-')) {
|
||||||
|
hostname = hostname.substring(0, hostname.length - 1);
|
||||||
|
}
|
||||||
|
if (hostname.startsWith('-')) {
|
||||||
|
hostname = hostname.substring(1);
|
||||||
|
}
|
||||||
|
if (hostname.isEmpty) {
|
||||||
|
hostname = 'selfprivacy-server';
|
||||||
|
}
|
||||||
|
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue