Fix channel management: add delete, edit, and content management functionality with proper navigation
This commit is contained in:
139
server.py
139
server.py
@@ -260,14 +260,14 @@ def upload_file():
|
||||
|
||||
if channel and channel.is_active:
|
||||
# Get next order number for this channel
|
||||
max_order = db.session.query(db.func.max(ChannelContent.order)).filter_by(channel_id=channel_id).scalar() or 0
|
||||
max_order = db.session.query(db.func.max(ChannelContent.order_index)).filter_by(channel_id=channel_id).scalar() or 0
|
||||
|
||||
# Add to channel
|
||||
channel_content = ChannelContent(
|
||||
channel_id=channel_id,
|
||||
media_file_id=media_file.id,
|
||||
duration=int(display_duration),
|
||||
order=max_order + 1
|
||||
display_duration=int(display_duration),
|
||||
order_index=max_order + 1
|
||||
)
|
||||
db.session.add(channel_content)
|
||||
db.session.commit()
|
||||
@@ -353,6 +353,139 @@ def add_channel():
|
||||
|
||||
return redirect(url_for('view_channels'))
|
||||
|
||||
@app.route('/delete_channel/<int:channel_id>')
|
||||
@login_required
|
||||
def delete_channel(channel_id):
|
||||
channel = StreamingChannel.query.get_or_404(channel_id)
|
||||
|
||||
# Check permissions
|
||||
if current_user.role != 'admin' and channel.created_by != current_user.id:
|
||||
flash('Access denied. You can only delete your own channels.', 'error')
|
||||
return redirect(url_for('view_channels'))
|
||||
|
||||
# Prevent deleting default channel
|
||||
if channel.is_default:
|
||||
flash('Cannot delete the default channel.', 'error')
|
||||
return redirect(url_for('view_channels'))
|
||||
|
||||
# Check if any players are assigned to this channel
|
||||
assigned_players = Player.query.filter_by(channel_id=channel_id).count()
|
||||
if assigned_players > 0:
|
||||
flash(f'Cannot delete channel. {assigned_players} player(s) are assigned to this channel.', 'error')
|
||||
return redirect(url_for('view_channels'))
|
||||
|
||||
channel_name = channel.name
|
||||
db.session.delete(channel)
|
||||
db.session.commit()
|
||||
|
||||
log_activity('Channel deleted', f'Deleted channel: {channel_name}')
|
||||
flash(f'Channel "{channel_name}" deleted successfully!', 'success')
|
||||
return redirect(url_for('view_channels'))
|
||||
|
||||
@app.route('/edit_channel/<int:channel_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_channel(channel_id):
|
||||
channel = StreamingChannel.query.get_or_404(channel_id)
|
||||
|
||||
# Check permissions
|
||||
if current_user.role != 'admin' and channel.created_by != current_user.id:
|
||||
flash('Access denied. You can only edit your own channels.', 'error')
|
||||
return redirect(url_for('view_channels'))
|
||||
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
# If setting as default, unset other defaults
|
||||
is_default = 'is_default' in request.form
|
||||
if is_default and not channel.is_default:
|
||||
StreamingChannel.query.filter_by(is_default=True).update({'is_default': False})
|
||||
|
||||
channel.name = request.form['name']
|
||||
channel.description = request.form.get('description', '')
|
||||
channel.is_default = is_default
|
||||
channel.is_active = 'is_active' in request.form
|
||||
|
||||
db.session.commit()
|
||||
|
||||
log_activity('Channel updated', f'Updated channel: {channel.name}')
|
||||
flash(f'Channel "{channel.name}" updated successfully!', 'success')
|
||||
except Exception as e:
|
||||
flash(f'Error updating channel: {str(e)}', 'error')
|
||||
|
||||
return redirect(url_for('view_channels'))
|
||||
|
||||
return render_template('edit_channel.html', channel=channel)
|
||||
|
||||
@app.route('/manage_content/<int:channel_id>')
|
||||
@login_required
|
||||
def manage_content(channel_id):
|
||||
channel = StreamingChannel.query.get_or_404(channel_id)
|
||||
|
||||
# Check permissions
|
||||
if current_user.role != 'admin' and channel.created_by != current_user.id:
|
||||
flash('Access denied. You can only manage content of your own channels.', 'error')
|
||||
return redirect(url_for('view_channels'))
|
||||
|
||||
# Get all available media files
|
||||
available_media = MediaFile.query.filter_by(is_active=True).order_by(MediaFile.upload_date.desc()).all()
|
||||
|
||||
# Get current channel content with media file details
|
||||
channel_content = ChannelContent.query.filter_by(channel_id=channel_id).order_by(ChannelContent.order_index).all()
|
||||
|
||||
return render_template('manage_content.html', channel=channel, available_media=available_media, channel_content=channel_content)
|
||||
|
||||
@app.route('/add_content_to_channel', methods=['POST'])
|
||||
@login_required
|
||||
def add_content_to_channel():
|
||||
channel_id = request.form['channel_id']
|
||||
media_file_id = request.form['media_file_id']
|
||||
duration = request.form.get('duration', 10)
|
||||
|
||||
channel = StreamingChannel.query.get_or_404(channel_id)
|
||||
|
||||
# Check permissions
|
||||
if current_user.role != 'admin' and channel.created_by != current_user.id:
|
||||
flash('Access denied.', 'error')
|
||||
return redirect(url_for('view_channels'))
|
||||
|
||||
# Get next order number
|
||||
max_order = db.session.query(db.func.max(ChannelContent.order_index)).filter_by(channel_id=channel_id).scalar() or 0
|
||||
|
||||
# Add content
|
||||
content = ChannelContent(
|
||||
channel_id=channel_id,
|
||||
media_file_id=media_file_id,
|
||||
display_duration=int(duration),
|
||||
order_index=max_order + 1
|
||||
)
|
||||
|
||||
db.session.add(content)
|
||||
db.session.commit()
|
||||
|
||||
media_file = MediaFile.query.get(media_file_id)
|
||||
log_activity('Content added to channel', f'Added {media_file.original_name} to {channel.name}')
|
||||
flash('Content added to channel successfully!', 'success')
|
||||
|
||||
return redirect(url_for('manage_content', channel_id=channel_id))
|
||||
|
||||
@app.route('/remove_content_from_channel/<int:content_id>')
|
||||
@login_required
|
||||
def remove_content_from_channel(content_id):
|
||||
content = ChannelContent.query.get_or_404(content_id)
|
||||
channel = content.channel
|
||||
|
||||
# Check permissions
|
||||
if current_user.role != 'admin' and channel.created_by != current_user.id:
|
||||
flash('Access denied.', 'error')
|
||||
return redirect(url_for('view_channels'))
|
||||
|
||||
db.session.delete(content)
|
||||
db.session.commit()
|
||||
|
||||
log_activity('Content removed from channel', f'Removed content from {channel.name}')
|
||||
flash('Content removed from channel successfully!', 'success')
|
||||
|
||||
return redirect(url_for('manage_content', channel_id=channel.id))
|
||||
|
||||
# User Management Routes
|
||||
@app.route('/add_user', methods=['POST'])
|
||||
@login_required
|
||||
|
||||
@@ -57,7 +57,11 @@
|
||||
<i class="bi bi-person-circle"></i> {{ current_user.username }}
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="{{ url_for('admin') }}"><i class="bi bi-house"></i> Dashboard</a></li>
|
||||
{% if current_user.role == 'admin' %}
|
||||
<li><a class="dropdown-item" href="{{ url_for('admin') }}"><i class="bi bi-house"></i> Admin Dashboard</a></li>
|
||||
{% else %}
|
||||
<li><a class="dropdown-item" href="{{ url_for('user_dashboard') }}"><i class="bi bi-house"></i> User Dashboard</a></li>
|
||||
{% endif %}
|
||||
<li><a class="dropdown-item" href="{{ url_for('view_schedules') }}"><i class="bi bi-calendar"></i> Schedules</a></li>
|
||||
<li><a class="dropdown-item" href="{{ url_for('view_channels') }}"><i class="bi bi-collection-play"></i> Channels</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
@@ -259,16 +263,16 @@
|
||||
}
|
||||
|
||||
function editChannel(channelId) {
|
||||
alert('Edit channel functionality coming soon!');
|
||||
window.location.href = `/edit_channel/${channelId}`;
|
||||
}
|
||||
|
||||
function manageContent(channelId) {
|
||||
alert('Content management functionality coming soon!');
|
||||
window.location.href = `/manage_content/${channelId}`;
|
||||
}
|
||||
|
||||
function deleteChannel(channelId) {
|
||||
if (confirm('Are you sure you want to delete this channel?')) {
|
||||
alert('Delete channel functionality coming soon!');
|
||||
if (confirm('Are you sure you want to delete this channel? This action cannot be undone.')) {
|
||||
window.location.href = `/delete_channel/${channelId}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
39
templates/edit_channel.html
Normal file
39
templates/edit_channel.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit Channel</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-4">
|
||||
<h2>Edit Channel</h2>
|
||||
<form method="post">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Channel Name</label>
|
||||
<input type="text" class="form-control" name="name" value="{{ channel.name }}" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="description" class="form-label">Description</label>
|
||||
<textarea class="form-control" name="description">{{ channel.description or '' }}</textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="is_default" {{ 'checked' if channel.is_default else '' }}>
|
||||
<label class="form-check-label">Set as default channel</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="is_active" {{ 'checked' if channel.is_active else '' }}>
|
||||
<label class="form-check-label">Channel is active</label>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Update Channel</button>
|
||||
<a href="{{ url_for('view_channels') }}" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
13
templates/manage_content.html
Normal file
13
templates/manage_content.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Manage Content</title><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"></head>
|
||||
<body><div class="container mt-4"><h2>{{ channel.name }} - Content Management</h2>
|
||||
<div class="row"><div class="col-md-6"><h4>Current Content</h4>
|
||||
{% for content in channel_content %}<div class="card mb-2"><div class="card-body">{{ content.media_file.original_name }} ({{ content.display_duration }}s)
|
||||
<a href="/remove_content_from_channel/{{ content.id }}" class="btn btn-sm btn-danger float-end">Remove</a></div></div>{% endfor %}
|
||||
</div><div class="col-md-6"><h4>Add Content</h4><form method="post" action="/add_content_to_channel">
|
||||
<input type="hidden" name="channel_id" value="{{ channel.id }}"><select name="media_file_id" class="form-select mb-2">
|
||||
{% for media in available_media %}<option value="{{ media.id }}">{{ media.original_name }}</option>{% endfor %}</select>
|
||||
<input type="number" name="duration" value="10" class="form-control mb-2" placeholder="Duration">
|
||||
<button type="submit" class="btn btn-success">Add</button></form></div></div>
|
||||
<a href="/channels" class="btn btn-primary mt-3">Back</a></div></body></html>
|
||||
Reference in New Issue
Block a user