325 lines
8.7 KiB
Python
325 lines
8.7 KiB
Python
"""
|
|
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)
|