from datetime import datetime from sqlalchemy.ext.associationproxy import association_proxy from app import db from .game_state import GameState from .game_player import GamePlayer from .role import Role from .review import Review class Game(db.Model): __tablename__ = 'game' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), index=True, unique=True, nullable=False) #state = db.Column(db.Enum(GameState), server_default=GameState(1).name, nullable=False) hidden = db.Column(db.Boolean, server_default='1', nullable=False) paused = db.Column(db.Boolean, server_default='0', nullable=False) start_time = db.Column(db.DateTime) end_time = db.Column(db.DateTime) players = db.relationship( 'GamePlayer', back_populates='game', cascade="save-update, merge, delete, delete-orphan") users = association_proxy('players', 'user', creator=lambda user: GamePlayer(user=user)) objectives = db.relationship( 'Objective', lazy='select', backref=db.backref('game', lazy='joined'), cascade="save-update, merge, delete, delete-orphan") notifications = db.relationship( 'Notification', lazy='select', backref=db.backref('game', lazy='joined'), cascade="save-update, merge, delete, delete-orphan") def usernames(self): return [user.name for user in self.users] def last_player_locations(self, offset=None): # pylint: disable=not-an-iterable return [location for location in [player.last_location(offset=offset) for player in self.players if player.user.locations] if location is not None] def last_locations(self, players, offset=None): ''' Returns last locations for given players within time boundaries of game Parameters: players (Player or User list): players for whom the last location is returned offset (int): Offset in minutes. Only locations older than this amount of minutes will be returned. ''' locations = [] for player in players: if isinstance(player, GamePlayer): player = player.user location = player.last_location(self, offset=offset) if location: locations.append(location) return locations def bunnies(self): # pylint: disable=not-an-iterable return [gameplayer for gameplayer in self.players if gameplayer.role == Role.bunny] def owned_by(self, user): '''given user is an owner of this game''' # pylint: disable=not-an-iterable return user in [gameplayer.user for gameplayer in self.players if gameplayer.role == Role.owner] def unreviewed_bunny_photos(self): # pylint: disable=not-an-iterable return [pcp for pcps in [player.player_caught_players for player in self.players] for pcp in pcps if pcp.review == Review.none] def is_active(self): return self.get_state() == GameState.active def get_state(self): now = datetime.utcnow() start = (self.start_time or datetime.min).replace(tzinfo=None) if now < start: # Before Game if self.hidden: return GameState.hidden return GameState.published end = (self.end_time or datetime.max).replace(tzinfo=None) if start < now < end: # During Game if self.paused: return GameState.paused return GameState.active if now > end: # After Game if self.hidden: return GameState.hidden return GameState.finished def delete(self): db.session.delete(self) for user in self.users: if not user.last_login: db.session.delete(user) db.session.commit() def remove_player(self, user): # pylint: disable=not-an-iterable if user.role_in_game(self) == Role.owner: if len([player for player in self.players if player.role == Role.owner]) < 2: return "Can't remove only owner from game" self.users.remove(user) if not user.last_login: db.session.delete(user) db.session.commit() return False