Fix orientation parameter handling and template URL endpoints

- Add orientation parameter support to create_group and edit_group functions
- Fix manage_group.html template URL endpoint from 'update_group_content_order' to 'update_group_content_order_route'
- Add orientation field and filtering to edit_group.html template with JavaScript functionality
- Update group_player_management.py to handle orientation validation in create and edit operations
- Fix docker-compose.yml to include build directive and correct volume paths
- Update entrypoint.sh to handle fresh deployments without migrations
- Ensure orientation consistency across group and player management

These changes resolve:
- Internal Server Error on manage_group page
- Missing orientation parameter in group creation/editing
- Template URL endpoint mismatches
- Docker deployment issues with fresh installations
This commit is contained in:
2025-08-01 15:15:59 -04:00
parent 70d76f45e7
commit 318f783de3
7 changed files with 76 additions and 18 deletions

6
app.py
View File

@@ -488,7 +488,8 @@ def create_group():
if request.method == 'POST': if request.method == 'POST':
group_name = request.form['name'] group_name = request.form['name']
player_ids = request.form.getlist('players') player_ids = request.form.getlist('players')
create_group_util(group_name, player_ids) orientation = request.form.get('orientation', 'Landscape')
create_group_util(group_name, player_ids, orientation)
flash(f'Group "{group_name}" created successfully.', 'success') flash(f'Group "{group_name}" created successfully.', 'success')
return redirect(url_for('dashboard')) return redirect(url_for('dashboard'))
players = Player.query.all() players = Player.query.all()
@@ -514,7 +515,8 @@ def edit_group(group_id):
if request.method == 'POST': if request.method == 'POST':
name = request.form['name'] name = request.form['name']
player_ids = request.form.getlist('players') player_ids = request.form.getlist('players')
edit_group_util(group_id, name, player_ids) orientation = request.form.get('orientation', group.orientation)
edit_group_util(group_id, name, player_ids, orientation)
flash(f'Group "{name}" updated successfully.', 'success') flash(f'Group "{name}" updated successfully.', 'success')
return redirect(url_for('dashboard')) return redirect(url_for('dashboard'))
players = Player.query.all() players = Player.query.all()

View File

@@ -1,6 +1,7 @@
#version: '"1.1.0"' #version: '"1.1.0"'
services: services:
web: web:
build: .
image: digiserver:latest image: digiserver:latest
ports: ports:
- "8880:5000" - "8880:5000"
@@ -12,5 +13,5 @@ services:
- SECRET_KEY=Ma_Duc_Dupa_Merele_Lui_Ana - SECRET_KEY=Ma_Duc_Dupa_Merele_Lui_Ana
volumes: volumes:
- /opt/digi-s/instance:/app/instance - /opt/digi-s/instance:/app/instance
- /opt/digi-s/static/uploads:/app/static/uploads - /opt/digi-s/uploads:/app/static/uploads
restart: unless-stopped restart: unless-stopped

View File

@@ -7,16 +7,7 @@ mkdir -p instance
# Check if database exists # Check if database exists
if [ ! -f instance/dashboard.db ]; then if [ ! -f instance/dashboard.db ]; then
echo "No database found, initializing..." echo "No database found, creating fresh database..."
# Remove and recreate migrations directory to ensure clean state
rm -rf migrations
mkdir -p migrations
# Initialize the database
flask db init
flask db migrate -m "Initial migration"
flask db upgrade
# Create admin user if environment variables are set # Create admin user if environment variables are set
if [ -n "$ADMIN_USER" ] && [ -n "$ADMIN_PASSWORD" ]; then if [ -n "$ADMIN_USER" ] && [ -n "$ADMIN_PASSWORD" ]; then
@@ -26,8 +17,11 @@ if [ ! -f instance/dashboard.db ]; then
echo "Warning: ADMIN_USER or ADMIN_PASSWORD not set, skipping admin creation" echo "Warning: ADMIN_USER or ADMIN_PASSWORD not set, skipping admin creation"
fi fi
else else
echo "Existing database found, applying migrations..." echo "Existing database found, skipping initialization..."
flask db upgrade echo "Creating admin user if needed..."
if [ -n "$ADMIN_USER" ] && [ -n "$ADMIN_PASSWORD" ]; then
flask create-admin --username "$ADMIN_USER" --password "$ADMIN_PASSWORD" 2>/dev/null || echo "Default user '$ADMIN_USER' already exists."
fi
fi fi
echo "Starting DigiServer..." echo "Starting DigiServer..."

Binary file not shown.

View File

@@ -49,12 +49,24 @@
</select> </select>
</div> </div>
</div> </div>
<div class="col-md-6 col-12">
<div class="mb-3">
<label for="orientation" class="form-label">Group Orientation</label>
<select class="form-control {{ 'dark-mode' if theme == 'dark' else '' }}" id="orientation" name="orientation" required>
<option value="Landscape" {% if group.orientation == 'Landscape' %}selected{% endif %}>Landscape</option>
<option value="Portret" {% if group.orientation == 'Portret' %}selected{% endif %}>Portret</option>
</select>
</div>
</div>
</div> </div>
<!-- Add this above the player selection --> <!-- Add this above the player selection -->
<div class="alert alert-warning" role="alert"> <div class="alert alert-warning" role="alert">
<strong>Warning:</strong> Adding new players to this group will delete their individual playlists. <strong>Warning:</strong> Adding new players to this group will delete their individual playlists.
Removing players from the group will allow them to have their own playlists again. Removing players from the group will allow them to have their own playlists again.
</div> </div>
<div id="orientation-warning" class="alert alert-danger d-none" role="alert">
No players with the selected orientation are available.
</div>
<div class="text-center"> <div class="text-center">
<button type="submit" class="btn btn-primary">Save Changes</button> <button type="submit" class="btn btn-primary">Save Changes</button>
<a href="{{ url_for('dashboard') }}" class="btn btn-secondary mt-3">Back to Dashboard</a> <a href="{{ url_for('dashboard') }}" class="btn btn-secondary mt-3">Back to Dashboard</a>
@@ -62,5 +74,45 @@
</form> </form>
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Get all players and their orientations from the backend
const players = [
{% for player in players %}
{id: {{ player.id }}, username: "{{ player.username }}", orientation: "{{ player.orientation }}", inGroup: {% if player in group.players %}true{% else %}false{% endif %}},
{% endfor %}
];
const orientationSelect = document.getElementById('orientation');
const playersSelect = document.getElementById('players');
const orientationWarning = document.getElementById('orientation-warning');
function filterPlayers() {
const selectedOrientation = orientationSelect.value;
const currentSelection = Array.from(playersSelect.selectedOptions).map(option => option.value);
playersSelect.innerHTML = '';
let compatibleCount = 0;
players.forEach(player => {
if (player.orientation === selectedOrientation) {
const option = document.createElement('option');
option.value = player.id;
option.textContent = player.username;
// Re-select if it was previously selected
if (currentSelection.includes(player.id.toString()) || player.inGroup) {
option.selected = true;
}
playersSelect.appendChild(option);
compatibleCount++;
}
});
orientationWarning.classList.toggle('d-none', compatibleCount > 0);
}
orientationSelect.addEventListener('change', filterPlayers);
// Initial filter on page load
filterPlayers();
</script>
</body> </body>
</html> </html>

View File

@@ -189,7 +189,7 @@ document.addEventListener('DOMContentLoaded', function() {
}); });
// Send to server // Send to server
fetch('{{ url_for("update_group_content_order", group_id=group.id) }}', { fetch('{{ url_for("update_group_content_order_route", group_id=group.id) }}', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',

View File

@@ -35,15 +35,24 @@ def create_group(name, player_ids, orientation='Landscape'):
log_group_created(name) log_group_created(name)
return new_group return new_group
def edit_group(group_id, name, player_ids): def edit_group(group_id, name, player_ids, orientation=None):
""" """
Edit an existing group, updating its name and players. Edit an existing group, updating its name, orientation, and players.
Handles locking/unlocking players appropriately. Handles locking/unlocking players appropriately.
""" """
group = Group.query.get_or_404(group_id) group = Group.query.get_or_404(group_id)
old_name = group.name # Store old name in case it changes old_name = group.name # Store old name in case it changes
group.name = name group.name = name
# Update orientation if provided
if orientation:
group.orientation = orientation
# Validate that all selected players have the matching orientation
for player_id in player_ids:
player = Player.query.get(player_id)
if player and player.orientation != orientation:
raise ValueError(f"Player '{player.username}' has orientation '{player.orientation}', which does not match group orientation '{orientation}'.")
# Get current players in the group # Get current players in the group
current_player_ids = [player.id for player in group.players] current_player_ids = [player.id for player in group.players]