updated pages

This commit is contained in:
2025-07-16 16:08:40 +03:00
parent 94fad22d85
commit f075cdf871
12 changed files with 1808 additions and 26 deletions

View File

@@ -89,13 +89,18 @@ def create_user():
return redirect(url_for('admin.index'))
@bp.route('/delete_user/<int:user_id>', methods=['POST'])
@bp.route('/delete_user', methods=['POST'])
@login_required
@admin_required
def delete_user(user_id):
"""Delete a user"""
def delete_user():
"""Delete a user using POST form data"""
user_id = request.form.get('user_id')
if not user_id:
flash('User ID is required.', 'danger')
return redirect(url_for('admin.index'))
# Prevent self-deletion
if user_id == current_user.id:
if int(user_id) == current_user.id:
flash('You cannot delete your own account.', 'danger')
return redirect(url_for('admin.index'))
@@ -206,8 +211,8 @@ def upload_assets():
@login_required
@admin_required
def clean_unused_files():
"""Clean unused files from uploads folder"""
from flask import current_app
"""Clean unused files from uploads folder - API endpoint"""
from flask import current_app, jsonify
from app.models.content import Content
try:
@@ -217,6 +222,7 @@ def clean_unused_files():
content_files = {content.file_name for content in Content.query.all()}
# Get all files in upload folder
deleted_count = 0
if os.path.exists(upload_folder):
all_files = set(os.listdir(upload_folder))
@@ -224,7 +230,6 @@ def clean_unused_files():
unused_files = all_files - content_files
# Delete unused files
deleted_count = 0
for file_name in unused_files:
file_path = os.path.join(upload_folder, file_name)
if os.path.isfile(file_path):
@@ -233,13 +238,243 @@ def clean_unused_files():
deleted_count += 1
except Exception as e:
print(f"Error deleting {file_path}: {e}")
flash(f'Cleaned {deleted_count} unused files.', 'success')
log_action(f'Cleaned {deleted_count} unused files')
else:
flash('Upload folder does not exist.', 'info')
log_action(f'Cleaned {deleted_count} unused files')
return jsonify({'success': True, 'deleted_count': deleted_count})
except Exception as e:
flash(f'Error cleaning files: {str(e)}', 'danger')
return jsonify({'success': False, 'message': str(e)})
@bp.route('/optimize_database', methods=['POST'])
@login_required
@admin_required
def optimize_database():
"""Optimize database performance"""
from flask import jsonify
try:
# SQLite optimization commands
db.session.execute(db.text('VACUUM;'))
db.session.execute(db.text('ANALYZE;'))
db.session.commit()
log_action('Database optimized')
return jsonify({'success': True, 'message': 'Database optimized successfully'})
except Exception as e:
db.session.rollback()
return jsonify({'success': False, 'message': str(e)})
@bp.route('/scheduled_tasks', methods=['GET'])
@login_required
@admin_required
def get_scheduled_tasks():
"""Get all scheduled tasks"""
from flask import jsonify
from app.models.scheduled_task import ScheduledTask
try:
tasks = ScheduledTask.query.order_by(ScheduledTask.created_at.desc()).all()
tasks_data = []
for task in tasks:
task_dict = task.to_dict()
# Format next run time
if task.next_run:
task_dict['next_run'] = task.next_run.strftime('%Y-%m-%d %H:%M')
else:
task_dict['next_run'] = calculate_next_run(task.schedule)
tasks_data.append(task_dict)
return jsonify({'success': True, 'tasks': tasks_data})
except Exception as e:
return jsonify({'success': False, 'message': str(e)})
@bp.route('/create_scheduled_task', methods=['POST'])
@login_required
@admin_required
def create_scheduled_task():
"""Create a new scheduled task"""
from app.models.scheduled_task import ScheduledTask
name = request.form.get('name', '').strip()
task_type = request.form.get('task_type', '').strip()
schedule = request.form.get('schedule', '').strip()
enabled = 'enabled' in request.form or request.form.get('enabled') == 'true'
# Handle time and frequency form data for quick setup
time_str = request.form.get('time')
frequency = request.form.get('frequency')
if time_str and frequency:
# Convert time and frequency to cron expression
hour, minute = time_str.split(':')
if frequency == 'daily':
schedule = f"{minute} {hour} * * *"
elif frequency == 'weekly':
schedule = f"{minute} {hour} * * 0" # Sunday
elif frequency == 'monthly':
schedule = f"{minute} {hour} 1 * *" # 1st of month
# Generate name if not provided
if not name:
name = f"{task_type.replace('_', ' ').title()} - {frequency.title()}"
# Validation
if not task_type or not schedule:
flash('Task type and schedule are required.', 'danger')
return redirect(url_for('admin.index'))
if not name:
name = f"{task_type.replace('_', ' ').title()} Task"
try:
# Create new scheduled task
task = ScheduledTask(
name=name,
task_type=task_type,
schedule=schedule,
enabled=enabled
)
# Calculate next run time
task.next_run = calculate_next_run_datetime(schedule)
db.session.add(task)
db.session.commit()
log_action(f"Scheduled task '{name}' created")
flash(f'Scheduled task "{name}" created successfully.', 'success')
except Exception as e:
db.session.rollback()
flash(f'Error creating scheduled task: {str(e)}', 'danger')
return redirect(url_for('admin.index'))
@bp.route('/toggle_task/<int:task_id>', methods=['POST'])
@login_required
@admin_required
def toggle_task(task_id):
"""Toggle a scheduled task on/off"""
from flask import jsonify
from app.models.scheduled_task import ScheduledTask
try:
task = ScheduledTask.query.get_or_404(task_id)
task.enabled = not task.enabled
db.session.commit()
status = 'enabled' if task.enabled else 'disabled'
log_action(f"Scheduled task '{task.name}' {status}")
return jsonify({'success': True, 'enabled': task.enabled})
except Exception as e:
db.session.rollback()
return jsonify({'success': False, 'message': str(e)})
@bp.route('/delete_task/<int:task_id>', methods=['DELETE'])
@login_required
@admin_required
def delete_task(task_id):
"""Delete a scheduled task"""
from flask import jsonify
from app.models.scheduled_task import ScheduledTask
try:
task = ScheduledTask.query.get_or_404(task_id)
task_name = task.name
db.session.delete(task)
db.session.commit()
log_action(f"Scheduled task '{task_name}' deleted")
return jsonify({'success': True})
except Exception as e:
db.session.rollback()
return jsonify({'success': False, 'message': str(e)})
@bp.route('/edit_user', methods=['POST'])
@login_required
@admin_required
def edit_user():
"""Edit a user"""
user_id = request.form.get('user_id')
if not user_id:
flash('User ID is required.', 'danger')
return redirect(url_for('admin.index'))
# Prevent self-editing
if int(user_id) == current_user.id:
flash('You cannot edit your own account.', 'danger')
return redirect(url_for('admin.index'))
user = User.query.get_or_404(user_id)
# Get form data
role = request.form.get('role', 'user')
is_active = 'is_active' in request.form
password = request.form.get('password', '').strip()
if role not in ['user', 'admin']:
flash('Invalid role specified.', 'danger')
return redirect(url_for('admin.index'))
try:
# Update user
user.role = role
user.is_active_user = is_active
# Update password if provided
if password:
if len(password) < 6:
flash('Password must be at least 6 characters long.', 'danger')
return redirect(url_for('admin.index'))
user.set_password(password)
db.session.commit()
log_action(f"User '{user.username}' updated - Role: {role}, Active: {is_active}")
flash(f'User "{user.username}" updated successfully.', 'success')
except Exception as e:
db.session.rollback()
flash(f'Error updating user: {str(e)}', 'danger')
return redirect(url_for('admin.index'))
def calculate_next_run(cron_expression):
"""Calculate next run time from cron expression (simplified)"""
try:
parts = cron_expression.split()
if len(parts) >= 2:
minute, hour = parts[0], parts[1]
return f"Next run: {hour}:{minute.zfill(2)}"
return "Invalid schedule"
except:
return "Invalid schedule"
def calculate_next_run_datetime(cron_expression):
"""Calculate next run datetime from cron expression (basic implementation)"""
from datetime import datetime, timedelta
try:
parts = cron_expression.split()
if len(parts) >= 2:
minute = int(parts[0])
hour = int(parts[1])
now = datetime.now()
next_run = now.replace(hour=hour, minute=minute, second=0, microsecond=0)
# If the time has passed today, schedule for tomorrow
if next_run <= now:
next_run += timedelta(days=1)
return next_run
except:
pass
return None

