Development
This commit is contained in:
parent
27f2356cd1
commit
19f0bfa79c
4 changed files with 115 additions and 21 deletions
|
|
@ -25,10 +25,20 @@ DASHB_INTERVAL_SECS = 60
|
|||
QUEUE_MAX_LINES = 50
|
||||
|
||||
|
||||
_config_cache = None
|
||||
_config_mtime = None
|
||||
|
||||
def load_config():
|
||||
global _config_cache, _config_mtime
|
||||
try:
|
||||
mtime = os.path.getmtime(CONFIG_FILE)
|
||||
if _config_cache is not None and mtime == _config_mtime:
|
||||
return copy.deepcopy(_config_cache)
|
||||
with open(CONFIG_FILE) as f:
|
||||
return json.load(f)
|
||||
data = json.load(f)
|
||||
_config_cache = data
|
||||
_config_mtime = mtime
|
||||
return copy.deepcopy(data)
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,19 +35,38 @@ def options_save():
|
|||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
||||
@bp.route('/action/captiveportal/splash_save', methods=['POST'])
|
||||
@bp.route('/action/captiveportal/portal_save', methods=['POST'])
|
||||
@auth.require_level('administrator')
|
||||
def splash_save():
|
||||
cfg = config_utils.load_config()
|
||||
before = copy.deepcopy(cfg.get('captive_portal', {}))
|
||||
def portal_save():
|
||||
cfg = config_utils.load_config()
|
||||
vlan_name = sanitize.name(request.form.get('vlan_name', ''))
|
||||
|
||||
splash_text = sanitize.description(request.form.get('splash_text', ''))
|
||||
terms = [t.strip() for t in request.form.getlist('terms') if t.strip()]
|
||||
vlan = next((v for v in cfg.get('vlans', []) if v['name'] == vlan_name), None)
|
||||
if not vlan or vlan.get('restricted_vlan') != 'c':
|
||||
flash('Captive portal VLAN not found.', 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
after = {**before, 'splash_text': splash_text, 'terms': terms}
|
||||
cfg.setdefault('captive_portal', {}).update(after)
|
||||
before = {
|
||||
'portal_splash_title': vlan.get('portal_splash_title', ''),
|
||||
'portal_splash_text': vlan.get('portal_splash_text', ''),
|
||||
'portal_terms': vlan.get('portal_terms', []),
|
||||
}
|
||||
|
||||
splash_title = sanitize.description(request.form.get('portal_splash_title', ''))
|
||||
splash_text = sanitize.description(request.form.get('portal_splash_text', ''))
|
||||
terms = [t.strip() for t in request.form.getlist('portal_terms') if t.strip()]
|
||||
|
||||
vlan['portal_splash_title'] = splash_title
|
||||
vlan['portal_splash_text'] = splash_text
|
||||
vlan['portal_terms'] = terms
|
||||
|
||||
after = {
|
||||
'portal_splash_title': splash_title,
|
||||
'portal_splash_text': splash_text,
|
||||
'portal_terms': terms,
|
||||
}
|
||||
changes = config_utils.diff_fields(before, after)
|
||||
flash(config_utils.record_group(
|
||||
cfg, 'captive_portal', 'setting', 'captive_portal', changes, 'core apply'
|
||||
cfg, 'vlans', 'portal', vlan_name, changes, 'core apply'
|
||||
), 'success')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
|
|
|||
|
|
@ -64,32 +64,81 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "table",
|
||||
"datasource": "captive_portals",
|
||||
"empty_message": "No captive portal VLANs configured. Set Restricted VLAN = Captive Portal on the Network Layout page.",
|
||||
"columns": [
|
||||
{
|
||||
"label": "VLAN",
|
||||
"field": "vlan_name",
|
||||
"class": "col-mono"
|
||||
},
|
||||
{
|
||||
"label": "Title",
|
||||
"field": "portal_splash_title"
|
||||
},
|
||||
{
|
||||
"label": "Splash Text",
|
||||
"field": "portal_splash_text"
|
||||
},
|
||||
{
|
||||
"label": "Terms",
|
||||
"field": "portal_terms_display",
|
||||
"class": "col-narrow"
|
||||
}
|
||||
],
|
||||
"row_actions": [
|
||||
{
|
||||
"client_requirement": "client_is_administrator+",
|
||||
"method": "js_edit",
|
||||
"target": "portal-edit-form",
|
||||
"text": "Edit",
|
||||
"class": "btn-ghost btn-sm"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "card",
|
||||
"label": "Splash Screen",
|
||||
"id": "portal-edit-form",
|
||||
"label": "Edit Portal",
|
||||
"client_requirement": "client_is_administrator+",
|
||||
"items": [
|
||||
{
|
||||
"type": "form",
|
||||
"action": "/action/captiveportal/splash_save",
|
||||
"action": "/action/captiveportal/portal_save",
|
||||
"method": "post",
|
||||
"items": [
|
||||
{
|
||||
"type": "hidden",
|
||||
"name": "vlan_name",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"label": "Welcome Text",
|
||||
"name": "splash_text",
|
||||
"label": "Title",
|
||||
"name": "portal_splash_title",
|
||||
"input_type": "text",
|
||||
"value": "%CAPTIVE_SPLASH_TEXT%",
|
||||
"hint": "Welcome message shown at the top of the login page."
|
||||
"hint": "Heading shown at the top of the login page."
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"label": "Splash Text",
|
||||
"name": "portal_splash_text",
|
||||
"input_type": "text",
|
||||
"hint": "Welcome message shown below the title."
|
||||
},
|
||||
{
|
||||
"type": "hr"
|
||||
},
|
||||
{
|
||||
"type": "editable_list",
|
||||
"label": "Terms",
|
||||
"name": "terms",
|
||||
"items": "%CAPTIVE_TERMS%",
|
||||
"name": "portal_terms",
|
||||
"items": "[]",
|
||||
"add_label": "Add Term",
|
||||
"item_placeholder": "e.g. I agree to the acceptable use policy.",
|
||||
"hint": "Each term renders as a required checkbox the user must tick before submitting credentials."
|
||||
"hint": "Each term renders as a required checkbox the user must tick before submitting credentials. Leave empty for no terms."
|
||||
},
|
||||
{
|
||||
"type": "button_row",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,23 @@ def collect_tokens(cfg):
|
|||
|
||||
tokens['CAPTIVE_HTTP_PORT'] = str(cp.get('http_port', 8081))
|
||||
tokens['CAPTIVE_HTTPS_DOMAIN'] = cp.get('https_domain', '')
|
||||
tokens['CAPTIVE_SPLASH_TEXT'] = cp.get('splash_text', '')
|
||||
tokens['CAPTIVE_TERMS'] = json.dumps(cp.get('terms', []))
|
||||
|
||||
display_rows = []
|
||||
for vlan in captive_vlans:
|
||||
terms = vlan.get('portal_terms', [])
|
||||
n = len(terms)
|
||||
display_rows.append({
|
||||
'vlan_name': vlan['name'],
|
||||
'portal_splash_title': vlan.get('portal_splash_title', ''),
|
||||
'portal_splash_text': vlan.get('portal_splash_text', ''),
|
||||
'portal_terms': terms,
|
||||
'portal_terms_display': f'{n} term{"s" if n != 1 else ""}' if n else '--',
|
||||
})
|
||||
|
||||
content = factory.load_json(f'{factory.PAGES_DIR}/captiveportal/content.json')
|
||||
for table_item in factory.iter_table_items(content.get('items', [])):
|
||||
ds = table_item.get('datasource', '')
|
||||
data = display_rows if ds == 'captive_portals' else []
|
||||
tokens[factory.table_token_key(ds)] = factory.build_table(table_item, tokens, data)
|
||||
|
||||
return tokens
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue