From fbed2ee32ccad31acec4c3b2e1af6c7abd40469a Mon Sep 17 00:00:00 2001 From: Joh Dokler Date: Thu, 25 Nov 2021 15:43:03 +0100 Subject: [PATCH] Add FAQ glossary --- sledilnik/faq/admin.py | 29 +++++++++++-- sledilnik/faq/api.py | 13 +++++- .../faq/migrations/0005_auto_20211125_1514.py | 41 +++++++++++++++++++ .../faq/migrations/0006_auto_20211125_1515.py | 34 +++++++++++++++ .../faq/migrations/0007_auto_20211125_1516.py | 21 ++++++++++ .../faq/migrations/0008_auto_20211125_1519.py | 18 ++++++++ sledilnik/faq/models.py | 23 +++++++++++ sledilnik/faq/static/faq/admin/easymde.css | 3 ++ sledilnik/faq/translation.py | 5 +++ 9 files changed, 182 insertions(+), 5 deletions(-) create mode 100644 sledilnik/faq/migrations/0005_auto_20211125_1514.py create mode 100644 sledilnik/faq/migrations/0006_auto_20211125_1515.py create mode 100644 sledilnik/faq/migrations/0007_auto_20211125_1516.py create mode 100644 sledilnik/faq/migrations/0008_auto_20211125_1519.py create mode 100644 sledilnik/faq/static/faq/admin/easymde.css diff --git a/sledilnik/faq/admin.py b/sledilnik/faq/admin.py index 4dc2a6a..7e43bc1 100644 --- a/sledilnik/faq/admin.py +++ b/sledilnik/faq/admin.py @@ -1,18 +1,39 @@ from adminsortable2.admin import SortableInlineAdminMixin -from modeltranslation.admin import TranslationStackedInline +from modeltranslation.admin import TranslationAdmin, TranslationStackedInline from django.contrib import admin -from sledilnik.utils import TranslationAdmin - from . import models +class MediaMixin: + + js = ( + 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', + 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js', + 'modeltranslation/js/tabbed_translation_fields.js', + ) + css = { + 'screen': ( + 'modeltranslation/css/tabbed_translation_fields.css', + 'faq/admin/easymde.css', + ), + } + + class FaqInline(SortableInlineAdminMixin, TranslationStackedInline): model = models.Faq extra = 0 +class GlossaryTermInline(SortableInlineAdminMixin, TranslationStackedInline): + model = models.GlossaryTerm + extra = 0 + + @admin.register(models.Project) class ProjectAdmin(TranslationAdmin): - inlines = [FaqInline] + inlines = [FaqInline, GlossaryTermInline] + + class Media(MediaMixin): + pass diff --git a/sledilnik/faq/api.py b/sledilnik/faq/api.py index 317b7a2..a2ff77b 100644 --- a/sledilnik/faq/api.py +++ b/sledilnik/faq/api.py @@ -5,7 +5,7 @@ from django.conf import settings from django.utils import translation -from .models import Project, Faq +from .models import Project, Faq, GlossaryTerm class FaqResource(ModelResource): @@ -16,12 +16,23 @@ class Meta: def dehydrate(self, bundle): del(bundle.data["resource_uri"]) + return bundle + +class GlossaryTermResource(ModelResource): + class Meta: + queryset = GlossaryTerm.objects.all() + fields = ["position", "term", "definition"] + cache = SimpleCache(timeout=60, public=True) + + def dehydrate(self, bundle): + del(bundle.data["resource_uri"]) return bundle class FaqProjectResource(ModelResource): faq = fields.ToManyField(FaqResource, "faqs", full=True, use_in="detail") + glossary = fields.ToManyField(GlossaryTermResource, "glossary", full=True, use_in="detail") class Meta: resource_name = "faq" diff --git a/sledilnik/faq/migrations/0005_auto_20211125_1514.py b/sledilnik/faq/migrations/0005_auto_20211125_1514.py new file mode 100644 index 0000000..819e592 --- /dev/null +++ b/sledilnik/faq/migrations/0005_auto_20211125_1514.py @@ -0,0 +1,41 @@ +# Generated by Django 3.1.7 on 2021-11-25 14:14 + +from django.db import migrations, models +import django.db.models.deletion +import sledilnik.easymde.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('faq', '0004_auto_20211124_1515'), + ] + + operations = [ + migrations.CreateModel( + name='Glossary', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('position', models.PositiveIntegerField(default=0, verbose_name='Position')), + ('slug', models.SlugField(help_text='Used to reference the term in the text: some term', max_length=100, verbose_name='Slug')), + ('term', models.CharField(max_length=100, verbose_name='Term')), + ('definition', sledilnik.easymde.models.MarkdownField(verbose_name='Definition')), + ], + options={ + 'ordering': ['position'], + }, + ), + migrations.AddConstraint( + model_name='faq', + constraint=models.UniqueConstraint(fields=('project', 'question'), name='unique_question_per_project'), + ), + migrations.AddField( + model_name='glossary', + name='project', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='glossary', to='faq.project', verbose_name='Project'), + ), + migrations.AddConstraint( + model_name='glossary', + constraint=models.UniqueConstraint(fields=('project', 'slug'), name='unique_slug_per_project'), + ), + ] diff --git a/sledilnik/faq/migrations/0006_auto_20211125_1515.py b/sledilnik/faq/migrations/0006_auto_20211125_1515.py new file mode 100644 index 0000000..2b40717 --- /dev/null +++ b/sledilnik/faq/migrations/0006_auto_20211125_1515.py @@ -0,0 +1,34 @@ +# Generated by Django 3.1.7 on 2021-11-25 14:15 + +from django.db import migrations, models +import sledilnik.easymde.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('faq', '0005_auto_20211125_1514'), + ] + + operations = [ + migrations.AddField( + model_name='glossary', + name='definition_en', + field=sledilnik.easymde.models.MarkdownField(null=True, verbose_name='Definition'), + ), + migrations.AddField( + model_name='glossary', + name='definition_sl', + field=sledilnik.easymde.models.MarkdownField(null=True, verbose_name='Definition'), + ), + migrations.AddField( + model_name='glossary', + name='term_en', + field=models.CharField(max_length=100, null=True, verbose_name='Term'), + ), + migrations.AddField( + model_name='glossary', + name='term_sl', + field=models.CharField(max_length=100, null=True, verbose_name='Term'), + ), + ] diff --git a/sledilnik/faq/migrations/0007_auto_20211125_1516.py b/sledilnik/faq/migrations/0007_auto_20211125_1516.py new file mode 100644 index 0000000..ae1a999 --- /dev/null +++ b/sledilnik/faq/migrations/0007_auto_20211125_1516.py @@ -0,0 +1,21 @@ +# Generated by Django 3.1.7 on 2021-11-25 14:16 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('faq', '0006_auto_20211125_1515'), + ] + + operations = [ + migrations.RenameModel( + old_name='Glossary', + new_name='GlossaryTerm', + ), + migrations.AlterModelOptions( + name='glossaryterm', + options={'ordering': ['position'], 'verbose_name': 'Glossary term', 'verbose_name_plural': 'Glossary terms'}, + ), + ] diff --git a/sledilnik/faq/migrations/0008_auto_20211125_1519.py b/sledilnik/faq/migrations/0008_auto_20211125_1519.py new file mode 100644 index 0000000..402d863 --- /dev/null +++ b/sledilnik/faq/migrations/0008_auto_20211125_1519.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.7 on 2021-11-25 14:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('faq', '0007_auto_20211125_1516'), + ] + + operations = [ + migrations.AlterField( + model_name='glossaryterm', + name='slug', + field=models.SlugField(help_text='Used to reference the glossary term in the FAQ text: <span data-term="slug">some term</span>', max_length=100, verbose_name='Slug'), + ), + ] diff --git a/sledilnik/faq/models.py b/sledilnik/faq/models.py index 0bc26e7..dd29798 100644 --- a/sledilnik/faq/models.py +++ b/sledilnik/faq/models.py @@ -22,6 +22,29 @@ class Faq(models.Model): class Meta: ordering = ["position"] + constraints = [ + models.UniqueConstraint(fields=["project", "question"], name="unique_question_per_project"), + ] def __str__(self): return self.question + + +class GlossaryTerm(models.Model): + project = models.ForeignKey(Project, verbose_name=_("Project"), on_delete=models.CASCADE, related_name="glossary") + position = models.PositiveIntegerField(_("Position"), default=0, null=False, blank=False) + + slug = models.SlugField(_("Slug"), max_length=100, help_text=_('Used to reference the glossary term in the FAQ text: <span data-term="slug">some term</span>')) + term = models.CharField(_("Term"), max_length=100) + definition = MarkdownField(_("Definition")) + + class Meta: + verbose_name = _("Glossary term") + verbose_name_plural = _("Glossary terms") + ordering = ["position"] + constraints = [ + models.UniqueConstraint(fields=["project", "slug"], name="unique_slug_per_project"), + ] + + def __str__(self): + return self.term diff --git a/sledilnik/faq/static/faq/admin/easymde.css b/sledilnik/faq/static/faq/admin/easymde.css new file mode 100644 index 0000000..33d2b3e --- /dev/null +++ b/sledilnik/faq/static/faq/admin/easymde.css @@ -0,0 +1,3 @@ +.CodeMirror-scroll { + min-height: 3rem !important; +} diff --git a/sledilnik/faq/translation.py b/sledilnik/faq/translation.py index b1e3f1c..b769ce8 100644 --- a/sledilnik/faq/translation.py +++ b/sledilnik/faq/translation.py @@ -10,3 +10,8 @@ class ProjectTranslationOptions(TranslationOptions): @register(models.Faq) class FaqTranslationOptions(TranslationOptions): fields = ["question", "answer"] + + +@register(models.GlossaryTerm) +class GlossaryTermTranslationOptions(TranslationOptions): + fields = ["term", "definition"]