First Commit
This commit is contained in:
commit
ce0758fbbb
496 changed files with 52062 additions and 0 deletions
0
quiz/__init__.py
Normal file
0
quiz/__init__.py
Normal file
25
quiz/admin.py
Normal file
25
quiz/admin.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
from django.contrib import admin
|
||||
from django.db.models import QuerySet
|
||||
from .models import *
|
||||
|
||||
@admin.action(description="Activer les quizes séléctionnés")
|
||||
def activate(modelAdmin, request, querySet: QuerySet):
|
||||
updated = querySet.update(is_active=True)
|
||||
modelAdmin.message_user(request, f"{updated} quiz(es) ont été activé(s).")
|
||||
|
||||
@admin.action(description="Désactiver les quizes séléctionnés")
|
||||
def deactivate(modelAdmin, request, querySet: QuerySet):
|
||||
updated = querySet.update(is_active=False)
|
||||
modelAdmin.message_user(request, f"{updated} quiz(es) ont été désactivé(s).")
|
||||
|
||||
class QuizAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'author', 'is_active', 'created', 'updated')
|
||||
list_filter = ('author', 'is_active', 'created', 'updated')
|
||||
search_fields = ('title', 'author__username')
|
||||
ordering = ('-created',)
|
||||
fields = ('title', 'author', 'is_active')
|
||||
actions = [activate, deactivate]
|
||||
|
||||
admin.site.register(Quiz, QuizAdmin)
|
||||
admin.site.register(Question)
|
||||
admin.site.register(Choice)
|
||||
6
quiz/apps.py
Normal file
6
quiz/apps.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class QuizConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'quiz'
|
||||
7
quiz/context_processors.py
Normal file
7
quiz/context_processors.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
from .models import Quiz
|
||||
from users.decorators import groups_required
|
||||
|
||||
groups_required('Administrateur', 'SuperAdmin')
|
||||
def pending_quizes_count(request):
|
||||
count = Quiz.objects.filter(is_active=False).count()
|
||||
return {'pending_quizes_count': count}
|
||||
27
quiz/forms.py
Normal file
27
quiz/forms.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
from django import forms
|
||||
from .models import *
|
||||
|
||||
# Gestion des formulaires pour les quiz en se servant du model
|
||||
class QuizForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Quiz
|
||||
fields = ['name', 'description', 'image']
|
||||
labels = {
|
||||
'name': '',
|
||||
'description': '',
|
||||
'image': '(Pas obligatoire) '
|
||||
}
|
||||
widgets = {
|
||||
'name': forms.TextInput(attrs={'placeholder': 'Nom du quiz'}),
|
||||
'description': forms.Textarea(attrs={'placeholder': 'Un text de description pour que les membres aient une idée du contenu du quiz'}),
|
||||
}
|
||||
|
||||
class QuestionForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Question
|
||||
fields = ['question']
|
||||
|
||||
class ChoiceForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Choice
|
||||
fields = ['choice', 'is_correct']
|
||||
71
quiz/migrations/0001_initial.py
Normal file
71
quiz/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# Generated by Django 4.2.17 on 2025-01-04 13:39
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Quiz',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=155)),
|
||||
('description', models.TextField(default='')),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('updated', models.DateTimeField(auto_now=True)),
|
||||
('is_active', models.BooleanField(default=True)),
|
||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quizzes', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserQuiz',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('score', models.IntegerField(default=0)),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('updated', models.DateTimeField(auto_now=True)),
|
||||
('quiz', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_quizzes', to='quiz.quiz')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_quizzes', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Question',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('question', models.CharField(max_length=255)),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('updated', models.DateTimeField(auto_now=True)),
|
||||
('quiz', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='questions', to='quiz.quiz')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Choice',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('choice', models.CharField(max_length=255)),
|
||||
('is_correct', models.BooleanField(default=False)),
|
||||
('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='choices', to='quiz.question')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserAnswer',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('choice', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_answers', to='quiz.choice')),
|
||||
('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_answers', to='quiz.question')),
|
||||
('user_quiz', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_answers', to='quiz.userquiz')),
|
||||
],
|
||||
options={
|
||||
'unique_together': {('user_quiz', 'question')},
|
||||
},
|
||||
),
|
||||
]
|
||||
18
quiz/migrations/0002_quiz_image.py
Normal file
18
quiz/migrations/0002_quiz_image.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 4.2.17 on 2025-01-04 14:11
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('quiz', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='quiz',
|
||||
name='image',
|
||||
field=models.ImageField(blank=True, default='', upload_to='quiz_images/'),
|
||||
),
|
||||
]
|
||||
0
quiz/migrations/__init__.py
Normal file
0
quiz/migrations/__init__.py
Normal file
57
quiz/models.py
Normal file
57
quiz/models.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
from django.db import models
|
||||
from users.models import User
|
||||
|
||||
class Quiz(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='quizzes')
|
||||
name = models.CharField(max_length=155)
|
||||
description = models.TextField(default="")
|
||||
image = models.ImageField(upload_to='quiz_images/', default='', blank=True)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
updated = models.DateTimeField(auto_now=True)
|
||||
is_active = models.BooleanField(default=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Question(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE, related_name='questions')
|
||||
question = models.CharField(max_length=255)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
updated = models.DateTimeField(auto_now=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.question
|
||||
|
||||
class Choice(models.Model): # Renommé au singulier
|
||||
id = models.AutoField(primary_key=True)
|
||||
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='choices')
|
||||
choice = models.CharField(max_length=255)
|
||||
is_correct = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
return self.choice
|
||||
|
||||
class UserQuiz(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_quizzes')
|
||||
quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE, related_name='user_quizzes') # Ajouté
|
||||
score = models.IntegerField(default=0)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
updated = models.DateTimeField(auto_now=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user.username} - {self.quiz.name}"
|
||||
|
||||
class UserAnswer(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
user_quiz = models.ForeignKey(UserQuiz, on_delete=models.CASCADE, related_name='user_answers')
|
||||
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='user_answers')
|
||||
choice = models.ForeignKey(Choice, on_delete=models.CASCADE, related_name='user_answers')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user_quiz.user.username} - {self.question.question}"
|
||||
|
||||
class Meta:
|
||||
unique_together = ('user_quiz', 'question') # Empêche qu'un utilisateur réponde plusieurs fois à la même question.
|
||||
8
quiz/templatetags/quiz_tags.py
Normal file
8
quiz/templatetags/quiz_tags.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.filter
|
||||
def get_item(dictionary, key):
|
||||
return dictionary.get(key)
|
||||
3
quiz/tests.py
Normal file
3
quiz/tests.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
10
quiz/urls.py
Normal file
10
quiz/urls.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.home, name='quiz_home'),
|
||||
path('<int:quiz_id>/', views.quiz, name='quiz'),
|
||||
path('result/<int:user_quiz_id>/', views.result, name='quiz_result'),
|
||||
path('create/', views.create_quiz, name='create_quiz'),
|
||||
path('create/<int:quiz_id>/', views.create_responses_quiz, name='create_responses_quiz'),
|
||||
]
|
||||
149
quiz/views.py
Normal file
149
quiz/views.py
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
from django.shortcuts import render, get_object_or_404, redirect
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from .models import *
|
||||
from users.models import UserLevel, UserInventory
|
||||
from shop.models import Item
|
||||
from .forms import *
|
||||
|
||||
@login_required
|
||||
def home(request):
|
||||
quizes = Quiz.objects.filter(is_active=True)
|
||||
my_quizes = Quiz.objects.filter(author=request.user)
|
||||
|
||||
if request.user.is_superuser:
|
||||
quizes = Quiz.objects.all()
|
||||
|
||||
|
||||
# Récupérer les meilleurs scores de l'utilisateur pour chaque quiz
|
||||
user_scores = {}
|
||||
if request.user.is_authenticated:
|
||||
user_quiz_scores = UserQuiz.objects.filter(
|
||||
user=request.user
|
||||
).values('quiz_id').annotate(
|
||||
best_score=models.Max('score')
|
||||
)
|
||||
user_scores = {score['quiz_id']: score['best_score'] for score in user_quiz_scores}
|
||||
|
||||
return render(request, "games/quiz/home.html", {
|
||||
"quizes": quizes,
|
||||
"my_quizes": my_quizes,
|
||||
"user_scores": user_scores
|
||||
})
|
||||
|
||||
@login_required
|
||||
def quiz(request, quiz_id):
|
||||
quiz = get_object_or_404(Quiz, id=quiz_id)
|
||||
|
||||
if request.method == 'POST':
|
||||
# Vérifier si l'utilisateur a déjà participé à ce quiz
|
||||
user_quiz = UserQuiz.objects.filter(user=request.user, quiz=quiz).first()
|
||||
if user_quiz:
|
||||
# Si oui, supprimer les anciennes réponses
|
||||
UserAnswer.objects.filter(user_quiz=user_quiz).delete()
|
||||
else:
|
||||
# Si non, créer une nouvelle entrée
|
||||
user_quiz = UserQuiz.objects.create(user=request.user, quiz=quiz)
|
||||
|
||||
score = 0
|
||||
for question in quiz.questions.all():
|
||||
choice_id = request.POST.get(f'question_{question.id}')
|
||||
if choice_id:
|
||||
choice = Choice.objects.get(id=choice_id)
|
||||
UserAnswer.objects.create(
|
||||
user_quiz=user_quiz,
|
||||
question=question,
|
||||
choice=choice
|
||||
)
|
||||
if choice.is_correct:
|
||||
score += 1
|
||||
|
||||
user_quiz.score = score
|
||||
user_quiz.save()
|
||||
return redirect('quiz_result', user_quiz_id=user_quiz.id)
|
||||
|
||||
return render(request, "games/quiz/quiz.html", {
|
||||
"quiz": quiz,
|
||||
"questions": quiz.questions.all()
|
||||
})
|
||||
|
||||
@login_required
|
||||
def result(request, user_quiz_id):
|
||||
user_quiz = get_object_or_404(UserQuiz, id=user_quiz_id, user=request.user)
|
||||
total_questions = user_quiz.quiz.questions.count()
|
||||
|
||||
# Vérifiez si l'utilisateur a déjà joué à ce quiz
|
||||
if not UserQuiz.objects.filter(user=request.user, quiz=user_quiz.quiz).exists():
|
||||
# Si c'est la première fois que l'on joue, alors on gagne 10 pièces d'or + 10 points d'expérience par réponse correcte
|
||||
inventory_item = UserInventory.objects.get(user=user_quiz.user, item=Item.objects.get(name='Or'))
|
||||
inventory_item.quantity += 10
|
||||
inventory_item.save()
|
||||
|
||||
user_level = request.user.level
|
||||
user_level.experience += 10 * user_quiz.score
|
||||
user_level.save()
|
||||
else:
|
||||
# Si l'utilisateur a déjà joué, ajoutez 1 point d'expérience par réponse correcte
|
||||
user_level = request.user.level
|
||||
user_level.experience += 1 * user_quiz.score
|
||||
user_level.save()
|
||||
|
||||
return render(request, "games/quiz/result.html", {
|
||||
"user_quiz": user_quiz,
|
||||
"total_questions": total_questions,
|
||||
"percentage": (user_quiz.score / total_questions) * 100 if total_questions > 0 else 0
|
||||
})
|
||||
|
||||
@login_required
|
||||
def create_quiz(request):
|
||||
form = QuizForm()
|
||||
if request.method == 'POST':
|
||||
quiz = Quiz.objects.create(author=request.user, name=request.POST.get('name'), description=request.POST.get('description'), is_active=False)
|
||||
return redirect('create_responses_quiz', quiz_id=quiz.id)
|
||||
|
||||
return render(request, "games/quiz/create_quiz.html", {"form": form})
|
||||
|
||||
@login_required
|
||||
def create_responses_quiz(request, quiz_id):
|
||||
quiz = get_object_or_404(Quiz, id=quiz_id, author=request.user)
|
||||
questions = quiz.questions.all()
|
||||
choices = []
|
||||
for question in questions:
|
||||
choices.append(question.choices.all())
|
||||
|
||||
form = QuestionForm()
|
||||
|
||||
if request.method == 'POST':
|
||||
# Parcourir les données POST pour trouver les questions et réponses
|
||||
for key in request.POST:
|
||||
if key.startswith('ask-'):
|
||||
question_text = request.POST[key]
|
||||
if question_text: # Vérifie si la question n'est pas vide
|
||||
# Créer la question
|
||||
question = Question.objects.create(
|
||||
quiz=quiz,
|
||||
question=question_text
|
||||
)
|
||||
|
||||
# Récupérer le numéro de la question depuis la clé
|
||||
question_num = key.split('-')[1]
|
||||
|
||||
# Chercher toutes les réponses associées à cette question
|
||||
response_prefix = f'response-{question_num}-'
|
||||
correct_response_key = f'is_correct-{question_num}'
|
||||
correct_response_value = request.POST.get(correct_response_key)
|
||||
|
||||
for response_key in request.POST:
|
||||
if response_key.startswith(response_prefix):
|
||||
response_text = request.POST[response_key]
|
||||
if response_text: # Vérifie si la réponse n'est pas vide
|
||||
response_num = response_key.split('-')[-1]
|
||||
is_correct = (response_num == correct_response_value)
|
||||
Choice.objects.create(
|
||||
question=question,
|
||||
choice=response_text,
|
||||
is_correct=is_correct # Par défaut, aucune réponse n'est correcte
|
||||
)
|
||||
|
||||
return redirect('create_responses_quiz', quiz.id) # Redirection vers la page d'accueil
|
||||
|
||||
return render(request, "games/quiz/create_responses_quiz.html", {"form": form, "quiz": quiz})
|
||||
Loading…
Add table
Add a link
Reference in a new issue