24 changed files with 570 additions and 0 deletions
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>{% load static %} |
||||
<html> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
{% block 'extra_css' %}{% endblock %} |
||||
<link rel="icon" href="{% static 'includes/' %}{{favicon}}"> |
||||
<title>EscapeGame</title> |
||||
</head> |
||||
<body class="bg-light" style="">{% if messages %}{% for message in messages %} |
||||
<p>{{message}}</p>{% endfor %}{% endif %}{% block 'body' %} |
||||
{% endblock %}</body> |
||||
</html> |
||||
@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
|
||||
<!DOCTYPE html>{% load static %} |
||||
<html lang="fr"><head> |
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8"> |
||||
<meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
<meta name="description" content="Escape Game"> |
||||
<meta name="author" content="Christophe SCAYA"> |
||||
<link rel="icon" href="{% static 'escape-icon-2.jpg' %}"> |
||||
|
||||
<title>Cover Template for Bootstrap</title> |
||||
|
||||
<!-- Bootstrap core CSS --> |
||||
<link href="{% static 'bootstrap.min.css' %}" rel="stylesheet"> |
||||
|
||||
<!-- Custom styles for this template --> |
||||
<link href="{% static 'cover.css' %}" rel="stylesheet"> |
||||
</head> |
||||
|
||||
<body class="text-center"> |
||||
|
||||
<div class="cover-container d-flex h-100 p-3 mx-auto flex-column"> |
||||
<header class="masthead mb-auto"> |
||||
<div class="inner"> |
||||
<h4 class="masthead-brand">{{title}}</h4> |
||||
</div> |
||||
</header> |
||||
|
||||
{% for message in messages %} |
||||
<div class="container-fluid p-0"> |
||||
<div class="alert {{ message.tags }} alert-dismissible" role="alert" > |
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"> |
||||
<span aria-hidden="True">×</span> |
||||
</button> |
||||
{{ message }} |
||||
</div> |
||||
</div> |
||||
{% endfor %}{% block 'contenu' %}{% endblock %} |
||||
|
||||
<footer class="mastfoot mt-auto"></footer> |
||||
</div> |
||||
|
||||
|
||||
<!-- Bootstrap core JavaScript |
||||
================================================== --> |
||||
<!-- Placed at the end of the document so the pages load faster --> |
||||
<script src="{% static 'jquery-3.2.1.slim.min.js' %}" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> |
||||
<!--<script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery-slim.min.js"><\/script>')</script>--> |
||||
<script src="{% static 'popper.min.js' %}"></script> |
||||
<script src="{% static 'bootstrap.min.js' %}"></script> |
||||
|
||||
</body> |
||||
</html> |
||||
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
from django import forms |
||||
from django.core.exceptions import ValidationError |
||||
from django.utils.translation import gettext_lazy as _ |
||||
from .models import Equipe |
||||
|
||||
def validateEquipe(value): |
||||
if len(Equipe.objects.filter(code=value)) == 0: |
||||
raise ValidationError( |
||||
_("Cette équipe n'existe pas"), |
||||
params={'value': value}, |
||||
) |
||||
|
||||
class LoginForm(forms.Form): |
||||
equipe = forms.DecimalField(label="Code équipe", min_value=1000, max_value=9999, decimal_places=0, validators=[validateEquipe]) |
||||
|
||||
class CreateGameForm(forms.Form): |
||||
nb_equipes = forms.DecimalField(label="Nombre d'équipes", min_value=0, max_value=10, decimal_places=0) |
||||
nb_challenges = forms.DecimalField(label="Nombre de challenges", min_value=0, max_value=10, decimal_places=0) |
||||
@ -0,0 +1,68 @@
@@ -0,0 +1,68 @@
|
||||
from .models import * |
||||
from django.db.models import Max; |
||||
from django.apps import apps |
||||
from datetime import datetime |
||||
|
||||
def getMaxChallenge(equipe): |
||||
max_rank = Challenge.objects.filter(equipe=equipe).aggregate(max_rank=Max("rank"))['max_rank'] |
||||
try: |
||||
challenge = Challenge.objects.filter(equipe=equipe, rank=max_rank)[0] |
||||
return challenge |
||||
except Challenge.DoesNotExist: |
||||
return None |
||||
|
||||
""" |
||||
Fonction createChallenge |
||||
Ajoute un challenge à l'équipe fournie et le retourne. Si le nombre max de challenges est déjà atteint, |
||||
la fonction retourne None. |
||||
Si prevZone est fournie, la zone du nouveau challenge sera la plus éloignée possible. |
||||
""" |
||||
def createChallenge(equipe,prevZone=None): |
||||
max_rank = Challenge.objects.filter(equipe=equipe).aggregate(max_rank=Max("rank"))['max_rank'] |
||||
if max_rank is None: |
||||
max_rank = 0 |
||||
if max_rank < apps.get_app_config('app').nb_challenges: |
||||
challenge = Challenge(equipe=equipe,zone=attributeZone(prevZone)) |
||||
challenge.save() |
||||
return challenge |
||||
else: |
||||
return None |
||||
|
||||
""" |
||||
Fonction attributeZone |
||||
Cette fonction recherche une zone avec l'attribut libre et lui donne l'attribut A |
||||
Si une zone est donnée en paramètre, le zone recherchée sera la zone libre la plus éloignée de celle fournie en paramètre. |
||||
""" |
||||
def attributeZone(zone=None): |
||||
if zone is None: |
||||
max_id = Zone.objects.filter(etat='L').aggregate(max_id=Max("id"))['max_id'] |
||||
if max_id is None:#aucune zone libre disponible |
||||
return None |
||||
print("max_id "+str(max_id)) |
||||
pk = random.randint(1, max_id) |
||||
zone = Zone.objects.get(pk=pk) |
||||
zone.etat = 'A' |
||||
zone.save() |
||||
return zone |
||||
else: |
||||
return None#todo |
||||
|
||||
def startEquipeTime(equipe): |
||||
if equipe.start_time is None: |
||||
equipe.start_time = datetime.now() |
||||
equipe.save() |
||||
|
||||
def stopEquipeTime(equipe): |
||||
if equipe.end_time is None: |
||||
equipe.end_time = datetime.now() |
||||
equipe.save() |
||||
|
||||
def startChallengeTime(challenge): |
||||
if challenge.start_time is None: |
||||
challenge.start_time = datetime.now() |
||||
challenge.save() |
||||
|
||||
def stopChallengeTime(equipe): |
||||
if challenge.end_time is None: |
||||
challenge.end_time = datetime.now() |
||||
challenge.save() |
||||
@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
|
||||
# Generated by Django 4.1 on 2022-08-12 12:03 |
||||
|
||||
from django.db import migrations, models |
||||
import django.db.models.deletion |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('app', '0003_alter_zone_code_alter_distance_unique_together'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.CreateModel( |
||||
name='Equipe', |
||||
fields=[ |
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
('nom', models.CharField(max_length=50)), |
||||
('code', models.IntegerField(default=3892)), |
||||
('start_time', models.TimeField()), |
||||
('end_time', models.TimeField()), |
||||
], |
||||
), |
||||
migrations.AlterField( |
||||
model_name='zone', |
||||
name='code', |
||||
field=models.IntegerField(default=4254), |
||||
), |
||||
migrations.CreateModel( |
||||
name='Challenge', |
||||
fields=[ |
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
('code', models.IntegerField(default=6920)), |
||||
('start_time', models.TimeField()), |
||||
('end_time', models.TimeField()), |
||||
('equipe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.equipe')), |
||||
('zone', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.zone')), |
||||
], |
||||
), |
||||
] |
||||
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
# Generated by Django 4.1 on 2022-08-22 14:30 |
||||
|
||||
import app.models |
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('app', '0004_equipe_alter_zone_code_challenge'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='challenge', |
||||
name='code', |
||||
field=models.IntegerField(default=app.models.random_string, unique=True), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='equipe', |
||||
name='code', |
||||
field=models.IntegerField(default=app.models.random_string, unique=True), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='zone', |
||||
name='code', |
||||
field=models.IntegerField(default=3734), |
||||
), |
||||
] |
||||
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.1 on 2022-08-22 14:32 |
||||
|
||||
import app.models |
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('app', '0005_alter_challenge_code_alter_equipe_code_and_more'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='zone', |
||||
name='code', |
||||
field=models.IntegerField(default=app.models.random_string, unique=True), |
||||
), |
||||
] |
||||
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
# Generated by Django 4.1 on 2022-08-23 13:45 |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('app', '0006_alter_zone_code'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='challenge', |
||||
name='end_time', |
||||
field=models.TimeField(null=True), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='challenge', |
||||
name='start_time', |
||||
field=models.TimeField(null=True), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='equipe', |
||||
name='end_time', |
||||
field=models.TimeField(null=True), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='equipe', |
||||
name='start_time', |
||||
field=models.TimeField(null=True), |
||||
), |
||||
] |
||||
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
# Generated by Django 4.1 on 2022-08-23 13:47 |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('app', '0007_alter_challenge_end_time_alter_challenge_start_time_and_more'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='challenge', |
||||
name='end_time', |
||||
field=models.TimeField(blank=True, null=True), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='challenge', |
||||
name='start_time', |
||||
field=models.TimeField(blank=True, null=True), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='equipe', |
||||
name='end_time', |
||||
field=models.TimeField(blank=True, null=True), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='equipe', |
||||
name='start_time', |
||||
field=models.TimeField(blank=True, null=True), |
||||
), |
||||
] |
||||
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.1 on 2022-08-24 13:43 |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('app', '0008_alter_challenge_end_time_alter_challenge_start_time_and_more'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AddField( |
||||
model_name='challenge', |
||||
name='rank', |
||||
field=models.IntegerField(default=1), |
||||
), |
||||
] |
||||
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.1 on 2022-08-24 13:56 |
||||
|
||||
from django.db import migrations, models |
||||
import django.db.models.deletion |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('app', '0009_challenge_rank'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='challenge', |
||||
name='zone', |
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='app.zone'), |
||||
), |
||||
] |
||||
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.1 on 2022-08-24 20:49 |
||||
|
||||
from django.db import migrations, models |
||||
import django.db.models.deletion |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('app', '0010_alter_challenge_zone'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='challenge', |
||||
name='zone', |
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.zone'), |
||||
), |
||||
] |
||||
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.1 on 2022-09-01 20:56 |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('app', '0011_alter_challenge_zone'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AddField( |
||||
model_name='zone', |
||||
name='description', |
||||
field=models.TextField(default=''), |
||||
), |
||||
] |
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,110 @@
@@ -0,0 +1,110 @@
|
||||
/* |
||||
* Globals |
||||
*/ |
||||
|
||||
/* Links */ |
||||
a, |
||||
a:focus, |
||||
a:hover { |
||||
color: #fff; |
||||
} |
||||
|
||||
/* Custom default button */ |
||||
.btn-secondary, |
||||
.btn-secondary:hover, |
||||
.btn-secondary:focus { |
||||
color: #333; |
||||
text-shadow: none; /* Prevent inheritance from `body` */ |
||||
background-color: #fff; |
||||
border: .05rem solid #fff; |
||||
} |
||||
|
||||
|
||||
/* |
||||
* Base structure |
||||
*/ |
||||
|
||||
html, |
||||
body { |
||||
height: 100%; |
||||
background-color: #666; |
||||
} |
||||
|
||||
body { |
||||
display: -ms-flexbox; |
||||
display: -webkit-box; |
||||
display: flex; |
||||
-ms-flex-pack: center; |
||||
-webkit-box-pack: center; |
||||
justify-content: center; |
||||
color: #fff; |
||||
text-shadow: 0 .05rem .1rem rgba(0, 0, 0, .5); |
||||
box-shadow: inset 0 0 5rem rgba(0, 0, 0, .5); |
||||
} |
||||
|
||||
.cover-container { |
||||
max-width: 42em; |
||||
} |
||||
|
||||
|
||||
/* |
||||
* Header |
||||
*/ |
||||
.masthead { |
||||
margin-bottom: 2rem; |
||||
} |
||||
|
||||
.masthead-brand { |
||||
margin-bottom: 0; |
||||
} |
||||
|
||||
.nav-masthead .nav-link { |
||||
padding: .25rem 0; |
||||
font-weight: 700; |
||||
color: rgba(255, 255, 255, .5); |
||||
background-color: transparent; |
||||
border-bottom: .25rem solid transparent; |
||||
} |
||||
|
||||
.nav-masthead .nav-link:hover, |
||||
.nav-masthead .nav-link:focus { |
||||
border-bottom-color: rgba(255, 255, 255, .25); |
||||
} |
||||
|
||||
.nav-masthead .nav-link + .nav-link { |
||||
margin-left: 1rem; |
||||
} |
||||
|
||||
.nav-masthead .active { |
||||
color: #fff; |
||||
border-bottom-color: #fff; |
||||
} |
||||
|
||||
@media (min-width: 48em) { |
||||
.masthead-brand { |
||||
float: left; |
||||
} |
||||
.nav-masthead { |
||||
float: right; |
||||
} |
||||
} |
||||
|
||||
|
||||
/* |
||||
* Cover |
||||
*/ |
||||
.cover { |
||||
padding: 0 1.5rem; |
||||
} |
||||
.cover .btn-lg { |
||||
padding: .75rem 1.25rem; |
||||
font-weight: 700; |
||||
} |
||||
|
||||
|
||||
/* |
||||
* Footer |
||||
*/ |
||||
.mastfoot { |
||||
color: rgba(255, 255, 255, .5); |
||||
} |
||||
|
After Width: | Height: | Size: 11 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
{% extends 'admin_template.html' %}{% block 'body' %} |
||||
<div> |
||||
<h3>Interface de gestion :</h3> |
||||
<div> |
||||
<a href={% url 'app:createNewGame' %}>Créer un nouveau jeu</a> |
||||
<p>{{ info }}</p> |
||||
</div> |
||||
<div> |
||||
<table width="100%" border=1 class="table table-striped w-auto table-responsive-lg"> |
||||
<thead> |
||||
<tr> |
||||
<th scope="col"></th>{% for equipe in liste_equipe %} |
||||
<th scope="col">{{equipe.nom}}</th>{% endfor %} |
||||
</tr> |
||||
</thead> |
||||
<tbody>{% for equipe in liste_equipe %} |
||||
<tr> |
||||
<td scope="col">{{equipe.nom}}</td> |
||||
</tr>{% endfor %} |
||||
</tbody> |
||||
</table> |
||||
</div> |
||||
</form> |
||||
</div>{% endblock %} |
||||
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
{% extends 'default_template.html' %}{% block 'contenu' %} |
||||
<div>{% if form %} |
||||
<h3>Bienvenue dans cet EscapeGame !</h3> |
||||
<p>Pour commencer l'aventure,<br/>saisissez le code de votre équipe ! </p> |
||||
<form action="{% url "app:setEquipe" %}" method="POST">{% csrf_token %} |
||||
{{ form }} |
||||
<input type="submit" value="OK"> |
||||
<!--<table> |
||||
{{ form.as_table }} |
||||
<tr> |
||||
<td colspan="2"><input type="submit" value="OK"></td> |
||||
</tr> |
||||
</table>--> |
||||
</form>{% elif zone %} |
||||
<h3>Bienvenue équipe {{equipe_nom}} ! Pour votre prochain challenge, rendez-vous dans la zone {{zone}} |
||||
et flashez le QR code pour connaître votre prochaine mission ! </h3> |
||||
{% endif %} |
||||
</div>{% endblock %} |
||||
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
{% extends 'default_template.html' %}{% block 'contenu' %} |
||||
<main role="main" class="inner cover">{{zone.description |safe}} |
||||
</main>{% endblock %} |
||||
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
from django.urls import path |
||||
|
||||
from . import views |
||||
|
||||
app_name = 'app' |
||||
urlpatterns = [ |
||||
path('', views.displayZone, name='displayZone'), |
||||
path('<int:zone_id>/', views.displayZone, name='displayZone'), |
||||
path('setEquipe/', views.setEquipe, name='setEquipe'), |
||||
path('dashboard/', views.dashboard, name='dashboard'), |
||||
path('dashboard/createNewGame', views.createNewGame, name='createNewGame'), |
||||
] |
||||
Loading…
Reference in new issue