Skip to content

Commit

Permalink
Merge pull request #345 from MAKENTNU/feature/faq-categories-admin
Browse files Browse the repository at this point in the history
Added categories on admin page
  • Loading branch information
ddabble committed Oct 29, 2021
2 parents 4c5fe51 + 0ae0d1f commit ae2d774
Show file tree
Hide file tree
Showing 20 changed files with 336 additions and 77 deletions.
8 changes: 7 additions & 1 deletion faq/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.utils.translation import gettext_lazy as _

from web.widgets import SemanticMultipleSelectInput
from .models import Question
from .models import Category, Question


class QuestionForm(forms.ModelForm):
Expand All @@ -12,3 +12,9 @@ class Meta:
widgets = {
'categories': SemanticMultipleSelectInput(prompt_text=_("Choose categories")),
}


class CategoryForm(forms.ModelForm):
class Meta:
model = Category
fields = '__all__'
15 changes: 15 additions & 0 deletions faq/models.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
from django.db import models
from django.db.models import Prefetch
from django.utils.translation import gettext_lazy as _

from web.multilingual.modelfields import MultiLingualRichTextUploadingField, MultiLingualTextField


class CategoryQuerySet(models.QuerySet):

def prefetch_questions_and_default_order_by(self, *, questions_attr_name: str):
"""
Returns a ``QuerySet`` where all the categories' questions have been prefetched
and can be accessed through the attribute with the same name as ``questions_attr_name``.
"""
return self.order_by('name').prefetch_related(
Prefetch('questions', queryset=Question.objects.order_by('title'), to_attr=questions_attr_name)
)


class Category(models.Model):
name = MultiLingualTextField(unique=True, verbose_name=_("Category"))

objects = CategoryQuerySet.as_manager()

class Meta:
verbose_name = _("Category")
verbose_name_plural = _("Categories")
Expand Down
3 changes: 3 additions & 0 deletions faq/static/faq/css/admin_category_list.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#page-title {
margin-bottom: 1.5em;
}
3 changes: 3 additions & 0 deletions faq/static/faq/css/admin_question_list.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#page-title {
margin-bottom: 1.5em;
}
13 changes: 4 additions & 9 deletions faq/static/faq/css/faq_list.css
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
#outer-accordion {
width: 100%;
font-size: 150%;
}

.ui.accordion .title:not(.ui) {
display: flex;
#page-title {
margin-bottom: 2em;
}

#page-title {
margin-bottom: 5%;
.questions.accordion .content .button {
margin: -1em 0 1em;
}
6 changes: 6 additions & 0 deletions faq/templates/faq/admin_category_create.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{% extends 'faq/admin_category_edit.html' %}
{% load i18n %}


{% block title %}{% trans "New Category" %}{% endblock title %}
{% block form_header %}{% trans "New Category" %}{% endblock form_header %}
31 changes: 31 additions & 0 deletions faq/templates/faq/admin_category_edit.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{% extends 'web/base.html' %}
{% load static %}
{% load i18n %}


{% block title %}{% trans "Edit Category" %}{% endblock title %}

{% block extra_head %}
<script src="{% static 'ckeditor/ckeditor-init.js' %}"></script>
<script src="{% static 'ckeditor/ckeditor/ckeditor.js' %}"></script>
{% endblock extra_head %}

{% block body %}
<h1 class="ui centered header">
{% block form_header %}{% trans "Edit Category" %}{% endblock form_header %}
</h1>
<form class="ui form text container" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.non_field_errors }}

<div class="field">
<label>{{ form.name.label }}</label>
{{ form.name }}
</div>

<input class="ui make-bg-yellow right floated submit button" type="submit" value="{% trans "Save" %}"/>
<a class="ui right floated red button" href="{% url 'admin_category_list' %}">
{% trans "Cancel" context "abort action" %}
</a>
</form>
{% endblock body %}
53 changes: 53 additions & 0 deletions faq/templates/faq/admin_category_list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{% extends 'web/base.html' %}
{% load static %}
{% load i18n %}


{% block title %}{% trans "Categories" %}{% endblock title %}

{% block extra_head %}
<link rel="stylesheet" href="{% static 'faq/css/admin_category_list.css' %}"/>
{% endblock extra_head %}

{% block body %}
<div class="ui container">

<h1 id="page-title" class="ui header">
<a href="{% url 'faq_admin_panel' %}">
<i class="blue chevron circle left icon"></i>
</a>
{% trans "Categories" %}
{% if perms.faq.add_category %}
<a href="{% url 'category_create' %}">
<i class="green plus icon"></i>
</a>
{% endif %}
</h1>

