feature/post-test-answers #23

Merged
s470631 merged 11 commits from feature/post-test-answers into master 2022-01-22 14:19:05 +01:00
23 changed files with 453 additions and 213 deletions

View File

@ -59,7 +59,8 @@ INSTALLED_APPS = [
"trials",
"answers",
"questions",
"categories"
"categories",
"tools"
]
# AUTHENTICATION_BACKENDS = ['config.authh.SettingsBackend']
MIDDLEWARE = [

View File

@ -16,11 +16,12 @@ Including another URLconf
from django.contrib import admin
from django.urls import include
from django.urls import path
from .views import home, welcome
from .views import home, welcome, help
urlpatterns = [
path('', welcome, name='welcome'),
path('home', home, name='home'),
path('help', help, name='help'),
path('users/', include("users.urls")),
path('questions/', include("questions.urls")),
path('answers/', include("answers.urls")),

View File

@ -7,12 +7,16 @@ from trials.models import Test
@login_required
def home(request):
context = {}
# TODO replace
#context['tests'] = Test.objects.filter(owner=request.user)
context['tests'] = Test.objects.all
# context = {
# 'latest_question_list': latest_question_list,
# }
return render(request, 'home.html', context)
@login_required
def help(request):
return render(request, 'help.html', )
def welcome(request):
return render(request, 'welcome.html')

View File

@ -1,6 +1,6 @@
.sidenav {
height: 100%;
width: 160px;
width: 195px;
position: fixed;
z-index: 1;
top: 0;
@ -8,6 +8,7 @@
background-color: #FF0B7E;
overflow-x: :hidden;
padding-top: 20px;
overflow-y: scroll;
}
.sidenav a {
@ -38,7 +39,7 @@
}
.main {
margin-left: 160px;
margin-left: 190px;
padding: 0px 40px;
}
@ -66,6 +67,25 @@
font-size: 13px;
padding-bottom: 15px;
color: #808080;
/*transform: translate(150%,0%);*/
width:100%;
text-align:center;
}
.left {
float:left;
width: 175px;
}
.center {
display: inline-block;
margin:0 auto;
width: 175px;
}
.right {
float:right;
width: 175px;
}
.mainTestContainer button {
@ -81,6 +101,37 @@
transform: translate(200%,0%);
}
.doubleButton button{
height: 30px;
width: 150px;
color: #FFF;
font-size: 17px;
background: #00916E;
cursor: pointer;
border-radius: 25px;
border: none;
outline: none;
transform: translate(150%,0%);
}
.defaultButton {
height: 30px;
width: 150px;
color: #FFF;
font-size: 17px;
background: #00916E;
cursor: pointer;
border-radius: 25px;
border: none;
outline: none;
}
.defaultButton a {
color: inherit;
text-decoration: inherit;
}
.mainTestContainer a {
color: inherit;
text-decoration: inherit;
@ -88,6 +139,7 @@
.mainTestDesc{
padding-bottom: 15px;
text-align: center;
}
.mainTestQuest {
@ -263,14 +315,57 @@ background-color:#FF0B7E
color: #00916E;
}
.testContent{
padding-top: 15px;
padding-bottom: 15px;
padding-left: 20px;
}
.testContent input[type=submit]{
height: 30px;
width: 150px;
color: #FFF;
font-size: 15px;
font-size: 17px;
background: #00916E;
cursor: pointer;
border-radius: 25px;
border: none;
outline: none;
margin-top: 15px;
}
.linkDefault {
padding-top: 15px;
}
.linkDefault a {
color: #00916E;
text-decoration: none;
}
.newContainer input[type=submit]{
height: 30px;
width: 150px;
color: #FFF;
font-size: 17px;
background: #00916E;
cursor: pointer;
border-radius: 25px;
border: none;
outline: none;
}
.editContainer {
overflow: scroll;
}
.editContainerLine {
padding: 10px 0px 10px 0px;
}
.editContainerSection {
padding-bottom: 15px;
}
.editContainerSection h2 {
display: inline;
}

View File

@ -0,0 +1,48 @@
{% extends "base.html" %}
{% load filters %}
{% load rest_framework %}
{% block title %}New Test{% endblock %}
{% block content %}
<div class="newContainer">
<form method="post">
<h1>Add questions</h1>
{% for i in number_of_questions|times %}
<h2>Question {{i}}</h2>
<label for="desc">Description: </label>
<input id="desc" type="text" name="desc">
<br>
<br>
<label for="ans1">Answer 1: </label>
<input id="ans1" type="text" name="ans1">
<br>
<br>
<label for="ans2">Answer 2: </label>
<input id="ans2" type="text" name="ans2">
<br>
<br>
<label for="ans3">Answer 3: </label>
<input id="ans3" type="text" name="ans3">
<br>
<br>
<label for="ans4">Answer 4: </label>
<input id="ans4" type="text" name="ans4">
<br>
<br>
<label for="category">Correct: </label>
<select name="category" id="category">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<br>
<br>
{% endfor %}
<input type="submit" value="Create test">
</form>
</div>
{% endblock %}

View File

@ -12,9 +12,11 @@
<body>
<div class="sidenav">
<a href="/home">Home</a>
<a href="/test/create">Create test</a>
<a href="/users/tests">Your tests</a>
<a href="{% url 'home' %}">Home</a>
<a href="{% url 'newTest' %}">Create test</a>
<a href="{% url 'myTests' %}">Your tests</a>
<a href="{% url 'solvedTests' %}">Solved tests</a>
<a href="{% url 'help' %}">Help</a>
<p>Categories</p>
<a href="/category/JezykPolski">Język polski</a>
<a href="/category/JezykAngielski">Język angielski</a>

View File

@ -10,15 +10,14 @@
{{test.name}}
</div>
<div class="mainTestMeta">
Category: {{test.category}}
<div class="left">Category: {{test.category}}</div>
<div class="center">Passing score: {{test.passing_score}}</div>
<div class="right">Questions: {{test.questions|length}}</div>
</div>
<div class="mainTestDesc">
<!-- TODO 250 words limit-->
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>
<div class="mainTestMeta">
Passing score: {{test.passing_score}}
</div>
<button><a href="/tests/{{test.id}}/show">Start</a></button>
</div>
<br>

41
templates/createTest.html Normal file
View File

@ -0,0 +1,41 @@
{% extends "base.html" %}
{% load rest_framework %}
{% block title %}New Test{% endblock %}
{% block content %}
<div class="newContainer">
<form method="post">
<h1>Create test</h1>
<label for="name">Name: </label>
<input id="name" type="text" name="name" value="New test">
<br>
<br>
<label for="category">Category: </label>
<select name="category" id="category">
<option value="JezykPolski">Język Polski</option>
<option value="JezykAngielski">Język Angielski</option>
<option value="JezykNiemiecki">Język Niemiecki</option>
<option value="Matematyka">Matematyka</option>
<option value="Informatyka">Informatyka</option>
<option value="Fizyka">Fizyka</option>
<option value="Chemia">Chemia</option>
<option value="Biologia">Biologia</option>
<option value="Geografia">Geografia</option>
<option value="Historia">Historia</option>
</select>
<br>
<br>
<label for="questions">Number of questions: </label>
<input id="questions" type="number" name="questions" value="10">
<br>
<br>
<label for="passing">Passing score: </label>
<input id="passing" type="number" name="passing" value="5">
<br>
<br>
<input type="submit" value="Add questions">
</form>
</div>
{% endblock %}

48
templates/editTest.html Normal file
View File

@ -0,0 +1,48 @@
{% extends "base.html" %}
{% load rest_framework %}
{% block title %}{{ test.name }} - Edit{% endblock %}
{% block additional_head %}
<meta charset="UTF-8">
{% endblock %}
{% block content %}
<div class="editContainer">
<form method="post" novalidate>
<div class="editContainerSection">
<div class="editContainerLine">
<label for="name"><h2>Name:</h2></label>
<input id="name" type="text" name="name" value="New test">
</div>
</div>
{% for question in test.questions.all %}
<div class="editContainerSection">
<div class="editContainerLine">
<label for="desc"><b>Description:</b></label>
<input id="desc" type="text" name="desc", value="{{ question.description }}">
</div>
{% for answer in question.answers.all %}
<div class="editContainerLine">
<label for="ans-{{ forloop.counter }}">Answer {{ forloop.counter }}: </label>
<input id="ans-{{ forloop.counter }}" type="text" name="ans-{{ forloop.counter }}", value="{{ answer.description }}">
</div>
{% endfor %}
<div class="editContainerLine">
<label for="category">Correct: </label>
<select name="category" id="category">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
</div>
</div>
{% endfor %}
<div class="testContent">
<input type="submit" value="Edit test">
</div>
</form>
</div>
{% endblock %}

View File

@ -23,32 +23,31 @@
{% endblock %}
{% block content %}
<div class="card">
<div class="card" style="border: none;">
<div class="card-body test_body">
<div class="card-header test_title">
<div class="card-header test_title" style="background:#00916E; color: #FFF;">
{{ test.name }}
</div>
{% for question in test.questions.all %}
<div class="question_title">
{{ question.description }}
</div>
<div class="list-group">
<form method="post" novalidate>
{% 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>
{% for question in test.questions.all %}
<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>
{% endfor %}
<div class="testContent">
<input type="submit" value="Send answers">
</div>
</form>
</div>
<input class="testContent" type="submit" value="Send answers">
{# <button type="submit" class="testContent" value="Send answers"></button>#}
</form>
</div>
{% endblock %}

View File

@ -1,48 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ test.name }}</title>
<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>
</head>
<body>
<div class="card">
<div class="card-body test_body">
<div class="card-header test_title">
{{ test.name }}
</div>
{% for question in test.questions.all %}
<div class="question_title">
{{ 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.description }}
</label>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
</body>
</html>

8
templates/help.html Normal file
View File

@ -0,0 +1,8 @@
{% extends "base.html" %}
{% block title %}Help{% endblock %}
{% block content %}
<h1>In the future, there will be an app manual here</h1>
{% endblock %}

View File

@ -10,15 +10,14 @@
{{test.name}}
</div>
<div class="mainTestMeta">
Category: {{test.category}}
<div class="left">Category: {{test.category}}</div>
<div class="center">Passing score: {{test.passing_score}}</div>
<div class="right">Questions: {{test.questions|length}}</div>
</div>
<div class="mainTestDesc">
<!-- TODO 250 words limit-->
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>
<div class="mainTestMeta">
Passing score: {{test.passing_score}} / Questions: {{test.questions|length}}
</div>
<button><a href="/tests/{{test.id}}/show">Start</a></button>
</div>
<br>

View File

@ -16,6 +16,9 @@
</p>
{% endfor %}
<input type="submit" value="Login">
<div class="linkDefault">
<a href="{% url 'resetPassword' %}">Reset password</a>
</div>
</form>
{% endblock %}

View File

@ -1,120 +0,0 @@
<html>
<head>
<title>Login</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" integrity="sha384-gfdkjb5BdAXd+lj+gudLWI+BXq4IuLW5IT+brZEZsLFm++aCMlF1V92rMkPaX4PP" crossorigin="anonymous">
<style>
body,
html {
margin: 0;
padding: 0;
height: 100%;
background: #7abecc !important;
}
.user_card {
width: 350px;
margin-top: auto;
margin-bottom: auto;
background: #74cfbf;
position: relative;
display: flex;
justify-content: center;
flex-direction: column;
padding: 10px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
-webkit-box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
-moz-box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
border-radius: 5px;
}
.form_container {
margin-top: 20px;
}
#form-title{
color: #fff;
}
.login_btn {
width: 100%;
background: #33ccff !important;
color: white !important;
}
.login_btn:focus {
box-shadow: none !important;
outline: 0px !important;
}
.login_container {
padding: 0 2rem;
}
.input-group-text {
background: #f7ba5b !important;
color: white !important;
border: 0 !important;
border-radius: 0.25rem 0 0 0.25rem !important;
}
.input_user,
.input_pass:focus {
box-shadow: none !important;
outline: 0px !important;
}
#messages{
background-color: grey;
color: #fff;
padding: 10px;
margin-top: 10px;
}
</style>
</head>
<body>
<div class="container h-100">
<div class="d-flex justify-content-center h-100">
<div class="user_card">
<div class="d-flex justify-content-center">
<h3 id="form-title">LOGIN</h3>
</div>
<div class="d-flex justify-content-center form_container">
<form method="POST" action="">
{% csrf_token %}
<div class="input-group mb-3">
<div class="input-group-append">
<span class="input-group-text"><i class="fas fa-user"></i></span>
</div>
<input type="text" name="username" placeholder="Username..." class="form-control">
</div>
<div class="input-group mb-2">
<div class="input-group-append">
<span class="input-group-text"><i class="fas fa-key"></i></span>
</div>
<input type="password" name="password" placeholder="Password..." class="form-control" >
</div>
<div class="d-flex justify-content-center mt-3 login_container">
<input class="btn login_btn" type="submit" value="Login">
</div>
</form>
</div>
<div class="mt-4">
<div class="d-flex justify-content-center links">
Don't have an account? <a href="{% url 'register' %}" class="ml-2">Sign Up</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -4,6 +4,8 @@
{% block content %}
<p>You have been logged out successfully</p>
<a class="btn btn-primary" href="/home">Home</a>
<div class="linkDefault">
<a href="{% url 'welcome' %}">Continue</a>
</div>
{% endblock %}

