From 8aa4373a6b03345095e2798e725515ecfcca25c2 Mon Sep 17 00:00:00 2001 From: Matthew Grotke Date: Mon, 8 Jun 2026 01:38:18 -0400 Subject: [PATCH] Development --- .../app/pages/clientcredentials/action.py | 8 +++--- .../app/pages/clientcredentials/content.json | 23 ++++++++++++++++ .../app/pages/clientcredentials/view.py | 26 +++++++++++++++++-- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/docker/routlin-dash/app/pages/clientcredentials/action.py b/docker/routlin-dash/app/pages/clientcredentials/action.py index 684201a..fd3dbd8 100644 --- a/docker/routlin-dash/app/pages/clientcredentials/action.py +++ b/docker/routlin-dash/app/pages/clientcredentials/action.py @@ -238,13 +238,15 @@ def addedit(): flash(f"Username '{username}' is already taken.", 'error') return redirect(f'/{_PAGE}') conn.close() - flash(f"Credential '{username}' updated.", 'success') + if password: + flash(f'User account "{username}" updated with password "{password}".', 'success') + else: + flash(f'User account "{username}" updated.', 'success') else: if not password: import secrets, string password = ''.join(secrets.choice(string.ascii_lowercase + string.digits) for _ in range(8)) - flash(f"Auto-generated password for '{username}': {password}", 'success') try: hashed = _hash_password(password, digest_type) @@ -267,7 +269,7 @@ def addedit(): flash(f"Username '{username}' already exists.", 'error') return redirect(f'/{_PAGE}') conn.close() - flash(f"Credential '{username}' added.", 'success') + flash(f'User account "{username}" created with password "{password}".', 'success') return redirect(f'/{_PAGE}') diff --git a/docker/routlin-dash/app/pages/clientcredentials/content.json b/docker/routlin-dash/app/pages/clientcredentials/content.json index 63d5fa3..5aafa9f 100644 --- a/docker/routlin-dash/app/pages/clientcredentials/content.json +++ b/docker/routlin-dash/app/pages/clientcredentials/content.json @@ -22,6 +22,24 @@ "type": "table", "datasource": "sqlite:client_credentials", "empty_message": "No credentials configured.", + "toolbar": { + "items": [ + { + "type": "select", + "name": "type_filter", + "value": "all", + "filter_col": "user_type_label", + "options": "%TYPE_FILTER_OPTIONS%" + }, + { + "type": "select", + "name": "vlan_filter", + "value": "all", + "filter_col": "vlan", + "options": "%CRED_VLAN_FILTER_OPTIONS%" + } + ] + }, "columns": [ { "label": "Username", @@ -42,6 +60,11 @@ "field": "vlan", "class": "col-narrow col-mono" }, + { + "label": "Expiration", + "field": "expiration_label", + "class": "col-narrow" + }, { "label": "Enabled", "field": "enabled", diff --git a/docker/routlin-dash/app/pages/clientcredentials/view.py b/docker/routlin-dash/app/pages/clientcredentials/view.py index 4fb7b09..641d608 100644 --- a/docker/routlin-dash/app/pages/clientcredentials/view.py +++ b/docker/routlin-dash/app/pages/clientcredentials/view.py @@ -1,3 +1,4 @@ +import datetime import json import sqlite3 import time @@ -48,6 +49,16 @@ def _load_credentials(): return [] +def _format_expiration(date_set, expires_seconds): + if not expires_seconds: + return 'Never' + expires_ts = (date_set or 0) + expires_seconds + now = int(time.time()) + if expires_ts <= now: + return 'Expired' + return datetime.datetime.fromtimestamp(expires_ts).strftime('%Y-%m-%d') + + def _format_session(session_seconds): if not session_seconds: return 'No limit' @@ -75,7 +86,17 @@ def collect_tokens(cfg): cfg.get('radius', {}).get('options', {}).get('default_expiration_seconds', 0) or 0 ) + tokens['TYPE_FILTER_OPTIONS'] = ( + '' + '' + '' + ) + vlans = [v for v in cfg.get('vlans', []) if not v.get('is_vpn')] + tokens['CRED_VLAN_FILTER_OPTIONS'] = ( + '' + + ''.join(f'' for v in vlans) + ) tokens['VLAN_OPTIONS'] = json.dumps( [{'value': '', 'label': '-- Select VLAN --'}] + [{'value': v['name'], 'label': f"{v['name']} (VLAN {v['vlan_id']})"} for v in vlans] @@ -103,8 +124,9 @@ def collect_tokens(cfg): for row in raw_rows: r = dict(row) r.pop('password', None) - r['user_type_label'] = USER_TYPE_LABELS.get(r.get('user_type'), str(r.get('user_type', ''))) - r['expires_label'] = _format_session(r.get('session_seconds', 0)) + r['user_type_label'] = USER_TYPE_LABELS.get(r.get('user_type'), str(r.get('user_type', ''))) + r['expires_label'] = _format_session(r.get('session_seconds', 0)) + r['expiration_label'] = _format_expiration(r.get('date_set', 0), r.get('expires_seconds', 0)) display_rows.append(r) content = factory.load_json(f'{factory.PAGES_DIR}/clientcredentials/content.json')