Skip to content

Commit

Permalink
Updated timezone and removed the configs in settings.py in favor of H…
Browse files Browse the repository at this point in the history
…unt settings

Fixed team logic for Hunts

renamed a field
  • Loading branch information
JasonLovesDoggo committed Dec 3, 2023
1 parent 8225255 commit a2dcd83
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 70 deletions.
74 changes: 48 additions & 26 deletions .idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions core/migrations/0020_remove_hunt_form_in_ending_text_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Generated by Django 4.1.13 on 2023-12-03 02:29

from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("core", "0019_alter_qrcode_key_hunt_logicpuzzlehint_belongs_to_and_more"),
]

operations = [
migrations.RemoveConstraint(
model_name="hunt",
name="form_in_ending_text",
),
migrations.RenameField(
model_name="hunt",
old_name="team_size",
new_name="max_team_size",
),
migrations.AlterField(
model_name="hunt",
name="early_access_users",
field=models.ManyToManyField(
blank=True,
help_text="Users that can access this hunt before it starts",
related_name="early_access_users",
to=settings.AUTH_USER_MODEL,
),
),
]
55 changes: 32 additions & 23 deletions core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
import random
import secrets

from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.utils import timezone
from django.utils.html import format_html

Expand All @@ -33,8 +34,6 @@ def in_team(self) -> bool:
return True
except AttributeError:
return False


def generate_hint_key():
return secrets.token_urlsafe(48)

Expand Down Expand Up @@ -82,12 +81,12 @@ def codes(cls, team: "Team"):
def code_pks(cls, team: "Team"):
r = random.Random(team.id)
pks = [a["pk"] for a in QrCode.objects.all().values("pk")]
pks = pks[: settings.PATH_LENGTH]
pks = pks[: team.hunt.path_length]
r.shuffle(pks)
if isinstance((pk := settings.ALWAYS_LAST_QR_PK), int):
if isinstance((pk := team.hunt.ending_location_id), int):
i = pks.index(pk) if pk in pks else r.randrange(0, len(pks))
pks = pks[:i] + pks[i + 1 :] + [pk]
if isinstance((pk := settings.ALWAYS_FIRST_QR_PK), int):
if isinstance((pk := team.hunt.starting_location_id), int):
i = pks.index(pk) if pk in pks else r.randrange(0, len(pks))
pks = [pk] + pks[:i] + pks[i + 1 :]
return pks
Expand Down Expand Up @@ -144,8 +143,12 @@ def members(self):

@property
def is_full(self):
return self.members.count() >= settings.MAX_TEAM_SIZE

return self.members.count() >= self.hunt.max_team_size

@property
def is_empty(self):
return self.members.count() == 0

def join(self, user: User):
if user in self.members.all():
return
Expand All @@ -171,7 +174,6 @@ def save(self, *args, **kwargs):
Invite.objects.create(team=self, code=generate_invite_code())
return data


