CRUD Operations for Library models
This commit is contained in:
@@ -22,4 +22,5 @@ urlpatterns = [
|
|||||||
path('account/', include('accounts.urls')),
|
path('account/', include('accounts.urls')),
|
||||||
path('', include('homepage.urls')),
|
path('', include('homepage.urls')),
|
||||||
path('play/', include('components.urls')),
|
path('play/', include('components.urls')),
|
||||||
|
path('library/', include('library.urls')),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -8,3 +8,39 @@ a.qp-a-button {
|
|||||||
@apply p-6 rounded-md font-extrabold hover:scale-105 transition duration-300 shadow-md;
|
@apply p-6 rounded-md font-extrabold hover:scale-105 transition duration-300 shadow-md;
|
||||||
}
|
}
|
||||||
.register input{@apply p-3 rounded-full bg-gray-200 focus:scale-105 transition duration-200 font-black;}
|
.register input{@apply p-3 rounded-full bg-gray-200 focus:scale-105 transition duration-200 font-black;}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
@apply flex flex-col gap-4 max-w-md mx-auto p-6 bg-white rounded-xl shadow-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group form {
|
||||||
|
@apply flex flex-col gap-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group form p {
|
||||||
|
@apply flex flex-col gap-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group form p label {
|
||||||
|
@apply text-gray-900 font-semibold text-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group form p input {
|
||||||
|
@apply p-3 rounded-full bg-gray-200 focus:scale-105 transition duration-200 font-black
|
||||||
|
focus:outline-none focus:ring-2 focus:ring-blue-400 focus:bg-blue-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group form p select {
|
||||||
|
@apply p-3 rounded-md bg-gray-200 focus:scale-105 transition duration-200 font-black
|
||||||
|
focus:outline-none focus:ring-2 focus:ring-blue-400 focus:bg-blue-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group form p textarea {
|
||||||
|
@apply p-3 rounded-xl bg-gray-200 focus:scale-105 transition duration-200 font-black
|
||||||
|
focus:outline-none focus:ring-2 focus:ring-blue-400 focus:bg-blue-100 min-h-[100px];
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group form p button {
|
||||||
|
@apply p-3 rounded-full bg-indigo-500 hover:bg-indigo-600 text-white focus:scale-105
|
||||||
|
transition duration-200 font-black shadow-md hover:shadow-lg;
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
|||||||
<div class="absolute bottom-0 grid place-content-center gap-2 w-full">
|
<div class="absolute bottom-0 sticky grid place-content-center gap-2 w-full">
|
||||||
<div class="flex space-x-2 pb-4">
|
<div class="flex space-x-2 pb-4">
|
||||||
<p class="text-sm font-extralight"><a href="#">Impressum</a></p>
|
<p class="text-sm font-extralight"><a href="#">Impressum</a></p>
|
||||||
<p class="text-sm font-extralight"><a href="#">Datenschutz</a></p>
|
<p class="text-sm font-extralight"><a href="#">Datenschutz</a></p>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<ul class="flex space-x-4 qp-nav-list">
|
<ul class="flex space-x-4 qp-nav-list">
|
||||||
<li><a href="#">Bibliothek</a></li>
|
<li><a href="{% url 'library:overview_quiz' %}">Bibliothek</a></li>
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<li><a href="{% url 'accounts:home' %}">Konto</a></li>
|
<li><a href="{% url 'accounts:home' %}">Konto</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
12
core/library/forms.py
Normal file
12
core/library/forms.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from django import forms
|
||||||
|
from .models import QivipQuiz, QivipQuestion
|
||||||
|
|
||||||
|
class QuizForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = QivipQuiz
|
||||||
|
fields = ['name', 'description', 'status', 'category', 'tags']
|
||||||
|
|
||||||
|
class QuestionForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = QivipQuestion
|
||||||
|
fields = ['quiz_id', 'data']
|
||||||
@@ -9,7 +9,9 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% include 'homepage/partials/_nav.html' %}
|
{% include 'homepage/partials/_nav.html' %}
|
||||||
{% block content%}{% endblock %}
|
<div class="max-w-screen-lg mx-auto">
|
||||||
|
{% block content%}{% endblock %}
|
||||||
|
</div>
|
||||||
{% include 'homepage/partials/_footer.html' %}
|
{% include 'homepage/partials/_footer.html' %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
11
core/library/templates/library/delete_confirmation.html
Normal file
11
core/library/templates/library/delete_confirmation.html
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'library/base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Löschen</h1>
|
||||||
|
<p>Soll das Quiz "{{ object.name }}" wirklich gelöscht werden?</p>
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button type="submit">Löschen</button>
|
||||||
|
<a href="{% url 'library:overview_quiz' %}">Abbrechen</a>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
19
core/library/templates/library/detail_quiz.html
Normal file
19
core/library/templates/library/detail_quiz.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{% extends 'library/base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{{ quiz.name }}</h1>
|
||||||
|
<p>{{ quiz.description }}</p>
|
||||||
|
<a href="{% url 'library:edit_quiz' quiz.id %}">Bearbeiten</a>
|
||||||
|
<a href="{% url 'library:delete_quiz' quiz.id %}">Löschen</a>
|
||||||
|
|
||||||
|
<h2>Fragen</h2>
|
||||||
|
<ul>
|
||||||
|
<a href="{% url 'library:new_question' %}">Neue Frage erstellen</a>
|
||||||
|
{% for question in questions %}
|
||||||
|
<li>{{ question.data }}</li>
|
||||||
|
<a href="{% url 'library:edit_question' question.id %}">Bearbeiten</a>
|
||||||
|
<a href="{% url 'library:delete_question' question.id %}">Löschen</a>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
13
core/library/templates/library/form.html
Normal file
13
core/library/templates/library/form.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{% extends 'library/base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Formular</h1>
|
||||||
|
<h2>{{ form.name.value }}</h2>
|
||||||
|
<div class="input-group">
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<button type="submit">Speichern</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
19
core/library/templates/library/overview_quiz.html
Normal file
19
core/library/templates/library/overview_quiz.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{% extends 'library/base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Übersicht</h1>
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<a href="{% url 'library:new_quiz' %}" class="bg-blue-500 text-white px-4 py-2 rounded-md">Neues Quiz erstellen</a>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
|
{% for quiz in quizzes %}
|
||||||
|
<div class="bg-white rounded-lg p-4 shadow-md">
|
||||||
|
<h2 class="text-lg font-bold"><a href="{% url 'library:detail_quiz' quiz.id %}">{{ quiz.name }}</a></h2>
|
||||||
|
<p class="text-sm text-gray-600">{{ quiz.description }}</p>
|
||||||
|
<a href="#">Spiel starten</a>
|
||||||
|
<a href="{% url 'library:edit_quiz' quiz.id %}">Bearbeiten</a>
|
||||||
|
<a href="{% url 'library:delete_quiz' quiz.id %}">Löschen</a>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
15
core/library/urls.py
Normal file
15
core/library/urls.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
app_name = 'library'
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('', views.overview_quiz, name='overview_quiz'),
|
||||||
|
path('new/', views.new_quiz, name='new_quiz'),
|
||||||
|
path('edit/<int:pk>/', views.edit_quiz, name='edit_quiz'),
|
||||||
|
path('delete/<int:pk>/', views.delete_quiz, name='delete_quiz'),
|
||||||
|
path('detail/<int:pk>/', views.detail_quiz, name='detail_quiz'), # Hier werden Fragen gelistet (Quiz-Spezifisch)
|
||||||
|
path('question/new/', views.new_question, name='new_question'),
|
||||||
|
path('question/edit/<int:pk>/', views.edit_question, name='edit_question'),
|
||||||
|
path('question/delete/<int:pk>/', views.delete_question, name='delete_question'),
|
||||||
|
]
|
||||||
@@ -1,3 +1,99 @@
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from .models import QivipQuiz, QivipQuestion
|
||||||
|
from .forms import QuizForm, QuestionForm
|
||||||
|
|
||||||
# Create your views here.
|
# Übersicht aller Quizze
|
||||||
|
@login_required
|
||||||
|
def overview_quiz(request):
|
||||||
|
quizzes = QivipQuiz.objects.filter(user_id=request.user)
|
||||||
|
return render(request, 'library/overview_quiz.html', {'quizzes': quizzes})
|
||||||
|
|
||||||
|
# Neues Quiz erstellen
|
||||||
|
@login_required
|
||||||
|
def new_quiz(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = QuizForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
quiz = form.save(commit=False)
|
||||||
|
quiz.user_id = request.user
|
||||||
|
quiz.save()
|
||||||
|
form.save_m2m() # Speichert die Many-to-Many Beziehungen (Tags)
|
||||||
|
return redirect('library:edit_quiz', pk=quiz.pk)
|
||||||
|
else:
|
||||||
|
form = QuizForm()
|
||||||
|
return render(request, 'library/form.html', {'form': form})
|
||||||
|
|
||||||
|
# Quiz bearbeiten
|
||||||
|
@login_required
|
||||||
|
def edit_quiz(request, pk):
|
||||||
|
quiz = get_object_or_404(QivipQuiz, pk=pk, user_id=request.user)
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = QuizForm(request.POST, instance=quiz)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
return redirect('library:overview_quiz')
|
||||||
|
else:
|
||||||
|
form = QuizForm(instance=quiz)
|
||||||
|
return render(request, 'library/form.html', {'form': form})
|
||||||
|
|
||||||
|
# Quiz löschen
|
||||||
|
@login_required
|
||||||
|
def delete_quiz(request, pk):
|
||||||
|
quiz = get_object_or_404(QivipQuiz, pk=pk, user_id=request.user)
|
||||||
|
if request.method == 'POST':
|
||||||
|
quiz.delete()
|
||||||
|
return redirect('library:overview_quiz')
|
||||||
|
return render(request, 'library/delete_confirmation.html', {'object': quiz})
|
||||||
|
|
||||||
|
# Quiz anzeigen
|
||||||
|
@login_required
|
||||||
|
def detail_quiz(request, pk):
|
||||||
|
quiz = get_object_or_404(QivipQuiz, pk=pk, user_id=request.user)
|
||||||
|
questions = QivipQuestion.objects.filter(quiz_id=quiz)
|
||||||
|
return render(request, 'library/detail_quiz.html', {'quiz': quiz, 'questions': questions})
|
||||||
|
|
||||||
|
# Übersicht aller Fragen
|
||||||
|
@login_required
|
||||||
|
def question_list(request):
|
||||||
|
questions = QivipQuestion.objects.filter(quiz_id__user_id=request.user)
|
||||||
|
return render(request, 'library/question_list.html', {'questions': questions})
|
||||||
|
|
||||||
|
# Neue Frage erstellen
|
||||||
|
@login_required
|
||||||
|
def new_question(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = QuestionForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
question = form.save(commit=False)
|
||||||
|
# Prüfe ob der User Zugriff auf das Quiz hat
|
||||||
|
if question.quiz_id.user_id != request.user:
|
||||||
|
return redirect('library:question_list')
|
||||||
|
question.save()
|
||||||
|
return redirect('library:edit_question', pk=question.pk)
|
||||||
|
else:
|
||||||
|
form = QuestionForm()
|
||||||
|
return render(request, 'library/form.html', {'form': form})
|
||||||
|
|
||||||
|
# Frage bearbeiten
|
||||||
|
@login_required
|
||||||
|
def edit_question(request, pk):
|
||||||
|
question = get_object_or_404(QivipQuestion, pk=pk, quiz_id__user_id=request.user)
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = QuestionForm(request.POST, instance=question)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
return redirect('library:edit_question', pk=pk)
|
||||||
|
else:
|
||||||
|
form = QuestionForm(instance=question)
|
||||||
|
return render(request, 'library/form.html', {'form': form})
|
||||||
|
|
||||||
|
# Frage löschen
|
||||||
|
@login_required
|
||||||
|
def delete_question(request, pk):
|
||||||
|
question = get_object_or_404(QivipQuestion, pk=pk, quiz_id__user_id=request.user)
|
||||||
|
if request.method == 'POST':
|
||||||
|
question.delete()
|
||||||
|
return redirect('library:detail_quiz', pk=question.quiz_id.pk)
|
||||||
|
return render(request, 'library/delete_confirmation.html', {'object': question})
|
||||||
|
|||||||
Reference in New Issue
Block a user