mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-05-14 05:52:51 +00:00
Added ignored domains list config
This commit is contained in:
parent
211eab9f44
commit
c12e8c5ad3
6 changed files with 218 additions and 31 deletions
|
@ -727,5 +727,7 @@
|
|||
"dnsCacheNumber": "DNS cache size must be a number",
|
||||
"errors": "Errors",
|
||||
"redirectHttpsWarning": "If you have enabled \"Redirect to HTTPS automatically\" on your AdGuard Home server, you must select an HTTPS connection and use the HTTPS port of your server.",
|
||||
"logsSettingsDescription": "Configure query logs"
|
||||
"logsSettingsDescription": "Configure query logs",
|
||||
"ignoredDomains": "Ignored domains",
|
||||
"noIgnoredDomainsAdded": "No domains to ignore added"
|
||||
}
|
|
@ -727,5 +727,7 @@
|
|||
"dnsCacheNumber": "El tamaño de caché de DNS debe ser un número",
|
||||
"errors": "Errores",
|
||||
"redirectHttpsWarning": "Si tienes activado \"Redireccionar a HTTPS automáticamente\" en tu servidor AdGuard Home, debes seleccionar una conexión HTTPS y utilizar el puerto de HTTPS de tu servidor.",
|
||||
"logsSettingsDescription": "Configura los registros de peticiones"
|
||||
"logsSettingsDescription": "Configura los registros de peticiones",
|
||||
"ignoredDomains": "Dominios ignorados",
|
||||
"noIgnoredDomainsAdded": "No hay añadidos dominios para ignorar"
|
||||
}
|
27
lib/models/querylog_config.dart
Normal file
27
lib/models/querylog_config.dart
Normal file
|
@ -0,0 +1,27 @@
|
|||
class QueryLogConfig {
|
||||
final List<String>? ignored;
|
||||
final int? interval;
|
||||
final bool? enabled;
|
||||
final bool? anonymizeClientIp;
|
||||
|
||||
QueryLogConfig({
|
||||
this.ignored,
|
||||
this.interval,
|
||||
this.enabled,
|
||||
this.anonymizeClientIp,
|
||||
});
|
||||
|
||||
factory QueryLogConfig.fromJson(Map<String, dynamic> json) => QueryLogConfig(
|
||||
ignored: json["ignored"] == null ? [] : List<String>.from(json["ignored"]!.map((x) => x)),
|
||||
interval: json["interval"],
|
||||
enabled: json["enabled"],
|
||||
anonymizeClientIp: json["anonymize_client_ip"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"ignored": ignored == null ? [] : List<dynamic>.from(ignored!.map((x) => x)),
|
||||
"interval": interval,
|
||||
"enabled": enabled,
|
||||
"anonymize_client_ip": anonymizeClientIp,
|
||||
};
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:adguard_home_manager/screens/settings/logs_settings/logs_settings.dart';
|
||||
import 'package:adguard_home_manager/widgets/section_label.dart';
|
||||
import 'package:adguard_home_manager/widgets/custom_checkbox_list_tile.dart';
|
||||
|
||||
class LogsConfigOptions extends StatelessWidget {
|
||||
|
@ -13,6 +16,8 @@ class LogsConfigOptions extends StatelessWidget {
|
|||
final void Function(double?) updateRetentionTime;
|
||||
final void Function() onClear;
|
||||
final void Function() onConfirm;
|
||||
final List<DomainListItemController> ignoredDomainsControllers;
|
||||
final void Function(List<DomainListItemController>) updateIgnoredDomainsControllers;
|
||||
|
||||
const LogsConfigOptions({
|
||||
super.key,
|
||||
|
@ -24,11 +29,15 @@ class LogsConfigOptions extends StatelessWidget {
|
|||
required this.retentionTime,
|
||||
required this.updateRetentionTime,
|
||||
required this.onClear,
|
||||
required this.onConfirm
|
||||
required this.onConfirm,
|
||||
required this.ignoredDomainsControllers,
|
||||
required this.updateIgnoredDomainsControllers
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const Uuid uuid = Uuid();
|
||||
|
||||
final List<String> dropdownItemTranslation = [
|
||||
AppLocalizations.of(context)!.hours6,
|
||||
AppLocalizations.of(context)!.hours24,
|
||||
|
@ -37,7 +46,28 @@ class LogsConfigOptions extends StatelessWidget {
|
|||
AppLocalizations.of(context)!.days90,
|
||||
];
|
||||
|
||||
return Column(
|
||||
void validateDomain(String value, String id) {
|
||||
final domainRegex = RegExp(r'^([a-z0-9|-]+\.)*[a-z0-9|-]+\.[a-z]+$');
|
||||
bool error = false;
|
||||
if (domainRegex.hasMatch(value)) {
|
||||
error = false;
|
||||
}
|
||||
else {
|
||||
error = true;
|
||||
}
|
||||
updateIgnoredDomainsControllers(
|
||||
ignoredDomainsControllers.map((entry) {
|
||||
if (entry.id != id) return entry;
|
||||
return DomainListItemController(
|
||||
id: id,
|
||||
controller: entry.controller,
|
||||
error: error
|
||||
);
|
||||
}).toList()
|
||||
);
|
||||
}
|
||||
|
||||
return ListView(
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
|
@ -100,12 +130,83 @@ class LogsConfigOptions extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
ElevatedButton.icon(
|
||||
onPressed: onClear,
|
||||
icon: const Icon(Icons.delete_rounded),
|
||||
label: Text(AppLocalizations.of(context)!.clearLogs),
|
||||
)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 24, bottom: 8),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SectionLabel(
|
||||
label: AppLocalizations.of(context)!.ignoredDomains,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 0),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
child: IconButton(
|
||||
onPressed: () => updateIgnoredDomainsControllers([
|
||||
...ignoredDomainsControllers,
|
||||
DomainListItemController(
|
||||
id: uuid.v4(),
|
||||
controller: TextEditingController(),
|
||||
error: false
|
||||
),
|
||||
]),
|
||||
icon: const Icon(Icons.add)
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
if (ignoredDomainsControllers.isNotEmpty) ...ignoredDomainsControllers.map((controller) => Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 12, bottom: 12, left: 24, right: 10
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: controller.controller,
|
||||
onChanged: (v) => validateDomain(v, controller.id),
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(Icons.link_rounded),
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(10)
|
||||
)
|
||||
),
|
||||
labelText: AppLocalizations.of(context)!.domain,
|
||||
errorText: controller.error
|
||||
? AppLocalizations.of(context)!.invalidDomain
|
||||
: null
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Padding(
|
||||
padding: controller.error
|
||||
? const EdgeInsets.only(bottom: 24)
|
||||
: const EdgeInsets.all(0),
|
||||
child: IconButton(
|
||||
onPressed: () => updateIgnoredDomainsControllers(
|
||||
ignoredDomainsControllers.where((e) => e.id != controller.id).toList()
|
||||
),
|
||||
icon: const Icon(Icons.remove_circle_outline_outlined)
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
if (ignoredDomainsControllers.isEmpty) Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.noIgnoredDomainsAdded,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,29 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:adguard_home_manager/screens/settings/logs_settings/config_widgets.dart';
|
||||
|
||||
import 'package:adguard_home_manager/models/querylog_config.dart';
|
||||
import 'package:adguard_home_manager/classes/process_modal.dart';
|
||||
import 'package:adguard_home_manager/functions/snackbar.dart';
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||
|
||||
class DomainListItemController {
|
||||
final String id;
|
||||
final TextEditingController controller;
|
||||
bool error;
|
||||
|
||||
DomainListItemController({
|
||||
required this.id,
|
||||
required this.controller,
|
||||
required this.error
|
||||
});
|
||||
}
|
||||
|
||||
class LogsSettings extends StatefulWidget {
|
||||
const LogsSettings({super.key});
|
||||
|
||||
|
@ -18,9 +32,12 @@ class LogsSettings extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _LogsSettingsState extends State<LogsSettings> {
|
||||
final Uuid uuid = const Uuid();
|
||||
|
||||
bool generalSwitch = false;
|
||||
bool anonymizeClientIp = false;
|
||||
double? retentionTime;
|
||||
List<DomainListItemController> _ignoredDomainsControllers = [];
|
||||
|
||||
List<int> retentionItems = [
|
||||
21600000,
|
||||
|
@ -37,20 +54,27 @@ class _LogsSettingsState extends State<LogsSettings> {
|
|||
|
||||
final result = await serversProvider.apiClient2!.getQueryLogInfo();
|
||||
|
||||
if (mounted) {
|
||||
if (result.successful == true) {
|
||||
setState(() {
|
||||
generalSwitch = result.content['enabled'];
|
||||
anonymizeClientIp = result.content['anonymize_client_ip'];
|
||||
retentionTime = result.content['interval'] != null
|
||||
? double.parse(result.content['interval'].toString())
|
||||
: null;
|
||||
loadStatus = LoadStatus.loaded;
|
||||
});
|
||||
}
|
||||
else {
|
||||
setState(() => loadStatus = LoadStatus.error);
|
||||
}
|
||||
if (!mounted) return;
|
||||
if (result.successful == true) {
|
||||
final data = result.content as QueryLogConfig;
|
||||
setState(() {
|
||||
generalSwitch = data.enabled ?? false;
|
||||
anonymizeClientIp = data.anonymizeClientIp ?? false;
|
||||
retentionTime = data.interval != null
|
||||
? double.parse(data.interval.toString())
|
||||
: null;
|
||||
if (data.ignored != null) {
|
||||
_ignoredDomainsControllers = data.ignored!.map((e) => DomainListItemController(
|
||||
id: uuid.v4(),
|
||||
controller: TextEditingController(text: e),
|
||||
error: false
|
||||
)).toList();
|
||||
}
|
||||
loadStatus = LoadStatus.loaded;
|
||||
});
|
||||
}
|
||||
else {
|
||||
setState(() => loadStatus = LoadStatus.error);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,6 +89,10 @@ class _LogsSettingsState extends State<LogsSettings> {
|
|||
final serversProvider = Provider.of<ServersProvider>(context);
|
||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||
|
||||
final validValues = _ignoredDomainsControllers.where(
|
||||
(d) => d.controller.text == "" || d.error == true
|
||||
).isEmpty;
|
||||
|
||||
void clearQueries() async {
|
||||
ProcessModal processModal = ProcessModal();
|
||||
processModal.open(AppLocalizations.of(context)!.updatingSettings);
|
||||
|
@ -99,7 +127,8 @@ class _LogsSettingsState extends State<LogsSettings> {
|
|||
data: {
|
||||
"enabled": generalSwitch,
|
||||
"interval": retentionTime,
|
||||
"anonymize_client_ip": anonymizeClientIp
|
||||
"anonymize_client_ip": anonymizeClientIp,
|
||||
"ignored": _ignoredDomainsControllers.map((e) => e.controller.text).toList()
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -128,10 +157,24 @@ class _LogsSettingsState extends State<LogsSettings> {
|
|||
title: Text(AppLocalizations.of(context)!.logsSettings),
|
||||
actions: [
|
||||
if (loadStatus == LoadStatus.loaded) IconButton(
|
||||
onPressed: updateConfig,
|
||||
onPressed: validValues ? () => updateConfig() : null,
|
||||
icon: const Icon(Icons.save_rounded),
|
||||
tooltip: AppLocalizations.of(context)!.save,
|
||||
),
|
||||
if (loadStatus == LoadStatus.loaded) PopupMenuButton(
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
onTap: clearQueries,
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.delete_rounded),
|
||||
const SizedBox(width: 8),
|
||||
Text(AppLocalizations.of(context)!.clearLogs),
|
||||
],
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 8)
|
||||
],
|
||||
),
|
||||
|
@ -151,7 +194,9 @@ class _LogsSettingsState extends State<LogsSettings> {
|
|||
retentionTime: retentionTime,
|
||||
updateRetentionTime: (v) => setState(() => retentionTime = v),
|
||||
onClear: clearQueries,
|
||||
onConfirm: updateConfig
|
||||
onConfirm: updateConfig,
|
||||
ignoredDomainsControllers: _ignoredDomainsControllers,
|
||||
updateIgnoredDomainsControllers: (v) => setState(() => _ignoredDomainsControllers = v),
|
||||
);
|
||||
|
||||
case LoadStatus.error:
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:convert';
|
|||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
|
||||
import 'package:adguard_home_manager/models/blocked_services.dart';
|
||||
import 'package:adguard_home_manager/models/querylog_config.dart';
|
||||
import 'package:adguard_home_manager/models/dns_info.dart';
|
||||
import 'package:adguard_home_manager/models/encryption.dart';
|
||||
import 'package:adguard_home_manager/models/dhcp.dart';
|
||||
|
@ -627,10 +628,19 @@ class ApiClientV2 {
|
|||
Future<ApiResponse> getQueryLogInfo() async {
|
||||
final result = await HttpRequestClient.get(urlPath: '/querylog/config', server: server);
|
||||
if (result.successful) {
|
||||
return ApiResponse(
|
||||
successful: true,
|
||||
content: jsonDecode(result.body!)
|
||||
);
|
||||
try {
|
||||
return ApiResponse(
|
||||
successful: true,
|
||||
content: QueryLogConfig.fromJson(jsonDecode(result.body!))
|
||||
);
|
||||
} catch (e, stackTrace) {
|
||||
Sentry.captureException(
|
||||
e,
|
||||
stackTrace: stackTrace,
|
||||
hint: Hint.withMap({ "statusCode": result.statusCode.toString() })
|
||||
);
|
||||
return const ApiResponse(successful: false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return const ApiResponse(successful: false);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue