luci-app: Code fixes, updated log

This commit is contained in:
gSpot
2021-03-26 23:49:38 +03:00
parent 399ce9fb7f
commit 03eac5f427
16 changed files with 333 additions and 260 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ LUCI_APP=1
OWRT_VERSION="19.07" OWRT_VERSION="19.07"
RUAB_VERSION="0.9.0-2" RUAB_VERSION="0.9.0-2"
RUAB_MOD_LUA_VERSION="0.9.0-2" RUAB_MOD_LUA_VERSION="0.9.0-2"
RUAB_LUCI_APP_VERSION="0.9.0-4" RUAB_LUCI_APP_VERSION="0.9.0-5"
BASE_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_openwrt/master" BASE_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_openwrt/master"
PKG_DIR="/tmp" PKG_DIR="/tmp"
+1 -1
View File
@@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_VERSION:=0.9.0 PKG_VERSION:=0.9.0
PKG_RELEASE:=4 PKG_RELEASE:=5
LUCI_TITLE:=LuCI support for ruantiblock LUCI_TITLE:=LuCI support for ruantiblock
LUCI_DEPENDS:=+ruantiblock +luci-mod-admin-full LUCI_DEPENDS:=+ruantiblock +luci-mod-admin-full
LUCI_PKGARCH:=all LUCI_PKGARCH:=all
@@ -1,217 +1,7 @@
'use strict'; 'use strict';
'require ui'; 'require ui';
return L.Class.extend({ document.head.append(E('style', {'type': 'text/css'},
view: L.view.extend({
viewName: null,
title: null,
logFacilities: [
'kern',
'user',
'mail',
'daemon',
'auth',
'syslog',
'lpr',
'news',
],
logLevels: {
'emerg': E('span', { 'class': 'zonebadge log-emerg' }, E('strong', _('Emergency'))),
'alert': E('span', { 'class': 'zonebadge log-alert' }, E('strong', _('Alert'))),
'crit': E('span', { 'class': 'zonebadge log-crit' }, E('strong', _('Critical'))),
'err': E('span', { 'class': 'zonebadge log-err' }, E('strong', _('Error'))),
'warn': E('span', { 'class': 'zonebadge log-warn' }, E('strong', _('Warning'))),
'notice': E('span', { 'class': 'zonebadge log-notice' }, E('strong', _('Notice'))),
'info': E('span', { 'class': 'zonebadge log-info' }, E('strong', _('Info'))),
'debug': E('span', { 'class': 'zonebadge log-debug' }, E('strong', _('Debug'))),
},
tailValue: 25,
logSortingValue: 'asc',
logLevelsStat: {},
logLevelsDropdown: null,
totalLogLines: 0,
htmlEntities: function(str) {
return String(str).replace(
/&/g, '&').replace(
/</g, '&#60;').replace(
/>/g, '&#62;').replace(
/"/g, '&#34;').replace(
/'/g, '&#39;');
},
/**
*
* @param {number} tail
* @returns {string}
* Returns the raw content of the log
*
*/
getLogData: function(tail) {
throw new Error('getLogData needs to be reloaded in subclass');
},
/**
*
* @param {string} logdata
* @param {number} tail
* @returns {Array<number, string|null, string|null, string|null, string|null>}
* Returns an array of values: [ #, Timestamp, Level, Facility, Message ]
*
*/
parseLogData: function(logdata, tail) {
throw new Error('parseLogData needs to be reloaded in subclass');
},
setLevelFilter: function(cArr) {
let logLevelsKeys = Object.keys(this.logLevels);
if(logLevelsKeys.length > 0) {
let selectedLevels = this.logLevelsDropdown.getValue();
if(logLevelsKeys.length === selectedLevels.length) {
return cArr;
};
return cArr.filter(s => selectedLevels.length === 0 || selectedLevels.includes(s[2]));
};
return cArr;
},
setRegexpFilter: function(cArr) {
let fPattern = document.getElementById('logFilter').value;
if(!fPattern) {
return cArr;
};
let fArr = [];
try {
let regExp = new RegExp(`(${fPattern})`, 'giu');
cArr.forEach((e, i) => {
if(e[4] !== null && regExp.test(e[4])) {
e[4] = e[4].replace(regExp, '<span class="log-highlight-item">$1</span>');
fArr.push(e);
};
});
} catch(err) {
if(err.name === 'SyntaxError') {
ui.addNotification(null,
E('p', {}, _('Invalid regular expression') + ': ' + err.message));
return cArr;
} else {
throw err;
};
};
return fArr;
},
makeLogArea: function(logdataArray) {
let lines = `<div class="tr"><div class="td center log-entry-empty">${_('No entries available...')}</div></div>`;
let logTable = E('div', { 'id': 'logTable', 'class': 'table' });
for(let level of Object.keys(this.logLevels)) {
this.logLevelsStat[level] = 0;
};
if(logdataArray.length > 0) {
lines = [];
logdataArray.forEach((e, i) => {
if(e[2] in this.logLevels) {
this.logLevelsStat[e[2]] = this.logLevelsStat[e[2]] + 1;
};
lines.push(
`<div class="tr log-${e[2] || 'empty'}"><div class="td left" data-title="#">${e[0]}</div>` +
((e[1]) ? `<div class="td left" data-title="${_('Timestamp')}">${e[1]}</div>` : '') +
((e[2]) ? `<div class="td left" data-title="${_('Level')}">${e[2]}</div>` : '') +
((e[3]) ? `<div class="td left" data-title="${_('Facility')}">${e[3]}</div>` : '') +
((e[4]) ? `<div class="td left log-entry-message-cell" data-title="${_('Message')}">${e[4]}</div>` : '') +
`</div>`
);
});
lines = lines.join('');
logTable.append(
E('div', { 'class': 'tr table-titles' }, [
E('div', { 'class': 'th left log-entry-number' }, '#'),
(logdataArray[0][1]) ? E('div', { 'class': 'th left log-entry-time' }, _('Timestamp')) : '',
(logdataArray[0][2]) ? E('div', { 'class': 'th left log-entry-log-level' }, _('Level')) : '',
(logdataArray[0][3]) ? E('div', { 'class': 'th left log-entry-facility' }, _('Facility')) : '',
(logdataArray[0][4]) ? E('div', { 'class': 'th left log-entry-message' }, _('Message')) : '',
])
);
};
try {
logTable.insertAdjacentHTML('beforeend', lines);
} catch(err) {
if(err.name === 'SyntaxError') {
ui.addNotification(null,
E('p', {}, _('HTML/XML error') + ': ' + err.message), 'error');
};
throw err;
};
let levelsStatString = '';
if((Object.values(this.logLevelsStat).reduce((s,c) => s + c, 0)) > 0) {
Object.entries(this.logLevelsStat).forEach(e => {
if(e[0] in this.logLevels && e[1] > 0) {
levelsStatString += `<span class="log-entries-count-level log-${e[0]}" title="${e[0]}">${e[1]}</span>`;
};
});
};
return E([
E('div', { 'class': 'log-entries-count' },
`${_('Entries')}: ${logdataArray.length} / ${this.totalLogLines}${levelsStatString}`
),
logTable
]);
},
downloadLog: function(ev) {
let formElems = Array.from(document.forms.logForm.elements);
formElems.forEach(e => e.disabled = true);
return this.getLogData(0).then(logdata => {
logdata = logdata || '';
let link = E('a', {
'download': this.viewName + '.log',
'href': URL.createObjectURL(
new Blob([ logdata ], { type: 'text/plain' })),
});
link.click();
URL.revokeObjectURL(link.href);
}).catch(() => {
ui.addNotification(null,
E('p', {}, _('Download error') + ': ' + err.message));
}).finally(() => {
formElems.forEach(e => e.disabled = false);
});
},
load: function() {
// Restoring settings from localStorage
let tailValueLocal = localStorage.getItem(`luci-app-${this.viewName}-tailValue`);
if(tailValueLocal) {
this.tailValue = Number(tailValueLocal);
};
let logSortingLocal = localStorage.getItem(`luci-app-${this.viewName}-logSorting`);
if(logSortingLocal) {
this.logSortingValue = logSortingLocal;
};
return this.getLogData(this.tailValue);
},
render: function(logdata) {
document.head.append(E('style', {'type': 'text/css'},
` `
.log-entry-empty { .log-entry-empty {
} }
@@ -221,6 +11,13 @@ return L.Class.extend({
.log-entry-time { .log-entry-time {
min-width: 14em !important; min-width: 14em !important;
} }
.log-entry-host {
min-width: 10em !important;
}
.log-entry-host-cell {
word-break: break-all !important;
word-wrap: break-word !important;
}
.log-entry-log-level { .log-entry-log-level {
max-width: 5em !important; max-width: 5em !important;
} }
@@ -291,9 +88,234 @@ log-emerg td {
border: 1px solid #ccc; border: 1px solid #ccc;
font-weight: normal; font-weight: normal;
} }
` .log-host-dropdown-item {
)); }
`));
return L.Class.extend({
view: L.view.extend({
viewName: null,
title: null,
logLevels: {
'emerg': E('span', { 'class': 'zonebadge log-emerg' }, E('strong', _('Emergency'))),
'alert': E('span', { 'class': 'zonebadge log-alert' }, E('strong', _('Alert'))),
'crit': E('span', { 'class': 'zonebadge log-crit' }, E('strong', _('Critical'))),
'err': E('span', { 'class': 'zonebadge log-err' }, E('strong', _('Error'))),
'warn': E('span', { 'class': 'zonebadge log-warn' }, E('strong', _('Warning'))),
'notice': E('span', { 'class': 'zonebadge log-notice' }, E('strong', _('Notice'))),
'info': E('span', { 'class': 'zonebadge log-info' }, E('strong', _('Info'))),
'debug': E('span', { 'class': 'zonebadge log-debug' }, E('strong', _('Debug'))),
},
tailValue: 25,
logSortingValue: 'asc',
logLevelsStat: {},
logHosts: {},
logHostsDropdown: null,
logLevelsDropdown: null,
totalLogLines: 0,
htmlEntities: function(str) {
return String(str).replace(
/&/g, '&#38;').replace(
/</g, '&#60;').replace(
/>/g, '&#62;').replace(
/"/g, '&#34;').replace(
/'/g, '&#39;');
},
makelogHostsDropdownItem: function(host) {
return E(
'span',
{ 'class': 'zonebadge log-host-dropdown-item' },
E('strong', host)
);
},
/**
*
* @param {number} tail
* @returns {string}
* Returns the raw content of the log
*
*/
getLogData: function(tail) {
throw new Error('getLogData must be overridden by a subclass');
},
/**
*
* @param {string} logdata
* @param {number} tail
* @returns {Array<number, string|null, string|null, string|null, string|null, string|null>}
* Returns an array of values: [ #, Timestamp, Host, Level, Facility, Message ]
*
*/
parseLogData: function(logdata, tail) {
throw new Error('parseLogData must be overridden by a subclass');
},
setHostFilter: function(cArr) {
let logHostsKeys = Object.keys(this.logHosts);
if(logHostsKeys.length > 0) {
let selectedHosts = this.logHostsDropdown.getValue();
this.logHostsDropdown.addChoices(Object.keys(this.logHosts), this.logHosts);
if(selectedHosts.length === 0 || logHostsKeys.length === selectedHosts.length) {
return cArr;
};
return cArr.filter(e => selectedHosts.includes(e[2]));
};
return cArr;
},
setLevelFilter: function(cArr) {
let logLevelsKeys = Object.keys(this.logLevels);
if(logLevelsKeys.length > 0) {
let selectedLevels = this.logLevelsDropdown.getValue();
if(selectedLevels.length === 0 || logLevelsKeys.length === selectedLevels.length) {
return cArr;
};
return cArr.filter(e => selectedLevels.includes(e[3]));
};
return cArr;
},
setRegexpFilter: function(cArr) {
let fPattern = document.getElementById('logFilter').value;
if(!fPattern) {
return cArr;
};
let fArr = [];
try {
let regExp = new RegExp(`(${fPattern})`, 'giu');
cArr.forEach((e, i) => {
if(e[5] !== null && regExp.test(e[5])) {
e[5] = e[5].replace(regExp, '<span class="log-highlight-item">$1</span>');
fArr.push(e);
};
});
} catch(err) {
if(err.name === 'SyntaxError') {
ui.addNotification(null,
E('p', {}, _('Invalid regular expression') + ': ' + err.message));
return cArr;
} else {
throw err;
};
};
return fArr;
},
makeLogArea: function(logdataArray) {
let lines = `<div class="tr"><div class="td center log-entry-empty">${_('No entries available...')}</div></div>`;
let logTable = E('div', { 'id': 'logTable', 'class': 'table' });
for(let level of Object.keys(this.logLevels)) {
this.logLevelsStat[level] = 0;
};
if(logdataArray.length > 0) {
lines = [];
logdataArray.forEach((e, i) => {
if(e[3] in this.logLevels) {
this.logLevelsStat[e[3]] = this.logLevelsStat[e[3]] + 1;
};
lines.push(
`<div class="tr log-${e[3] || 'empty'}"><div class="td left" data-title="#">${e[0]}</div>` +
((e[1]) ? `<div class="td left" data-title="${_('Timestamp')}">${e[1]}</div>` : '') +
((e[2]) ? `<div class="td left log-entry-host-cell" data-title="${_('Host')}">${e[2]}</div>` : '') +
((e[3]) ? `<div class="td left" data-title="${_('Level')}">${e[3]}</div>` : '') +
((e[4]) ? `<div class="td left" data-title="${_('Facility')}">${e[4]}</div>` : '') +
((e[5]) ? `<div class="td left log-entry-message-cell" data-title="${_('Message')}">${e[5]}</div>` : '') +
`</div>`
);
});
lines = lines.join('');
logTable.append(
E('div', { 'class': 'tr table-titles' }, [
E('div', { 'class': 'th left log-entry-number' }, '#'),
(logdataArray[0][1]) ? E('div', { 'class': 'th left log-entry-time' }, _('Timestamp')) : '',
(logdataArray[0][2]) ? E('div', { 'class': 'th left log-entry-host' }, _('Host')) : '',
(logdataArray[0][3]) ? E('div', { 'class': 'th left log-entry-log-level' }, _('Level')) : '',
(logdataArray[0][4]) ? E('div', { 'class': 'th left log-entry-facility' }, _('Facility')) : '',
(logdataArray[0][5]) ? E('div', { 'class': 'th left log-entry-message' }, _('Message')) : '',
])
);
};
try {
logTable.insertAdjacentHTML('beforeend', lines);
} catch(err) {
if(err.name === 'SyntaxError') {
ui.addNotification(null,
E('p', {}, _('HTML/XML error') + ': ' + err.message), 'error');
};
throw err;
};
let levelsStatString = '';
if((Object.values(this.logLevelsStat).reduce((s,c) => s + c, 0)) > 0) {
Object.entries(this.logLevelsStat).forEach(e => {
if(e[0] in this.logLevels && e[1] > 0) {
levelsStatString += `<span class="log-entries-count-level log-${e[0]}" title="${e[0]}">${e[1]}</span>`;
};
});
};
return E([
E('div', { 'class': 'log-entries-count' },
`${_('Entries')}: ${logdataArray.length} / ${this.totalLogLines}${levelsStatString}`
),
logTable
]);
},
downloadLog: function(ev) {
let formElems = Array.from(document.forms.logForm.elements);
formElems.forEach(e => e.disabled = true);
return this.getLogData(0).then(logdata => {
logdata = logdata || '';
let link = E('a', {
'download': this.viewName + '.log',
'href': URL.createObjectURL(
new Blob([ logdata ], { type: 'text/plain' })),
});
link.click();
URL.revokeObjectURL(link.href);
}).catch(() => {
ui.addNotification(null,
E('p', {}, _('Download error') + ': ' + err.message));
}).finally(() => {
formElems.forEach(e => e.disabled = false);
});
},
load: function() {
// Restoring settings from localStorage
let tailValueLocal = localStorage.getItem(`luci-app-${this.viewName}-tailValue`);
if(tailValueLocal) {
this.tailValue = Number(tailValueLocal);
};
let logSortingLocal = localStorage.getItem(`luci-app-${this.viewName}-logSorting`);
if(logSortingLocal) {
this.logSortingValue = logSortingLocal;
};
return this.getLogData(this.tailValue);
},
render: function(logdata) {
let logWrapper = E('div', { let logWrapper = E('div', {
'id': 'logWrapper', 'id': 'logWrapper',
'style': 'width:100%; min-height:20em; padding: 0 0 0 45px; font-size:0.9em !important' 'style': 'width:100%; min-height:20em; padding: 0 0 0 45px; font-size:0.9em !important'
@@ -324,6 +346,31 @@ log-emerg td {
'style': 'max-width:4em !important', 'style': 'max-width:4em !important',
}); });
let logHostsDropdownElem = '';
let logHostsKeys = Object.keys(this.logHosts);
if(logHostsKeys.length > 0) {
this.logHostsDropdown = new ui.Dropdown(
null,
this.logHosts,
{
id: 'logHostsDropdown',
multiple: true,
select_placeholder: _('All'),
}
);
logHostsDropdownElem = E(
'div', { 'class': 'cbi-value' }, [
E('label', {
'class': 'cbi-value-title',
'for': 'logHostsDropdown',
}, _('Hosts')),
E('div', { 'class': 'cbi-value-field' },
this.logHostsDropdown.render()
),
]
);
};
let logLevelsDropdownElem = ''; let logLevelsDropdownElem = '';
let logLevelsKeys = Object.keys(this.logLevels); let logLevelsKeys = Object.keys(this.logLevels);
if(logLevelsKeys.length > 0) { if(logLevelsKeys.length > 0) {
@@ -335,8 +382,6 @@ log-emerg td {
sort: logLevelsKeys, sort: logLevelsKeys,
multiple: true, multiple: true,
select_placeholder: _('All'), select_placeholder: _('All'),
display_items: 3,
dropdown_items: -1,
} }
); );
logLevelsDropdownElem = E( logLevelsDropdownElem = E(
@@ -405,6 +450,7 @@ log-emerg td {
]), ]),
]), ]),
logHostsDropdownElem,
logLevelsDropdownElem, logLevelsDropdownElem,
E('div', { 'class': 'cbi-value' }, [ E('div', { 'class': 'cbi-value' }, [
@@ -427,7 +473,7 @@ log-emerg td {
E('label', { E('label', {
'class': 'cbi-value-title', 'class': 'cbi-value-title',
'for': 'logFilter', 'for': 'logFilter',
}), }, _('Refresh log')),
E('div', { 'class': 'cbi-value-field' }, [ E('div', { 'class': 'cbi-value-field' }, [
logFormSubmitBtn, logFormSubmitBtn,
E('form', { E('form', {
@@ -455,18 +501,18 @@ log-emerg td {
let tail = (tailInput.value && tailInput.value > 0) ? tailInput.value : 0 let tail = (tailInput.value && tailInput.value > 0) ? tailInput.value : 0
return this.getLogData(tail).then(logdata => { return this.getLogData(tail).then(logdata => {
logdata = logdata || ''; logdata = logdata || '';
logWrapper.innerHTML = '';
let loglines = this.makeLogArea( logWrapper.append(
this.setRegexpFilter( this.makeLogArea(
this.setLevelFilter( this.setRegexpFilter(
this.parseLogData(logdata, tail) this.setLevelFilter(
this.setHostFilter(
this.parseLogData(logdata, tail)
)
)
) )
) )
); );
logWrapper.innerHTML = '';
logWrapper.append(loglines);
}).finally(() => { }).finally(() => {
formElems.forEach(e => e.disabled = false); formElems.forEach(e => e.disabled = false);
logDownloadBtn.disabled = false; logDownloadBtn.disabled = false;
@@ -1,9 +1,9 @@
'require fs'; 'require fs';
'require ui'; 'require ui';
'require view.log.baselog as baselog'; 'require view.log.abstract-log as abc';
'require view.ruantiblock.tools as tools'; 'require view.ruantiblock.tools as tools';
return baselog.view.extend({ return abc.view.extend({
viewName: 'ruantiblock', viewName: 'ruantiblock',
title: _('Ruantiblock') + ' - ' + _('Log'), title: _('Ruantiblock') + ' - ' + _('Log'),
@@ -22,6 +22,7 @@ return baselog.view.extend({
return [ return [
lineNum, // # (Number) lineNum, // # (Number)
strArray.slice(0, 5).join(' '), // Timestamp (String) strArray.slice(0, 5).join(' '), // Timestamp (String)
null, // Host (String)
logLevel[1], // Level (String) logLevel[1], // Level (String)
logLevel[0], // Facility (String) logLevel[0], // Facility (String)
this.htmlEntities(strArray.slice(6).join(' ')), // Message (String) this.htmlEntities(strArray.slice(6).join(' ')), // Message (String)
@@ -30,9 +31,14 @@ return baselog.view.extend({
// syslog-ng // syslog-ng
syslog_ngHandler: function(strArray, lineNum) { syslog_ngHandler: function(strArray, lineNum) {
if(!(strArray[3] in this.logHosts)) {
this.logHosts[strArray[3]] = this.makelogHostsDropdownItem(strArray[3]);
};
return [ return [
lineNum, // # (Number) lineNum, // # (Number)
strArray.slice(0, 3).join(' '), // Timestamp (String) strArray.slice(0, 3).join(' '), // Timestamp (String)
strArray[3], // Host (String)
null, // Level (String) null, // Level (String)
null, // Facility (String) null, // Facility (String)
this.htmlEntities(strArray.slice(4).join(' ')), // Message (String) this.htmlEntities(strArray.slice(4).join(' ')), // Message (String)
@@ -48,7 +54,7 @@ return baselog.view.extend({
if(logger) { if(logger) {
return fs.exec_direct(logger, [ '-e', tools.app_name ]).catch(err => { return fs.exec_direct(logger, [ '-e', tools.app_name ]).catch(err => {
ui.addNotification(null, E('p', {}, _('Unable to load log data: ' + err.message))); ui.addNotification(null, E('p', {}, _('Unable to load log data:') + ' ' + err.message));
return ''; return '';
}); });
}; };
@@ -250,8 +250,6 @@ return L.view.extend({
let proxy_local_clients = (typeof(section) === 'object') ? section.proxy_local_clients : null; let proxy_local_clients = (typeof(section) === 'object') ? section.proxy_local_clients : null;
status_token_value = (Array.isArray(status_array)) ? tools.normalize_value(status_array[4]) : null; status_token_value = (Array.isArray(status_array)) ? tools.normalize_value(status_array[4]) : null;
document.head.append(E('style', {'type': 'text/css'}, tools.css));
let status_string = E('div', { let status_string = E('div', {
'id': 'status', 'id': 'status',
'name': 'status', 'name': 'status',
@@ -2,30 +2,8 @@
'require fs'; 'require fs';
'require ui'; 'require ui';
return L.Class.extend({ document.head.append(E('style', {'type': 'text/css'},
app_name: 'ruantiblock', `
exec_path: '/usr/bin/ruantiblock',
init_path: '/etc/init.d/ruantiblock',
token_file: '/var/run/ruantiblock.token',
parsers_dir: '/usr/bin',
torrc_file: '/etc/tor/torrc',
user_entries_file: '/etc/ruantiblock/user_entries',
fqdn_filter_file: '/etc/ruantiblock/fqdn_filter',
ip_filter_file: '/etc/ruantiblock/ip_filter',
crontab_file: '/etc/crontabs/root',
info_label_starting: '<span class="label-status starting">' + _('Starting') + '</span>',
info_label_running: '<span class="label-status running">' + _('Enabled') + '</span>',
info_label_updating: '<span class="label-status updating">' + _('Updating') + '</span>',
info_label_stopped: '<span class="label-status stopped">' + _('Disabled') + '</span>',
info_label_error: '<span class="label-status error">' + _('Error') + '</span>',
blacklist_sources: {
'rublacklist': 'https://rublacklist.net',
'zapret-info': 'https://github.com/zapret-info/z-i',
'antifilter': 'https://antifilter.download',
},
css: `
.label-status { .label-status {
display: inline; display: inline;
margin: 0px 2px 0px 0 !important; margin: 0px 2px 0px 0 !important;
@@ -53,7 +31,31 @@ return L.Class.extend({
} }
.total-proxy { .total-proxy {
background-color: #ffb937 !important; background-color: #ffb937 !important;
}`, }
`));
return L.Class.extend({
app_name: 'ruantiblock',
exec_path: '/usr/bin/ruantiblock',
init_path: '/etc/init.d/ruantiblock',
token_file: '/var/run/ruantiblock.token',
parsers_dir: '/usr/bin',
torrc_file: '/etc/tor/torrc',
user_entries_file: '/etc/ruantiblock/user_entries',
fqdn_filter_file: '/etc/ruantiblock/fqdn_filter',
ip_filter_file: '/etc/ruantiblock/ip_filter',
crontab_file: '/etc/crontabs/root',
info_label_starting: '<span class="label-status starting">' + _('Starting') + '</span>',
info_label_running: '<span class="label-status running">' + _('Enabled') + '</span>',
info_label_updating: '<span class="label-status updating">' + _('Updating') + '</span>',
info_label_stopped: '<span class="label-status stopped">' + _('Disabled') + '</span>',
info_label_error: '<span class="label-status error">' + _('Error') + '</span>',
blacklist_sources: {
'rublacklist': 'https://rublacklist.net',
'zapret-info': 'https://github.com/zapret-info/z-i',
'antifilter': 'https://antifilter.download',
},
normalize_value: function(v) { normalize_value: function(v) {
return (v && typeof(v) === 'string') ? v.trim().replace(/\r?\n/g, '') : v; return (v && typeof(v) === 'string') ? v.trim().replace(/\r?\n/g, '') : v;
@@ -386,6 +386,12 @@ msgstr "Записи"
msgid "Facility" msgid "Facility"
msgstr "Категория" msgstr "Категория"
msgid "Host"
msgstr "Хост"
msgid "Hosts"
msgstr "Хосты"
msgid "Info" msgid "Info"
msgstr "Информация" msgstr "Информация"
@@ -413,6 +419,9 @@ msgstr "Нет доступных записей..."
msgid "Notice" msgid "Notice"
msgstr "Сообщение" msgstr "Сообщение"
msgid "Refresh log"
msgstr "Обновить лог"
msgid "Sorting entries" msgid "Sorting entries"
msgstr "Сортировка записей" msgstr "Сортировка записей"
@@ -113,6 +113,9 @@ msgstr ""
msgid "Hour" msgid "Hour"
msgstr "" msgstr ""
msgid "Hour"
msgstr ""
msgid "Interval" msgid "Interval"
msgstr "" msgstr ""
@@ -356,6 +359,12 @@ msgstr ""
msgid "Facility" msgid "Facility"
msgstr "" msgstr ""
msgid "Host"
msgstr ""
msgid "Hosts"
msgstr ""
msgid "Info" msgid "Info"
msgstr "" msgstr ""
@@ -383,6 +392,9 @@ msgstr ""
msgid "Notice" msgid "Notice"
msgstr "" msgstr ""
msgid "Refresh log"
msgstr ""
msgid "Sorting entries" msgid "Sorting entries"
msgstr "" msgstr ""
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -317,8 +317,8 @@ function BlackListParser:fill_domain_tables(val)
end end
function BlackListParser:sink() function BlackListParser:sink()
-- Needs to be reloaded in subclass -- Must be overridden by a subclass
error("Method BlackListParser:sink() needs to be reloaded in subclass!") error("Method BlackListParser:sink() must be overridden by a subclass!")
end end
function BlackListParser:optimize_ip_table() function BlackListParser:optimize_ip_table()
@@ -294,7 +294,7 @@ class BlackListParser(Config):
raise FieldValueError() raise FieldValueError()
def parser_func(self): def parser_func(self):
"""Needs to be reloaded in subclass""" """Must be overridden by a subclass"""
raise NotImplementedError() raise NotImplementedError()
def _check_sld_masks(self, sld): def _check_sld_masks(self, sld):