From 34fa5122f98af4ac635dfc26a64f6d2d3e4fafcb Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Wed, 6 Nov 2019 01:33:53 +0100 Subject: luci-app-ddns: convert to client side implementation Signed-off-by: Ansuel Smith --- .../luci-static/resources/view/ddns/overview.js | 994 +++++++++++++++++++++ .../resources/view/status/include/70_ddns.js | 46 + 2 files changed, 1040 insertions(+) create mode 100644 applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js create mode 100644 applications/luci-app-ddns/htdocs/luci-static/resources/view/status/include/70_ddns.js (limited to 'applications/luci-app-ddns/htdocs/luci-static') diff --git a/applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js b/applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js new file mode 100644 index 0000000000..f19445366c --- /dev/null +++ b/applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js @@ -0,0 +1,994 @@ +'use strict'; +'require uci'; +'require rpc'; +'require fs'; +'require form'; +'require tools.widgets as widgets'; + +var callGetLogServices, callInitAction, callDDnsGetStatus; + +var NextUpdateStrings = {}; + +NextUpdateStrings = { + 'Verify' : _("Verify"), + 'Run once' : _("Run once"), + 'Disabled' : _("Disabled"), + 'Stopped' : _("Stopped") +} + +var time_res = {}; +time_res['seconds'] = 1; +time_res['minutes'] = 60; +time_res['hours'] = 3600; + +callGetLogServices = rpc.declare({ + object: 'luci.ddns', + method: 'get_services_log', + params: [ 'service_name' ], + expect: { }, +}); + +callInitAction = rpc.declare({ + object: 'luci', + method: 'setInitAction', + params: [ 'name', 'action' ], + expect: { result: false } +}); + +callDDnsGetStatus = rpc.declare({ + object: 'luci.ddns', + method: 'get_ddns_state', + expect: { } +}); + +return L.view.extend({ + + callDDnsGetEnv: rpc.declare({ + object: 'luci.ddns', + method: 'get_env', + expect: { } + }), + + callDDnsGetServicesStatus: rpc.declare({ + object: 'luci.ddns', + method: 'get_services_status', + expect: { } + }), + + poll_status: function(map, data) { + var status = data[1] || [], service = data[0] || [], rows = map.querySelectorAll('.cbi-section-table-row[data-sid]'), + section_id, cfg_detail_ip, cfg_update, cfg_status, host, ip, last_update, + next_update, service_status, reload, cfg_enabled, stop, + ddns_enabled = map.querySelector('[data-name="_enabled"]').querySelector('.cbi-value-field'), + ddns_toggle = map.querySelector('[data-name="_toggle"]').querySelector('button'); + + ddns_toggle.innerHTML = status['_enabled'] ? _('Stop DDNS') : _('Start DDNS') + + L.dom.content(ddns_enabled, function() { + return E([], [ + E('div', {}, status['_enabled'] ? _('DDNS Autostart enabled') : [ + _('DDNS Autostart disabled'), + E('div', { 'class' : 'cbi-value-description' }, + _("Currently DDNS updates are not started at boot or on interface events.") + "
" + + _("This is the default if you run DDNS scripts by yourself (i.e. via cron with force_interval set to '0')")) + ]),]); + }); + + for (var i = 0; i < rows.length; i++) { + section_id = rows[i].getAttribute('data-sid'); + cfg_detail_ip = rows[i].querySelector('[data-name="_cfg_detail_ip"]'); + cfg_update = rows[i].querySelector('[data-name="_cfg_update"]'); + cfg_status = rows[i].querySelector('[data-name="_cfg_status"]'); + reload = rows[i].querySelector('.cbi-section-actions .reload'); + stop = rows[i].querySelector('.cbi-section-actions .stop'); + cfg_enabled = uci.get('ddns', section_id, 'enabled'); + + reload.disabled = (status['_enabled'] == 0 || cfg_enabled == 0); + + host = uci.get('ddns', section_id, 'lookup_host') || _('Configuration Error'); + ip = _('No Data'); + last_update = _('Never'); + next_update = _('Unknown'); + service_status = '' + _('Not Running') + ''; + + if (service[section_id]) { + stop.disabled = (!service[section_id].pid || (service[section_id].pid && cfg_enabled == '1')); + if (service[section_id].ip) + ip = service[section_id].ip; + if (service[section_id].last_update) + last_update = service[section_id].last_update; + if (service[section_id].next_update) + next_update = NextUpdateStrings[service[section_id].next_update] || service[section_id].next_update; + if (service[section_id].pid) + service_status = '' + _('Running') + ' : ' + service[section_id].pid; + } + + cfg_detail_ip.innerHTML = host + '
' + ip; + cfg_update.innerHTML = last_update + '
' + next_update; + cfg_status.innerHTML = service_status; + } + + return; + }, + + load: function() { + return Promise.all([ + this.callDDnsGetServicesStatus(), + callDDnsGetStatus(), + this.callDDnsGetEnv(), + fs.lines('/etc/ddns/services'), + fs.lines('/etc/ddns/services_ipv6'), + uci.load('ddns') + ]); + }, + + render: function(data) { + var resolved = data[0] || []; + var status = data[1] || []; + var env = data[2] || []; + var logdir = uci.get('ddns', 'global', 'ddns_logdir') || "/var/log/ddns"; + + var services4 = []; + var services6 = []; + + data[3].forEach(function(item) { + if (!item.startsWith("#")) { + services4.push(item.split('\t')[0].slice(1,-1)); + } + }); + + data[4].forEach(function(item) { + if (!item.startsWith("#")) { + services6.push(item.split('\t')[0].slice(1,-1)); + } + }); + + var m, s, o; + + m = new form.Map('ddns', _('Dynamic DNS'),); + + var is = m.section(form.NamedSection, 'global', 'ddns', _('Information')); + + s = is; + + o = s.option(form.DummyValue, '_version', _('Dynamic DNS Version')); + o.cfgvalue = function() { + return status[this.option]; + }; + + o = s.option(form.DummyValue, '_enabled', _('State')); + o.cfgvalue = function() { + var res = status[this.option]; + if (!res) { + this.description = _("Currently DDNS updates are not started at boot or on interface events.") + "
" + + _("This is the default if you run DDNS scripts by yourself (i.e. via cron with force_interval set to '0')") + } + return res ? _('DDNS Autostart enabled') : _('DDNS Autostart disabled') + }; + + o = s.option(form.DummyValue, '_toggle', ' '); + o.cfgvalue = function() { + var action = status['_enabled'] ? 'stop' : 'start'; + return E([], [ + E('button', { + 'class': 'cbi-button cbi-button-apply', + 'click': L.ui.createHandlerFn(this, function() { + return callDDnsGetStatus().then(L.bind(function(data) { + return callInitAction('ddns', action == 'stop' ? 'disable' : 'enable').then(function() { + return callInitAction('ddns', action); + }); + }, this)).then(L.bind(m.render, m)); + }) + }, _(action.toUpperCase() + ' DDns'))]); + }; + + o = s.option(form.DummyValue, '_restart', ' '); + o.cfgvalue = function() { + return E([], [ + E('button', { + 'class': 'cbi-button cbi-button-apply', + 'click': L.ui.createHandlerFn(this, function() { + return callInitAction('ddns', 'restart').then(L.bind(m.render, m)); + }) + }, _('Restart DDns'))]); + }; + + // DDns hints + + if (!env['has_ipv6']) { + o = s.option(form.DummyValue, '_no_ipv6'); + o.rawhtml = true; + o.title = '' + _("IPv6 not supported") + ''; + o.cfgvalue = function() { return _("IPv6 is currently not (fully) supported by this system") + "
" + + _("Please follow the instructions on OpenWrt's homepage to enable IPv6 support") + "
" + + _("or update your system to the latest OpenWrt Release")}; + } + + if (!env['has_ssl']) { + o = s.option(form.DummyValue, '_no_https'); + o.titleref = L.url("admin", "system", "opkg") + o.rawhtml = true; + o.title = '' + _("HTTPS not supported") + ''; + o.cfgvalue = function() { return _("Neither GNU Wget with SSL nor cURL installed to support secure updates via HTTPS protocol.") + + "
- " + + _("You should install 'wget' or 'curl' or 'uclient-fetch' with 'libustream-*ssl' package.") + + "
- " + + _("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")}; + } + + if (!env['has_bindnet']) { + o = s.option(form.DummyValue, '_no_bind_network'); + o.titleref = L.url("admin", "system", "opkg") + o.rawhtml = true; + o.title = '' + _("Binding to a specific network not supported") + ''; + o.cfgvalue = function() { return _("Neither GNU Wget with SSL nor cURL installed to select a network to use for communication.") + + "
- " + + _("You should install 'wget' or 'curl' package.") + + "
- " + + _("GNU Wget will use the IP of given network, cURL will use the physical interface.") + + "
- " + + _("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")}; + } + + if (!env['has_proxy']) { + o = s.option(form.DummyValue, '_no_proxy'); + o.titleref = L.url("admin", "system", "opkg") + o.rawhtml = true; + o.title = '' + _("cURL without Proxy Support") + ''; + o.cfgvalue = function() { return _("cURL is installed, but libcurl was compiled without proxy support.") + + "
- " + + _("You should install 'wget' or 'uclient-fetch' package or replace libcurl.") + + "
- " + + _("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")}; + } + + if (!env['has_forceip']) { + o = s.option(form.DummyValue, '_no_force_ip'); + o.titleref = L.url("admin", "system", "opkg") + o.rawhtml = true; + o.title = '' + _("Force IP Version not supported") + ''; + o.cfgvalue = function() { return _("BusyBox's nslookup and Wget do not support to specify " + + "the IP version to use for communication with DDNS Provider!") + + "
- " + _("You should install 'wget' or 'curl' or 'uclient-fetch' package.") + }; + } + + if (!env['has_bindhost']) { + o = s.option(form.DummyValue, '_no_dnstcp'); + o.titleref = L.url("admin", "system", "opkg") + o.rawhtml = true; + o.title = '' + _("DNS requests via TCP not supported") + ''; + o.cfgvalue = function() { return _("BusyBox's nslookup and hostip do not support to specify to use TCP " + + "instead of default UDP when requesting DNS server!") + + "
- " + + _("You should install 'bind-host' or 'knot-host' or 'drill' package for DNS requests.")}; + } + + if (!env['has_dnsserver']) { + o = s.option(form.DummyValue, '_no_dnsserver'); + o.titleref = L.url("admin", "system", "opkg") + o.rawhtml = true; + o.title = '' + _("Using specific DNS Server not supported") + ''; + o.cfgvalue = function() { return _("BusyBox's nslookup in the current compiled version " + + "does not handle given DNS Servers correctly!") + + "
- " + + _("You should install 'bind-host' or 'knot-host' or 'drill' or 'hostip' package, " + + "if you need to specify a DNS server to detect your registered IP.")}; + } + + if (env['has_ssl'] && !env['has_cacerts']) { + o = s.option(form.DummyValue, '_no_certs'); + o.titleref = L.url("admin", "system", "opkg") + o.rawhtml = true; + o.title = '' + _("No certificates found") + ''; + o.cfgvalue = function() { return _("If using secure communication you should verify server certificates!") + + "
- " + + _("Install 'ca-certificates' package or needed certificates " + + "by hand into /etc/ssl/certs default directory")}; + } + + // DDns services + s = m.section(form.GridSection, 'service', _('Services')); + s.anonymous = true; + s.addremove = true; + s.addbtntitle = _('Add new services...'); + + s.anonymous = true; + s.addremove = true; + s.sortable = true; + + s.handleAdd = function(ev) { + var m2 = new form.Map('ddns'), + s2 = m2.section(form.NamedSection, '_new_'); + + s2.render = function() { + return Promise.all([ + {}, + this.renderUCISection('_new_') + ]).then(this.renderContents.bind(this)); + }; + + name = s2.option(form.Value, 'name', _('Name')); + name.rmempty = false; + name.datatype = 'uciname'; + name.placeholder = _('New DDns Service…'); + name.validate = function(section_id, value) { + if (uci.get('ddns', value) != null) + return _('The service name is already used'); + + return true; + }; + + m2.render().then(L.bind(function(nodes) { + L.ui.showModal(_('Add new services...'), [ + nodes, + E('div', { 'class': 'right' }, [ + E('button', { + 'class': 'btn', + 'click': L.ui.hideModal + }, _('Cancel')), ' ', + E('button', { + 'class': 'cbi-button cbi-button-positive important', + 'click': L.ui.createHandlerFn(this, function(ev) { + var nameval = name.isValid('_new_') ? name.formvalue('_new_') : null; + + if (nameval == null || nameval == '') + return; + + return m.save(function() { + uci.add('ddns', 'service', nameval); + }).then(L.bind(m.children[1].renderMoreOptionsModal, m.children[1], nameval)); + }) + }, _('Create service')) + ]) + ], 'cbi-modal'); + + nodes.querySelector('[id="%s"] input[type="text"]'.format(name.cbid('_new_'))).focus(); + }, this)); + }; + + s.renderRowActions = function(section_id) { + var tdEl = this.super('renderRowActions', [ section_id, _('Edit') ]), + cfg_enabled = uci.get('ddns', section_id, 'enabled'), + reload_opt = { + 'class': 'cbi-button cbi-button-neutral reload', + 'click': L.ui.createHandlerFn(this, function() { + return fs.exec('/usr/lib/ddns/dynamic_dns_lucihelper.sh', + [ '-S', section_id, '--', 'start' ]).then(L.bind(m.render, m)); + }), + 'title': _('Reload this service'), + }, + stop_opt = { + 'class': 'cbi-button cbi-button-neutral stop', + 'click': L.ui.createHandlerFn(this, function() { + return fs.exec('/usr/lib/ddns/dynamic_dns_lucihelper.sh', + [ '-S', section_id, '--', 'start' ]).then(L.bind(m.render, m)); + }), + 'title': _('Stop this service'), + }; + + if (status['_enabled'] == 0 || cfg_enabled == 0) + reload_opt['disabled'] = 'disabled'; + + if (!resolved[section_id] || !resolved[section_id].pid || + (resolved[section_id].pid && cfg_enabled == '1')) + stop_opt['disabled'] = 'disabled'; + + L.dom.content(tdEl.lastChild, [ + E('button', stop_opt, _('Stop')), + E('button', reload_opt, _('Reload')), + tdEl.lastChild.childNodes[0], + tdEl.lastChild.childNodes[1], + tdEl.lastChild.childNodes[2] + ]); + + return tdEl; + }; + + o = s.option(form.DummyValue, '_cfg_name', _('Name')); + o.modalonly = false; + o.textvalue = function(section_id) { + return '' + section_id + ''; + } + + o = s.option(form.DummyValue, '_cfg_detail_ip', _('Lookup Hostname') + "
" + _('Registered IP')); + o.rawhtml = true; + o.modalonly = false; + o.textvalue = function(section_id) { + var host = uci.get('ddns', section_id, 'lookup_host') || _('Configuration Error'), + ip = _('No Data'); + if (resolved[section_id] && resolved[section_id].ip) + ip = resolved[section_id].ip; + + return host + '
' + ip; + }; + + o = s.option(form.Flag, 'enabled', _('Enabled')); + o.rmempty = false; + o.editable = true; + o.modalonly = false; + + o = s.option(form.DummyValue, '_cfg_update', _('Last Update') + "
" + _('Next Update')); + o.rawhtml = true; + o.modalonly = false; + o.textvalue = function(section_id) { + var last_update = _('Never'), next_update = _('Unknown'); + if (resolved[section_id]) { + if (resolved[section_id].last_update) + last_update = resolved[section_id].last_update; + if (resolved[section_id].next_update) + next_update = NextUpdateStrings[resolved[section_id].next_update] || resolved[section_id].next_update; + } + + return last_update + '
' + next_update; + }; + + s.modaltitle = function(section_id) { + return _('DDns Service') + ' » ' + section_id; + }; + + o = s.option(form.DummyValue, '_cfg_status', _('Status')); + o.modalonly = false; + o.textvalue = function(section_id) { + var text = '' + _('Not Running') + ''; + + if (resolved[section_id] && resolved[section_id].pid) + text = '' + _('Running') + ' : ' + resolved[section_id].pid; + + return text; + } + + + s.tab('basic', _('Basic Settings')); + s.tab('advanced', _('Advanced Settings')); + s.tab('timer', _('Timer Settings')); + s.tab('logview', _('Log File Viewer')); + + // TAB: BASIC + + // enabled + o = s.taboption('basic', form.Flag, 'enabled', _('Enabled'),_("If this service section is disabled it could not be started." + "
" + + "Neither from LuCI interface nor from console")); + o.modalonly = true; + o.rmempty = false; + o.default = '1'; + + // lookup_host + + o = s.taboption('basic', form.Value, 'lookup_host', _("Lookup Hostname"), + _("Hostname/FQDN to validate, if IP update happen or necessary") ); + o.rmempty = false; + o.placeholder = "myhost.example.com"; + o.datatype = 'and(minlength(3),hostname("strict"))'; + o.modalonly = true; + + // use_ipv6 + + o = s.taboption('basic', form.ListValue, 'use_ipv6', _("IP address version"), + _("Defines which IP address 'IPv4/IPv6' is send to the DDNS provider")); + o.default = '0'; + o.modalonly = true; + o.rmempty = false; + + o.value("0", _("IPv4-Address")) + if (env["has_ipv6"]) + o.value("1", _("IPv6-Address")) + + // service_name + + o = s.taboption('basic', form.ListValue, 'ipv4_service_name', _("DDNS Service provider") + " [IPv4]"); + o.depends("use_ipv6", "0") + o.modalonly = true; + + for (var i = 0; i < services4.length; i++) + o.value(services4[i]); + + o.value('-',"-- " + _("custom") + " --"); + + o.cfgvalue = function(section_id) { + return uci.get('ddns', section_id, 'service_name'); + } + + o.write = function(section_id, formvalue) { + if (formvalue != '-') { + uci.set('ddns', section_id, 'update_url', null); + uci.set('ddns', section_id, 'update_script', null); + return uci.set('ddns', section_id, 'service_name', formvalue); + } + return uci.set('ddns', section_id, 'service_name', null); + }; + + o = s.taboption('basic', form.ListValue, 'ipv6_service_name', _("DDNS Service provider") + " [IPv6]"); + o.depends("use_ipv6", "1") + o.modalonly = true; + + for (var i = 0; i < services6.length; i++) + o.value(services6[i]); + + o.value('-',"-- " + _("custom") + " --"); + + o.cfgvalue = function(section_id) { + return uci.get('ddns', section_id, 'service_name'); + } + + o.write = function(section_id, formvalue) { + if (formvalue != '-') { + uci.set('ddns', section_id, 'update_url', null); + uci.set('ddns', section_id, 'update_script', null); + return uci.set('ddns', section_id, 'service_name', formvalue); + } + return uci.set('ddns', section_id, 'service_name', null); + }; + + // update_url + + o = s.taboption('basic', form.Value, 'update_url', _("Custom update-URL"), + _("Update URL to be used for updating your DDNS Provider." + "
" + + "Follow instructions you will find on their WEB page.")); + o.modalonly = true; + o.rmempty = false; + o.depends("ipv6_service_name","-"); + o.depends("ipv4_service_name","-"); + + // update_script + + o = s.taboption('basic', form.Value, 'update_script', _("Custom update-script"), + _("Custom update script to be used for updating your DDNS Provider.")); + o.modalonly = true; + o.rmempty = false; + o.depends("ipv6_service_name","-"); + o.depends("ipv4_service_name","-"); + + // domain + + o = s.taboption('basic', form.Value, 'domain', _("Domain"), + _("Replaces [USERNAME] in Update-URL (URL-encoded)")); + o.modalonly = true; + o.rmempty = false; + + // username + + o = s.taboption('basic', form.Value, 'username', _("Username"), + _("Replaces [USERNAME] in Update-URL (URL-encoded)")); + o.modalonly = true; + o.rmempty = false; + + // password + + + o = s.taboption('basic', form.Value, 'password', _("Password"), + _("Replaces [PASSWORD] in Update-URL (URL-encoded)")); + o.password = true; + o.modalonly = true; + o.rmempty = false; + + // param_enc + + o = s.taboption('basic', form.Value, 'param_enc', _("Optional Encoded Parameter"), + _("Optional: Replaces [PARAMENC] in Update-URL (URL-encoded)")); + o.optional = true; + o.modalonly = true; + + // param_opt + + o = s.taboption('basic', form.Value, 'param_opt', _("Optional Parameter"), + _("Optional: Replaces [PARAMOPT] in Update-URL (NOT URL-encoded)")); + o.optional = true; + o.modalonly = true; + + // use_https + + if (env['has_ssl']) { + o = s.taboption('basic', form.Flag, 'use_https', _("Use HTTP Secure"), + _("Enable secure communication with DDNS provider")); + o.optional = true; + o.modalonly = true; + + o = s.taboption('basic', form.Value, 'cacert', + _("Path to CA-Certificate"), + _("directory or path/file") + "
" + + _("or") + '' + " IGNORE " + '' + + _("to run HTTPS without verification of server certificates (insecure)")); + o.modalonly = true; + o.depends("use_https", "1"); + o.placeholder = "/etc/ssl/certs"; + o.rmempty = false; + }; + + // TAB Advanced + + // ip_source + + o = s.taboption('advanced', form.ListValue, 'ip_source', _("IP address source"), + _("Defines the source to read systems IP-Address from, that will be send to the DDNS provider")); + + o.modalonly = true; + o.default = "network"; + o.value("network", _("Network")); + o.value("web", _("URL")); + o.value("interface", _("Interface")); + o.value("script", _("Script")); + + o.write = function(section_id, formvalue) { + switch(formvalue) { + case 'network': + uci.set('ddns', section_id, "ip_url",null); + uci.set('ddns', section_id, "ip_interface",null); + uci.set('ddns', section_id, "ip_script",null); + break; + case 'web': + uci.set('ddns', section_id, "ip_network",null); + uci.set('ddns', section_id, "ip_interface",null); + uci.set('ddns', section_id, "ip_script",null); + break; + case 'interface': + uci.set('ddns', section_id, "ip_network",null); + uci.set('ddns', section_id, "ip_url",null); + uci.set('ddns', section_id, "ip_script",null); + break; + case 'script': + uci.set('ddns', section_id, "ip_network",null); + uci.set('ddns', section_id, "ip_url",null); + uci.set('ddns', section_id, "ip_interface",null); + break; + default: + break; + }; + + return uci.set('ddns', section_id, 'ip_source', formvalue ) + }; + + // ip_network + + o = s.taboption('advanced', widgets.ZoneSelect, 'ip_network', _("Network"), + _("Defines the network to read systems IP-Address from")); + o.depends('ip_source','network'); + o.modalonly = true; + o.default = 'wan'; + o.multiple = false; + + // ip_url + + o = s.taboption('advanced', form.Value, 'ip_url', _("URL to detect"), + _("Defines the Web page to read systems IP-Address from" + '
' + + _('Example for IPv4' + ': http://checkip.dyndns.com') + '
' + + _('Example for IPv6' + ': http://checkipv6.dyndns.com'))); + o.depends("ip_source", "web") + + o.modalonly = true; + + // ip_interface + + o = s.taboption('advanced', widgets.ZoneSelect, 'ip_interface', _("Interface"), + _("Defines the interface to read systems IP-Address from")); + + o.modalonly = true; + o.depends("ip_source", "interface") + o.multiple = false; + o.default = 'wan'; + + // ip_script + + o = s.taboption('advanced', form.Value, 'ip_script', _("Script"), + _("User defined script to read systems IP-Address")); + + o.modalonly = true; + o.depends("ip_source", "script") + o.placeholder = "/path/to/script.sh" + + // interface + + o = s.taboption('advanced', widgets.ZoneSelect, 'interface', _("Event Network"), + _("Network on which the ddns-updater scripts will be started")); + + o.modalonly = true; + o.multiple = false; + o.default = 'wan'; + o.depends("ip_source", "web"); + o.depends("ip_source", "script"); + + // interface_show + + o = s.taboption('advanced', form.DummyValue, '_interface', _("Event Network"), + _("Network on which the ddns-updater scripts will be started")); + o.depends("ip_source", "interface"); + o.depends("ip_source", "network"); + o.forcewrite = true; + o.modalonly = true; + o.cfgvalue = function(section_id) { + return uci.get('ddns', section_id, 'interface') || _('This will be autoset to the selected interface'); + }; + o.write = function(section_id) { + var opt = this.section.children.filter(function(o) { return o.option == 'ip_source' })[0].formvalue(section_id); + var val = this.section.children.filter(function(o) { return o.option == 'ip_'+opt })[0].formvalue(section_id); + return uci.set('ddns', section_id, 'interface', val); + }; + + // bind_network + + if (env['has_bindnet']) { + o = s.taboption('advanced', widgets.ZoneSelect, 'bind_network', _("Bind Network"), + _('OPTIONAL: Network to use for communication') + '
' + + _("Network on which the ddns-updater scripts will be started")); + o.depends("ip_source", "web"); + o.optional = true; + o.rmempty = true; + o.modalonly = true; + } + + // force_ipversion + + if (env['has_forceip']) { + o = s.taboption('advanced', form.Flag, 'force_ipversion', _("Force IP Version"), + _('OPTIONAL: Force the usage of pure IPv4/IPv6 only communication.')); + o.optional = true; + o.rmempty = true; + o.modalonly = true; + } + + // dns_server + + if (env['has_dnsserver']) { + o = s.taboption("advanced", form.Value, "dns_server", + _("DNS-Server"), + _("OPTIONAL: Use non-default DNS-Server to detect 'Registered IP'.") + "
" + + _("Format: IP or FQDN")); + o.placeholder = "mydns.lan" + o.optional = true; + o.rmempty = true; + o.modalonly = true; + } + + // force_dnstcp + + if (env['has_bindhost']) { + o = s.taboption("advanced", form.Flag, "force_dnstcp", + _("Force TCP on DNS"), + _("OPTIONAL: Force the use of TCP instead of default UDP on DNS requests.")); + o.optional = true; + o.rmempty = true; + o.modalonly = true; + } + + // proxy + + if (env['has_proxy']) { + o = s.taboption("advanced", form.Value, "proxy", _("PROXY-Server"), + _("OPTIONAL: Proxy-Server for detection and updates.") + "
" + + _("Format") + ": " + '' + "[user:password@]proxyhost:port" + '' + "
" + + _("IPv6 address must be given in square brackets") + ": " + + '' + " [2001:db8::1]:8080" + ''); + o.optional = true; + o.rmempty = true; + o.modalonly = true; + } + + // use_syslog + + o = s.taboption("advanced", form.ListValue, "use_syslog", _("Log to syslog"), + _("Writes log messages to syslog. Critical Errors will always be written to syslog.")); + o.modalonly = true; + o.placeholder = "2" + o.optional = true; + o.value("0", _("No logging")) + o.value("1", _("Info")) + o.value("2", _("Notice")) + o.value("3", _("Warning")) + o.value("4", _("Error")) + + // use_logfile + + o = s.taboption("advanced", form.Flag, "use_logfile", _("Log to file")); + o.default = '1'; + o.optional = true; + o.modalonly = true; + o.cfgvalue = function(section_id) { + this.description = _("Writes detailed messages to log file. File will be truncated automatically.") + "
" + + _("File") + ': "' + logdir + '/' + section_id + '.log"'; + return uci.get('ddns', section_id, 'use_logfile'); + }; + + // TAB Timer + + // check_interval + o = s.taboption("timer", form.Value, "check_interval", _("Check Interval")); + o.placeholder = "30"; + o.modalonly = true; + o.datatype = 'uinteger'; + + o.validate = function(section_id, formvalue) { + var unit = this.section.children.filter(function(o) { return o.option == 'check_unit' })[0].formvalue(section_id), + time_to_sec = time_res[unit || 'minutes'] * formvalue; + + if (formvalue && time_to_sec < 300) + return _('Values below 5 minutes == 300 seconds are not supported'); + + return true; + + }; + + // check_interval + o = s.taboption("timer", form.ListValue, "check_unit",'Check Unit'); + o.description = _("Interval unit to check for changed IP"); + o.modalonly = true; + o.default = "minutes" + o.value("seconds", _("seconds")); + o.value("minutes", _("minutes")); + o.value("hours", _("hours")); + + // force_interval + + o = s.taboption("timer", form.Value, "force_interval", _("Force Interval")); + o.description = _("Interval to force updates send to DDNS Provider" + "
" + + "Setting this parameter to 0 will force the script to only run once"); + o.placeholder = "72"; + o.optional = true; + o.modalonly = true; + o.datatype = 'uinteger'; + + o.validate = function(section_id, formvalue) { + + if (!formvalue) + return true; + + var check_unit = this.section.children.filter(function(o) { return o.option == 'check_unit' })[0].formvalue(section_id), + check_val = this.section.children.filter(function(o) { return o.option == 'check_interval' })[0].formvalue(section_id), + force_unit = this.section.children.filter(function(o) { return o.option == 'force_unit' })[0].formvalue(section_id), + check_to_sec = time_res[check_unit || 'minutes'] * ( check_val || '30'), + force_to_sec = time_res[force_unit || 'minutes'] * formvalue; + + if (force_to_sec != 0 && force_to_sec < check_to_sec) + return _("Values lower 'Check Interval' except '0' are not supported"); + + return true; + }; + + // force_unit + + o = s.taboption("timer", form.ListValue, "force_unit",'Force Unit'); + o.description = _("Interval unit to force updates send to DDNS Provider"); + o.modalonly = true; + o.optional = true; + o.default = "minutes" + o.value("minutes", _("minutes")); + o.value("hours", _("hours")); + o.value("hours", _("days")); + + // retry_count + + o = s.taboption("timer", form.Value, "retry_count", _("Error Retry Counter")); + o.description = _("On Error the script will stop execution after given number of retrys") + + "
" + + _("The default setting of '0' will retry infinite."); + o.placeholder = "0"; + o.optional = true; + o.modalonly = true; + o.datatype = 'uinteger'; + + // retry_interval + + o = s.taboption("timer", form.Value, "retry_interval", _("Error Retry Interval")); + o.description = _("On Error the script will stop execution after given number of retrys") + + "
" + + _("The default setting of '0' will retry infinite."); + o.placeholder = "60"; + o.optional = true; + o.modalonly = true; + o.datatype = 'uinteger'; + + // retry_unit + + o = s.taboption("timer", form.ListValue, "retry_unit",'Retry Unit'); + o.description = _("On Error the script will retry the failed action after given time"); + o.modalonly = true; + o.optional = true; + o.default = "seconds" + o.value("seconds", _("seconds")); + o.value("minutes", _("minutes")); + + // TAB logview + + o = s.taboption("logview", form.DummyValue, '_read_log', ''); + o.depends('use_logfile','1'); + o.modalonly = true; + o.cfgvalue = function(section_id) { + return E([], [ + E('button', { + 'class': 'cbi-button cbi-button-apply', + 'click': L.ui.createHandlerFn(this, function() { + var o = this.section.children.filter(function(o) { return o.option == '_logview' })[0]; + return callGetLogServices(section_id).then(L.bind(o.update_log, o)); + }) + }, _('Read / Reread log file'))]); + }; + + o = s.taboption("logview", form.DummyValue, "_logview"); + o.depends('use_logfile','1'); + o.modalonly = true; + + o.update_log = L.bind(function(view, log_data) { + return document.getElementById('log_area').innerHTML = log_data.result; + }, o, this) + + o.render = L.bind(function() { + return E([ + E('p', {}, _('This is the current content of the log file in ') + logdir + ' for this service.'), + E('p', {}, E('textarea', { 'style': 'width:100%', 'rows': 20, 'readonly' : 'readonly', 'id' : 'log_area' }, _('Please press [Read] button') )) + ]); + }, o, this) + + + // Advanced Configuration Section + + s = m.section(form.NamedSection, 'global', 'ddns', _('Global Configuration')); + s.description = _('Configure here the details for all Dynamic DNS services including this LuCI application.') + + '
' + + _("It is NOT recommended for casual users to change settings on this page.") + + '
' + + '' + + _('For detailed information about parameter settings look here.') + + ''; + s.addremove = false; + + o = s.option(form.Flag, 'upd_privateip', _("Allow non-public IP's")); + o.description = _("Non-public and by default blocked IP's") + ':' + + '
IPv4: ' + + '0/8, 10/8, 100.64/10, 127/8, 169.254/16, 172.16/12, 192.168/16' + + '
IPv6: ' + + '::/32, f000::/4"'; + o.default = "0"; + o.optional = true; + + o = s.option(form.Value, 'ddns_dateformat', _('Date format')); + o.description = '' + + _("For supported codes look here") + + '
' + + _('Current setting: ') + '' + status['_curr_dateformat'] + ''; + o.default = "%F %R" + o.optional = true; + o.rmempty = true; + + o = s.option(form.Value, 'ddns_rundir', _('Status directory')); + o.description = _('Directory contains PID and other status information for each running section.'); + o.default = "/var/run/ddns"; + o.optional = true; + o.rmempty = true; + + o = s.option(form.Value, 'ddns_logdir', _('Log directory')); + o.description = _('Directory contains Log files for each running section.'); + o.default = "/var/log/ddns"; + o.optional = true; + o.rmempty = true; + o.validate = function(section_id, formvalue) { + if (formvalue.indexOf('../') !== -1) + return _('"../" not allowed in path for Security Reason.') + + return true; + } + + o = s.option(form.Value, 'ddns_loglines', _('Log length')); + o.description = _('Number of last lines stored in log files'); + o.datatype = 'min(1)'; + o.default = '250'; + + if (env['has_wget'] && env['has_curl']) { + + o = s.option(form.Flag, 'use_curl', _('Use cURL')); + o.description = _('If Wget and cURL package are installed, Wget is used for communication by default.'); + o.default = "0"; + o.optional = true; + o.rmempty = true; + + } + + return m.render().then(L.bind(function(m, nodes) { + L.Poll.add(L.bind(function() { + return Promise.all([ + this.callDDnsGetServicesStatus(), + callDDnsGetStatus() + ]).then(L.bind(this.poll_status, this, nodes)); + }, this), 5); + return nodes; + }, this, m)); + } +}); diff --git a/applications/luci-app-ddns/htdocs/luci-static/resources/view/status/include/70_ddns.js b/applications/luci-app-ddns/htdocs/luci-static/resources/view/status/include/70_ddns.js new file mode 100644 index 0000000000..698cf8d254 --- /dev/null +++ b/applications/luci-app-ddns/htdocs/luci-static/resources/view/status/include/70_ddns.js @@ -0,0 +1,46 @@ +'use strict'; +'require rpc'; +'require uci'; + +return L.Class.extend({ + title: _('Dynamic DNS'), + + callDDnsGetServicesStatus: rpc.declare({ + object: 'luci.ddns', + method: 'get_services_status', + expect: { } + }), + + load: function() { + return Promise.all([ + this.callDDnsGetServicesStatus(), + uci.load('ddns') + ]); + }, + + render: function(data) { + var services = data[0]; + + var table = E('div', { 'class': 'table' }, [ + E('div', { 'class': 'tr table-titles' }, [ + E('div', { 'class': 'th' }, _('Configuration')), + E('div', { 'class': 'th' }, _('Next Update')), + E('div', { 'class': 'th' }, _('Lookup Hostname')), + E('div', { 'class': 'th' }, _('Registered IP')), + E('div', { 'class': 'th' }, _('Network')) + ]) + ]); + + cbi_update_table(table, Object.keys(services).map(function(key, index) { + return [ + key, + services[key].next_update ? _(services[key].next_update) : _('Unknown'), + uci.get('ddns',key,'lookup_host'), + services[key].ip ? services[key].ip : _('No Data'), + (uci.get('ddns',key,'use_ipv6') == '1' ? 'IPv6' : 'IPv4') + ' / ' + uci.get('ddns',key,'interface') + ]; + }), E('em', _('There is no service configured.'))); + + return E([table]); + } +}); -- cgit v1.2.3