Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added /current page #5

Merged
merged 8 commits into from
Dec 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion scavenger2022/core/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _l
from django.urls import reverse
from .models import *
from .forms import *


Expand All @@ -19,6 +18,18 @@ class InviteInLine(admin.StackedInline):
readonly_fields = ("invites",)


class LogicPuzzleAdmin(admin.ModelAdmin):
list_display = (
"qr_index",
"hint",
)
search_fields = (
"hint",
"qr_index",
)
ordering = ("qr_index",)


class TeamAdmin(admin.ModelAdmin):
readonly_fields = ("current_qr_i", "path")
inlines = [
Expand Down Expand Up @@ -70,3 +81,4 @@ class UserAdmin(UserAdmin_):
admin.site.register(User, UserAdmin)
admin.site.register(Team, TeamAdmin)
admin.site.register(QrCode, QrCodeAdmin)
admin.site.register(LogicPuzzleHint, LogicPuzzleAdmin)
14 changes: 7 additions & 7 deletions scavenger2022/core/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
import datetime


def cutoff(request):
def start(request):
return dict(
CUTOFF=(cutoff := settings.CUTOFF),
CUTOFF_BEFORE=cutoff > datetime.datetime.utcnow(),
CUTOFF_UNTIL=cutoff - datetime.datetime.utcnow(),
CUTON=(cuton := settings.CUTON),
CUTON_BEFORE=cuton > datetime.datetime.utcnow(),
CUTON_UNTIL=cuton - datetime.datetime.utcnow(),
START=(start := settings.START),
START_BEFORE=start > datetime.datetime.utcnow(),
START_UNTIL=start - datetime.datetime.utcnow(),
END=(end := settings.END),
END_BEFORE=end > datetime.datetime.utcnow(),
END_UNTIL=end - datetime.datetime.utcnow(),
)
3 changes: 1 addition & 2 deletions scavenger2022/core/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ class Meta:
"members",
"is_active",
"is_open",
"completed_qr_codes",
"current_qr_code",
"solo",
"current_qr_i",
)


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Generated by Django 4.1.3 on 2022-12-12 22:57

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("core", "0012_remove_user_chosen"),
]

operations = [
migrations.CreateModel(
name="LogicPuzzleHint",
fields=[
("id", models.AutoField(primary_key=True, serialize=False)),
(
"hint",
models.TextField(
help_text="Hint for the logic puzzle", max_length=1024
),
),
("notes", models.TextField(blank=True, help_text="Internal notes")),
(
"qr_index",
models.IntegerField(
help_text="The index of the QR code that this hint is for, that is everyone on their nth QR code will get same same hint (starting from 1)",
unique=True,
),
),
],
),
migrations.AlterField(
model_name="qrcode",
name="notes",
field=models.TextField(blank=True, help_text="Internal notes"),
),
]
13 changes: 13 additions & 0 deletions scavenger2022/core/migrations/0014_merge_20221212_1857.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Generated by Django 4.1.3 on 2022-12-12 23:57

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("core", "0013_logicpuzzlehint_alter_qrcode_notes"),
("core", "0013_remove_team_completed_qr_codes_and_more"),
]

operations = []
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 4.1.3 on 2022-12-13 00:16

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("core", "0014_merge_20221212_1857"),
]

operations = [
migrations.AlterModelOptions(
name="hint",
options={"permissions": [("view_before_start", "Play game before start")]},
),
migrations.AlterField(
model_name="invite",
name="team",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="invites",
to="core.team",
),
),
]
68 changes: 57 additions & 11 deletions scavenger2022/core/models.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import random
import secrets

from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.conf import settings


class User(AbstractUser):
Expand All @@ -13,6 +13,14 @@ class User(AbstractUser):
"Team", related_name="members", on_delete=models.CASCADE, blank=True, null=True
)

@property
def in_team(self) -> bool:
try:
_ = self.team.solo
return True
except AttributeError:
return False


