Add tournaments #38

Merged
s470631 merged 1 commits from faeture/tournaments into master 2022-05-25 00:07:08 +02:00
12 changed files with 418 additions and 13 deletions
Showing only changes of commit 9867281dd8 - Show all commits

View File

@ -1,14 +1,19 @@
{% extends "base.html" %}
{% load rest_framework %}
{% block title %}Stwórz turniej{% endblock %}
{% block content %}
<h1>Stwórz turniej</h1>
<form method="post" novalidate>
<span>name:<input id="name" type="text" name="name" value="{{ tournament.name }}"></span><br>
<span>passing score:<input id="passing_score" type="text" name="passing_score" value="{{ tournament.passing_score }}"></span>
{% for question in questions %}
<div class="mainTestName">
<div class="question_title" style="padding-top:15px; padding-bottom:10px; padding-left:5px;">
<input class="form-check-input me-1" type="radio" value={{ question.id }}>
<input class="form-check-input me-1" type="radio" name={{ question.id }} value={{ question.id }}>
{{ question.description }}
</div>
<div class="list-group">
@ -20,9 +25,10 @@
</div>
{% endfor %}
</div>
</form>
<div class="testContent">
<input type="submit" value="Wyślij odpowiedzi">
<div class="testContent">
<input type="submit" value="Stwórz turniej">
</div>
</form>
{% endblock %}

View File

@ -0,0 +1,54 @@
{% extends "base.html" %}
{% load rest_framework %}
{% block title %}{{ test.name }}{% endblock %}
{% block additional_head %}
<meta charset="UTF-8">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<style>
.test_title {
font-size: 40px;
}
.test_body {
width: 50%;
}
.question_title {
font-size: 20px;
}
</style>
{% endblock %}
{% block content %}
<div class="card" style="border: none;">
<div class="card-body test_body">
<div class="card-header test_title" style="background:#00916E; color: #FFF;">
{{ tournament.name }}
</div>
<form method="post" novalidate>
{% for question in questions %}
<div class="question_title" style="padding-top:15px; padding-bottom:10px; padding-left:5px;">
{{ question.description }}
</div>
<div class="list-group">
{% for answer in question.answers.all %}
<label class="list-group-item">
<input class="form-check-input me-1" type="radio" name={{ question.id }} value={{ answer.id }}>
{{ answer.description }}
</label>
{% endfor %}
</div>
{% endfor %}
<div class="testContent">
<input type="submit" value="Wyślij odpowiedzi">
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,56 @@
{% extends "base.html" %}
{% load social_share %}
{% block title %}Test result{% endblock %}
{% block content %}
<div class="resultContainer ">
<img class="resultImage" src="http://kmit.in/emagazine/wp-content/uploads/2018/02/karnataka-results.jpg" alt="Card image cap">
<div class="resultBody">
<h5 class="resultMsg">
<!-- Quite good! All the best for next quiz!-->
{% if request.session.percentage == 100 %}
Idealnie, widzę że ten temat nie ma dla ciebie tajemnic!
{% elif request.session.percentage >= 75 %}
Bardzo dobrze, ale są jeszcze pewne braki ;)
{% elif request.session.percentage >= 50 %}
Nie jest źle, wiedziałeś więcej niż mniej
{% elif request.session.percentage >= 25 %}
Masz spore braki, powinieneś trochę więcej się pouczyć
{% else %}
Słabiutko, ale następnym razem będzie lepiej
{% endif %}
</h5>
<h5 class="resultScore">Rezultat: {{ request.session.status }}</h5>
<h5 class="resultText">Twój wynik: {{ request.session.points }}</h5>
<h5 class="resultText">Próg zaliczenia: {{ request.session.passing }}</h5>
<h5 class="resultText">Maksymalny wynik: {{ request.session.max }}</h5>
<h5 class="resultText">Wynik procentowy: {{ request.session.percentage }}%</h5>
<div class="resultContainerSapce"><br></div>
<span><label for="rate"><h5>Jak oceniasz test:</h5></label></span>
<select name="rate" id="rate">
<option value="1">Tragiczny</option>
<option value="2">Słaby</option>
<option value="3">Przeciętny</option>
<option value="4">Dobry</option>
<option value="5">Genialny</option>
</select>
<span><button class="defaultButton">
<a href='' onclick="this.href='rateTest?rate='+document.getElementById('rate').value">Oceń</a>
</button></span>
<div class="resultContainerSapce"><br></div>
{% if request.session.password == "" %}
<h5>Udostępnij:</h5>
{% post_to_facebook object_or_url %}
{% post_to_linkedin object_or_url %}
{% endif %}
<div class="resultContainerSapce"><br></div>
<button class="defaultButton"><a href="{% url 'home' %}">Strona główna</a></button>
</div>
</div>
{% endblock %}

View File