29
templates/myTests.html Normal file
View File

@ -0,0 +1,29 @@
{% extends "base.html" %}
{% block title %}My Tests{% endblock %}
{% block content %}
<h1>Check your tests</h1>
{% for test in tests %}
<div class="mainTestContainer">
<div class="mainTestName">
{{test.name}}
</div>
<div class="mainTestMeta">
<div class="left">Category: {{test.category}}</div>
<div class="center">Passing score: {{test.passing_score}}</div>
<div class="right">Questions: {{test.questions|length}}</div>
</div>
<div class="mainTestDesc">
<!-- TODO 250 words limit-->
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>
<div class="doubleButton">
<button><a href="/tests/{{test.id}}/show">Start</a></button>
<button><a href="/tests/{{test.id}}/edit">Edit</a></button>
</div>
</div>
<br>
{% endfor %}
{% endblock %}

View File

@ -6,10 +6,23 @@
<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!</h5>
<h5 class="resultMsg">
Quite good! All the best for next quiz!
<!-- {% if max_score == 100 %}-->
<!-- Idealnie, widzę że ten temat nie ma dla ciebie tajemnic! -->
<!-- {% elif max_score >= 75 %}-->
<!-- Bardzo dobrze, ale są jeszcze pewne braki ;)-->
<!-- {% elif max_score >= 50 %}-->
<!-- Nie jest źle, wiedziałeś więcej niż mniej-->
<!-- {% elif max_score >= 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">Result: {{ status }}</h5>
<h5 class="resultScore">Score: {{ points }}</h5>
<a class="btn btn-primary" href="/home">Home</a>
<button class="defaultButton"><a href="{% url 'home' %}">Home</a></button>
{# <p class="resultText">Percentage: 60%</p>#}
{# <p class="resultText">Correct answers: 3</p>#}
{# <p class="resultText">Incorrect answers: 2</p>#}

View File

View File

@ -0,0 +1,6 @@
from django import template
register = template.Library()
@register.filter(name='times')
def times(number):
return range(number)

View File

@ -38,4 +38,5 @@ class PasswordResetConfirmShortcut:
if serializer.is_valid():
return Response({"detail": cons.PASSWORD_HAS_BEEN_CHANGED}, status=status.HTTP_200_OK)
else:
return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)

View File

@ -4,7 +4,7 @@ from rest_framework.routers import DefaultRouter
from trials.views import TestModelViewSet
from trials.views import TestTemplateView
from trials.views import TestValidateAPIView
from trials.views import TestResultView
from trials.views import TestResultView, addTest, addQuestions, myTests, editTest, solvedTests, EditTestTemplateView
router = DefaultRouter(trailing_slash=False)
router.register("items", TestModelViewSet)
@ -12,7 +12,12 @@ router.register("items", TestModelViewSet)
urlpatterns = [
path('<int:test_id>/show', TestTemplateView.as_view()),
path('<int:test_id>/mark', TestValidateAPIView.as_view()),
path('<int:test_id>/result', TestResultView.as_view())
path('<int:test_id>/result', TestResultView.as_view()),
path('<int:test_id>/edit', EditTestTemplateView.as_view()),
path('add/test', addTest, name="newTest"),
path('add/questions', addQuestions, name="addQuestions"),
path('my', myTests, name="myTests"),
path('solved', solvedTests, name="solvedTests")
]
urlpatterns += router.urls

View File

@ -1,3 +1,4 @@
import requests
from django.views.generic import TemplateView
from rest_framework import views
from rest_framework import viewsets
@ -6,15 +7,118 @@ from rest_framework.response import Response
from trials.models import Test
from trials.serializers import TestSerializer
from django.conf import settings
from django.shortcuts import render, redirect
from django import template
from django.http import HttpResponseRedirect, HttpResponse
from django.template import loader
from django.template.loader import render_to_string, get_template
from django.http import HttpRequest
import requests
def addTest(request):
if request.POST:
data = request.POST
return addQuestions(request="GET", data_about_test=data)
return render(request, 'createTest.html')
def addQuestions(request, data_about_test):
number_of_question = 0
if request == "GET":
for key, value in data_about_test.items():
if key == "questions":
number_of_question = int(value)
context = {
"number_of_questions": number_of_question
}
template_name = "addQuestions.html"
template = get_template(template_name)
return HttpResponse(template.render(context))
# return render(response, 'addQuestions.html')
if request.POST:
pass
def myTests(request):
context = {}
# context['tests']=Test.objects.filter(category=request.user)
context['tests']=Test.objects.filter(category="Matematyka")
#context['tests'] = Test.objects.all
return render(request, 'myTests.html', context)
def solvedTests(request):
# TODO implementation
context = {}
# context['tests']=Test.objects.filter(category=request.user)
context['tests']=Test.objects.filter(category="Matematyka")
#context['tests'] = Test.objects.all
return render(request, 'myTests.html', context)
def editTest(request):
pass
# TODO
class EditTestTemplateView(TemplateView):
PASSED = "passed"
FAILED = "failed"
UNKNOWN = "unknown"
PASSED = {
True: PASSED,
False: FAILED
}
permission_classes = []
template_name = settings.BASE_DIR + f"/templates/editTest.html"
test_id = None
def get_queryset(self):
return Test.objects.all()
def get_context_data(self, test_id, **kwargs):
self.test_id = test_id
context = super().get_context_data(**kwargs)
context["test"] = self.get_queryset().filter(id=test_id).prefetch_related("questions__answers").first()
return context
def get_score(self, test: Test, answers):
return test.get_score(answers)
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):
test = Test.objects.get(id=kwargs.get("test_id"))
score = self.get_score(test, self.formatted_responses(request.POST))
status = score >= test.passing_score
context = {
"status": self.PASSED.get(status, self.UNKNOWN),
"points": score
}
template_name = "result.html"
template = get_template(template_name)
return HttpResponse(template.render(context))
class TestModelViewSet(viewsets.ModelViewSet):
queryset = Test.objects.all()
serializer_class = TestSerializer
class TestTemplateView(TemplateView):
PASSED = "passed"
FAILED = "failed"