From 9aa84f855c961b55a0f2b32977e844f0183c0c93 Mon Sep 17 00:00:00 2001 From: Michael Woods Date: Sun, 21 Dec 2025 23:30:18 -0500 Subject: [PATCH] Trying to fix profile dashboard timestamps. --- packetserver/http/server.py | 12 +++++++ packetserver/http/templates/profile.html | 4 +-- packetserver/runners/http_user_manager.py | 43 +++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/packetserver/http/server.py b/packetserver/http/server.py index 0a113b5..274a9c1 100644 --- a/packetserver/http/server.py +++ b/packetserver/http/server.py @@ -17,6 +17,18 @@ app = FastAPI( # Define templates EARLY (before importing dashboard) templates = Jinja2Templates(directory=BASE_DIR / "templates") +from datetime import datetime, timezone + +@templates.env.filters.register +def timestamp_to_date(ts): + if ts is None: + return "Never" + try: + dt = datetime.fromtimestamp(float(ts), tz=timezone.utc) + return dt.strftime("%Y-%m-%d %H:%M:%S UTC") + except (ValueError, TypeError): + return "Invalid" + # Static files app.mount("/static", StaticFiles(directory=BASE_DIR / "static"), name="static") diff --git a/packetserver/http/templates/profile.html b/packetserver/http/templates/profile.html index 1491a55..59eb938 100644 --- a/packetserver/http/templates/profile.html +++ b/packetserver/http/templates/profile.html @@ -32,8 +32,8 @@ - - + +
HTTP Enabled{% if profile.http_enabled %}Yes{% else %}No{% endif %}
RF Gateway Enabled{% if profile.rf_enabled %}Yes{% else %}No (blacklisted){% endif %}
HTTP Account Created{{ profile.http_created_at }}
Last HTTP Login{{ profile.http_last_login or "Never" }}
HTTP Account Created{{ profile.http_created_at | timestamp_to_date }}
Last HTTP Login{{ profile.http_last_login | timestamp_to_date or "Never" }}
diff --git a/packetserver/runners/http_user_manager.py b/packetserver/runners/http_user_manager.py index 680a034..3a8fdbc 100644 --- a/packetserver/runners/http_user_manager.py +++ b/packetserver/runners/http_user_manager.py @@ -91,6 +91,11 @@ def main(): p_dump = subparsers.add_parser("dump", help="Dump JSON details of the BBS user (incl. UUID and hidden flag)") p_dump.add_argument("callsign", help="Callsign to dump") + # sync missing + p_sync = subparsers.add_parser("sync-missing", help="Add missing HttpUser objects for existing BBS users") + p_sync.add_argument("--dry-run", action="store_true", help="Show what would be done without changes") + p_sync.add_argument("--enable", action="store_true", help="Set http_enabled=True for new users (default False)") + args = parser.parse_args() # Open the database @@ -264,6 +269,44 @@ def main(): print(json.dumps(dump_data, indent=4)) + elif args.command == "sync-missing": + import secrets + import string + + def generate_password(length=20): + alphabet = string.ascii_letters + string.digits + "!@#$%^&*" + return ''.join(secrets.choice(alphabet) for _ in range(length)) + + bbs_users = root.get('users', {}) + http_users = get_or_create_http_users(root) + + missing = [call for call in bbs_users if call not in http_users and call != "SYSTEM"] + if not missing: + print("No missing HTTP users—all BBS users have HttpUser objects") + else: + print(f"Found {len(missing)} BBS users without HTTP accounts:") + for call in sorted(missing): + print(f" - {call}") + + if args.dry_run: + print("\n--dry-run: No changes made") + else: + confirm_msg = f"Create {len(missing)} new HttpUser objects (http_enabled={'True' if args.enable else 'False'})?" + if not confirm(confirm_msg): + print("Aborted") + else: + created_count = 0 + for call in missing: + password = generate_password() # strong random, not printed + new_http = HttpUser(call, password) + new_http.http_enabled = args.enable + http_users[call] = new_http + created_count += 1 + + transaction.commit() + print(f"\nSync complete: {created_count} HTTP users added (passwords random & hidden)") + print("Use 'set-password ' to set a known password before enabling login") + finally: connection.close() db.close()