<div class="ui relaxed divided list">
{% for category in categories %}
<div class="item">
<div class="content">
<div class="ui header">
{{ category.name }}
{% if perms.faq.change_category %}
<a href="{% url 'category_update' category.pk %}">
<i class="make-col-yellow pencil icon"></i>
</a>
{% endif %}

{% if perms.faq.delete_category %}
<a class="delete-modal-button"
data-url="{% url 'category_delete' category.pk %}"
data-obj-name="{{ category }}">
<i class="large red delete icon"></i>
</a>
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>

</div>
{% endblock body %}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% extends 'faq/question_edit.html' %}
{% extends 'faq/admin_question_edit.html' %}
{% load i18n %}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ <h1 class="ui centered header">
<div class="field">
<label>{{ form.categories.label }}
<span data-content="{% trans "Choose one or more categories" %}.">
<i class="ui make-col-yellow question circle icon"></i>
<i class="make-col-yellow question circle icon"></i>
</span>
</label>
{{ form.categories }}
</div>

<input class="ui right floated make-bg-yellow submit button" type="submit" value="{% trans "Save" %}"/>
<a class="ui right floated red button" href="{% url 'faq_admin_list' %}">
<a class="ui right floated red button" href="{% url 'admin_question_list' %}">
{% trans "Cancel" context "abort action" %}
</a>
</form>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,49 @@
{% extends 'web/base.html' %}
{% load static %}
{% load i18n %}


{% block title %}{% trans "Questions" %}{% endblock title %}

{% block extra_head %}
<link rel="stylesheet" href="{% static 'faq/css/admin_question_list.css' %}"/>
{% endblock extra_head %}

{% block body %}
<div class="ui container">

<h1>
<h1 id="page-title" class="ui header">
<a href="{% url 'faq_admin_panel' %}">
<i class="blue chevron circle left icon"></i>
</a>
{% trans "Questions" %}
{% if perms.faq.add_question %}
<a href="{% url 'faq_create' %}">
<a href="{% url 'question_create' %}">
<i class="green plus icon"></i>
</a>
{% endif %}
</h1>

<div class="ui relaxed divided list">
{% for question in questions %}
<div class="item">
<div class="content">
<div class="ui header">
{{ question.title }}
{% if perms.faq.change_question %}
<a href="{% url 'faq_edit' pk=question.pk %}">
<a href="{% url 'question_update' question.pk %}">
<i class="make-col-yellow pencil icon"></i>
</a>
{% endif %}

{% if perms.faq.delete_question %}
<a class="delete-modal-button"
data-url="{% url 'faq_delete' question.pk %}"
data-url="{% url 'question_delete' question.pk %}"
data-obj-name="{{ question }}">
<i class="large red delete icon"></i>
</a>
{% endif %}
</div>
<div class="description">{{ question.answer|safe }}</div>
</div>
</div>
{% endfor %}
Expand Down
42 changes: 42 additions & 0 deletions faq/templates/faq/faq_admin_panel.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{% extends 'web/base.html' %}
{% load static %}
{% load i18n %}
{% load permission_tags %}


{% block title %}{% trans "FAQ Admin Panel" %}{% endblock title %}

{% block body %}
<div class="ui container">
<h1 class="ui header">
<a href="{% url 'adminpanel' %}">
<i class="blue chevron circle left icon"></i>
</a>
{% trans "FAQ Admin Panel" %}
</h1>
<div class="ui four doubling stackable cards">
<div class="ui yellow card">
<a class="content" href="{% url 'admin_question_list' %}">
<div class="center aligned header">
<i class="grey question circle outline icon"></i>
{% trans "Questions" %}
</div>
<div class="description">
{% trans "Here you can create, edit and delete questions" %}.
</div>
</a>
</div>
<div class="ui yellow card">
<a class="content" href="{% url 'admin_category_list' %}">
<div class="center aligned header">
<i class="grey newspaper outline icon"></i>
{% trans "Categories" %}
</div>
<div class="description">
{% trans "Here you can create, edit and delete categories" %}.
</div>
</a>
</div>
</div>
</div>
{% endblock body %}
31 changes: 20 additions & 11 deletions faq/templates/faq/faq_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
{% load static %}


{% block title %}{% trans "Frequently Asked Questions" %}{% endblock title %}

