docs(settings): Update README + Copilot instructions; bump Program Info to 2025.1.0-alpha.11
README: Add System Settings API endpoints; describe new tabbed Settings layout with role gating; add Vite dev proxy tip to use relative /api paths. Copilot instructions: Note SystemSetting key–value store in data model; document system_settings.py (CRUD + supplement-table convenience endpoint); reference apiSystemSettings.ts; note defaults seeding via init_defaults.py. Program Info: Bump version to 2025.1.0-alpha.11; changelog explicitly tied to the Settings page (Events tab: supplement-table URL moved; Academic Calendar: set active period; proxy note); README docs mention. No functional changes to API or UI code in this commit; documentation and program info only.
This commit is contained in:
203
server/routes/system_settings.py
Normal file
203
server/routes/system_settings.py
Normal file
@@ -0,0 +1,203 @@
|
||||
"""
|
||||
System Settings API endpoints.
|
||||
Provides key-value storage for system-wide configuration.
|
||||
"""
|
||||
from flask import Blueprint, jsonify, request
|
||||
from server.database import Session
|
||||
from models.models import SystemSetting
|
||||
from server.permissions import admin_or_higher
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
system_settings_bp = Blueprint('system_settings', __name__, url_prefix='/api/system-settings')
|
||||
|
||||
|
||||
@system_settings_bp.route('', methods=['GET'])
|
||||
@admin_or_higher
|
||||
def get_all_settings():
|
||||
"""
|
||||
Get all system settings.
|
||||
Admin+ only.
|
||||
"""
|
||||
session = Session()
|
||||
try:
|
||||
settings = session.query(SystemSetting).all()
|
||||
return jsonify({
|
||||
'settings': [s.to_dict() for s in settings]
|
||||
}), 200
|
||||
except SQLAlchemyError as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
|
||||
@system_settings_bp.route('/<key>', methods=['GET'])
|
||||
@admin_or_higher
|
||||
def get_setting(key):
|
||||
"""
|
||||
Get a specific system setting by key.
|
||||
Admin+ only.
|
||||
"""
|
||||
session = Session()
|
||||
try:
|
||||
setting = session.query(SystemSetting).filter_by(key=key).first()
|
||||
if not setting:
|
||||
return jsonify({'error': 'Setting not found'}), 404
|
||||
return jsonify(setting.to_dict()), 200
|
||||
except SQLAlchemyError as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
|
||||
@system_settings_bp.route('/<key>', methods=['POST', 'PUT'])
|
||||
@admin_or_higher
|
||||
def update_setting(key):
|
||||
"""
|
||||
Create or update a system setting.
|
||||
Admin+ only.
|
||||
|
||||
Request body:
|
||||
{
|
||||
"value": "string",
|
||||
"description": "string" (optional)
|
||||
}
|
||||
"""
|
||||
session = Session()
|
||||
try:
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return jsonify({'error': 'No data provided'}), 400
|
||||
|
||||
value = data.get('value')
|
||||
description = data.get('description')
|
||||
|
||||
# Try to find existing setting
|
||||
setting = session.query(SystemSetting).filter_by(key=key).first()
|
||||
|
||||
if setting:
|
||||
# Update existing
|
||||
setting.value = value
|
||||
if description is not None:
|
||||
setting.description = description
|
||||
else:
|
||||
# Create new
|
||||
setting = SystemSetting(
|
||||
key=key,
|
||||
value=value,
|
||||
description=description
|
||||
)
|
||||
session.add(setting)
|
||||
|
||||
session.commit()
|
||||
return jsonify(setting.to_dict()), 200
|
||||
except SQLAlchemyError as e:
|
||||
session.rollback()
|
||||
return jsonify({'error': str(e)}), 500
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
|
||||
@system_settings_bp.route('/<key>', methods=['DELETE'])
|
||||
@admin_or_higher
|
||||
def delete_setting(key):
|
||||
"""
|
||||
Delete a system setting.
|
||||
Admin+ only.
|
||||
"""
|
||||
session = Session()
|
||||
try:
|
||||
setting = session.query(SystemSetting).filter_by(key=key).first()
|
||||
if not setting:
|
||||
return jsonify({'error': 'Setting not found'}), 404
|
||||
|
||||
session.delete(setting)
|
||||
session.commit()
|
||||
return jsonify({'message': 'Setting deleted successfully'}), 200
|
||||
except SQLAlchemyError as e:
|
||||
session.rollback()
|
||||
return jsonify({'error': str(e)}), 500
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
|
||||
# Convenience endpoints for specific settings
|
||||
@system_settings_bp.route('/supplement-table', methods=['GET'])
|
||||
@admin_or_higher
|
||||
def get_supplement_table_settings():
|
||||
"""
|
||||
Get supplement table URL and enabled status.
|
||||
Admin+ only.
|
||||
"""
|
||||
session = Session()
|
||||
try:
|
||||
url_setting = session.query(SystemSetting).filter_by(key='supplement_table_url').first()
|
||||
enabled_setting = session.query(SystemSetting).filter_by(key='supplement_table_enabled').first()
|
||||
|
||||
return jsonify({
|
||||
'url': url_setting.value if url_setting else '',
|
||||
'enabled': enabled_setting.value == 'true' if enabled_setting else False,
|
||||
}), 200
|
||||
except SQLAlchemyError as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
|
||||
@system_settings_bp.route('/supplement-table', methods=['POST'])
|
||||
@admin_or_higher
|
||||
def update_supplement_table_settings():
|
||||
"""
|
||||
Update supplement table URL and enabled status.
|
||||
Admin+ only.
|
||||
|
||||
Request body:
|
||||
{
|
||||
"url": "https://...",
|
||||
"enabled": true/false
|
||||
}
|
||||
"""
|
||||
session = Session()
|
||||
try:
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return jsonify({'error': 'No data provided'}), 400
|
||||
|
||||
url = data.get('url', '')
|
||||
enabled = data.get('enabled', False)
|
||||
|
||||
# Update or create URL setting
|
||||
url_setting = session.query(SystemSetting).filter_by(key='supplement_table_url').first()
|
||||
if url_setting:
|
||||
url_setting.value = url
|
||||
else:
|
||||
url_setting = SystemSetting(
|
||||
key='supplement_table_url',
|
||||
value=url,
|
||||
description='URL für Vertretungsplan (Stundenplan-Änderungstabelle)'
|
||||
)
|
||||
session.add(url_setting)
|
||||
|
||||
# Update or create enabled setting
|
||||
enabled_setting = session.query(SystemSetting).filter_by(key='supplement_table_enabled').first()
|
||||
if enabled_setting:
|
||||
enabled_setting.value = 'true' if enabled else 'false'
|
||||
else:
|
||||
enabled_setting = SystemSetting(
|
||||
key='supplement_table_enabled',
|
||||
value='true' if enabled else 'false',
|
||||
description='Ob Vertretungsplan aktiviert ist'
|
||||
)
|
||||
session.add(enabled_setting)
|
||||
|
||||
session.commit()
|
||||
|
||||
return jsonify({
|
||||
'url': url,
|
||||
'enabled': enabled,
|
||||
'message': 'Supplement table settings updated successfully'
|
||||
}), 200
|
||||
except SQLAlchemyError as e:
|
||||
session.rollback()
|
||||
return jsonify({'error': str(e)}), 500
|
||||
finally:
|
||||
session.close()
|
||||
Reference in New Issue
Block a user