mirror of
https://github.com/tjsga/scavenger-hunt-2021.git
synced 2025-04-03 19:30:16 -04:00
feat: finished frontend, added detail page, and categories
This commit is contained in:
parent
8eddee53fb
commit
e446db893e
1
Pipfile
1
Pipfile
|
@ -9,3 +9,4 @@ psycopg2-binary = "~=2.8.6"
|
|||
social-auth-app-django = "~=4.0.0"
|
||||
gunicorn = "*"
|
||||
whitenoise = "*"
|
||||
django-ckeditor = "*"
|
96
Pipfile.lock
generated
96
Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "b4008672fb38a3e89baf1655aa6b39685d638b0b7f6012ef5fb8da7b48ed33c2"
|
||||
"sha256": "91d9b3fd6ebf46b5342b7ad4b05cbcb362e289f9ec1abf7e931ab806a9751afe"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
|
@ -19,7 +19,6 @@
|
|||
"sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9",
|
||||
"sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.4.1"
|
||||
},
|
||||
"certifi": {
|
||||
|
@ -81,47 +80,72 @@
|
|||
},
|
||||
"charset-normalizer": {
|
||||
"hashes": [
|
||||
"sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b",
|
||||
"sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"
|
||||
"sha256:5d209c0a931f215cee683b6445e2d77677e7e75e159f78def0db09d68fafcaa6",
|
||||
"sha256:5ec46d183433dcbd0ab716f2d7f29d8dee50505b3fdb40c6b985c7c4f5a3591f"
|
||||
],
|
||||
"markers": "python_version >= '3'",
|
||||
"version": "==2.0.4"
|
||||
"version": "==2.0.6"
|
||||
},
|
||||
"cryptography": {
|
||||
"hashes": [
|
||||
"sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d",
|
||||
"sha256:1e056c28420c072c5e3cb36e2b23ee55e260cb04eee08f702e0edfec3fb51959",
|
||||
"sha256:240f5c21aef0b73f40bb9f78d2caff73186700bf1bc6b94285699aff98cc16c6",
|
||||
"sha256:26965837447f9c82f1855e0bc8bc4fb910240b6e0d16a664bb722df3b5b06873",
|
||||
"sha256:37340614f8a5d2fb9aeea67fd159bfe4f5f4ed535b1090ce8ec428b2f15a11f2",
|
||||
"sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713",
|
||||
"sha256:3d8427734c781ea5f1b41d6589c293089704d4759e34597dce91014ac125aad1",
|
||||
"sha256:7ec5d3b029f5fa2b179325908b9cd93db28ab7b85bb6c1db56b10e0b54235177",
|
||||
"sha256:8e56e16617872b0957d1c9742a3f94b43533447fd78321514abbe7db216aa250",
|
||||
"sha256:b01fd6f2737816cb1e08ed4807ae194404790eac7ad030b34f2ce72b332f5586",
|
||||
"sha256:bf40af59ca2465b24e54f671b2de2c59257ddc4f7e5706dbd6930e26823668d3",
|
||||
"sha256:de4e5f7f68220d92b7637fc99847475b59154b7a1b3868fb7385337af54ac9ca",
|
||||
"sha256:eb8cc2afe8b05acbd84a43905832ec78e7b3873fb124ca190f574dca7389a87d",
|
||||
"sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9"
|
||||
"sha256:0a7dcbcd3f1913f664aca35d47c1331fce738d44ec34b7be8b9d332151b0b01e",
|
||||
"sha256:1eb7bb0df6f6f583dd8e054689def236255161ebbcf62b226454ab9ec663746b",
|
||||
"sha256:21ca464b3a4b8d8e86ba0ee5045e103a1fcfac3b39319727bc0fc58c09c6aff7",
|
||||
"sha256:34dae04a0dce5730d8eb7894eab617d8a70d0c97da76b905de9efb7128ad7085",
|
||||
"sha256:3520667fda779eb788ea00080124875be18f2d8f0848ec00733c0ec3bb8219fc",
|
||||
"sha256:3fa3a7ccf96e826affdf1a0a9432be74dc73423125c8f96a909e3835a5ef194a",
|
||||
"sha256:5b0fbfae7ff7febdb74b574055c7466da334a5371f253732d7e2e7525d570498",
|
||||
"sha256:695104a9223a7239d155d7627ad912953b540929ef97ae0c34c7b8bf30857e89",
|
||||
"sha256:8695456444f277af73a4877db9fc979849cd3ee74c198d04fc0776ebc3db52b9",
|
||||
"sha256:94cc5ed4ceaefcbe5bf38c8fba6a21fc1d365bb8fb826ea1688e3370b2e24a1c",
|
||||
"sha256:94fff993ee9bc1b2440d3b7243d488c6a3d9724cc2b09cdb297f6a886d040ef7",
|
||||
"sha256:9965c46c674ba8cc572bc09a03f4c649292ee73e1b683adb1ce81e82e9a6a0fb",
|
||||
"sha256:a00cf305f07b26c351d8d4e1af84ad7501eca8a342dedf24a7acb0e7b7406e14",
|
||||
"sha256:a305600e7a6b7b855cd798e00278161b681ad6e9b7eca94c721d5f588ab212af",
|
||||
"sha256:cd65b60cfe004790c795cc35f272e41a3df4631e2fb6b35aa7ac6ef2859d554e",
|
||||
"sha256:d2a6e5ef66503da51d2110edf6c403dc6b494cc0082f85db12f54e9c5d4c3ec5",
|
||||
"sha256:d9ec0e67a14f9d1d48dd87a2531009a9b251c02ea42851c060b25c782516ff06",
|
||||
"sha256:f44d141b8c4ea5eb4dbc9b3ad992d45580c1d22bf5e24363f2fbf50c2d7ae8a7"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.4.7"
|
||||
"version": "==3.4.8"
|
||||
},
|
||||
"defusedxml": {
|
||||
"hashes": [
|
||||
"sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69",
|
||||
"sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==0.7.1"
|
||||
},
|
||||
"django": {
|
||||
"hashes": [
|
||||
"sha256:7f92413529aa0e291f3be78ab19be31aefb1e1c9a52cd59e130f505f27a51f13",
|
||||
"sha256:f27f8544c9d4c383bbe007c57e3235918e258364577373d4920e9162837be022"
|
||||
"sha256:95b318319d6997bac3595517101ad9cc83fe5672ac498ba48d1a410f47afecd2",
|
||||
"sha256:e93c93565005b37ddebf2396b4dc4b6913c1838baa82efdfb79acedd5816c240"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.2.6"
|
||||
"version": "==3.2.7"
|
||||
},
|
||||
"django-ckeditor": {
|
||||
"hashes": [
|
||||
"sha256:346b26b9d60dc8a88524d0eaaf406f4e91a4b3c22d208ae87aa032bf500b251c",
|
||||
"sha256:f0d108f67a81a04e26d8de11255fe314f51026eaf8eb0534a807512ae3c21620"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==6.1.0"
|
||||
},
|
||||
"django-js-asset": {
|
||||
"hashes": [
|
||||
"sha256:8ec12017f26eec524cab436c64ae73033368a372970af4cf42d9354fcb166bdd",
|
||||
"sha256:c163ae80d2e0b22d8fb598047cd0dcef31f81830e127cfecae278ad574167260"
|
||||
],
|
||||
"version": "==1.2.2"
|
||||
},
|
||||
"gunicorn": {
|
||||
"hashes": [
|
||||
"sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e",
|
||||
"sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==20.1.0"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
|
@ -136,7 +160,6 @@
|
|||
"sha256:42bf6354c2ed8c6acb54d971fce6f88193d97297e18602a3a886603f9d7730cc",
|
||||
"sha256:8f0215fcc533dd8dd1bee6f4c412d4f0cd7297307d43ac61666389e3bc3198a3"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.1.1"
|
||||
},
|
||||
"psycopg2-binary": {
|
||||
|
@ -185,7 +208,6 @@
|
|||
"sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
|
||||
"sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.20"
|
||||
},
|
||||
"pyjwt": {
|
||||
|
@ -193,7 +215,6 @@
|
|||
"sha256:934d73fbba91b0483d3857d1aff50e96b2a892384ee2c17417ed3203f173fca1",
|
||||
"sha256:fba44e7898bbca160a2b2b501f492824fc8382485d3a6f11ba5d0c1937ce6130"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.1.0"
|
||||
},
|
||||
"python3-openid": {
|
||||
|
@ -215,7 +236,6 @@
|
|||
"sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24",
|
||||
"sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==2.26.0"
|
||||
},
|
||||
"requests-oauthlib": {
|
||||
|
@ -231,7 +251,6 @@
|
|||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"social-auth-app-django": {
|
||||
|
@ -248,24 +267,29 @@
|
|||
"sha256:5ab43b3b15dce5f059db69cc3082c216574739f0edbc98629c8c6e8769c67eb4",
|
||||
"sha256:983b53167ac56e7ba4909db555602a6e7a98c97ca47183bb222eb85ba627bf2b"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==4.1.0"
|
||||
},
|
||||
"sqlparse": {
|
||||
"hashes": [
|
||||
"sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0",
|
||||
"sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"
|
||||
"sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae",
|
||||
"sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.4.1"
|
||||
"version": "==0.4.2"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4",
|
||||
"sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
|
||||
"version": "==1.26.6"
|
||||
},
|
||||
"whitenoise": {
|
||||
"hashes": [
|
||||
"sha256:d234b871b52271ae7ed6d9da47ffe857c76568f11dd30e28e18c5869dbd11e12",
|
||||
"sha256:d963ef25639d1417e8a247be36e6aedd8c7c6f0a08adcb5a89146980a96b577c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.3.0"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import Challenge, Class
|
||||
from .models import Challenge, Class, Category
|
||||
|
||||
admin.site.register(Category)
|
||||
admin.site.register(Challenge)
|
||||
admin.site.register(Class)
|
||||
|
|
23
hunt/apps/main/migrations/0003_category.py
Normal file
23
hunt/apps/main/migrations/0003_category.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 3.2.7 on 2021-09-20 08:01
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('main', '0002_alter_class_challenges_completed'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Category',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=200)),
|
||||
('slug', models.SlugField(max_length=200)),
|
||||
('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='challenges', to='main.category')),
|
||||
],
|
||||
),
|
||||
]
|
23
hunt/apps/main/migrations/0004_auto_20210920_0804.py
Normal file
23
hunt/apps/main/migrations/0004_auto_20210920_0804.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 3.2.7 on 2021-09-20 08:04
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('main', '0003_category'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='category',
|
||||
name='category',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='challenge',
|
||||
name='category',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='challenges', to='main.category'),
|
||||
),
|
||||
]
|
25
hunt/apps/main/migrations/0005_auto_20210920_0818.py
Normal file
25
hunt/apps/main/migrations/0005_auto_20210920_0818.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 3.2.7 on 2021-09-20 08:18
|
||||
|
||||
import ckeditor.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('main', '0004_auto_20210920_0804'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='challenge',
|
||||
name='short_description',
|
||||
field=models.CharField(default='', max_length=500),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='challenge',
|
||||
name='description',
|
||||
field=ckeditor.fields.RichTextField(),
|
||||
),
|
||||
]
|
19
hunt/apps/main/migrations/0006_category_category.py
Normal file
19
hunt/apps/main/migrations/0006_category_category.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 3.2.7 on 2021-09-20 08:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('main', '0005_auto_20210920_0818'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='category',
|
||||
name='category',
|
||||
field=models.CharField(default='', max_length=200),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
18
hunt/apps/main/migrations/0007_challenge_available.py
Normal file
18
hunt/apps/main/migrations/0007_challenge_available.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.7 on 2021-09-20 08:36
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('main', '0006_category_category'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='challenge',
|
||||
name='available',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.7 on 2021-09-20 08:39
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('main', '0007_challenge_available'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='challenge',
|
||||
old_name='available',
|
||||
new_name='unblocked',
|
||||
),
|
||||
]
|
|
@ -1,15 +1,26 @@
|
|||
from django.db import models
|
||||
from django.db.models.fields.related import ManyToManyField
|
||||
from ckeditor.fields import RichTextField
|
||||
|
||||
class Category(models.Model):
|
||||
id = models.AutoField(primary_key=True, null=False, blank=False)
|
||||
name = models.CharField(max_length=200, null=False, blank=False)
|
||||
category = models.CharField(max_length=200, null=False, blank=False)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Challenge(models.Model):
|
||||
id = models.AutoField(primary_key=True, null=False, blank=False)
|
||||
name = models.CharField(max_length=100, null=False, blank=False)
|
||||
description = models.CharField(max_length=500, null=False, blank=False)
|
||||
short_description = models.CharField(max_length=500, null=False, blank=False)
|
||||
description = RichTextField(null=False, blank=False)
|
||||
flag = models.CharField(max_length=50, null=False, blank=False)
|
||||
points = models.IntegerField(null=False, blank=False)
|
||||
exclusive = models.BooleanField(default=False)
|
||||
locked = models.BooleanField(default=False)
|
||||
unblocked = models.BooleanField(default=False)
|
||||
category = models.ForeignKey(Category, null=True, blank=True, related_name='challenges', on_delete=models.SET_NULL)
|
||||
|
||||
def __str__(self):
|
||||
return "{} ({})".format(self.name, self.id)
|
||||
|
@ -30,5 +41,4 @@ class Class(models.Model):
|
|||
sum = 0
|
||||
for c in self.challenges_completed.all():
|
||||
sum += c.points
|
||||
return sum
|
||||
|
||||
return sum
|
|
@ -8,4 +8,5 @@ urlpatterns = [
|
|||
path("", views.index, name="index"),
|
||||
path("overview/", views.overview, name="overview"),
|
||||
path("validate/", views.validate_flag, name="validate_flag"),
|
||||
path("challenge/<int:challenge_id>", views.challenge_detail, name="challenge_detail")
|
||||
]
|
|
@ -4,12 +4,12 @@ from django.http.response import JsonResponse
|
|||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse
|
||||
|
||||
from .models import Challenge, Class
|
||||
from .models import Challenge, Class, Category
|
||||
|
||||
|
||||
@login_required
|
||||
def index(request):
|
||||
if request.user.is_participant():
|
||||
if request.user.is_participant() or request.user.is_staff:
|
||||
"""
|
||||
Challenges fall into one of three statuses with respect to the user:
|
||||
- available (user can complete)
|
||||
|
@ -17,15 +17,18 @@ def index(request):
|
|||
- locked (can only be completed by one class and has been completed)
|
||||
"""
|
||||
challenges_completed_by_class = set(Class.objects.get(year=str(request.user.graduation_year)).challenges_completed.all())
|
||||
challenges_dict = dict()
|
||||
for c in Challenge.objects.all():
|
||||
if c in challenges_completed_by_class:
|
||||
challenges_dict[c.id] = [c, "completed"]
|
||||
elif c.locked:
|
||||
challenges_dict[c.id] = [c, "locked"]
|
||||
else:
|
||||
challenges_dict[c.id] = [c, "available"]
|
||||
return render(request, 'main/index.html', context={"challenges_dict": challenges_dict})
|
||||
categories_dict = dict()
|
||||
for category in Category.objects.all():
|
||||
challenges_dict = dict()
|
||||
for c in category.challenges.all():
|
||||
if c in challenges_completed_by_class:
|
||||
challenges_dict[c.id] = [c, "completed"]
|
||||
elif c.locked:
|
||||
challenges_dict[c.id] = [c, "locked"]
|
||||
else:
|
||||
challenges_dict[c.id] = [c, "available"]
|
||||
categories_dict[category.id] = [category, challenges_dict]
|
||||
return render(request, "main/index.html", context={"categories": categories_dict})
|
||||
else:
|
||||
return redirect(reverse("main:overview"))
|
||||
|
||||
|
@ -34,9 +37,26 @@ def overview(request):
|
|||
data = sorted([(c.year, c.get_points()) for c in Class.objects.all()])
|
||||
return render(request, 'main/overview.html', context={'data': data})
|
||||
|
||||
@login_required
|
||||
def challenge_detail(request, challenge_id):
|
||||
if request.user.is_participant() or request.user.is_staff:
|
||||
c = get_object_or_404(Challenge, pk=challenge_id)
|
||||
challenges_completed_by_class = set(Class.objects.get(year=str(request.user.graduation_year)).challenges_completed.all())
|
||||
if not c.unblocked:
|
||||
status = 'blocked'
|
||||
elif c in challenges_completed_by_class:
|
||||
status = 'completed'
|
||||
elif c.locked:
|
||||
status = 'locked'
|
||||
else:
|
||||
status = 'available'
|
||||
return render(request, 'main/detail.html', context={'status': status, 'challenge': c})
|
||||
else:
|
||||
return redirect(reverse("main:overview"))
|
||||
|
||||
@login_required
|
||||
def validate_flag(request):
|
||||
if request.is_ajax() and request.user.is_participant():
|
||||
if request.is_ajax() and (request.user.is_participant() or request.user.is_staff):
|
||||
challenge = get_object_or_404(Challenge, id=int(request.POST.get("challenge_id")))
|
||||
flag = request.POST.get("flag")
|
||||
if flag == challenge.flag:
|
||||
|
@ -53,4 +73,5 @@ def validate_flag(request):
|
|||
response = {"result": "failure"}
|
||||
return JsonResponse(response)
|
||||
else:
|
||||
return PermissionDenied
|
||||
return PermissionDenied
|
||||
|
|
@ -38,6 +38,7 @@ INSTALLED_APPS = [
|
|||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'social_django',
|
||||
'ckeditor',
|
||||
'hunt.apps.main',
|
||||
'hunt.apps.auth',
|
||||
'hunt.apps.users',
|
||||
|
|
11
hunt/static/css/detail.css
Normal file
11
hunt/static/css/detail.css
Normal file
|
@ -0,0 +1,11 @@
|
|||
.available {
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
.completed {
|
||||
background-color: lightgreen;
|
||||
}
|
||||
|
||||
.locked {
|
||||
background-color: lightsalmon;
|
||||
}
|
|
@ -21,4 +21,14 @@
|
|||
|
||||
.left-div {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
|
@ -31,10 +31,13 @@
|
|||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>cd
|
||||
</div>
|
||||
<script src='https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js' integrity='sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1' crossorigin='anonymous'></script>
|
||||
<script src='https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js' integrity='sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM' crossorigin='anonymous'></script>
|
||||
{% block main %}{% endblock %}
|
||||
<div class="footer text-right">
|
||||
This application was developed by Lauren Delwiche (2022) and Rushil Umaretiya (2023).
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
55
hunt/templates/main/detail.html
Normal file
55
hunt/templates/main/detail.html
Normal file
|
@ -0,0 +1,55 @@
|
|||
{% extends 'base_with_nav.html' %}
|
||||
|
||||
{% load static %}
|
||||
|
||||
{% block head %}
|
||||
<link rel='stylesheet' href="{% static 'css/detail.css' %}">
|
||||
<script>
|
||||
function checkFlag(challenge_id) {
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url: "{% url 'main:validate_flag' %}",
|
||||
data: {
|
||||
csrfmiddlewaretoken: '{{ csrf_token }}',
|
||||
dataType: 'json',
|
||||
challenge_id: challenge_id,
|
||||
flag: $("#" + challenge_id).val(),
|
||||
},
|
||||
success: function(data) {
|
||||
if (data.result == "success") {
|
||||
$("#box" + challenge_id).removeClass("available").addClass("completed");
|
||||
} else {
|
||||
$("#" + challenge_id).css("background-color", "red");
|
||||
}
|
||||
},
|
||||
failure: function() {
|
||||
$("#" + challenge_id).css("background-color", "red");
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<a href="{% url 'main:index' %}"><button class="btn btn-secondary float-left m-md-2">Back</button></a>
|
||||
<div class="col-md-4 col-12 m-auto mt-md-3 p-md-5 {% if status == 'available' %}available{% elif status == 'completed' %}completed{% else %}locked{% endif %}">
|
||||
{% if status == 'blocked' %}
|
||||
<h1>This challenge is unavailable. Please try again later.</h1>
|
||||
{% elif status == 'completed' %}
|
||||
<h1>{{ challenge.name }}</h1>
|
||||
<div class="text-left pt-md-2">{{ challenge.description | safe }}</div>
|
||||
<hr>
|
||||
<h3>Solved!</h3>
|
||||
{% elif status == 'locked' %}
|
||||
<h1>This challenge is unavailable. Please try again later.</h1>
|
||||
{% elif status == 'available' %}
|
||||
<h1>{{ challenge.name }}</h1>
|
||||
<div class="text-left pt-md-2">{{ challenge.description | safe }}</div>
|
||||
<hr>
|
||||
<input type="text" id="{{ status.0.id }}" placeholder="Enter the flag here"/>
|
||||
<input type="submit" value="Submit" onclick="checkFlag({{ status.0.id }})" />
|
||||
{% else %}
|
||||
<h1>There's an error with this challenge. Please contact the organizers.</h1>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -31,29 +31,57 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class='row'>
|
||||
{% for challenge, status in challenges_dict.items %}
|
||||
<div class='col-lg-3 col-md-4 col-sm-6 col-xs-12'>
|
||||
<div id="box{{ status.0.id }}" class="box {% if status.1 == 'available' %}available{% elif status.1 == 'completed' %}completed{% else %}locked{% endif %}">
|
||||
<div class="centered-div">
|
||||
<h4>{{ status.0.name }}</h4>
|
||||
<p>Points: {{ status.0.points }}</p>
|
||||
</div>
|
||||
<div class="left-div">
|
||||
{% if status.0.exclusive %}
|
||||
<p>This challenge's points are only available to the first class to complete it.</p>
|
||||
{% elif status.1 == 'locked' %}
|
||||
<p>This challenge was exclusive and has already been completed by another class.</p>
|
||||
{% endif %}
|
||||
<p>{{ status.0.description }}</p>
|
||||
</div>
|
||||
{% if status.1 == 'available' %}
|
||||
<hr>
|
||||
<input type="text" id="{{ status.0.id }}" placeholder="Enter the flag here"/>
|
||||
<input type="submit" value="Submit" onclick="checkFlag({{ status.0.id }})" />
|
||||
{% endif %}
|
||||
</div>
|
||||
<h1 class="border-bottom p-md-2">Fall Hoco Scavenger Hunt 2021</h1>
|
||||
{% for category, challenges in categories.values %}
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<h1 class="ml-3">{{ category.name }}</h1>
|
||||
<p style="cursor: pointer;" onclick="document.getElementById('c-{{ category.id }}').style.display = document.getElementById('c-{{ category.id }}').style.display === 'none' ? 'flex' : 'none'" class="ml-auto mr-3 btn btn-primary">toggle</p>
|
||||
</div>
|
||||
<div id="c-{{ category.id }}" class='row'>
|
||||
{% for challenge, status in challenges.items %}
|
||||
{% if status.0.unblocked %}
|
||||
<a href="challenge/{{ status.0.id }}" class='col-lg-3 col-md-4 col-sm-6 col-xs-12'>
|
||||
<div id="box{{ status.0.id }}" class="box {% if status.1 == 'available' %}available{% elif status.1 == 'completed' %}completed{% else %}locked{% endif %} p-3">
|
||||
<div class="centered-div">
|
||||
<h4>{{ status.0.name }}</h4>
|
||||
<p>Points: {{ status.0.points }}</p>
|
||||
</div>
|
||||
<div class="{% if status.1 == 'completed' %}center{% else %}left{% endif %}-div">
|
||||
{% if status.0.exclusive %}
|
||||
<p>This challenge's points are only available to the first class to complete it.</p>
|
||||
<p>{{ status.0.short_description }}</p>
|
||||
{% elif status.1 == 'locked' %}
|
||||
<p>This challenge was exclusive and has already been completed by another class.</p>
|
||||
{% elif status.1 == 'completed' %}
|
||||
<h3>Solved!</h3>
|
||||
{% else %}
|
||||
<p>{{ status.0.short_description }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if status.1 == 'available' %}
|
||||
<hr>
|
||||
<input type="text" id="{{ status.0.id }}" placeholder="Enter the flag here"/>
|
||||
<input type="submit" value="Submit" onclick="checkFlag({{ status.0.id }})" />
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
{% else %}
|
||||
<div class='col-lg-3 col-md-4 col-sm-6 col-xs-12'>
|
||||
<div id="box{{ status.0.id }}" class="box locked p-3">
|
||||
<div class="centered-div">
|
||||
<h4>{{ status.0.name }}</h4>
|
||||
<p>Points: {{ status.0.points }}</p>
|
||||
</div>
|
||||
<div class="centered-div">
|
||||
<p>This challenge is currently unavailable.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
Loading…
Reference in New Issue
Block a user