{% block extra_head %}
<link rel="stylesheet" href="{% static 'faq/css/faq_list.css' %}"/>
{% endblock extra_head %}
Expand All @@ -12,23 +14,30 @@
<h1 id="page-title" class="ui text-centered make-col-blue header">
{% trans "Frequently Asked Questions" %}
</h1>
<div id="outer-accordion" class="ui styled accordion">
<div class="categories ui styled fluid accordion">
{% for category in categories %}
<div class="active title">
<i class="dropdown icon"></i>
<p>
<div class="title">
<div class="ui header">
<i class="dropdown icon"></i>
{{ category.name }}
</p>
</div>
</div>
<div class="content">
{# The content of the outer accordion contains another accordion. It makes the accordion nested #}
<div class="styled accordion">
{% for question in category.questions.all %}
<div class="active title">
<i class="dropdown icon"></i>
<div class="make-col-blue">{{ question.title }}</div>
<div class="questions styled fluid accordion">
{% for question in category.existing_questions %}
<div class="title">
<div class="ui make-col-blue header">
<i class="dropdown icon"></i>
{{ question.title }}
</div>
</div>
<div class="content">
{% if perms.faq.change_question %}
<a class="ui make-bg-yellow button" href="{% url 'question_update' question.pk %}">
<i class="edit icon"></i>{% trans "Edit" %}
</a>
{% endif %}
{{ question.answer|safe }}
</div>
{% endfor %}
Expand All @@ -42,6 +51,6 @@ <h1 id="page-title" class="ui text-centered make-col-blue header">

{% block extra_scripts %}
<script>
$('.ui.accordion').accordion();
$(".ui.accordion").accordion();
</script>
{% endblock extra_scripts %}
14 changes: 11 additions & 3 deletions faq/tests/test_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class UrlTests(TestCase):
def setUp(self):
self.category1 = Category.objects.create(name="Category 1")
self.category2 = Category.objects.create(name="Category 2")
self.categories = (self.category1, self.category2)

self.question1 = Question.objects.create(title="Question 1", answer="Answer to question 1!")
self.question1.categories.add(self.category1)
Expand All @@ -21,11 +22,18 @@ def setUp(self):
def test_all_get_request_paths_succeed(self):
path_predicates = [
Get(reverse('faq_list'), public=True),
Get(reverse('faq_admin_list'), public=False),
Get(reverse('faq_create'), public=False),
Get(reverse('faq_admin_panel'), public=False),
Get(reverse('admin_question_list'), public=False),
Get(reverse('question_create'), public=False),
*[
Get(reverse('faq_edit', kwargs={'pk': question.pk}), public=False)
Get(reverse('question_update', kwargs={'pk': question.pk}), public=False)
for question in self.questions
],
Get(reverse('admin_category_list'), public=False),
Get(reverse('category_create'), public=False),
*[
Get(reverse('category_update', kwargs={'pk': category.pk}), public=False)
for category in self.categories
],
]
assert_requesting_paths_succeeds(self, path_predicates)
13 changes: 9 additions & 4 deletions faq/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@

urlpatterns = [
path("", views.FAQListView.as_view(), name='faq_list'),
path("admin/", login_required(views.FAQAdminListView.as_view()), name='faq_admin_list'),
path("admin/create/", login_required(views.FAQCreateView.as_view()), name='faq_create'),
path("admin/<int:pk>/edit/", login_required(views.FAQEditView.as_view()), name='faq_edit'),
path("admin/<int:pk>/delete/", login_required(views.FAQDeleteView.as_view()), name='faq_delete'),
path("admin/", login_required(views.FAQAdminPanelView.as_view()), name='faq_admin_panel'),
path("admin/questions/", login_required(views.AdminQuestionListView.as_view()), name='admin_question_list'),
path("admin/questions/add/", login_required(views.QuestionCreateView.as_view()), name='question_create'),
path("admin/questions/<int:pk>/change/", login_required(views.QuestionUpdateView.as_view()), name='question_update'),
path("admin/questions/<int:pk>/delete/", login_required(views.QuestionDeleteView.as_view()), name='question_delete'),
path("admin/categories/", login_required(views.AdminCategoryListView.as_view()), name='admin_category_list'),
path("admin/categories/add/", login_required(views.CategoryCreateView.as_view()), name='category_create'),
path("admin/categories/<int:pk>/change/", login_required(views.CategoryUpdateView.as_view()), name='category_update'),
path("admin/categories/<int:pk>/delete/", login_required(views.CategoryDeleteView.as_view()), name='category_delete'),
]
Loading

0 comments on commit ae2d774

Please sign in to comment.