@ -3,8 +3,8 @@
{% block title %}Turnieje{% endblock %}
{% block content %}
<h1>Twoje testy</h1>
{% for test in tests %}
<h1>Turnieje</h1>
{% for tournament in tournaments %}
<div class="mainTestContainer">
<div class="mainTestName">
{{tournament.name}}
@ -15,7 +15,7 @@
<!-- <div class="mainTestDesc">-->
<!-- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus volutpat scelerisque tortor, id sodales leo finibus id. Vivamus id viverra nunc, ac faucibus metus. Nulla a mauris imperdiet sapien lobortis dapibus. Quisque ornare posuere pulvinar.-->
<!-- </div>-->
<button><a href="/tests/{{tournament.id}}/show">Rozwiąż</a></button>
<button><a href="/tests/{{tournament.id}}/tournament/show">Rozwiąż</a></button>
</div>
<br>
{% endfor %}

View File

@ -38,3 +38,24 @@ class TestManager(Manager):
)
return instance
class TournamentManager(Manager):
def create(
self, *,
name="",
questions=[],
passing_score=0,
**kwargs
):
Question = apps.get_model("questions", "Question")
instance = super().create(
name=name,
passing_score=passing_score
)
for q in questions:
qq = Question.objects.get(id=q)
qq.tournament.add(instance.id)
return instance

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2022-05-24 20:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('trials', '0023_tournament'),
]
operations = [
migrations.AlterField(
model_name='tournament',
name='password',
field=models.CharField(default='', max_length=100),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2022-05-24 21:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('trials', '0024_alter_tournament_password'),
]
operations = [
migrations.AddField(
model_name='tournament',
name='passing_score',
field=models.PositiveSmallIntegerField(default=0),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2022-05-24 21:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('trials', '0025_tournament_passing_score'),
]
operations = [
migrations.AddField(
model_name='tournament',
name='completions',
field=models.IntegerField(default=0),
),
]

View File

@ -0,0 +1,43 @@
# Generated by Django 3.2.9 on 2022-05-24 21:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('trials', '0026_tournament_completions'),
]
operations = [
migrations.AddField(
model_name='tournament',
name='avg_difficulty',
field=models.FloatField(default=0.0),
),
migrations.AddField(
model_name='tournament',
name='avg_rating',
field=models.IntegerField(default=0),
),
migrations.AddField(
model_name='tournament',
name='difficulty_label',
field=models.IntegerField(default=0),
),
migrations.AddField(
model_name='tournament',
name='rates_amount',
field=models.IntegerField(default=0),
),
migrations.AddField(
model_name='tournament',
name='total_percentage_scored_by_users',
field=models.IntegerField(default=0),
),
migrations.AddField(
model_name='tournament',
name='total_rating',
field=models.IntegerField(default=0),
),
]

View File

@ -2,7 +2,7 @@ from django.db import models
from questions.models import Question
from users.models import User
from .managers import TestManager
from .managers import TestManager, TournamentManager
class Test(models.Model):
@ -114,4 +114,70 @@ class Tournament(models.Model):
related_name="tournaments",
on_delete=models.CASCADE
)
password = models.CharField(max_length=100)
password = models.CharField(max_length=100, default="")
passing_score = models.PositiveSmallIntegerField(default=0)
completions = models.IntegerField(default=0)
total_percentage_scored_by_users = models.IntegerField(default=0)
total_rating = models.IntegerField(default=0)
avg_rating = models.IntegerField(default=0)
rates_amount = models.IntegerField(default=0)
difficulty_label = models.IntegerField(default=0)
avg_difficulty = models.FloatField(default=0.0)
objects = TournamentManager()
def get_score(self, answers):
"""
[
{
"question": 1,
"answer": 1
},
{
"question": 2,
"answer": 1
}
]
"""
points = 0
for answer in answers:
question = Question.objects.filter(tournament=self.id).get(id=answer["question"])
if question.answers.get(id=answer["answer"]).is_correct:
points += question.points
return points
def get_maxscore(self):
"""
[
{
"question": 1,
"answer": 1
},
{
"question": 2,
"answer": 1
}
]
"""
points = 0
for question in Question.objects.filter(tournament=self.id):
points += question.points
return points
def question_count(self):
return Question.objects.filter(tournament=self.id).count()
def get_author_name(self):
if self.created_by:
user = User.objects.get(email=self.created_by)
user_fullname = user.first_name + " " + user.last_name
else:
user_fullname = "SOITA"
return user_fullname
def name_and_passing_score(self):
return {
"name": self.name,
"passing_score": self.passing_score
}

View File

