From 3829d98e91849b291e3a9a34032d01b6f55e6030 Mon Sep 17 00:00:00 2001 From: DigiServer Developer Date: Sun, 14 Dec 2025 14:14:04 +0200 Subject: [PATCH] Implement editing users management and permission updates - Added auto-creation of PlayerUser records from player metadata (user_card_data) - Fixed player_user table schema (removed player_id, made user_code unique globally) - Created admin page for managing editing users (view, update names, delete) - Updated permissions: normal users can now access admin panel, editing users, and leftover media - Admin-only access: user management, system dependencies, logo customization - Fixed edited media workflow to preserve original files - Content.filename now points to edited_media folder, keeping originals intact - Added user display names in edited media page (shows name if set, code otherwise) - Fixed leftover media file size calculation (handle None values) - Split editing users into separate card on admin panel with description --- app/blueprints/admin.py | 23 +++++++++-------------- app/blueprints/api.py | 10 +++------- app/blueprints/players.py | 14 +++++++++++++- app/templates/admin/admin.html | 22 +++++++++++++++++----- app/templates/base.html | 4 +--- app/templates/players/edited_media.html | 4 ++-- 6 files changed, 45 insertions(+), 32 deletions(-) diff --git a/app/blueprints/admin.py b/app/blueprints/admin.py index c3f140a..415faa0 100644 --- a/app/blueprints/admin.py +++ b/app/blueprints/admin.py @@ -31,7 +31,6 @@ def admin_required(f): @admin_bp.route('/') @login_required -@admin_required def admin_panel(): """Display admin panel with system overview.""" try: @@ -351,7 +350,6 @@ def system_info(): @admin_bp.route('/leftover-media') @login_required -@admin_required def leftover_media(): """Display leftover media files not assigned to any playlist.""" from app.models.playlist import playlist_content @@ -374,12 +372,15 @@ def leftover_media(): leftover_pdfs = [c for c in leftover_content if c.content_type == 'pdf'] leftover_pptx = [c for c in leftover_content if c.content_type == 'pptx'] - # Calculate storage - total_leftover_size = sum(c.file_size for c in leftover_content) - images_size = sum(c.file_size for c in leftover_images) - videos_size = sum(c.file_size for c in leftover_videos) - pdfs_size = sum(c.file_size for c in leftover_pdfs) - pptx_size = sum(c.file_size for c in leftover_pptx) + # Calculate storage (handle None values) + def safe_file_size(content_list): + return sum(c.file_size or 0 for c in content_list) + + total_leftover_size = safe_file_size(leftover_content) + images_size = safe_file_size(leftover_images) + videos_size = safe_file_size(leftover_videos) + pdfs_size = safe_file_size(leftover_pdfs) + pptx_size = safe_file_size(leftover_pptx) return render_template('admin/leftover_media.html', leftover_images=leftover_images, @@ -401,7 +402,6 @@ def leftover_media(): @admin_bp.route('/delete-leftover-images', methods=['POST']) @login_required -@admin_required def delete_leftover_images(): """Delete all leftover images that are not part of any playlist""" from app.models.playlist import playlist_content @@ -457,7 +457,6 @@ def delete_leftover_images(): @admin_bp.route('/delete-leftover-videos', methods=['POST']) @login_required -@admin_required def delete_leftover_videos(): """Delete all leftover videos that are not part of any playlist""" from app.models.playlist import playlist_content @@ -513,7 +512,6 @@ def delete_leftover_videos(): @admin_bp.route('/delete-single-leftover/', methods=['POST']) @login_required -@admin_required def delete_single_leftover(content_id): """Delete a single leftover content file""" try: @@ -776,7 +774,6 @@ def upload_login_logo(): @admin_bp.route('/editing-users') @login_required -@admin_required def manage_editing_users(): """Display and manage users that edit images on players.""" try: @@ -803,7 +800,6 @@ def manage_editing_users(): @admin_bp.route('/editing-users//update', methods=['POST']) @login_required -@admin_required def update_editing_user(user_id: int): """Update editing user name.""" try: @@ -828,7 +824,6 @@ def update_editing_user(user_id: int): @admin_bp.route('/editing-users//delete', methods=['POST']) @login_required -@admin_required def delete_editing_user(user_id: int): """Delete editing user.""" try: diff --git a/app/blueprints/api.py b/app/blueprints/api.py index 02ccc9e..1455a2c 100644 --- a/app/blueprints/api.py +++ b/app/blueprints/api.py @@ -777,14 +777,10 @@ def receive_edited_media(): with open(metadata_path, 'w') as f: json.dump(metadata, f, indent=2) - # Copy the versioned image to the main uploads folder - import shutil - versioned_upload_path = os.path.join(base_upload_dir, new_filename) - shutil.copy2(edited_file_path, versioned_upload_path) - - # Update the content record to reference the new versioned filename + # Update the content record to reference the edited version path + # Keep original filename unchanged, point to edited_media folder old_filename = content.filename - content.filename = new_filename + content.filename = f"edited_media/{content.id}/{new_filename}" # Create edit record time_of_mod = None diff --git a/app/blueprints/players.py b/app/blueprints/players.py index 35703bb..ebf227b 100644 --- a/app/blueprints/players.py +++ b/app/blueprints/players.py @@ -343,6 +343,7 @@ def edited_media(player_id: int): # Get all edited media history from player from app.models.player_edit import PlayerEdit + from app.models.player_user import PlayerUser edited_media = PlayerEdit.query.filter_by(player_id=player_id)\ .order_by(PlayerEdit.created_at.desc())\ @@ -356,10 +357,21 @@ def edited_media(player_id: int): if content: content_files[edit.content_id] = content + # Get user mappings for display names + user_mappings = {} + for edit in edited_media: + if edit.user and edit.user not in user_mappings: + player_user = PlayerUser.query.filter_by(user_code=edit.user).first() + if player_user: + user_mappings[edit.user] = player_user.user_name or edit.user + else: + user_mappings[edit.user] = edit.user + return render_template('players/edited_media.html', player=player, edited_media=edited_media, - content_files=content_files) + content_files=content_files, + user_mappings=user_mappings) except Exception as e: log_action('error', f'Error loading edited media for player {player_id}: {str(e)}') flash('Error loading edited media.', 'danger') diff --git a/app/templates/admin/admin.html b/app/templates/admin/admin.html index edd6aab..051dac7 100644 --- a/app/templates/admin/admin.html +++ b/app/templates/admin/admin.html @@ -48,7 +48,8 @@ - + {% if current_user.is_admin %} +

