From 87b9eb358194a96a816f0914ff63739b1f0dedb9 Mon Sep 17 00:00:00 2001 From: Joh Dokler Date: Wed, 24 Nov 2021 16:08:53 +0100 Subject: [PATCH] FAQ management app and API (#46) --- sledilnik/faq/__init__.py | 0 sledilnik/faq/admin.py | 18 ++++++++ sledilnik/faq/api.py | 35 +++++++++++++++ sledilnik/faq/apps.py | 5 +++ sledilnik/faq/migrations/0001_initial.py | 45 +++++++++++++++++++ .../faq/migrations/0002_auto_20211124_1414.py | 34 ++++++++++++++ .../faq/migrations/0003_auto_20211124_1424.py | 21 +++++++++ .../faq/migrations/0004_auto_20211124_1515.py | 23 ++++++++++ sledilnik/faq/migrations/__init__.py | 0 sledilnik/faq/models.py | 27 +++++++++++ sledilnik/faq/tests.py | 3 ++ sledilnik/faq/translation.py | 12 +++++ sledilnik/faq/views.py | 3 ++ sledilnik/settings/base.py | 1 + sledilnik/urls.py | 6 ++- 15 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 sledilnik/faq/__init__.py create mode 100644 sledilnik/faq/admin.py create mode 100644 sledilnik/faq/api.py create mode 100644 sledilnik/faq/apps.py create mode 100644 sledilnik/faq/migrations/0001_initial.py create mode 100644 sledilnik/faq/migrations/0002_auto_20211124_1414.py create mode 100644 sledilnik/faq/migrations/0003_auto_20211124_1424.py create mode 100644 sledilnik/faq/migrations/0004_auto_20211124_1515.py create mode 100644 sledilnik/faq/migrations/__init__.py create mode 100644 sledilnik/faq/models.py create mode 100644 sledilnik/faq/tests.py create mode 100644 sledilnik/faq/translation.py create mode 100644 sledilnik/faq/views.py diff --git a/sledilnik/faq/__init__.py b/sledilnik/faq/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sledilnik/faq/admin.py b/sledilnik/faq/admin.py new file mode 100644 index 0000000..4dc2a6a --- /dev/null +++ b/sledilnik/faq/admin.py @@ -0,0 +1,18 @@ +from adminsortable2.admin import SortableInlineAdminMixin +from modeltranslation.admin import TranslationStackedInline + +from django.contrib import admin + +from sledilnik.utils import TranslationAdmin + +from . import models + + +class FaqInline(SortableInlineAdminMixin, TranslationStackedInline): + model = models.Faq + extra = 0 + + +@admin.register(models.Project) +class ProjectAdmin(TranslationAdmin): + inlines = [FaqInline] diff --git a/sledilnik/faq/api.py b/sledilnik/faq/api.py new file mode 100644 index 0000000..8d82d89 --- /dev/null +++ b/sledilnik/faq/api.py @@ -0,0 +1,35 @@ +from tastypie import fields +from tastypie.resources import ModelResource +from tastypie.cache import SimpleCache + +from django.conf import settings +from django.utils import translation + +from .models import Project, Faq + + +class FaqResource(ModelResource): + class Meta: + queryset = Faq.objects.all() + fields = ["position", "question", "answer"] + cache = SimpleCache(timeout=60, public=True) + + +class FaqProjectResource(ModelResource): + faq = fields.ToManyField(FaqResource, "faqs", full=True) + + class Meta: + resource_name = "faq" + queryset = Project.objects.all() + fields = ["id", "name"] + allowed_methods = ["get"] + cache = SimpleCache(timeout=60, public=True) + + def dehydrate(self, bundle): + lang = bundle.request.GET.get("lang") + + if lang not in [lng[0] for lng in settings.LANGUAGES]: + lang = settings.LANGUAGE_CODE + translation.activate(lang) + + return bundle diff --git a/sledilnik/faq/apps.py b/sledilnik/faq/apps.py new file mode 100644 index 0000000..adcba72 --- /dev/null +++ b/sledilnik/faq/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class FaqConfig(AppConfig): + name = 'faq' diff --git a/sledilnik/faq/migrations/0001_initial.py b/sledilnik/faq/migrations/0001_initial.py new file mode 100644 index 0000000..666a169 --- /dev/null +++ b/sledilnik/faq/migrations/0001_initial.py @@ -0,0 +1,45 @@ +# Generated by Django 3.1.7 on 2021-11-24 13:01 + +from django.db import migrations, models +import django.db.models.deletion +import sledilnik.easymde.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Project', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100, unique=True, verbose_name='Project name')), + ('name_sl', models.CharField(max_length=100, null=True, unique=True, verbose_name='Project name')), + ('name_en', models.CharField(max_length=100, null=True, unique=True, verbose_name='Project name')), + ], + options={ + 'ordering': ['name'], + }, + ), + migrations.CreateModel( + name='Faq', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('position', models.PositiveIntegerField(default=0, verbose_name='Position')), + ('question', models.CharField(max_length=500, verbose_name='Question')), + ('question_sl', models.CharField(max_length=500, null=True, verbose_name='Question')), + ('question_en', models.CharField(max_length=500, null=True, verbose_name='Question')), + ('answer', sledilnik.easymde.models.MarkdownField(verbose_name='Answer')), + ('answer_sl', sledilnik.easymde.models.MarkdownField(null=True, verbose_name='Answer')), + ('answer_en', sledilnik.easymde.models.MarkdownField(null=True, verbose_name='Answer')), + ('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='faq.project', verbose_name='Project')), + ], + options={ + 'ordering': ['position'], + }, + ), + ] diff --git a/sledilnik/faq/migrations/0002_auto_20211124_1414.py b/sledilnik/faq/migrations/0002_auto_20211124_1414.py new file mode 100644 index 0000000..c2edc04 --- /dev/null +++ b/sledilnik/faq/migrations/0002_auto_20211124_1414.py @@ -0,0 +1,34 @@ +# Generated by Django 3.1.7 on 2021-11-24 13:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('faq', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='project', + name='slug', + field=models.SlugField(default='', help_text='Used to query the API', max_length=100, unique=True, verbose_name='Slug'), + preserve_default=False, + ), + migrations.AlterField( + model_name='project', + name='name', + field=models.CharField(max_length=100, unique=True, verbose_name='Name'), + ), + migrations.AlterField( + model_name='project', + name='name_en', + field=models.CharField(max_length=100, null=True, unique=True, verbose_name='Name'), + ), + migrations.AlterField( + model_name='project', + name='name_sl', + field=models.CharField(max_length=100, null=True, unique=True, verbose_name='Name'), + ), + ] diff --git a/sledilnik/faq/migrations/0003_auto_20211124_1424.py b/sledilnik/faq/migrations/0003_auto_20211124_1424.py new file mode 100644 index 0000000..7cedfb5 --- /dev/null +++ b/sledilnik/faq/migrations/0003_auto_20211124_1424.py @@ -0,0 +1,21 @@ +# Generated by Django 3.1.7 on 2021-11-24 13:24 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('faq', '0002_auto_20211124_1414'), + ] + + operations = [ + migrations.RemoveField( + model_name='project', + name='name_en', + ), + migrations.RemoveField( + model_name='project', + name='name_sl', + ), + ] diff --git a/sledilnik/faq/migrations/0004_auto_20211124_1515.py b/sledilnik/faq/migrations/0004_auto_20211124_1515.py new file mode 100644 index 0000000..ea8e8a8 --- /dev/null +++ b/sledilnik/faq/migrations/0004_auto_20211124_1515.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1.7 on 2021-11-24 14:15 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('faq', '0003_auto_20211124_1424'), + ] + + operations = [ + migrations.RemoveField( + model_name='project', + name='slug', + ), + migrations.AlterField( + model_name='faq', + name='project', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='faqs', to='faq.project', verbose_name='Project'), + ), + ] diff --git a/sledilnik/faq/migrations/__init__.py b/sledilnik/faq/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sledilnik/faq/models.py b/sledilnik/faq/models.py new file mode 100644 index 0000000..0bc26e7 --- /dev/null +++ b/sledilnik/faq/models.py @@ -0,0 +1,27 @@ +from django.db import models +from django.utils.translation import gettext_lazy as _ +from sledilnik.easymde.models import MarkdownField + + +class Project(models.Model): + name = models.CharField(_("Name"), max_length=100, unique=True) + + class Meta: + ordering = ["name"] + + def __str__(self): + return self.name + + +class Faq(models.Model): + project = models.ForeignKey(Project, verbose_name=_("Project"), on_delete=models.CASCADE, related_name="faqs") + position = models.PositiveIntegerField(_("Position"), default=0, null=False, blank=False) + + question = models.CharField(_("Question"), max_length=500) + answer = MarkdownField(_("Answer")) + + class Meta: + ordering = ["position"] + + def __str__(self): + return self.question diff --git a/sledilnik/faq/tests.py b/sledilnik/faq/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/sledilnik/faq/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/sledilnik/faq/translation.py b/sledilnik/faq/translation.py new file mode 100644 index 0000000..b1e3f1c --- /dev/null +++ b/sledilnik/faq/translation.py @@ -0,0 +1,12 @@ +from modeltranslation.translator import register, TranslationOptions +from . import models + + +@register(models.Project) +class ProjectTranslationOptions(TranslationOptions): + fields = [] + + +@register(models.Faq) +class FaqTranslationOptions(TranslationOptions): + fields = ["question", "answer"] diff --git a/sledilnik/faq/views.py b/sledilnik/faq/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/sledilnik/faq/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/sledilnik/settings/base.py b/sledilnik/settings/base.py index fc4f155..d9d7bc1 100644 --- a/sledilnik/settings/base.py +++ b/sledilnik/settings/base.py @@ -29,6 +29,7 @@ INSTALLED_APPS = [ 'sledilnik', + 'sledilnik.faq', 'sledilnik.posts', 'sledilnik.modeling', 'sledilnik.restrictions', diff --git a/sledilnik/urls.py b/sledilnik/urls.py index 8a8cf82..6ac8ed7 100644 --- a/sledilnik/urls.py +++ b/sledilnik/urls.py @@ -6,9 +6,11 @@ from django.conf.urls.static import static from django.utils.translation import gettext_lazy as _ +import sledilnik.modeling.urls + from sledilnik.posts.api import PostResource from sledilnik.restrictions.api import RestrictionResource -import sledilnik.modeling.urls +from sledilnik.faq.api import FaqProjectResource admin.site.enable_nav_sidebar = False admin.site.site_header = _("Sledilnik Administration") @@ -18,7 +20,7 @@ api = Api(api_name='v1') api.register(PostResource()) api.register(RestrictionResource()) - +api.register(FaqProjectResource()) urlpatterns = [ path('admin/', admin.site.urls),