@ -1,7 +1,7 @@
from django.urls import path
from rest_framework.routers import DefaultRouter
from trials.views import TestModelViewSet, TestTemplateView, TestValidateAPIView, TestResultView, rateTest, addTest, addQuestions, myTests, solvedTests, solvedTestsDetailed, EditTestTemplateView, deleteTest, AddQuestionToExistingTest, RemoveQuestionFromExistingTest, EditQuestionTemplateView, editName, editVisible, editPassword, TestPasswordTemplateView, TournamentView, CreateTournamentView
from trials.views import TestModelViewSet, TestTemplateView, TestValidateAPIView, TestResultView, rateTest, addTest, addQuestions, myTests, solvedTests, solvedTestsDetailed, EditTestTemplateView, deleteTest, AddQuestionToExistingTest, RemoveQuestionFromExistingTest, EditQuestionTemplateView, editName, editVisible, editPassword, TestPasswordTemplateView, TournamentView, CreateTournamentView, TournamentTemplateView, TournamentResultView
router = DefaultRouter(trailing_slash=False)
router.register("items", TestModelViewSet)
@ -26,7 +26,9 @@ urlpatterns = [
path('solved', solvedTests, name="solvedTests"),
path('solved/<int:test_id>', solvedTestsDetailed, name="solvedTests"),
path('tournamets', TournamentView, name="tournaments"),
path('add/tournament', CreateTournamentView, name="CreateTournament")
path('add/tournament', CreateTournamentView, name="CreateTournament"),
path('<int:tournament_id>/tournament/show', TournamentTemplateView.as_view()),
path('<int:tournament_id>/tournament/result', TournamentResultView.as_view())
]
urlpatterns += router.urls

View File

@ -85,14 +85,28 @@ def addQuestions(request, **kwargs):
def TournamentView(request):
context = {}
context['tournament'] = Tournament.objects.all()
context['tournaments'] = Tournament.objects.all()
return render(request, 'tournaments.html', context)
def CreateTournamentView(request):
def CreateTournamentView(request, **kwargs):
if request.POST:
question_ids = []
dictt = dict(request.POST)
pyk = dictt.pop("name")
pyk2 = dictt.pop("passing_score")
name = request.POST.get("name")
passing_score = request.POST.get("passing_score")
for k, v in dictt.items():
question_ids.append(k)
Tournament.objects.create(name=name, questions=question_ids, passing_score=passing_score)
return render(request, 'home.html')
context = {}
context['questions'] = Question.objects.all()
return render(request, 'createTournament.html', context)
class AddQuestionToExistingTest(TemplateView):
template_name = settings.BASE_DIR + f"/templates/addQuestionToExistingTest.html"
@ -411,6 +425,91 @@ class TestTemplateView(TemplateView):
return HttpResponseRedirect(f'result')
class TournamentTemplateView(TemplateView):
PASSED = "Zaliczony"
FAILED = "Niezaliczony"
UNKNOWN = "nieznany"
PASSED = {
True: PASSED,
False: FAILED
}
permission_classes = []
template_name = settings.BASE_DIR + f"/templates/generic_tournament.html"
test_id = None
def get_queryset(self):
return Tournament.objects.all()
def get_context_data(self, tournament_id, **kwargs):
self.test_id = tournament_id
context = super().get_context_data(**kwargs)
context["tournament"] = self.get_queryset().filter(id=tournament_id)
context["questions"] = Question.objects.filter(tournament=tournament_id)
return context
def get_score(self, tournament: Tournament, answers):
return tournament.get_score(answers)
def get_maxscore(self, tournament: Tournament):
return tournament.get_maxscore()
def formatted_responses(self, unformatted_json):
formatted_response = list()
for question, answer in unformatted_json.items():
formatted_response.append(
{
"question": question,
"answer": answer
}
)
return formatted_response
def post(self, request, *args, **kwargs):
tournament = Tournament.objects.get(id=kwargs.get("tournament_id"))
score = self.get_score(tournament, self.formatted_responses(request.POST))
max = self.get_maxscore(tournament)
status = score >= tournament.passing_score
# context = {
# "status": self.PASSED.get(status, self.UNKNOWN),
# "points": score,
# "max": max,
# "passing": test.passing_score,
# "percentage": int(score / max * 100),
# "password": test.password
# }
request.session["status"] = self.PASSED.get(status, self.UNKNOWN)
request.session["points"] = score
request.session["max"] = max
request.session["passing"] = tournament.passing_score
request.session["percentage"] = int(score / max * 100)
request.session["password"] = tournament.password
# SolvedTest.objects.create(
# score=score,
# max=max,
# percentage=int(score / max * 100),
# user=request.user,
# test=test
# )
tournament.completions += 1
tournament.total_percentage_scored_by_users += int(score / max * 100)
if tournament.completions >= 5:
tournament.avg_difficulty = float(tournament.total_percentage_scored_by_users) / float(tournament.completions)
if tournament.avg_difficulty > 90.0:
tournament.difficulty_label = 1
elif tournament.avg_difficulty > 75.0:
tournament.difficulty_label = 2
elif tournament.avg_difficulty > 50.0:
tournament.difficulty_label = 3
elif tournament.avg_difficulty > 25.0:
tournament.difficulty_label = 4
else:
tournament.difficulty_label = 5
tournament.save()
return HttpResponseRedirect(f'result')
@login_required
def TestPasswordTemplateView(request, test_id):
test = Test.objects.get(id=test_id)
@ -471,3 +570,7 @@ class TestValidateAPIView(views.APIView):
class TestResultView(TemplateView):
permission_classes = []
template_name = settings.BASE_DIR + f"/templates/result.html"
class TournamentResultView(TemplateView):
permission_classes = []
template_name = settings.BASE_DIR + f"/templates/tournament_result.html"