def generate_hint_key():
return secrets.token_urlsafe(48)
Expand All @@ -28,9 +36,7 @@ class QrCode(models.Model):
max_length=1024,
help_text="Location of the QR code. Be specific—it's internal",
)
notes = models.TextField(
help_text="Internal notes",
)
notes = models.TextField(help_text="Internal notes", blank=True)
key = models.CharField(max_length=64, unique=True, default=generate_hint_key)

def __str__(self):
Expand Down Expand Up @@ -72,10 +78,12 @@ def __str__(self):
return self.hint

class Meta:
permissions = [("view_before_cutoff", "Play game before cutoff")]
permissions = [("view_before_start", "Play game before start")]


class Team(models.Model):
"""note, a user can currently be in multiple teams, in the future limit this to one per (class: Hunt)"""

# owner = models.ForeignKey(User, on_delete=models.PROTECT, related_name="teams_ownership") potentially add this later
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=64, unique=True, null=True)
Expand All @@ -94,10 +102,8 @@ def update_current_qr_i(self, i: int):

@property
def members(self):
return User.objects.filter(team=self)

def is_solo(self):
return self.members.count() == 1
"""Returns all members of the team, it's a related manager so to convert to queryset use .all() or filter it."""
return User.objects.filter(team=str(self.id))

def is_full(self):
return self.members.count() >= settings.MAX_TEAM_SIZE
Expand All @@ -107,12 +113,17 @@ def join(self, user: User):
return
if self.is_full():
raise IndexError("Team is full")
self.members.add(user)
self.save()
user.team = self
user.save()

def invites(self):
return Invite.objects.filter(team=self)

def get_qr_nth(self):
"""Get the total amount of qr codes the team has completed"""
print(int(self.current_qr_i) + 1) # todo remove. this is just for debugging
return int(self.current_qr_i) + 1

def __str__(self):
return str(self.name)

Expand All @@ -125,3 +136,38 @@ class Invite(models.Model):
invites = models.IntegerField(default=0)
team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name="invites")
code = models.CharField(max_length=32, unique=True)


# class Hunt(models.Model):
# id = models.AutoField(primary_key=True)
# name = models.CharField(max_length=64)
# start = models.DateTimeField()
# end = models.DateTimeField()
# is_active = models.BooleanField(default=False)
# team_size = models.IntegerField(default=4, help_text="Max Team size")
# final_qr_id = models.IntegerField(null=True, blank=True)
#
# def __str__(self):
# return self.name


class LogicPuzzleHint(models.Model):
id = models.AutoField(primary_key=True)
hint = models.TextField(
max_length=1024,
help_text="Hint for the logic puzzle",
)
notes = models.TextField(help_text="Internal notes", blank=True)
qr_index = models.IntegerField(
help_text="The index of the QR code that this hint is for, that is everyone on their nth QR code will get same same hint (starting from 1)",
unique=True,
)

# belongs_to = models.ForeignKey(Hunt, related_name="logic_puzzle_hunt", on_delete=models.CASCADE)

def __str__(self):
return str(self.hint)

@classmethod
def get_hint(cls, team: Team):
return cls.objects.get(qr_index=team.get_qr_nth()).hint
2 changes: 1 addition & 1 deletion scavenger2022/core/static/core/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ body > nav {
padding: 4px;
}

#cutoff-header {
#start-header {
text-align: center;
}

