class Player(models.Model): room = models.ForeignKey(Room, on_delete=models.CASCADE) uuid = models.UUIDField(default=uuid4, editable=False) name = models.CharField(max_length=50) color_value = models.IntegerField("Color", default=Color.player_default().value, choices=Color.player_choices()) created_date = models.DateTimeField("Creation Time", default=timezone.now) is_spectator = models.BooleanField("Is Spectator", default=False) @staticmethod def get_for_encoded_uuid(encoded_player_uuid): decoded_uuid = decode_uuid(encoded_player_uuid) return Player.objects.get(uuid=decoded_uuid) def __str__(self): return self.name def __repr__(self): return "<Player: id: {!r}, uuid: {!r}, name: {!r}>".format( self.id, self.encoded_uuid, self.name) @property def encoded_uuid(self): return encode_uuid(self.uuid) @property def color(self): if self.is_spectator: return Color.blank return Color.for_value(self.color_value) @property def connected(self): last_connection_event = ConnectionEvent.objects.filter( player=self).order_by("timestamp").last() return not last_connection_event or last_connection_event.event_type == ConnectionEventType.connected def update_color(self, color): with transaction.atomic(): color_event = ColorEvent(player=self, player_color_value=self.color.value, color_value=color.value) color_event.save() self.color_value = color.value self.save() return color_event def to_json(self): return { "uuid": self.encoded_uuid, "name": self.name, "color": self.color.name, "is_spectator": self.is_spectator }
def select_color(request): data = parse_body_json_or_400(request, required_keys=["room", "color"]) room = Room.get_for_encoded_uuid_or_404(data["room"]) player = _get_session_player(request.session, room) color = Color.for_name(data["color"]) color_event = player.update_color(color) publish_color_event(color_event) return HttpResponse("Received data: ", str(data))
class ColorEvent(Event): color_value = models.IntegerField(choices=Color.player_choices()) @property def color(self): return Color.for_value(self.color_value) def to_json(self): return { "type": "color", "player": self.player.to_json(), "player_color": self.player_color.name, "color": self.color.name, "timestamp": self.json_timestamp }
def goal_selected(request): data = parse_body_json_or_400(request, required_keys=["room", "slot", "color", "remove_color"]) room = Room.get_for_encoded_uuid_or_404(data["room"]) player = _get_session_player(request.session, room) game = room.current_game slot = int(data["slot"]) color = Color.for_name(data["color"]) remove_color = data["remove_color"] goal_event = game.update_goal(player, slot, color, remove_color) if not goal_event: return HttpResponseBadRequest("Blocked by Lockout") publish_goal_event(goal_event) return HttpResponse("Recieved data: " + str(data))
class GoalEvent(Event): square = models.ForeignKey("bingosync.Square", on_delete=models.CASCADE) color_value = models.IntegerField(choices=Color.goal_choices()) remove_color = models.BooleanField(default=False) @property def color(self): return Color.for_value(self.color_value) def to_json(self): return { "type": "goal", "player": self.player.to_json(), "square": self.square.to_json(), "player_color": self.player_color.name, "color": self.color.name, "remove": self.remove_color, "timestamp": self.json_timestamp }
def color(self): if self.is_spectator: return Color.blank return Color.for_value(self.color_value)
def player_color(self): return Color.for_value(self.player_color_value)
def color(self): return Color.for_value(self.color_value)
class Event(models.Model): player = models.ForeignKey("bingosync.Player", on_delete=models.CASCADE) timestamp = models.DateTimeField("Sent", default=timezone.now) player_color_value = models.IntegerField(choices=Color.player_choices()) @property def player_color(self): return Color.for_value(self.player_color_value) @property def json_timestamp(self): return self.timestamp.replace().timestamp() @staticmethod def event_classes(): return [ ChatEvent, GoalEvent, ColorEvent, RevealedEvent, ConnectionEvent, NewCardEvent ] @staticmethod def get_all_for_room(room): all_events = [] for event_class in Event.event_classes(): all_events.extend(event_class.objects.filter(player__room=room)) return sorted(all_events, key=lambda event: event.timestamp) @staticmethod def get_all_recent_for_room(room): recent_events = [] total_events = 0 for event_class in Event.event_classes(): total_events += event_class.objects.filter( player__room=room).count() recent_events.extend( event_class.objects.filter(player__room=room).filter( timestamp__gte=datetime.datetime.now( datetime.timezone.utc) - datetime.timedelta(hours=24))) all_included = total_events == len(recent_events) recent_events = sorted(recent_events, key=lambda event: event.timestamp) return {'events': recent_events, 'all_included': all_included} @staticmethod def get_latest_for_room(room): latest_events = [] for event_class in Event.event_classes(): try: latest_event = event_class.objects.filter( player__room=room).latest() latest_events.append(latest_event) except event_class.DoesNotExist: pass if latest_events: return sorted(latest_events, key=lambda event: event.timestamp)[-1] else: return None class Meta: abstract = True get_latest_by = "timestamp"