""" Group management utilities """ from app.extensions import db from app.models.group import Group from app.models.player import Player from app.models.content import Content from app.utils.logger import log_group_created, log_group_edited, log_group_deleted, log_content_reordered def create_group(name, player_ids=None, description=None): """ Create a new group Args: name (str): Group name player_ids (list): List of player IDs to add to group (optional) description (str): Group description (optional) Returns: tuple: (success, group_or_error_message) """ try: # Check if group name already exists if Group.query.filter_by(name=name).first(): return False, f"Group with name '{name}' already exists" # Create new group group = Group( name=name, description=description or "" ) # Add players to group if player_ids: players = Player.query.filter(Player.id.in_(player_ids)).all() for player in players: group.players.append(player) db.session.add(group) db.session.commit() log_group_created(name) return True, group except Exception as e: db.session.rollback() return False, str(e) def edit_group(group_id, name=None, player_ids=None, description=None): """ Edit an existing group Args: group_id (int): Group ID name (str): New group name (optional) player_ids (list): New list of player IDs (optional) description (str): New description (optional) Returns: tuple: (success, group_or_error_message) """ try: group = Group.query.get(group_id) if not group: return False, "Group not found" # Check for name conflicts if name and name != group.name: existing = Group.query.filter_by(name=name).first() if existing and existing.id != group_id: return False, f"Group with name '{name}' already exists" group.name = name # Update description if description is not None: group.description = description # Update players if player_ids is not None: # Clear current players group.players.clear() # Add new players if player_ids: players = Player.query.filter(Player.id.in_(player_ids)).all() for player in players: group.players.append(player) db.session.commit() log_group_edited(group.name) return True, group except Exception as e: db.session.rollback() return False, str(e) def delete_group(group_id): """ Delete a group (players remain, just removed from group) Args: group_id (int): Group ID Returns: tuple: (success, error_message) """ try: group = Group.query.get(group_id) if not group: return False, "Group not found" group_name = group.name # Remove all players from group group.players.clear() # Delete group db.session.delete(group) db.session.commit() log_group_deleted(group_name) return True, None except Exception as e: db.session.rollback() return False, str(e) def get_group_content(group_id): """ Get all unique content for players in a group Args: group_id (int): Group ID Returns: list: List of Content objects """ group = Group.query.get(group_id) if not group: return [] player_ids = [player.id for player in group.players] if not player_ids: return [] # Get unique content by filename, taking the first occurrence content_query = ( db.session.query( Content.file_name, db.func.min(Content.id).label('id'), db.func.min(Content.duration).label('duration'), db.func.min(Content.position).label('position') ) .filter(Content.player_id.in_(player_ids)) .group_by(Content.file_name) ) # Get the actual content objects content_ids = [c.id for c in content_query.all()] content = Content.query.filter(Content.id.in_(content_ids)).order_by(Content.position).all() return content def update_group_content_order(group_id, content_items): """ Update the order of content items for all players in a group Args: group_id (int): Group ID content_items (list): List of content items with new positions Returns: tuple: (success, error_message) """ try: group = Group.query.get(group_id) if not group: return False, "Group not found" player_ids = [player.id for player in group.players] if not player_ids: return True, None # No players in group # Update positions for all matching content across all players for i, item in enumerate(content_items): file_name = item.get('file_name') if file_name: Content.query.filter( Content.player_id.in_(player_ids), Content.file_name == file_name ).update({Content.position: i}) # Increment playlist version for all players and group group.increment_playlist_version() db.session.commit() log_content_reordered('group', group.name) return True, None except Exception as e: db.session.rollback() return False, str(e) def add_player_to_group(group_id, player_id): """ Add a player to a group Args: group_id (int): Group ID player_id (int): Player ID Returns: tuple: (success, error_message) """ try: group = Group.query.get(group_id) player = Player.query.get(player_id) if not group: return False, "Group not found" if not player: return False, "Player not found" if player not in group.players: group.players.append(player) db.session.commit() return True, None except Exception as e: db.session.rollback() return False, str(e) def remove_player_from_group(group_id, player_id): """ Remove a player from a group Args: group_id (int): Group ID player_id (int): Player ID Returns: tuple: (success, error_message) """ try: group = Group.query.get(group_id) player = Player.query.get(player_id) if not group: return False, "Group not found" if not player: return False, "Player not found" if player in group.players: group.players.remove(player) db.session.commit() return True, None except Exception as e: db.session.rollback() return False, str(e) def get_available_players(): """ Get all players that are not locked to any group Returns: list: List of Player objects """ return Player.query.filter_by(locked_to_group_id=None).all() def lock_players_to_group(group_id, player_ids): """ Lock specified players to a group (exclusive membership) Args: group_id (int): Group ID player_ids (list): List of player IDs to lock Returns: tuple: (success, error_message) """ try: group = Group.query.get(group_id) if not group: return False, "Group not found" players = Player.query.filter(Player.id.in_(player_ids)).all() for player in players: player.locked_to_group_id = group_id db.session.commit() return True, None except Exception as e: db.session.rollback() return False, str(e) def unlock_players_from_group(group_id): """ Unlock all players from a group Args: group_id (int): Group ID Returns: tuple: (success, error_message) """ try: players = Player.query.filter_by(locked_to_group_id=group_id).all() for player in players: player.locked_to_group_id = None db.session.commit() return True, None except Exception as e: db.session.rollback() return False, str(e)