Merge pull request 'refactor(digital-ocean-dns): Implement basic DTO for Digital Ocean DNS to avoid dynamic objects' (#247) from dto into master

Reviewed-on: https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/pulls/247
Reviewed-by: Inex Code <inex.code@selfprivacy.org>
This commit is contained in:
NaiJi ✨ 2023-07-28 05:19:45 +03:00
commit 55740ac59d
4 changed files with 167 additions and 41 deletions

View file

@ -4,8 +4,7 @@ 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/generic_result.dart'; import 'package:selfprivacy/logic/api_maps/generic_result.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/rest_api_map.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/rest_api_map.dart';
import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/json/digital_ocean_dns_info.dart';
import 'package:selfprivacy/logic/models/json/dns_records.dart';
class DigitalOceanDnsApi extends RestApiMap { class DigitalOceanDnsApi extends RestApiMap {
DigitalOceanDnsApi({ DigitalOceanDnsApi({
@ -92,13 +91,17 @@ class DigitalOceanDnsApi extends RestApiMap {
); );
} }
Future<GenericResult<List>> getDomains() async { Future<GenericResult<List<DigitalOceanDomain>>> getDomains() async {
List domains = []; List<DigitalOceanDomain> domains = [];
final Dio client = await getClient(); final Dio client = await getClient();
try { try {
final Response response = await client.get('/domains'); final Response response = await client.get('/domains');
domains = response.data['domains']; domains = response.data['domains']!
.map<DigitalOceanDomain>(
(final e) => DigitalOceanDomain.fromJson(e),
)
.toList();
} catch (e) { } catch (e) {
print(e); print(e);
return GenericResult( return GenericResult(
@ -114,25 +117,18 @@ class DigitalOceanDnsApi extends RestApiMap {
} }
Future<GenericResult<void>> createMultipleDnsRecords({ Future<GenericResult<void>> createMultipleDnsRecords({
required final ServerDomain domain, required final String domainName,
required final List<DnsRecord> records, required final List<DigitalOceanDnsRecord> records,
}) async { }) async {
final String domainName = domain.domainName;
final List<Future> allCreateFutures = <Future>[]; final List<Future> allCreateFutures = <Future>[];
final Dio client = await getClient(); final Dio client = await getClient();
try { try {
for (final DnsRecord record in records) { for (final DigitalOceanDnsRecord record in records) {
allCreateFutures.add( allCreateFutures.add(
client.post( client.post(
'/domains/$domainName/records', '/domains/$domainName/records',
data: { data: record.toJson(),
'type': record.type,
'name': record.name,
'data': record.content,
'ttl': record.ttl,
'priority': record.priority,
},
), ),
); );
} }
@ -155,17 +151,15 @@ class DigitalOceanDnsApi extends RestApiMap {
} }
Future<GenericResult<void>> removeSimilarRecords({ Future<GenericResult<void>> removeSimilarRecords({
required final ServerDomain domain, required final String domainName,
required final List records, required final List<DigitalOceanDnsRecord> records,
}) async { }) async {
final String domainName = domain.domainName;
final Dio client = await getClient(); final Dio client = await getClient();
try { try {
final List<Future> allDeleteFutures = []; final List<Future> allDeleteFutures = [];
for (final record in records) { for (final record in records) {
allDeleteFutures.add( allDeleteFutures.add(
client.delete("/domains/$domainName/records/${record['id']}"), client.delete('/domains/$domainName/records/${record.id}'),
); );
} }
await Future.wait(allDeleteFutures); await Future.wait(allDeleteFutures);
@ -183,12 +177,11 @@ class DigitalOceanDnsApi extends RestApiMap {
return GenericResult(success: true, data: null); return GenericResult(success: true, data: null);
} }
Future<GenericResult<List>> getDnsRecords({ Future<GenericResult<List<DigitalOceanDnsRecord>>> getDnsRecords(
required final ServerDomain domain, final String domainName,
}) async { ) async {
Response response; Response response;
final String domainName = domain.domainName; List<DigitalOceanDnsRecord> allRecords = [];
List allRecords = [];
/// Default amount is 20, but we will eventually overflow it, /// Default amount is 20, but we will eventually overflow it,
/// so I hardcode it to the maximum available amount in advance just in case /// so I hardcode it to the maximum available amount in advance just in case
@ -200,7 +193,12 @@ class DigitalOceanDnsApi extends RestApiMap {
final Dio client = await getClient(); final Dio client = await getClient();
try { try {
response = await client.get(url); response = await client.get(url);
allRecords = response.data['domain_records'] ?? []; allRecords = response.data['domain_records']
.map<DigitalOceanDnsRecord>(
(final e) => DigitalOceanDnsRecord.fromJson(e),
)
.toList() ??
[];
} catch (e) { } catch (e) {
print(e); print(e);
GenericResult( GenericResult(

View file

@ -0,0 +1,66 @@
import 'package:json_annotation/json_annotation.dart';
part 'digital_ocean_dns_info.g.dart';
/// https://docs.digitalocean.com/reference/api/api-reference/#tag/Domains
@JsonSerializable()
class DigitalOceanDomain {
DigitalOceanDomain({
required this.name,
this.ttl,
});
/// The name of the domain itself.
/// This should follow the standard domain format of domain.TLD.
///
/// For instance, example.com is a valid domain name.
final String name;
/// This value is the time to live for the records on this domain, in seconds.
///
/// This defines the time frame that clients can cache queried information before a refresh should be requested.
final int? ttl;
static DigitalOceanDomain fromJson(final Map<String, dynamic> json) =>
_$DigitalOceanDomainFromJson(json);
}
/// https://docs.digitalocean.com/reference/api/api-reference/#tag/Domain-Records
@JsonSerializable()
class DigitalOceanDnsRecord {
DigitalOceanDnsRecord({
required this.id,
required this.name,
required this.type,
required this.ttl,
required this.data,
this.priority,
});
/// A unique identifier for each domain record.
final int? id;
/// The host name, alias, or service being defined by the record.
final String name;
/// The type of the DNS record. For example: A, CNAME, TXT, ...
final String type;
/// This value is the time to live for the record, in seconds.
///
/// This defines the time frame that clients can cache queried information before a refresh should be requested.
final int ttl;
/// Variable data depending on record type.
///
/// For example, the "data" value for an A record would be the IPv4 address to which the domain will be mapped.
/// For a CAA record, it would contain the domain name of the CA being granted permission to issue certificates.
final String data;
/// The priority for SRV and MX records.
final int? priority;
static DigitalOceanDnsRecord fromJson(final Map<String, dynamic> json) =>
_$DigitalOceanDnsRecordFromJson(json);
Map<String, dynamic> toJson() => _$DigitalOceanDnsRecordToJson(this);
}

View file

@ -0,0 +1,41 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'digital_ocean_dns_info.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DigitalOceanDomain _$DigitalOceanDomainFromJson(Map<String, dynamic> json) =>
DigitalOceanDomain(
name: json['name'] as String,
ttl: json['ttl'] as int?,
);
Map<String, dynamic> _$DigitalOceanDomainToJson(DigitalOceanDomain instance) =>
<String, dynamic>{
'name': instance.name,
'ttl': instance.ttl,
};
DigitalOceanDnsRecord _$DigitalOceanDnsRecordFromJson(
Map<String, dynamic> json) =>
DigitalOceanDnsRecord(
id: json['id'] as int?,
name: json['name'] as String,
type: json['type'] as String,
ttl: json['ttl'] as int,
data: json['data'] as String,
priority: json['priority'] as int?,
);
Map<String, dynamic> _$DigitalOceanDnsRecordToJson(
DigitalOceanDnsRecord instance) =>
<String, dynamic>{
'id': instance.id,
'name': instance.name,
'type': instance.type,
'ttl': instance.ttl,
'data': instance.data,
'priority': instance.priority,
};

View file

@ -1,6 +1,7 @@
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/desired_dns_record.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/desired_dns_record.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/digital_ocean_dns/digital_ocean_dns_api.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/digital_ocean_dns/digital_ocean_dns_api.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/digital_ocean_dns_info.dart';
import 'package:selfprivacy/logic/models/json/dns_records.dart'; import 'package:selfprivacy/logic/models/json/dns_records.dart';
import 'package:selfprivacy/logic/providers/dns_providers/dns_provider.dart'; import 'package:selfprivacy/logic/providers/dns_providers/dns_provider.dart';
@ -59,7 +60,7 @@ class DigitalOceanDnsProvider extends DnsProvider {
domains = result.data domains = result.data
.map<String>( .map<String>(
(final el) => el['name'] as String, (final el) => el.name,
) )
.toList(); .toList();
@ -75,11 +76,22 @@ class DigitalOceanDnsProvider extends DnsProvider {
final String? ip4, final String? ip4,
}) async => }) async =>
_adapter.api().createMultipleDnsRecords( _adapter.api().createMultipleDnsRecords(
domain: domain, domainName: domain.domainName,
records: getProjectDnsRecords( records: getProjectDnsRecords(
domain.domainName, domain.domainName,
ip4, ip4,
), )
.map<DigitalOceanDnsRecord>(
(final e) => DigitalOceanDnsRecord(
name: e.name ?? '',
id: null,
data: e.content ?? '',
ttl: e.ttl,
type: e.type,
priority: e.priority,
),
)
.toList(),
); );
@override @override
@ -87,7 +99,7 @@ class DigitalOceanDnsProvider extends DnsProvider {
required final ServerDomain domain, required final ServerDomain domain,
final String? ip4, final String? ip4,
}) async { }) async {
final result = await _adapter.api().getDnsRecords(domain: domain); final result = await _adapter.api().getDnsRecords(domain.domainName);
if (result.data.isEmpty || !result.success) { if (result.data.isEmpty || !result.success) {
return GenericResult( return GenericResult(
success: result.success, success: result.success,
@ -98,15 +110,15 @@ class DigitalOceanDnsProvider extends DnsProvider {
} }
const ignoreType = 'SOA'; const ignoreType = 'SOA';
final filteredRecords = []; final List<DigitalOceanDnsRecord> filteredRecords = [];
for (final record in result.data) { for (final record in result.data) {
if (record['type'] != ignoreType) { if (record.type != ignoreType) {
filteredRecords.add(record); filteredRecords.add(record);
} }
} }
return _adapter.api().removeSimilarRecords( return _adapter.api().removeSimilarRecords(
domain: domain, domainName: domain.domainName,
records: filteredRecords, records: filteredRecords,
); );
} }
@ -116,7 +128,7 @@ class DigitalOceanDnsProvider extends DnsProvider {
required final ServerDomain domain, required final ServerDomain domain,
}) async { }) async {
final List<DnsRecord> records = []; final List<DnsRecord> records = [];
final result = await _adapter.api().getDnsRecords(domain: domain); final result = await _adapter.api().getDnsRecords(domain.domainName);
if (result.data.isEmpty || !result.success) { if (result.data.isEmpty || !result.success) {
return GenericResult( return GenericResult(
success: result.success, success: result.success,
@ -129,10 +141,10 @@ class DigitalOceanDnsProvider extends DnsProvider {
for (final rawRecord in result.data) { for (final rawRecord in result.data) {
records.add( records.add(
DnsRecord( DnsRecord(
name: rawRecord['name'], name: rawRecord.name,
type: rawRecord['type'], type: rawRecord.type,
content: rawRecord['data'], content: rawRecord.data,
ttl: rawRecord['ttl'], ttl: rawRecord.ttl,
proxied: false, proxied: false,
), ),
); );
@ -147,8 +159,17 @@ class DigitalOceanDnsProvider extends DnsProvider {
final ServerDomain domain, final ServerDomain domain,
) async => ) async =>
_adapter.api().createMultipleDnsRecords( _adapter.api().createMultipleDnsRecords(
domain: domain, domainName: domain.domainName,
records: [record], records: [
DigitalOceanDnsRecord(
data: record.content ?? '',
id: null,
name: record.name ?? '',
ttl: record.ttl,
type: record.type,
priority: record.priority,
),
],
); );
@override @override