updated pages
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"""
|
||||
|
||||
Reference in New Issue
Block a user