diff options
author | Tianling Shen <cnsztl@immortalwrt.org> | 2023-12-26 10:49:28 +0800 |
---|---|---|
committer | Paul Donald <itsascambutmailmeanyway@gmail.com> | 2023-12-30 02:45:13 +0000 |
commit | f0c6defa1eeea6d3e9614fd4974d6df2aef6646f (patch) | |
tree | 7f01d50fe4ad0a40d1d7cc7d35762428b1d4bafb /applications/luci-app-alist | |
parent | d5db17361a556f9c7eda8fa1a0b0c59d57034633 (diff) |
luci-app-alist: add new package
Add LuCI interface for the AList package.
Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
Diffstat (limited to 'applications/luci-app-alist')
5 files changed, 276 insertions, 0 deletions
diff --git a/applications/luci-app-alist/Makefile b/applications/luci-app-alist/Makefile new file mode 100644 index 0000000000..3c660830fa --- /dev/null +++ b/applications/luci-app-alist/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (C) 2023 ImmortalWrt.org + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI app for AList +LUCI_DEPENDS:=+alist + +include ../../luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/applications/luci-app-alist/htdocs/luci-static/resources/view/alist/config.js b/applications/luci-app-alist/htdocs/luci-static/resources/view/alist/config.js new file mode 100644 index 0000000000..25fde44075 --- /dev/null +++ b/applications/luci-app-alist/htdocs/luci-static/resources/view/alist/config.js @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: Apache-2.0 + +'use strict'; +'require form'; +'require poll'; +'require rpc'; +'require uci'; +'require validation'; +'require view'; + +var callServiceList = rpc.declare({ + object: 'service', + method: 'list', + params: ['name'], + expect: { '': {} } +}); + +function getServiceStatus() { + return L.resolveDefault(callServiceList('alist'), {}).then(function (res) { + var isRunning = false; + try { + isRunning = res['alist']['instances']['instance1']['running']; + } catch (e) { } + return isRunning; + }); +} + +function renderStatus(isRunning, port) { + var spanTemp = '<span style="color:%s"><strong>%s %s</strong></span>'; + var renderHTML; + if (isRunning) { + var button = String.format(' <a class="btn cbi-button" href="http://%s:%s" target="_blank" rel="noreferrer noopener">%s</a>', + window.location.hostname, port, _('Open Web Interface')); + renderHTML = spanTemp.format('green', _('AList'), _('RUNNING')) + button; + } else { + renderHTML = spanTemp.format('red', _('AList'), _('NOT RUNNING')); + } + + return renderHTML; +} + +var stubValidator = { + factory: validation, + apply: function(type, value, args) { + if (value != null) + this.value = value; + + return validation.types[type].apply(this, args); + }, + assert: function(condition) { + return !!condition; + } +}; + +return view.extend({ + load: function() { + return Promise.all([ + uci.load('alist') + ]); + }, + + render: function(data) { + var m, s, o; + var webport = uci.get(data[0], 'config', 'listen_http_port') || '5244'; + + m = new form.Map('alist', _('AList'), + _('A file list/WebDAV program that supports multiple storages, powered by Gin and Solidjs.') + '<br />' + + _('Default webUI/WebDAV login username is %s and password is %s.').format('<code>admin</code>', '<code>password</code>')); + + s = m.section(form.TypedSection); + s.anonymous = true; + s.render = function () { + poll.add(function () { + return L.resolveDefault(getServiceStatus()).then(function (res) { + var view = document.getElementById('service_status'); + view.innerHTML = renderStatus(res, webport); + }); + }); + + return E('div', { class: 'cbi-section', id: 'status_bar' }, [ + E('p', { id: 'service_status' }, _('Collecting data...')) + ]); + } + + s = m.section(form.NamedSection, 'config', 'alist'); + + o = s.option(form.Flag, 'enabled', _('Enable')); + o.default = o.disabled; + o.rmempty = false; + + o = s.option(form.Value, 'listen_addr', _('Listen address')); + o.placeholder = '0.0.0.0'; + o.validate = function(section_id, value) { + if (section_id && value) { + var m4 = value.match(/^([^\[\]:]+)$/), + m6 = value.match(/^\[(.+)\]$/ ); + + if ((!m4 && !m6) || !stubValidator.apply('ipaddr', m4 ? m4[1] : m6[1])) + return _('Expecting: %s').format(_('valid IP address')); + } + return true; + } + + o = s.option(form.Value, 'listen_http_port', _('Listen port')); + o.datatype = 'port'; + o.placeholder = '5244'; + + o = s.option(form.Value, 'site_login_expire', _('Login expiration time'), + _('User login expiration time (in hours).')); + o.datatype = 'uinteger'; + o.placeholder = '48'; + + o = s.option(form.Value, 'site_max_connections', _('Max connections'), + _('The maximum number of concurrent connections at the same time (0 = unlimited).')); + o.datatype = 'uinteger'; + o.placeholder = '0'; + + o = s.option(form.Flag, 'site_tls_insecure', _('Allow insecure connection'), + _('Allow connection even if the remote TLS certificate is invalid (<strong>not recommended</strong>).')); + + o = s.option(form.Flag, 'log_enable', _('Enable logging')); + o.default = o.enabled; + + o = s.option(form.Value, 'log_max_size', _('Max log size'), + _('The maximum size in megabytes of the log file before it gets rotated.')); + o.datatype = 'uinteger'; + o.placeholder = '5'; + o.depends('log_enable', '1'); + + o = s.option(form.Value, 'log_max_backups', _('Max log backups'), + _('The maximum number of old log files to retain.')); + o.datatype = 'uinteger'; + o.placeholder = '1'; + o.depends('log_enable', '1'); + + o = s.option(form.Value, 'log_max_age', _('Max log age'), + _('The maximum days of the log file to retain.')); + o.datatype = 'uinteger'; + o.placeholder = '15'; + o.depends('log_enable', '1'); + + return m.render(); + } +}); diff --git a/applications/luci-app-alist/htdocs/luci-static/resources/view/alist/log.js b/applications/luci-app-alist/htdocs/luci-static/resources/view/alist/log.js new file mode 100644 index 0000000000..f300abef9c --- /dev/null +++ b/applications/luci-app-alist/htdocs/luci-static/resources/view/alist/log.js @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: Apache-2.0 + +'use strict'; +'require dom'; +'require fs'; +'require poll'; +'require uci'; +'require view'; + +return view.extend({ + render: function() { + /* Thanks to luci-app-aria2 */ + var css = ' \ + #log_textarea { \ + padding: 10px; \ + text-align: left; \ + } \ + #log_textarea pre { \ + padding: .5rem; \ + word-break: break-all; \ + margin: 0; \ + } \ + .description { \ + background-color: #33ccff; \ + }'; + + var log_textarea = E('div', { 'id': 'log_textarea' }, + E('img', { + 'src': L.resource(['icons/loading.gif']), + 'alt': _('Loading...'), + 'style': 'vertical-align:middle' + }, _('Collecting data...')) + ); + + poll.add(L.bind(function() { + return fs.read_direct('/var/run/alist/log/alist.log', 'text') + .then(function(res) { + var log = E('pre', { 'wrap': 'pre' }, [ + res.trim() || _('Log is empty.') + ]); + + dom.content(log_textarea, log); + }).catch(function(err) { + var log; + + if (err.toString().includes('NotFoundError')) + log = E('pre', { 'wrap': 'pre' }, [ + _('Log file does not exist.') + ]); + else + log = E('pre', { 'wrap': 'pre' }, [ + _('Unknown error: %s').format(err) + ]); + + dom.content(log_textarea, log); + }); + })); + + return E([ + E('style', [ css ]), + E('div', {'class': 'cbi-map'}, [ + E('div', {'class': 'cbi-section'}, [ + log_textarea, + E('div', {'style': 'text-align:right'}, + E('small', {}, _('Refresh every %s seconds.').format(L.env.pollinterval)) + ) + ]) + ]) + ]); + }, + + handleSaveApply: null, + handleSave: null, + handleReset: null +}); diff --git a/applications/luci-app-alist/root/usr/share/luci/menu.d/luci-app-alist.json b/applications/luci-app-alist/root/usr/share/luci/menu.d/luci-app-alist.json new file mode 100644 index 0000000000..084085a132 --- /dev/null +++ b/applications/luci-app-alist/root/usr/share/luci/menu.d/luci-app-alist.json @@ -0,0 +1,28 @@ +{ + "admin/services/alist": { + "title": "AList", + "action": { + "type": "firstchild" + }, + "depends": { + "acl": [ "luci-app-alist" ], + "uci": { "alist": true } + } + }, + "admin/services/alist/config": { + "title": "Settings", + "order": 10, + "action": { + "type": "view", + "path": "alist/config" + } + }, + "admin/services/alist/log": { + "title": "Log", + "order": 20, + "action": { + "type": "view", + "path": "alist/log" + } + } +} diff --git a/applications/luci-app-alist/root/usr/share/rpcd/acl.d/luci-app-alist.json b/applications/luci-app-alist/root/usr/share/rpcd/acl.d/luci-app-alist.json new file mode 100644 index 0000000000..991dfa0291 --- /dev/null +++ b/applications/luci-app-alist/root/usr/share/rpcd/acl.d/luci-app-alist.json @@ -0,0 +1,17 @@ +{ + "luci-app-alist": { + "description": "Grant UCI access for luci-app-alist", + "read": { + "file": { + "/var/run/alist/log/alist.log": [ "read" ] + }, + "ubus": { + "service": [ "list" ] + }, + "uci": [ "alist" ] + }, + "write": { + "uci": [ "alist" ] + } + } +} |