"""Членство в группе: список, добавление по нику, удаление, смена роли.""" from __future__ import annotations from sqlmodel import Session, select from app.core.errors import ConflictError, ForbiddenError, NotFoundError, ValidationError from app.models import Group, GroupMember, User MAX_GROUP_SIZE = 10 def list_members(session: Session, group_id: int) -> list[tuple[GroupMember, User]]: rows = session.exec( select(GroupMember, User) .join(User, User.id == GroupMember.user_id) .where(GroupMember.group_id == group_id) .order_by(GroupMember.role.desc(), User.nickname) ).all() return [(m, u) for m, u in rows] def add_member_by_nickname(session: Session, group: Group, nickname: str) -> tuple[GroupMember, User]: nickname = (nickname or "").strip() if not nickname: raise ValidationError("Укажите никнейм игрока.") user = session.exec(select(User).where(User.nickname == nickname)).first() if user is None: raise NotFoundError("Игрок с таким ником не найден.") member_count = len( session.exec(select(GroupMember.id).where(GroupMember.group_id == group.id)).all() ) if member_count >= MAX_GROUP_SIZE: raise ConflictError(f"В группе уже максимум участников ({MAX_GROUP_SIZE}).") existing = session.exec( select(GroupMember).where( GroupMember.group_id == group.id, GroupMember.user_id == user.id ) ).first() if existing is not None: raise ConflictError("Игрок уже в группе.") member = GroupMember(group_id=group.id, user_id=user.id, role="member") # type: ignore[arg-type] session.add(member) session.commit() session.refresh(member) return member, user def remove_member(session: Session, group: Group, user_id: int) -> None: member = session.exec( select(GroupMember).where( GroupMember.group_id == group.id, GroupMember.user_id == user_id ) ).first() if member is None: raise NotFoundError("Игрок не состоит в группе.") if member.role == "owner": owners = session.exec( select(GroupMember).where( GroupMember.group_id == group.id, GroupMember.role == "owner" ) ).all() if len(owners) <= 1: raise ForbiddenError("Нельзя удалить последнего владельца группы.") # Сбросить активную группу у тех, для кого она была активной. user = session.get(User, user_id) if user is not None and user.active_group_id == group.id: user.active_group_id = None session.add(user) session.delete(member) session.commit() def change_role(session: Session, group: Group, user_id: int, role: str) -> GroupMember: if role not in ("owner", "member"): raise ValidationError("Недопустимая роль.") member = session.exec( select(GroupMember).where( GroupMember.group_id == group.id, GroupMember.user_id == user_id ) ).first() if member is None: raise NotFoundError("Игрок не состоит в группе.") if member.role == "owner" and role != "owner": # Без этого единственный владелец мог разжаловать сам себя, и группа # оставалась без владельца навсегда: назначить нового уже некому. owners = session.exec( select(GroupMember).where( GroupMember.group_id == group.id, GroupMember.role == "owner" ) ).all() if len(owners) <= 1: raise ForbiddenError("Нельзя снять роль с последнего владельца группы.") member.role = role session.add(member) session.commit() session.refresh(member) return member