...
This commit is contained in:
@@ -1,11 +1,32 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
from content.models import Link, MediaFile, Question, QuestionVersion, Level, Label, SharedQuestion
|
from content.models import Link, MediaFile, Question, QuestionVersion, Level, Label, SharedQuestion, SubmittedQuestion
|
||||||
from lib.mixins import PermissionsAdminMixin
|
from lib.mixins import PermissionsAdminMixin
|
||||||
from lib.utils import color_label
|
from lib.utils import color_label
|
||||||
|
|
||||||
|
|
||||||
|
class ActiveFilter(admin.SimpleListFilter):
|
||||||
|
title = "Aktiv/Inaktiv"
|
||||||
|
parameter_name = 'released'
|
||||||
|
|
||||||
|
def lookups(self, request, model_admin):
|
||||||
|
return [
|
||||||
|
(1, 'Inaktiv'),
|
||||||
|
(0, 'Aktiv')
|
||||||
|
]
|
||||||
|
|
||||||
|
def queryset(self, request, queryset):
|
||||||
|
v = int(self.value() or -1)
|
||||||
|
if v == 1:
|
||||||
|
return queryset.filter(**{self.parameter_name: True})
|
||||||
|
elif v == 0:
|
||||||
|
return queryset.filter(**{self.parameter_name: False})
|
||||||
|
else:
|
||||||
|
return queryset.filter(**{self.parameter_name: False})
|
||||||
|
# return queryset
|
||||||
|
|
||||||
|
|
||||||
@admin.register(SharedQuestion)
|
@admin.register(SharedQuestion)
|
||||||
class SharedQuestionAdmin(admin.ModelAdmin):
|
class SharedQuestionAdmin(admin.ModelAdmin):
|
||||||
search_fields = ('user__username',)
|
search_fields = ('user__username',)
|
||||||
@@ -25,6 +46,11 @@ class LabelAdmin(PermissionsAdminMixin, admin.ModelAdmin):
|
|||||||
list_editable = ('color',)
|
list_editable = ('color',)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(SubmittedQuestion)
|
||||||
|
class SubmittedQuestionAdmin(admin.ModelAdmin):
|
||||||
|
list_filter = [ActiveFilter,]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Question)
|
@admin.register(Question)
|
||||||
class QuestionAdmin(PermissionsAdminMixin, admin.ModelAdmin):
|
class QuestionAdmin(PermissionsAdminMixin, admin.ModelAdmin):
|
||||||
autocomplete_fields = ('medias', 'links', 'labels', 'shares')
|
autocomplete_fields = ('medias', 'links', 'labels', 'shares')
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import csv
|
import csv
|
||||||
|
from datetime import datetime
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from colorfield.fields import ColorField
|
from colorfield.fields import ColorField
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.dispatch import receiver
|
|
||||||
from django.forms.models import model_to_dict
|
from django.forms.models import model_to_dict
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from filer.fields.file import FilerFileField
|
from filer.fields.file import FilerFileField
|
||||||
@@ -63,10 +63,55 @@ class SharedQuestion(SharedPermissionBase):
|
|||||||
abstract = False
|
abstract = False
|
||||||
|
|
||||||
|
|
||||||
|
class SubmittedQuestion(DateAware):
|
||||||
|
name = models.CharField(max_length=500, unique=True)
|
||||||
|
buzzword = models.CharField(max_length=25, null=True, blank=True)
|
||||||
|
question = models.TextField()
|
||||||
|
awnser = models.TextField()
|
||||||
|
level = models.ForeignKey(Level, on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
|
labels = models.ManyToManyField(Label, blank=True)
|
||||||
|
medias = models.ManyToManyField(MediaFile, blank=True)
|
||||||
|
links = models.ManyToManyField(Link, blank=True)
|
||||||
|
shares = models.ManyToManyField(SharedQuestion, blank=True)
|
||||||
|
|
||||||
|
release = models.BooleanField(default=False)
|
||||||
|
released = models.BooleanField(default=False)
|
||||||
|
released_at = models.DateTimeField(null=True,blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.name} (#{self.id})"
|
||||||
|
|
||||||
|
|
||||||
|
from django.db.models.signals import post_save
|
||||||
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=SubmittedQuestion)
|
||||||
|
def release_submitted(sender, instance: SubmittedQuestion, **kwargs):
|
||||||
|
if instance.release:
|
||||||
|
n = Question.objects.create(
|
||||||
|
name=instance.name,
|
||||||
|
buzzword=instance.buzzword,
|
||||||
|
question=instance.question,
|
||||||
|
awnser=instance.awnser,
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
n.labels.set(instance.labels.all())
|
||||||
|
n.level_id = instance.level_id
|
||||||
|
n.save()
|
||||||
|
except:
|
||||||
|
n.delete()
|
||||||
|
raise
|
||||||
|
instance.released = True
|
||||||
|
instance.release = False
|
||||||
|
instance.released_at = datetime.now()
|
||||||
|
instance.save()
|
||||||
|
|
||||||
|
|
||||||
class Question(DateAware, AuthorAware, PublishedAware, DescriptionAware):
|
class Question(DateAware, AuthorAware, PublishedAware, DescriptionAware):
|
||||||
name = models.CharField(max_length=500, unique=True, db_index=True)
|
name = models.CharField(max_length=500, unique=True, db_index=True)
|
||||||
question = models.TextField(db_index=True)
|
|
||||||
buzzword = models.CharField(max_length=25, null=True, blank=True)
|
buzzword = models.CharField(max_length=25, null=True, blank=True)
|
||||||
|
question = models.TextField(db_index=True)
|
||||||
awnser = models.TextField(db_index=True)
|
awnser = models.TextField(db_index=True)
|
||||||
level = models.ForeignKey(Level, on_delete=models.SET_NULL, null=True)
|
level = models.ForeignKey(Level, on_delete=models.SET_NULL, null=True)
|
||||||
labels = models.ManyToManyField(Label, blank=True)
|
labels = models.ManyToManyField(Label, blank=True)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
<i class="fa fa-search" onclick="document.getElementById('search_q_form').submit();"></i>
|
<i class="fa fa-search" onclick="document.getElementById('search_q_form').submit();"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
{# {{ form.captcha }} #}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
50
content/templates/submit-question.html
Normal file
50
content/templates/submit-question.html
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<style type="text/css" rel="stylesheet">
|
||||||
|
.form_wrapper label,
|
||||||
|
.form_wrapper legend {
|
||||||
|
display: block;
|
||||||
|
/*
|
||||||
|
float: left;
|
||||||
|
width: 25%;
|
||||||
|
*/
|
||||||
|
font-size: initial;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form_wrapper textarea,
|
||||||
|
.form_wrapper input {
|
||||||
|
display: block;
|
||||||
|
/*
|
||||||
|
float: left;
|
||||||
|
width: 74%;
|
||||||
|
*/
|
||||||
|
margin-bottom: 1em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form_wrapper fieldset input {
|
||||||
|
display: initial;
|
||||||
|
float: initial;
|
||||||
|
width: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form_wrapper fieldset {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% if messages %}
|
||||||
|
<ul class="messages">
|
||||||
|
{% for message in messages %}
|
||||||
|
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
<div class="form_wrapper">
|
||||||
|
<form method="post" action="?">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_div }}
|
||||||
|
<input type="submit" value="Submit" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -2,6 +2,7 @@ from django.urls.conf import path
|
|||||||
from content.views import public
|
from content.views import public
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
path('add-question/', public.submit_question, name='add-questions'),
|
||||||
path('questions/', public.search_question, name='search-questions'),
|
path('questions/', public.search_question, name='search-questions'),
|
||||||
path('questions/<int:id>/csv/', public.as_csv, name='csv-question'),
|
path('questions/<int:id>/csv/', public.as_csv, name='csv-question'),
|
||||||
path('', public.search_question, name='search-questions'),
|
path('', public.search_question, name='search-questions'),
|
||||||
|
|||||||
@@ -1,18 +1,64 @@
|
|||||||
|
from django import forms
|
||||||
from django.http import HttpResponseNotFound, HttpResponse, HttpResponseBadRequest
|
from django.http import HttpResponseNotFound, HttpResponse, HttpResponseBadRequest
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render, redirect
|
||||||
|
from simplemathcaptcha.fields import MathCaptchaField
|
||||||
|
|
||||||
from content.models import Question
|
from content.models import Question, SubmittedQuestion
|
||||||
|
|
||||||
|
|
||||||
|
class SearchForm(forms.Form):
|
||||||
|
term = forms.CharField(max_length=100)
|
||||||
|
# captcha = MathCaptchaField()
|
||||||
|
|
||||||
|
|
||||||
|
class SubmitQuestion(forms.Form):
|
||||||
|
name = forms.CharField(max_length=500, required=True)
|
||||||
|
buzzword = forms.CharField(max_length=150, required=False)
|
||||||
|
question = forms.CharField(max_length=100000, widget=forms.Textarea, required=True)
|
||||||
|
awnser = forms.CharField(max_length=100000, widget=forms.Textarea, required=True)
|
||||||
|
captcha = MathCaptchaField()
|
||||||
|
# level = forms.ForeignKey(Level, on_delete=models.SET_NULL, null=True)
|
||||||
|
# labels = forms.ManyToManyField(Label, blank=True)
|
||||||
|
# medias = forms.ManyToManyField(MediaFile, blank=True)
|
||||||
|
# links = forms.ManyToManyField(Link, blank=True)
|
||||||
|
# shares = forms.ManyToManyField(SharedQuestion, blank=True)
|
||||||
|
|
||||||
|
|
||||||
def search_question(request):
|
def search_question(request):
|
||||||
term = request.GET.get('term')
|
term = request.GET.get('term')
|
||||||
items = []
|
items = []
|
||||||
published = Question.objects.filter(is_published=True)
|
published = Question.objects.filter(is_published=True)
|
||||||
|
form = SearchForm(data=request.GET)
|
||||||
if term:
|
if term:
|
||||||
|
if form.is_valid():
|
||||||
items = Question.get_by_tearchterm(term, published)
|
items = Question.get_by_tearchterm(term, published)
|
||||||
|
form.term = term
|
||||||
|
else:
|
||||||
|
return redirect('/')
|
||||||
else:
|
else:
|
||||||
items = published.all()[:10]
|
items = published.all()[:10]
|
||||||
return render(request, 'questions.html', {'items': items})
|
return render(request, 'questions.html', {'form': SearchForm(), 'items': items})
|
||||||
|
|
||||||
|
from django.contrib import messages
|
||||||
|
|
||||||
|
def submit_question(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = SubmitQuestion(data=request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
subq = SubmittedQuestion.objects.create(
|
||||||
|
name=form.cleaned_data['name'],
|
||||||
|
buzzword=form.cleaned_data['buzzword'],
|
||||||
|
question=form.cleaned_data['question'],
|
||||||
|
awnser=form.cleaned_data['awnser'],
|
||||||
|
)
|
||||||
|
messages.info(request, f"Angelegt mit ID {subq.id}")
|
||||||
|
return render(request, 'submit-question.html', {'form': SubmitQuestion()})
|
||||||
|
else:
|
||||||
|
[messages.error(request,f'Error in {err}') for err in form.errors]
|
||||||
|
return render(request, 'submit-question.html', {'form': form})
|
||||||
|
else:
|
||||||
|
form = SubmitQuestion()
|
||||||
|
return render(request, 'submit-question.html', {'form': form})
|
||||||
|
|
||||||
|
|
||||||
def as_csv(request, **kwargs):
|
def as_csv(request, **kwargs):
|
||||||
|
|||||||
@@ -15,4 +15,5 @@ django-jazzmin
|
|||||||
requests
|
requests
|
||||||
django-rest-swagger
|
django-rest-swagger
|
||||||
drf-yasg
|
drf-yasg
|
||||||
|
django-simple-math-captcha
|
||||||
django-guardian
|
django-guardian
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ INSTALLED_APPS = [
|
|||||||
'colorfield',
|
'colorfield',
|
||||||
'filer',
|
'filer',
|
||||||
'rest_framework_swagger',
|
'rest_framework_swagger',
|
||||||
|
'simplemathcaptcha',
|
||||||
# 'guardian',
|
# 'guardian',
|
||||||
'api',
|
'api',
|
||||||
'content',
|
'content',
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
<nav style="vertical-align: bottom; width: auto; justify-content: flex-end" class="navbar right">
|
<nav style="vertical-align: bottom; width: auto; justify-content: flex-end" class="navbar right">
|
||||||
<a class="nav-item p-3 btn btn-outline-dark mx-2" href="/questions/">Questions</a>
|
<a class="nav-item p-3 btn btn-outline-dark mx-2" href="/questions/">Questions</a>
|
||||||
<a class="nav-item p-3 btn btn-outline-dark mx-2" href="/quizes/">Quizes</a>
|
<a class="nav-item p-3 btn btn-outline-dark mx-2" href="/quizes/">Quizes</a>
|
||||||
|
<a class="nav-item p-3 btn btn-outline-success mx-2" href="/add-question/">Submit a Question</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user