From b8e324405f7d77891be8c54da3ba3f4b4485b9c8 Mon Sep 17 00:00:00 2001 From: Patrick Mayr Date: Sat, 30 Jul 2022 16:48:56 +0000 Subject: [PATCH] change slug to slugify of title or uuid + title --- fet2020/intern/admin.py | 69 ++++------- fet2020/intern/forms.py | 47 +++----- fet2020/intern/migrations/0001_initial.py | 25 ++-- fet2020/intern/models.py | 111 +++++++++--------- .../intern/attachment/attachment_create.html | 9 +- .../intern/attachment/attachment_update.html | 9 +- fet2020/templates/intern/task_create.html | 10 -- .../templates/intern/topic/topic_create.html | 9 +- .../templates/intern/topic/topic_update.html | 9 +- 9 files changed, 131 insertions(+), 167 deletions(-) diff --git a/fet2020/intern/admin.py b/fet2020/intern/admin.py index 46f67fe1..4249196c 100644 --- a/fet2020/intern/admin.py +++ b/fet2020/intern/admin.py @@ -1,7 +1,6 @@ from django.contrib import admin from django.db.models import F -from .models import TopicGroup, Topic, Attachment, Etherpad, FileUpload from .forms import ( TopicGroupAdminForm, TopicAdminForm, @@ -13,38 +12,38 @@ from .forms import ( EtherpadInlineForm, FileUploadInlineForm, ) +from .models import TopicGroup, Topic, Attachment, Etherpad, FileUpload class TopicInline(admin.TabularInline): - model = Topic form = TopicInlineForm + model = Topic extra = 0 + show_change_link = True verbose_name = "Thema" verbose_name_plural = "Themen" - show_change_link = True - readonly_fields = ("slug",) class AttachmentInline(admin.TabularInline): - model = Attachment form = AttachmentInlineForm + model = Attachment extra = 0 + show_change_link = True verbose_name = "Anhang Ordner" verbose_name_plural = "Anhang Ordner" - readonly_fields = ("slug",) class EtherpadInline(admin.TabularInline): - model = Etherpad form = EtherpadInlineForm + model = Etherpad extra = 0 verbose_name = "Etherpad" verbose_name_plural = "Etherpads" class FileUploadInline(admin.TabularInline): - model = FileUpload form = FileUploadInlineForm + model = FileUpload extra = 0 verbose_name = "Datei" verbose_name_plural = "Dateien" @@ -53,9 +52,11 @@ class FileUploadInline(admin.TabularInline): class TopicGroupAdmin(admin.ModelAdmin): form = TopicGroupAdminForm model = TopicGroup - search_fields = ("title",) - readonly_fields = ("slug",) + list_display = ["title", "order"] + search_fields = ("title",) + ordering = [F("order").asc(nulls_last=True)] + fieldsets = ( ( None, @@ -70,11 +71,8 @@ class TopicGroupAdmin(admin.ModelAdmin): }, ), ) - inlines = (TopicInline,) - - list_display = ["title", "order"] - ordering = [F("order").asc(nulls_last=True)] + readonly_fields = ("slug",) def add_view(self, request, form_url="", extra_context=None): extra_context = extra_context or {} @@ -103,17 +101,18 @@ class TopicGroupAdmin(admin.ModelAdmin): class TopicAdmin(admin.ModelAdmin): form = TopicAdminForm model = Topic - search_fields = ("title",) - readonly_fields = ("slug",) + list_display = ["title", "topic_group", "archive"] + list_filter = ["topic_group", "archive"] + search_fields = ("title",) + ordering = ["archive"] + fieldsets = ( ( None, { "fields": ( "title", - "shortterm", - "slug", "topic_group", "task_list", "archive", @@ -124,10 +123,6 @@ class TopicAdmin(admin.ModelAdmin): ) inlines = (AttachmentInline,) - list_filter = ["topic_group", "archive"] - list_display = ["title", "topic_group", "archive"] - ordering = ["archive"] - def add_view(self, request, form_url="", extra_context=None): extra_context = extra_context or {} extra_context["help_text"] = "Fette Schriften sind Pflichtfelder." @@ -156,32 +151,25 @@ class AttachmentAdmin(admin.ModelAdmin): form = AttachmentAdminForm model = Attachment - readonly_fields = ("slug",) + list_display = ["title", "topic"] + fieldsets = ( ( None, { "fields": ( "title", - "shortterm", - "slug", "topic", "description", ) }, ), ) - inlines = ( EtherpadInline, FileUploadInline, ) - list_display = [ - "title", - "topic", - ] - def add_view(self, request, form_url="", extra_context=None): extra_context = extra_context or {} extra_context["help_text"] = "Fette Schriften sind Pflichtfelder." @@ -210,14 +198,8 @@ class EtherpadAdmin(admin.ModelAdmin): form = EtherpadAdminForm model = Etherpad - list_filter = [ - "attachment", - ] - list_display = [ - "title", - "date", - "attachment", - ] + list_display = ["title", "date", "attachment"] + list_filter = ["attachment"] ordering = ["-date"] def add_view(self, request, form_url="", extra_context=None): @@ -248,13 +230,8 @@ class FileUploadAdmin(admin.ModelAdmin): form = FileUploadAdminForm model = FileUpload - list_filter = [ - "attachment", - ] - list_display = [ - "title", - "attachment", - ] + list_display = ["title", "attachment"] + list_filter = ["attachment"] def add_view(self, request, form_url="", extra_context=None): extra_context = extra_context or {} diff --git a/fet2020/intern/forms.py b/fet2020/intern/forms.py index 777a8ae4..4ba2706e 100644 --- a/fet2020/intern/forms.py +++ b/fet2020/intern/forms.py @@ -1,4 +1,6 @@ +from ckeditor.widgets import CKEditorWidget from ckeditor_uploader.widgets import CKEditorUploadingWidget + from django import forms from django.forms.widgets import HiddenInput from django.utils.translation import gettext_lazy as _ @@ -23,10 +25,6 @@ class TopicGroupAdminForm(forms.ModelForm): "short_description": _("Kurzbeschreibung"), } - help_texts = { - "shortterm": _("max. 10 Zeichen erlaubt."), - } - class TopicAdminForm(forms.ModelForm): class Meta: @@ -35,16 +33,11 @@ class TopicAdminForm(forms.ModelForm): labels = { "title": _("Titel"), - "shortterm": _("Kürzel für Link"), "slug": _("Permalink"), "task_list": _("Aufgabenbereich"), "description": _("Beschreibung"), } - help_texts = { - "shortterm": _("max. 10 Zeichen erlaubt."), - } - widgets = {"description": CKEditorUploadingWidget(config_name="default")} @@ -55,15 +48,11 @@ class AttachmentAdminForm(forms.ModelForm): labels = { "title": _("Titel"), - "shortterm": _("Kürzel für Link"), "slug": _("Permalink"), + "topic": _("Thema"), "description": _("Beschreibung"), } - help_texts = { - "shortterm": _("max. 10 Zeichen erlaubt."), - } - widgets = {"description": CKEditorUploadingWidget(config_name="default")} @@ -76,6 +65,11 @@ class EtherpadAdminForm(forms.ModelForm): "attachment", ] + labels = { + "title": _("Titel"), + "attachment": _("Anhang Ordner"), + } + class FileUploadAdminForm(forms.ModelForm): class Meta: @@ -86,20 +80,21 @@ class FileUploadAdminForm(forms.ModelForm): "attachment", ] + labels = { + "title": _("Titel"), + "attachment": _("Anhang Ordner"), + } + class TopicInlineForm(forms.ModelForm): class Meta: model = Topic fields = [ "title", - "shortterm", - "slug", ] labels = { "title": _("Titel"), - "shortterm": _("Kürzel für Link"), - "slug": _("Permalink"), } @@ -108,14 +103,10 @@ class AttachmentInlineForm(forms.ModelForm): model = Attachment fields = [ "title", - "shortterm", - "slug", ] labels = { "title": _("Titel"), - "shortterm": _("Kürzel für Link"), - "slug": _("Permalink"), } @@ -152,18 +143,17 @@ class TopicCreateForm(forms.ModelForm): model = Topic fields = [ "title", - "shortterm", "description", "topic_group", ] labels = { "title": _("Titel"), - "shortterm": _("Kürzel für den Link"), "description": _("Beschreibung"), } widgets = { + "description": CKEditorWidget(config_name="intern"), "topic_group": HiddenInput, } @@ -173,18 +163,17 @@ class TopicUpdateForm(forms.ModelForm): model = Topic fields = [ "title", - "shortterm", "description", "topic_group", ] labels = { "title": _("Titel"), - "shortterm": _("Kürzel für den Link"), "description": _("Beschreibung"), } widgets = { + "description": CKEditorWidget(config_name="intern"), "topic_group": HiddenInput, } @@ -195,18 +184,17 @@ class AttachmentCreateForm(forms.ModelForm): fields = [ "title", - "shortterm", "description", "topic", ] labels = { "title": _("Titel"), - "shortterm": _("Kürzel für den Link"), "description": _("Beschreibung"), } widgets = { + "description": CKEditorWidget(config_name="intern"), "topic": HiddenInput, } @@ -217,18 +205,17 @@ class AttachmentUpdateForm(forms.ModelForm): fields = [ "title", - "shortterm", "description", "topic", ] labels = { "title": _("Titel"), - "shortterm": _("Kürzel für den Link"), "description": _("Beschreibung"), } widgets = { + "description": CKEditorWidget(config_name="intern"), "topic": HiddenInput, } diff --git a/fet2020/intern/migrations/0001_initial.py b/fet2020/intern/migrations/0001_initial.py index 4a681272..cf327f05 100644 --- a/fet2020/intern/migrations/0001_initial.py +++ b/fet2020/intern/migrations/0001_initial.py @@ -1,8 +1,9 @@ -# Generated by Django 4.0.3 on 2022-04-20 20:55 +# Generated by Django 4.0.6 on 2022-07-30 16:33 import datetime from django.db import migrations, models import django.db.models.deletion +import fet2020.utils class Migration(migrations.Migration): @@ -10,7 +11,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('tasks', '0002_slug'), + ('tasks', '0002_alter_task_options_task_slug_task_slug_id_and_more'), ] operations = [ @@ -19,8 +20,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('title', models.CharField(max_length=128, verbose_name='Titel')), - ('shortterm', models.CharField(max_length=10)), - ('slug', models.SlugField(max_length=10)), + ('slug', models.SlugField()), ('description', models.TextField(blank=True, null=True)), ], options={ @@ -33,8 +33,8 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('title', models.CharField(max_length=128, verbose_name='Titel')), - ('shortterm', models.CharField(max_length=10, unique=True)), - ('slug', models.SlugField(max_length=10, unique=True)), + ('shortterm', models.CharField(blank=True, max_length=128, unique=True)), + ('slug', models.SlugField(unique=True)), ('short_description', models.TextField(blank=True, null=True)), ('order', models.PositiveSmallIntegerField(blank=True, null=True, unique=True, verbose_name='Reihenfolge')), ], @@ -48,8 +48,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('title', models.CharField(max_length=128, verbose_name='Titel')), - ('shortterm', models.CharField(max_length=10, unique=True)), - ('slug', models.SlugField(max_length=10, unique=True)), + ('slug', models.SlugField()), ('archive', models.BooleanField(default=False, verbose_name='Archiv')), ('description', models.TextField(blank=True, null=True)), ('task_list', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='tasks.tasklist')), @@ -79,7 +78,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('title', models.CharField(max_length=128, verbose_name='Titel')), - ('slug', models.SlugField(blank=True, null=True)), + ('slug_id', models.CharField(default=fet2020.utils.create_random_id, editable=False, max_length=8, unique=True)), ('etherpad_key', models.CharField(blank=True, max_length=50)), ('date', models.DateField(default=datetime.date.today, verbose_name='Datum')), ('attachment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='intern.attachment')), @@ -94,6 +93,14 @@ class Migration(migrations.Migration): name='topic', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='intern.topic'), ), + migrations.AddConstraint( + model_name='topic', + constraint=models.UniqueConstraint(fields=('slug', 'topic_group'), name='unique_intern_slug_topic_group'), + ), + migrations.AddConstraint( + model_name='topic', + constraint=models.UniqueConstraint(fields=('title', 'topic_group'), name='unique_intern_title_topic_group'), + ), migrations.AddConstraint( model_name='etherpad', constraint=models.UniqueConstraint(fields=('title', 'date', 'attachment'), name='unique_intern_etherpad'), diff --git a/fet2020/intern/models.py b/fet2020/intern/models.py index 7f0bff99..a832aad6 100644 --- a/fet2020/intern/models.py +++ b/fet2020/intern/models.py @@ -12,6 +12,7 @@ from django.utils.translation import gettext_lazy as _ from documents import create_pad, get_pad_html from documents.api import get_pad_link +from fet2020.utils import create_random_id from tasks.models import TaskList logger = logging.getLogger(__name__) @@ -20,8 +21,8 @@ logger = logging.getLogger(__name__) class TopicGroup(models.Model): title = models.CharField(verbose_name="Titel", max_length=128) - shortterm = models.CharField(max_length=10, unique=True) - slug = models.SlugField(max_length=10, unique=True) + shortterm = models.CharField(max_length=128, unique=True, blank=True) + slug = models.SlugField(unique=True) short_description = models.TextField(null=True, blank=True) @@ -42,24 +43,24 @@ class TopicGroup(models.Model): return reverse("intern:index") + "#" + self.slug def clean(self, *args, **kwargs): + if not self.shortterm: + self.shortterm = self.title self.slug = slugify(self.shortterm) class Topic(models.Model): - title = models.CharField(verbose_name="Titel", max_length=128) + title = models.CharField(max_length=128, verbose_name="Titel") + slug = models.SlugField() - shortterm = models.CharField(max_length=10, unique=True) - slug = models.SlugField(max_length=10, unique=True) + archive = models.BooleanField(default=False, verbose_name="Archiv") - archive = models.BooleanField(verbose_name="Archiv", default=False) - - description = models.TextField(null=True, blank=True) + description = models.TextField(blank=True, null=True) topic_group = models.ForeignKey( TopicGroup, on_delete=models.CASCADE, verbose_name="Themenbereich" ) task_list = models.ForeignKey( - TaskList, on_delete=models.CASCADE, null=True, blank=True + TaskList, blank=True, on_delete=models.CASCADE, null=True ) objects = models.Manager() @@ -68,6 +69,15 @@ class Topic(models.Model): verbose_name = "Thema" verbose_name_plural = "Themen" + constraints = [ + UniqueConstraint( + fields=["slug", "topic_group"], name="unique_intern_slug_topic_group" + ), + UniqueConstraint( + fields=["title", "topic_group"], name="unique_intern_title_topic_group" + ), + ] + def __str__(self): return self.title @@ -75,18 +85,17 @@ class Topic(models.Model): return reverse("intern:topic", kwargs={"slug": self.slug}) def clean(self, *args, **kwargs): - self.slug = slugify(self.shortterm) + self.slug = slugify(self.title) class Attachment(models.Model): - title = models.CharField(verbose_name="Titel", max_length=128) + title = models.CharField(max_length=128, verbose_name="Titel") - shortterm = models.CharField(max_length=10) - slug = models.SlugField(max_length=10) + slug = models.SlugField() - description = models.TextField(null=True, blank=True) + description = models.TextField(blank=True, null=True) - topic = models.ForeignKey(Topic, on_delete=models.CASCADE) + topic = models.ForeignKey(Topic, on_delete=models.CASCADE, verbose_name="Thema") objects = models.Manager() @@ -113,17 +122,21 @@ class Attachment(models.Model): return reverse("intern:attachment", kwargs=kwargs) def clean(self, *args, **kwargs): - self.slug = slugify(self.shortterm) + self.slug = slugify(self.title) class Etherpad(models.Model): - title = models.CharField(verbose_name="Titel", max_length=128) - slug = models.SlugField(null=True, blank=True) + title = models.CharField(max_length=128, verbose_name="Titel") - etherpad_key = models.CharField(max_length=50, blank=True) - date = models.DateField(verbose_name="Datum", default=date.today) + slug_id = models.CharField( + default=create_random_id, editable=False, max_length=8, unique=True + ) + etherpad_key = models.CharField(blank=True, max_length=50) + date = models.DateField(default=date.today, verbose_name="Datum") - attachment = models.ForeignKey(Attachment, on_delete=models.CASCADE) + attachment = models.ForeignKey( + Attachment, on_delete=models.CASCADE, verbose_name="Anhang Ordner" + ) objects = models.Manager() @@ -141,57 +154,43 @@ class Etherpad(models.Model): return self.title def get_absolute_url(self): - return get_pad_link(self.__get_pad_name()) - - def __get_pad_name(self): - return ( - slugify(self.date) - + "-" - + self.attachment.topic.slug - + "-" - + self.attachment.slug - + "-" - + self.slug - ) + return get_pad_link(self.etherpad_key) def clean(self): - self.slug = slugify(self.title) + pad_name = slugify(str(self.slug_id) + "-" + self.title[:40]) + if len(pad_name) > 50: + raise ValidationError( + _( + "Name zum Erstellen des Etherpads ist zu lange - max. 50 Zeichen. " + "(Länge: %(length)s, Name: %(pad_name)s)" + ), + params={"length": len(pad_name), "pad_name": pad_name}, + ) + self.etherpad_key = create_pad(pad_name) if not self.etherpad_key: - pad_name = self.__get_pad_name() - if len(pad_name) > 50: - raise ValidationError( - _( - "Name zum Erstellen des Etherpads ist zu lange - max. 50 Zeichen. (Länge: %(length)s, Name: %(pad_name)s)" - ), - params={"length": len(pad_name), "pad_name": pad_name}, - ) - - self.etherpad_key = create_pad(pad_name) - if not self.etherpad_key: - raise ValidationError( - _(f"Etherpad '{pad_name}' konnte nicht erstellt werden."), - ) + raise ValidationError( + _(f"Etherpad '{pad_name}' konnte nicht erstellt werden."), + ) @property def etherpad_html(self): - if not self.__get_pad_name(): - return None - - return get_pad_html(self.__get_pad_name()) + return get_pad_html(self.etherpad_key) def get_model_name(self): return self._meta.model_name class FileUpload(models.Model): - title = models.CharField(verbose_name="Titel", max_length=128, blank=True) + title = models.CharField(blank=True, max_length=128, verbose_name="Titel") file_field = models.FileField( - verbose_name="Dokument", upload_to="uploads/intern/files/" + upload_to="uploads/intern/files/", verbose_name="Dokument" ) - date = models.DateField(verbose_name="Datum", default=date.today) + date = models.DateField(default=date.today, verbose_name="Datum") - attachment = models.ForeignKey(Attachment, on_delete=models.CASCADE) + attachment = models.ForeignKey( + Attachment, on_delete=models.CASCADE, verbose_name="Anhang Ordner" + ) objects = models.Manager() diff --git a/fet2020/templates/intern/attachment/attachment_create.html b/fet2020/templates/intern/attachment/attachment_create.html index ea63f995..608e7c68 100644 --- a/fet2020/templates/intern/attachment/attachment_create.html +++ b/fet2020/templates/intern/attachment/attachment_create.html @@ -29,13 +29,14 @@ diff --git a/fet2020/templates/intern/attachment/attachment_update.html b/fet2020/templates/intern/attachment/attachment_update.html index ef151ffa..7c94656f 100644 --- a/fet2020/templates/intern/attachment/attachment_update.html +++ b/fet2020/templates/intern/attachment/attachment_update.html @@ -29,13 +29,14 @@ diff --git a/fet2020/templates/intern/task_create.html b/fet2020/templates/intern/task_create.html index 1f48ceb8..eaf3addf 100644 --- a/fet2020/templates/intern/task_create.html +++ b/fet2020/templates/intern/task_create.html @@ -28,16 +28,6 @@ - - diff --git a/fet2020/templates/intern/topic/topic_update.html b/fet2020/templates/intern/topic/topic_update.html index e8fb2704..f7bed2ed 100644 --- a/fet2020/templates/intern/topic/topic_update.html +++ b/fet2020/templates/intern/topic/topic_update.html @@ -29,13 +29,14 @@