👥 User Management

Manage application users, roles and permissions

@@ -56,8 +57,17 @@ Manage Users - - Manage Users That Edited Images +
+ + {% endif %} + + + @@ -73,7 +83,8 @@ - + {% if current_user.is_admin %} +

🔧 System Dependencies

Check and install required software dependencies

@@ -84,7 +95,7 @@
- +

🎨 Logo Customization

Upload custom logos for header and login page

@@ -94,6 +105,7 @@
+ {% endif %}
diff --git a/app/templates/base.html b/app/templates/base.html index 03306a2..7bb3d31 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -393,9 +393,7 @@ Playlists - {% if current_user.is_admin %} - Admin - {% endif %} + Admin Logout ({{ current_user.username }})
👤 Edited by: - {{ latest.user or 'Unknown' }} + {{ user_mappings.get(latest.user, latest.user or 'Unknown') }}
🕒 Modified: @@ -398,7 +398,7 @@ {% for edit in data.versions|sort(attribute='version', reverse=True) %}
+ onclick="event.stopPropagation(); selectVersion({{ content_id }}, {{ edit.version }}, '{{ edit.new_name }}', '{{ user_mappings.get(edit.user, edit.user or 'Unknown') }}', '{{ edit.time_of_modification | localtime('%Y-%m-%d %H:%M') if edit.time_of_modification else 'N/A' }}', '{{ edit.created_at | localtime('%Y-%m-%d %H:%M') }}', '{{ url_for('static', filename='uploads/edited_media/' ~ edit.content_id ~ '/' ~ edit.new_name) }}')">
{% if edit.new_name.lower().endswith(('.jpg', '.jpeg', '.png', '.gif', '.webp')) %}