View File

@@ -207,6 +207,55 @@ def get_player_content_status(player_id):
except Exception as e:
return jsonify({'error': f'Failed to get content status: {str(e)}'}), 500
@bp.route('/content/<int:content_id>/edit', methods=['POST'])
def edit_content_duration(content_id):
"""Edit content duration"""
from flask_login import current_user
# Require authentication for this operation
if not current_user.is_authenticated:
return jsonify({'error': 'Authentication required'}), 401
data = request.get_json()
if not data or 'duration' not in data:
return jsonify({'error': 'Duration required'}), 400
new_duration = data.get('duration')
# Validate duration
try:
new_duration = int(new_duration)
if new_duration < 1 or new_duration > 300:
return jsonify({'error': 'Duration must be between 1 and 300 seconds'}), 400
except (ValueError, TypeError):
return jsonify({'error': 'Invalid duration value'}), 400
# Find the content item
content = Content.query.get(content_id)
if not content:
return jsonify({'error': 'Content not found'}), 404
# Update the content duration
try:
old_duration = content.duration
content.duration = new_duration
# Update player's playlist version to trigger refresh
player = Player.query.get(content.player_id)
if player:
player.increment_playlist_version()
db.session.commit()
return jsonify({
'success': True,
'message': f'Content duration updated from {old_duration}s to {new_duration}s',
'new_duration': new_duration
})
except Exception as e:
db.session.rollback()
return jsonify({'error': f'Failed to update content: {str(e)}'}), 500
@bp.errorhandler(404)
def api_not_found(error):
"""API 404 handler"""