From e7593dc840213cea5c8ad5af3c6f6a7237db0eaa Mon Sep 17 00:00:00 2001 From: Jens Luedicke Date: Sat, 28 Jun 2025 11:30:34 +0200 Subject: [PATCH] Add System Settings. Enable/Disable User registration. --- app.py | 49 +++++++++++++++++++++- migrate_db.py | 37 ++++++++++++++++- models.py | 10 +++++ static/css/style.css | 74 ++++++++++++++++++++++++++++++++++ templates/admin_dashboard.html | 7 +--- templates/admin_settings.html | 31 ++++++++++++++ 6 files changed, 201 insertions(+), 7 deletions(-) create mode 100644 templates/admin_settings.html diff --git a/app.py b/app.py index 77e9565..d4584d7 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,5 @@ from flask import Flask, render_template, request, redirect, url_for, jsonify, flash, session, g -from models import db, TimeEntry, WorkConfig, User +from models import db, TimeEntry, WorkConfig, User, SystemSettings import logging from datetime import datetime, time, timedelta import os @@ -42,6 +42,23 @@ mail = Mail(app) # Initialize the database with the app db.init_app(app) +# Add this function to initialize system settings +def init_system_settings(): + # Check if registration_enabled setting exists, if not create it + if not SystemSettings.query.filter_by(key='registration_enabled').first(): + registration_setting = SystemSettings( + key='registration_enabled', + value='true', + description='Controls whether new user registration is allowed' + ) + db.session.add(registration_setting) + db.session.commit() + +# Call this function during app initialization (add it where you initialize the app) +@app.before_first_request +def initialize_app(): + init_system_settings() + # Authentication decorator def login_required(f): @wraps(f) @@ -123,6 +140,14 @@ def logout(): @app.route('/register', methods=['GET', 'POST']) def register(): + # Check if registration is enabled + reg_setting = SystemSettings.query.filter_by(key='registration_enabled').first() + registration_enabled = reg_setting and reg_setting.value == 'true' + + if not registration_enabled: + flash('Registration is currently disabled by the administrator.', 'error') + return redirect(url_for('login')) + if request.method == 'POST': username = request.form.get('username') email = request.form.get('email') @@ -681,5 +706,27 @@ def toggle_user_status(user_id): return redirect(url_for('admin_users')) +# Add this route to manage system settings +@app.route('/admin/settings', methods=['GET', 'POST']) +@admin_required +def admin_settings(): + if request.method == 'POST': + # Update registration setting + registration_enabled = 'registration_enabled' in request.form + + reg_setting = SystemSettings.query.filter_by(key='registration_enabled').first() + if reg_setting: + reg_setting.value = 'true' if registration_enabled else 'false' + db.session.commit() + flash('System settings updated successfully!', 'success') + + # Get current settings + settings = {} + for setting in SystemSettings.query.all(): + if setting.key == 'registration_enabled': + settings['registration_enabled'] = setting.value == 'true' + + return render_template('admin_settings.html', title='System Settings', settings=settings) + if __name__ == '__main__': app.run(debug=True) \ No newline at end of file diff --git a/migrate_db.py b/migrate_db.py index d94d51e..4734cb3 100644 --- a/migrate_db.py +++ b/migrate_db.py @@ -1,7 +1,7 @@ from app import app, db import sqlite3 import os -from models import User, TimeEntry, WorkConfig +from models import User, TimeEntry, WorkConfig, SystemSettings from werkzeug.security import generate_password_hash from datetime import datetime @@ -13,6 +13,9 @@ def migrate_database(): print("Database doesn't exist. Creating new database.") with app.app_context(): db.create_all() + + # Initialize system settings + init_system_settings() return print("Migrating existing database...") @@ -104,6 +107,20 @@ def migrate_database(): print("Adding is_blocked column to user table...") cursor.execute("ALTER TABLE user ADD COLUMN is_blocked BOOLEAN DEFAULT 0") + # Check if the system_settings table exists + cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='system_settings'") + if not cursor.fetchone(): + print("Creating system_settings table...") + cursor.execute(""" + CREATE TABLE system_settings ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + key VARCHAR(50) UNIQUE NOT NULL, + value VARCHAR(255) NOT NULL, + description VARCHAR(255), + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + """) + # Commit changes and close connection conn.commit() conn.close() @@ -112,6 +129,9 @@ def migrate_database(): # Create tables if they don't exist db.create_all() + # Initialize system settings + init_system_settings() + # Check if admin user exists admin = User.query.filter_by(username='admin').first() if not admin: @@ -154,6 +174,21 @@ def migrate_database(): print(f"Associated {len(orphan_configs)} existing work configs with admin user") print(f"Marked {len(existing_users)} existing users as verified") +def init_system_settings(): + """Initialize system settings with default values if they don't exist""" + # Check if registration_enabled setting exists + reg_setting = SystemSettings.query.filter_by(key='registration_enabled').first() + if not reg_setting: + print("Adding registration_enabled system setting...") + reg_setting = SystemSettings( + key='registration_enabled', + value='true', # Default to enabled + description='Controls whether new user registration is allowed' + ) + db.session.add(reg_setting) + db.session.commit() + print("Registration setting initialized to enabled") + if __name__ == "__main__": migrate_database() print("Database migration completed") \ No newline at end of file diff --git a/models.py b/models.py index 8ffc96a..2db9d7d 100644 --- a/models.py +++ b/models.py @@ -49,6 +49,16 @@ class User(db.Model): def __repr__(self): return f'' +class SystemSettings(db.Model): + id = db.Column(db.Integer, primary_key=True) + key = db.Column(db.String(50), unique=True, nullable=False) + value = db.Column(db.String(255), nullable=False) + description = db.Column(db.String(255)) + updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) + + def __repr__(self): + return f'' + class TimeEntry(db.Model): id = db.Column(db.Integer, primary_key=True) arrival_time = db.Column(db.DateTime, nullable=False) diff --git a/static/css/style.css b/static/css/style.css index f5a5061..fd6d830 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -522,4 +522,78 @@ input[type="time"]::-webkit-datetime-edit { .status-blocked { background-color: #f8d7da; color: #721c24; +} + +.settings-card { + background-color: #f8f9fa; + border-radius: 5px; + padding: 20px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + margin-bottom: 20px; +} + +.setting-description { + color: #6c757d; + font-size: 0.9em; + margin-top: 5px; +} + +.checkbox-container { + display: block; + position: relative; + padding-left: 35px; + margin-bottom: 12px; + cursor: pointer; + font-size: 16px; + user-select: none; +} + +.checkbox-container input { + position: absolute; + opacity: 0; + cursor: pointer; + height: 0; + width: 0; +} + +.checkmark { + position: absolute; + top: 0; + left: 0; + height: 25px; + width: 25px; + background-color: #eee; + border-radius: 4px; +} + +.checkbox-container:hover input ~ .checkmark { + background-color: #ccc; +} + +.checkbox-container input:checked ~ .checkmark { + background-color: #2196F3; +} + +.checkmark:after { + content: ""; + position: absolute; + display: none; +} + +.checkbox-container input:checked ~ .checkmark:after { + display: block; +} + +.checkbox-container .checkmark:after { + left: 9px; + top: 5px; + width: 5px; + height: 10px; + border: solid white; + border-width: 0 3px 3px 0; + transform: rotate(45deg); +} + +.form-actions { + margin-top: 20px; } \ No newline at end of file diff --git a/templates/admin_dashboard.html b/templates/admin_dashboard.html index fd44ea1..d431a5e 100644 --- a/templates/admin_dashboard.html +++ b/templates/admin_dashboard.html @@ -11,14 +11,11 @@ Manage Users - - {% endblock %} \ No newline at end of file diff --git a/templates/admin_settings.html b/templates/admin_settings.html new file mode 100644 index 0000000..c076d38 --- /dev/null +++ b/templates/admin_settings.html @@ -0,0 +1,31 @@ +{% extends "layout.html" %} + +{% block content %} +
+

System Settings

+ +
+
+

Registration Settings

+ +
+ +

+ When enabled, new users can register accounts. When disabled, only administrators can create new accounts. +

+
+ + +
+ +
+ +
+
+
+{% endblock %} \ No newline at end of file