class Invite(models.Model):
invites = models.IntegerField(default=0)
team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name="invites")
Expand All @@ -181,9 +183,9 @@ class Invite(models.Model):
class Hunt(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=64)
start = models.DateTimeField()
end = models.DateTimeField()
team_size = models.PositiveSmallIntegerField(default=4, help_text="Max Team size")
start = models.DateTimeField(blank=False, null=False)
end = models.DateTimeField(blank=False, null=False)
max_team_size = models.PositiveSmallIntegerField(default=4, help_text="Max Team size")
path_length = models.PositiveSmallIntegerField(
default=15,
help_text="Length of the path: The amount of codes each time will have to find before the end.",
Expand All @@ -198,6 +200,7 @@ class Hunt(models.Model):
User,
related_name="early_access_users",
help_text="Users that can access this hunt before it starts",
blank=True,
)
form_url = models.URLField(
help_text="Google form to fill out after the hunt", null=True, blank=True
Expand All @@ -215,7 +218,7 @@ def __str__(self):
@classmethod
def current_hunt(cls):
try:
return cls.objects.get(start__lt=timezone.now(), end__gt=timezone.now())
return cls.objects.get(start__lte=timezone.now(), end__gte=timezone.now())
except cls.DoesNotExist:
return None

Expand All @@ -224,10 +227,10 @@ def clean(self):
Due to how this was designed, it is not possible to have multiple hunts running at the same time.
This method prevents that from happening.
"""
overlapping_events = self.objects.filter(
start_date__lte=self.start, end_date__gte=self.end

overlapping_events = Hunt.objects.filter(
start__lte=self.start, end__gte=self.end # todo fix
).exclude(pk=self.pk)

if overlapping_events.exists():
raise ValidationError(
"This event overlaps with existing events. Please choose a different time. Or Delete the other event."
Expand All @@ -244,13 +247,6 @@ class Meta:
check=~models.Q(starting_location=models.F("ending_location")),
name="start_not_equal_end",
),
# make sure ending_text contains {{ }} for the form
models.CheckConstraint(
check=models.Q(ending_text__contains="{{")
& models.Q(ending_text__contains="}}"),
name="form_in_ending_text",
),
# Ensure there isn't a different hunt running in that timespan
]


Expand Down Expand Up @@ -287,3 +283,16 @@ def get_clue(cls, team: Team) -> str | None:
return hint.hint
except cls.DoesNotExist:
return None


@receiver(pre_save, sender=User)
def remove_empty_teams(sender, instance: User, **kwargs):
obj = User.objects.get(id=instance.id) # get the current object from the database
if obj.team is not None and obj.team != instance.team:
print("switching teams")
# raise ValueError(
# "User cannot be in multiple teams at the same time. Please leave your current team before joining a new one."

if instance.team.members.count() == 0:
print("deleting team")
obj.team.delete()
26 changes: 15 additions & 11 deletions core/views/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,27 @@
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.http import HttpResponseBadRequest
from django.http import HttpResponseBadRequest, HttpRequest
from django.shortcuts import redirect, render
from django.urls import reverse
from django.views.decorators.http import require_http_methods
from django.utils.translation import gettext as _

from ..models import Team, Invite, generate_invite_code
from ..models import Team, Invite, generate_invite_code, Hunt
from ..forms import TeamJoinForm, TeamMakeForm
from .qr import team_required


@login_required
@require_http_methods(["GET", "POST"])
def join(request):
if settings.START < datetime.datetime.now() and not request.user.team is None:
if settings.START < datetime.datetime.now() and request.user.team is not None:
messages.error(
request,
_("Since the hunt has already begun, switching teams is disallowed."),
_(
"Since the hunt has already begun, switching teams is disallowed. "
"If you need to switch teams, please contact an admin."
),
)
return redirect(reverse("index"))
if request.method == "POST":
Expand Down Expand Up @@ -67,11 +70,11 @@ def make(request):
if request.method == "POST":
form = TeamMakeForm(request.POST)
if form.is_valid():
form.save()
team = request.user.team = form.instance
raw: Team = form.save(commit=False)
raw.hunt = Hunt.current_hunt()
raw.save()
request.user.team = raw
request.user.save()
invite = Invite(team=team, code=generate_invite_code())
invite.save()
messages.success(
request,
_("Made team %(team_name)s")
Expand All @@ -84,9 +87,9 @@ def make(request):


@login_required
def solo(q):
q.user.team = (team := Team(solo=True))
team.save()
def solo(q: HttpRequest):
team = Team.objects.create(solo=True, hunt=Hunt.current_hunt(), name=f"{q.user.username}'s Solo Team")
q.user.team = team
q.user.save()
return redirect(reverse("index"))

Expand All @@ -96,4 +99,5 @@ def solo(q):
@team_required
def invite(q):
invites = Invite.objects.filter(team=q.user.team).values_list("code", flat=True)
print(invites) # todo fix
return render(q, "core/team_invite.html", context=dict(invites=invites))
12 changes: 2 additions & 10 deletions wlmac-scavenger/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@

LANGUAGE_CODE = "en"

TIME_ZONE = "UTC"
TIME_ZONE = "America/Toronto"

USE_I18N = True

Expand All @@ -113,15 +113,7 @@
scope="me_meta internal",
)

MAX_TEAM_SIZE: Final[int] = 4 # max # of people per team
ALWAYS_LAST_QR_PK: Final[
int
] = 1 # the pk of the last qr code (that all teams must go to last)
ALWAYS_FIRST_QR_PK: Final[
int
] = 2 # the pk of the first qr code (that all teams must go to first)
HINTS_GROUP_PK: Final[int] = 1 # the pk of the hints group (defined in init.py)
PATH_LENGTH: Final[int] = 15 # how many locations each team must ind
HINTS_GROUP_PK: Final[int] = 1 # the pk of the hints group (defined in commands/init.py)

try:
with open(os.path.join(os.path.dirname(__file__), "local_settings.py")) as f:
Expand Down

0 comments on commit a2dcd83

Please sign in to comment.