From 8ec7c37715e410c5564c512162be03383b577e39 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Wed, 22 Jan 2020 17:25:50 +0300 Subject: [PATCH] + client: handle check host --- client/src/__locales/en.json | 14 +- client/src/actions/filtering.js | 20 +++ client/src/api/Api.js | 7 + client/src/components/Filters/Check/Info.js | 127 +++++++++++++++++++ client/src/components/Filters/Check/index.js | 95 ++++++++++++++ client/src/components/Filters/UserRules.js | 2 +- client/src/components/Filters/index.js | 21 ++- client/src/components/ui/Card.css | 12 ++ client/src/containers/Filters.js | 2 + client/src/helpers/constants.js | 4 + client/src/helpers/helpers.js | 8 ++ client/src/reducers/filtering.js | 10 ++ 12 files changed, 318 insertions(+), 4 deletions(-) create mode 100644 client/src/components/Filters/Check/Info.js create mode 100644 client/src/components/Filters/Check/index.js diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index b594c20a..9e11009a 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -446,5 +446,17 @@ "autofix_warning_result": "As a result all DNS requests from your system will be processed by AdGuardHome by default.", "tags_title": "Tags", "tags_desc": "You can select the tags that correspond to the client. Tags can be included in the filtering rules and allow you to apply them more accurately. <0>Learn more", - "form_select_tags": "Select client tags" + "form_select_tags": "Select client tags", + "check_title": "Check the filtering", + "check_desc": "Check if the host name is filtered", + "check": "Check", + "form_enter_host": "Enter a host name", + "filtered_custom_rules": "Filtered by Custom filtering rules", + "host_whitelisted": "The host is whitelisted", + "check_ip": "IP addresses: {{ip}}", + "check_cname": "CNAME: {{cname}}", + "check_reason": "Reason: {{reason}}", + "check_rule": "Rule: {{rule}}", + "check_service": "Service name: {{service}}", + "check_not_found": "Doesn't exist in any filter" } diff --git a/client/src/actions/filtering.js b/client/src/actions/filtering.js index 117c22ee..ee8d5c03 100644 --- a/client/src/actions/filtering.js +++ b/client/src/actions/filtering.js @@ -161,3 +161,23 @@ export const setFiltersConfig = config => async (dispatch, getState) => { dispatch(setFiltersConfigFailure()); } }; + +export const checkHostRequest = createAction('CHECK_HOST_REQUEST'); +export const checkHostFailure = createAction('CHECK_HOST_FAILURE'); +export const checkHostSuccess = createAction('CHECK_HOST_SUCCESS'); + +export const checkHost = host => async (dispatch) => { + dispatch(checkHostRequest()); + try { + const data = await apiClient.checkHost(host); + const [hostname] = Object.values(host); + + dispatch(checkHostSuccess({ + hostname, + ...data, + })); + } catch (error) { + dispatch(addErrorToast({ error })); + dispatch(checkHostFailure()); + } +}; diff --git a/client/src/api/Api.js b/client/src/api/Api.js index 3d215144..97d2cc6f 100644 --- a/client/src/api/Api.js +++ b/client/src/api/Api.js @@ -82,6 +82,7 @@ class Api { FILTERING_REFRESH = { path: 'filtering/refresh', method: 'POST' }; FILTERING_SET_URL = { path: 'filtering/set_url', method: 'POST' }; FILTERING_CONFIG = { path: 'filtering/config', method: 'POST' }; + FILTERING_CHECK_HOST = { path: 'filtering/check_host', method: 'GET' }; getFilteringStatus() { const { path, method } = this.FILTERING_STATUS; @@ -141,6 +142,12 @@ class Api { return this.makeRequest(path, method, parameters); } + checkHost(params) { + const { path, method } = this.FILTERING_CHECK_HOST; + const url = getPathWithQueryString(path, params); + return this.makeRequest(url, method); + } + // Parental PARENTAL_STATUS = { path: 'parental/status', method: 'GET' }; PARENTAL_ENABLE = { path: 'parental/enable', method: 'POST' }; diff --git a/client/src/components/Filters/Check/Info.js b/client/src/components/Filters/Check/Info.js new file mode 100644 index 00000000..d3cd0136 --- /dev/null +++ b/client/src/components/Filters/Check/Info.js @@ -0,0 +1,127 @@ +import React, { Fragment } from 'react'; +import PropTypes from 'prop-types'; +import { withNamespaces } from 'react-i18next'; + +import { checkFiltered, checkRewrite, checkBlackList, checkNotFilteredNotFound, checkWhiteList } from '../../../helpers/helpers'; + +const getFilterName = (id, filters, t) => { + if (id === 0) { + return t('filtered_custom_rules'); + } + + const filter = filters.find(filter => filter.id === id); + + if (filter && filter.name) { + return t('query_log_filtered', { filter: filter.name }); + } + + return ''; +}; + +const getTitle = (reason, filterName, t) => { + if (checkNotFilteredNotFound(reason)) { + return t('check_not_found'); + } + + if (checkRewrite(reason)) { + return t('rewrite_applied'); + } + + if (checkBlackList(reason)) { + return filterName; + } + + if (checkWhiteList(reason)) { + return ( + +
+ {t('host_whitelisted')} +
+
+ {filterName} +
+
+ ); + } + + return ( + +
+ {t('check_reason', { reason })} +
+
+ {filterName} +
+
+ ); +}; + +const getColor = (reason) => { + if (checkFiltered(reason)) { + return 'red'; + } else if (checkRewrite(reason)) { + return 'blue'; + } else if (checkWhiteList(reason)) { + return 'green'; + } + + return ''; +}; + +const Info = ({ + filters, + hostname, + reason, + filter_id, + rule, + service_name, + cname, + ip_addrs, + t, +}) => { + const filterName = getFilterName(filter_id, filters, t); + const title = getTitle(reason, filterName, t); + const color = getColor(reason); + + return ( +
+
+ {hostname} +
+ +
{title}
+ + {rule && ( +
{t('check_rule', { rule })}
+ )} + + {service_name && ( +
{t('check_service', { service: service_name })}
+ )} + + {cname && ( +
{t('check_cname', { cname })}
+ )} + + {ip_addrs && ( +
+ {t('check_ip', { ip: ip_addrs.join(', ') })} +
+ )} +
+ ); +}; + +Info.propTypes = { + filters: PropTypes.array.isRequired, + hostname: PropTypes.string.isRequired, + reason: PropTypes.string.isRequired, + filter_id: PropTypes.number, + rule: PropTypes.string, + service_name: PropTypes.string, + cname: PropTypes.string, + ip_addrs: PropTypes.array, + t: PropTypes.func.isRequired, +}; + +export default withNamespaces()(Info); diff --git a/client/src/components/Filters/Check/index.js b/client/src/components/Filters/Check/index.js new file mode 100644 index 00000000..13011157 --- /dev/null +++ b/client/src/components/Filters/Check/index.js @@ -0,0 +1,95 @@ +import React, { Fragment } from 'react'; +import PropTypes from 'prop-types'; +import { Trans, withNamespaces } from 'react-i18next'; +import { Field, reduxForm } from 'redux-form'; +import flow from 'lodash/flow'; +import Card from '../../ui/Card'; + +import { renderInputField } from '../../../helpers/form'; +import Info from './Info'; + +const Check = (props) => { + const { + t, + handleSubmit, + pristine, + invalid, + processing, + check, + filters, + } = props; + + const { + hostname, + reason, + filter_id, + rule, + service_name, + cname, + ip_addrs, + } = check; + + return ( + +
+
+
+
+ + + + +
+ {check.hostname && ( + +
+ +
+ )} +
+
+
+
+ ); +}; + +Check.propTypes = { + t: PropTypes.func.isRequired, + handleSubmit: PropTypes.func.isRequired, + pristine: PropTypes.bool.isRequired, + invalid: PropTypes.bool.isRequired, + processing: PropTypes.bool.isRequired, + check: PropTypes.object.isRequired, + filters: PropTypes.array.isRequired, +}; + +export default flow([ + withNamespaces(), + reduxForm({ form: 'domainCheckForm' }), +])(Check); diff --git a/client/src/components/Filters/UserRules.js b/client/src/components/Filters/UserRules.js index a2f10507..312d175c 100644 --- a/client/src/components/Filters/UserRules.js +++ b/client/src/components/Filters/UserRules.js @@ -26,7 +26,7 @@ class UserRules extends Component { />
+
+ +
( normalizeOnBlur ? input.onBlur(normalizeOnBlur(event.target.value)) : input.onBlur()); + +export const checkFiltered = reason => reason.indexOf(FILTERED) === 0; +export const checkRewrite = reason => reason === FILTERED_STATUS.REWRITE; +export const checkBlackList = reason => reason === FILTERED_STATUS.FILTERED_BLACK_LIST; +export const checkWhiteList = reason => reason === FILTERED_STATUS.NOT_FILTERED_WHITE_LIST; +export const checkNotFilteredNotFound = reason => reason === FILTERED_STATUS.NOT_FILTERED_NOT_FOUND; diff --git a/client/src/reducers/filtering.js b/client/src/reducers/filtering.js index f3f3d894..da298426 100644 --- a/client/src/reducers/filtering.js +++ b/client/src/reducers/filtering.js @@ -79,6 +79,14 @@ const filtering = handleActions( ...payload, processingSetConfig: false, }), + + [actions.checkHostRequest]: state => ({ ...state, processingCheck: true }), + [actions.checkHostFailure]: state => ({ ...state, processingCheck: false }), + [actions.checkHostSuccess]: (state, { payload }) => ({ + ...state, + check: payload, + processingCheck: false, + }), }, { isModalOpen: false, @@ -89,6 +97,7 @@ const filtering = handleActions( processingConfigFilter: false, processingRemoveFilter: false, processingSetConfig: false, + processingCheck: false, isFilterAdded: false, filters: [], userRules: '', @@ -96,6 +105,7 @@ const filtering = handleActions( enabled: true, modalType: '', modalFilterUrl: '', + check: {}, }, );