Expand Down
52 changes: 26 additions & 26 deletions scavenger2022/core/templates/core/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Zen+Kaku+Gothic+New:wght@300;400&display=swap" rel="stylesheet">
{% if CUTOFF_BEFORE or CUTON_BEFORE %}
{% if START_BEFORE or END_BEFORE %}
<script type="module">
const e = document.getElementById("cutoff")
const eText = document.getElementById("cutoff-text")
const cutoffText = '{% translate "Starts in:" %}'
const cutonText = '{% translate "Ends in:" %}'
const cutoff = {{ CUTOFF.timestamp }} * 1000
const cuton = {{ CUTON.timestamp }} * 1000
const e = document.getElementById("start")
const eText = document.getElementById("start-text")
const startText = '{% translate "Starts in:" %}'
const endText = '{% translate "Ends in:" %}'
const start = {{ START.timestamp }} * 1000
const end = {{ END.timestamp }} * 1000
const intervalId = setInterval(() => {
let cutoff = true
let d = (cutoff - Date.now()) / 1000
let start = true
let d = (start - Date.now()) / 1000
if (d < 0) {
d = (cuton - Date.now()) / 1000
cutoff = false
d = (end - Date.now()) / 1000
start = false
}
const hour = Math.round(d / 3600 % 24) - 1
const minute = Math.round(d / 60 % 60)
Expand All @@ -35,8 +35,8 @@
s += ('0' + hour).slice(-2) + ':'
s += ('0' + minute).slice(-2) + ':'
s += ('0' + second).slice(-2)
e.innerText = s
eText.innerText = cutoff ? cutoffText : cutonText
e.innerText = s
eText.innerText = start ? startText : endText
}, 1000)
</script>
{% endif %}
Expand Down Expand Up @@ -77,37 +77,37 @@
<img src="https://maclyonsden.com/static/core/img/themes/logos/dark-transparent.png" style="height: 27px; display: inline; vertical-align: middle;" alt="Metropolis logo" />
Metropolis
</a>


<a href="https://doodle.maclyonsden.com">Doodles</a>

<span class="this">
Scavenger Hunt (2022)
</span>
</div>
</nav>
</div>
<!-- GENDO END CommonHeader -->
{% if CUTOFF_BEFORE %}
<nav id="cutoff-header">
<span id="cutoff-text">{% translate "Starts in: " %}</span>
<span id="cutoff">
{{ CUTOFF_UNTIL|format_time }}
{% if START_BEFORE %}
<nav id="start-header">
<span id="start-text">{% translate "Starts in: " %}</span>
<span id="start">
{{ START_UNTIL|format_time }}
</span>
</nav>
{% else %}
<nav id="cutoff-header">
<span id="cutoff-text">{% translate "Ends in: " %}</span>
<span id="cutoff">
{{ CUTON_UNTIL|format_time }}
<nav id="start-header">
<span id="start-text">{% translate "Ends in: " %}</span>
<span id="start">
{{ END_UNTIL|format_time }}
</span>
</nav>
{% endif %}
<nav id="main-header">
{% if request.user.is_staff %}
<a href="/admin">{% translate "Admin" %}</a>
{% endif %}
{% if request.user.team is not None %}
{% if request.user.in_team %}
{% if not request.user.team.solo %}
Team: {{ request.user.team.name }}
{% else %}
Expand Down
13 changes: 7 additions & 6 deletions scavenger2022/core/templates/core/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,20 @@
{% if not request.user.is_authenticated %}
Please <a href="{% url 'oauth_login' %}">login</a>.
{% else %}
<ul>
{% if request.user.in_team %}
Go to your <a href="{% url 'qr_first' %}">first hint</a>.
{% if not request.user.team.solo %}
Or <a href="{% url 'team_recruit' %}">invite team members</a>.
{% endif %}
{% else %}
<ul>
<li>Join a team: either scan your team leader's QR code or click the link</li>
<li><a href="{% url 'team_new' %}">{% translate "Make a team" %}</a></li>
<li><form action="{% url 'team_solo' %}" method="post">
{% csrf_token %}
<input class="fakea" type="submit" value="{% translate 'Go solo '%}" />
</form></li>
</ul>
{% if request.user.team is not None %}
Go to your <a href="{% url 'qr_first' %}">first hint</a>.
{% if not request.user.team.solo %}
Or <a href="{% url 'team_recruit' %}">invite team members</a>.
{% endif %}
{% endif %}
{% endif %}
{% endblock %}
Loading