diff --git a/fet2020/tasks/admin.py b/fet2020/tasks/admin.py index a41edd05..813ab541 100644 --- a/fet2020/tasks/admin.py +++ b/fet2020/tasks/admin.py @@ -5,8 +5,8 @@ from .models import Document, Task, TaskList class DocumentInline(admin.TabularInline): - model = Document form = DocumentInlineForm + model = Document extra = 0 verbose_name = "Dokument" verbose_name_plural = "Do­ku­men­ten­samm­lung" @@ -16,7 +16,6 @@ class TaskListAdmin(admin.ModelAdmin): form = TaskListAdminForm model = TaskList - readonly_fields = ("slug",) fieldsets = ( ( None, @@ -30,6 +29,7 @@ class TaskListAdmin(admin.ModelAdmin): }, ), ) + readonly_fields = ("slug",) def add_view(self, request, form_url="", extra_context=None): extra_context = extra_context or {} @@ -56,23 +56,34 @@ class TaskAdmin(admin.ModelAdmin): model = Task inlines = (DocumentInline,) - readonly_fields = ("slug",) fieldsets = ( ( None, { "fields": ( "title", - "shortterm", - "slug", "task_list", - "assigned_to", - "due_date", - "completed", - "completed_date", "note", "priority", - ) + ), + }, + ), + ( + "Fälligkeit", + { + "fields": ( + "due_date", + "assigned_to", + ), + }, + ), + ( + "Abgeschlossen", + { + "fields": ( + "completed_date", + "completed", + ), }, ), ) diff --git a/fet2020/tasks/forms.py b/fet2020/tasks/forms.py index 612915fb..f3b87227 100644 --- a/fet2020/tasks/forms.py +++ b/fet2020/tasks/forms.py @@ -1,3 +1,5 @@ +from ckeditor.widgets import CKEditorWidget + from django import forms from django.contrib.admin.widgets import FilteredSelectMultiple from django.contrib.auth.models import User @@ -18,13 +20,11 @@ class DocumentInlineForm(forms.ModelForm): model = Document fields = [ "title", - "slug", "date", ] labels = { "title": _("Titel"), - "slug": _("Permalink"), } @@ -65,6 +65,10 @@ class TaskAdminForm(forms.ModelForm): "priority": _("Priorität"), } + widgets = { + "note": CKEditorWidget(config_name="default"), + } + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # to get the self.fields set self.fields["assigned_to"].empty_label = "Alle" @@ -79,7 +83,6 @@ class TaskCreateForm(forms.ModelForm): fields = [ "title", - "shortterm", "task_list", "due_date", "assigned_to", @@ -88,16 +91,15 @@ class TaskCreateForm(forms.ModelForm): labels = { "title": _("Titel des Tasks"), - "shortterm": _("Kürzel für den Link (optional)"), "task_list": _("Task-Gruppe"), - "due_date": _("Fälligkeitsdatum"), "assigned_to": _("Zuweisen an"), + "due_date": _("Fälligkeitsdatum"), + "note": _("Notizen"), } widgets = { - "due_date": DateInput( - format=("%Y-%m-%d"), - ) + "due_date": DateInput(format=("%Y-%m-%d")), + "note": CKEditorWidget(config_name="intern"), } def __init__(self, *args, **kwargs): @@ -137,20 +139,25 @@ class TaskUpdateForm(forms.ModelForm): fields = [ "assigned_to", "due_date", - "priority", + "completed", + "completed_date", "note", "task_list", ] labels = { - "due_date": _("Fälligkeitsdatum"), "assigned_to": _("Zuweisen an"), + "due_date": _("Fälligkeitsdatum"), + "completed": _("Abgeschlossen"), + "completed_date": _("Datum der Fertigstellung"), + "note": _("Notizen"), } widgets = { "due_date": DateInput( format=("%Y-%m-%d"), ), + "note": CKEditorWidget(config_name="intern"), "task_list": HiddenInput, } @@ -173,14 +180,12 @@ class DocumentCreateForm(forms.ModelForm): fields = [ "title", - "shortterm", "date", "task", ] labels = { "title": _("Titel"), - "shortterm": _("Kürzel für den Link (optional)"), "date": _("Datum"), } @@ -197,7 +202,6 @@ class InternTaskCreateForm(TaskCreateForm): fields = [ "title", - "shortterm", "task_list", "due_date", "assigned_to", @@ -206,7 +210,6 @@ class InternTaskCreateForm(TaskCreateForm): labels = { "title": _("Titel des Tasks"), - "shortterm": _("Kürzel für den Link"), "task_list": _("Task-Gruppe"), "due_date": _("Fälligkeitsdatum"), "assigned_to": _("Zuweisen an"), diff --git a/fet2020/tasks/migrations/0002_slug.py b/fet2020/tasks/migrations/0002_alter_task_options_task_slug_task_slug_id_and_more.py similarity index 71% rename from fet2020/tasks/migrations/0002_slug.py rename to fet2020/tasks/migrations/0002_alter_task_options_task_slug_task_slug_id_and_more.py index 96e78e74..92428787 100644 --- a/fet2020/tasks/migrations/0002_slug.py +++ b/fet2020/tasks/migrations/0002_alter_task_options_task_slug_task_slug_id_and_more.py @@ -1,18 +1,18 @@ -# Generated by Django 4.0.3 on 2022-04-20 20:40 +# Generated by Django 4.0.6 on 2022-07-30 10:47 import datetime from django.db import migrations, models -from django.db.models import F import django.db.models.deletion import django.db.models.expressions from django.utils.text import slugify +import fet2020.utils def forwards_func(apps, schema_editor): Tasks = apps.get_model("tasks", "Task") for elem in Tasks.objects.all(): - elem.shortterm = slugify(elem.title[:25]) - elem.slug = slugify(elem.shortterm) + elem.slug_id = fet2020.utils.create_random_id() + elem.slug = elem.slug_id + "-" + slugify(elem.title) elem.save() TaskLists = apps.get_model("tasks", "TaskList") @@ -35,13 +35,13 @@ class Migration(migrations.Migration): ), migrations.AddField( model_name='task', - name='shortterm', - field=models.CharField(blank=True, max_length=25, null=True), + name='slug', + field=models.SlugField(blank=True, unique=True), ), migrations.AddField( model_name='task', - name='slug', - field=models.SlugField(blank=True, max_length=25, null=True), + name='slug_id', + field=models.CharField(default=fet2020.utils.create_random_id, editable=False, max_length=8, unique=True), ), migrations.AddField( model_name='tasklist', @@ -58,13 +58,17 @@ class Migration(migrations.Migration): name='name', field=models.CharField(max_length=128), ), + migrations.AlterField( + model_name='tasklist', + name='slug', + field=models.SlugField(blank=True, unique=True), + ), migrations.CreateModel( name='Document', 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(blank=True, max_length=20)), - ('slug', models.SlugField(blank=True, max_length=20)), + ('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')), ('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tasks.task')), @@ -74,24 +78,5 @@ class Migration(migrations.Migration): 'verbose_name_plural': 'Dokumente', }, ), - migrations.AddConstraint( - model_name='document', - constraint=models.UniqueConstraint(fields=('title', 'date', 'task'), name='unique_task_document'), - ), migrations.RunPython(forwards_func), - migrations.AlterField( - model_name='task', - name='shortterm', - field=models.CharField(blank=True, max_length=25), - ), - migrations.AlterField( - model_name='task', - name='slug', - field=models.SlugField(blank=True, max_length=25), - ), - migrations.AlterField( - model_name='tasklist', - name='slug', - field=models.SlugField(blank=True, unique=True), - ), ] diff --git a/fet2020/tasks/models.py b/fet2020/tasks/models.py index a7350362..3c7f5844 100644 --- a/fet2020/tasks/models.py +++ b/fet2020/tasks/models.py @@ -1,7 +1,8 @@ from datetime import date + from django.conf import settings -from django.core.validators import ValidationError from django.contrib.auth.models import User +from django.core.validators import ValidationError from django.db import models from django.db.models import F from django.db.models.constraints import UniqueConstraint @@ -11,6 +12,7 @@ from django.utils.text import slugify from django.utils.translation import gettext_lazy as _ from documents import create_pad +from fet2020.utils import create_random_id from .managers import TaskManager @@ -43,8 +45,10 @@ class TaskList(models.Model): class Task(models.Model): title = models.CharField(verbose_name="Titel", max_length=128) - shortterm = models.CharField(max_length=25, blank=True) - slug = models.SlugField(max_length=25, blank=True) + slug_id = models.CharField( + default=create_random_id, max_length=8, unique=True, editable=False + ) + slug = models.SlugField(unique=True, blank=True) task_list = models.ForeignKey( TaskList, verbose_name="Aufgabenbereich", on_delete=models.CASCADE, null=True @@ -87,14 +91,12 @@ class Task(models.Model): return self.title def get_absolute_url(self): - return reverse("tasks:task-detail", kwargs={"pk": self.id}) - - def clean(self): - if not self.shortterm: - self.shortterm = slugify(self.title[:25]) - self.slug = slugify(self.shortterm) + return reverse("tasks:task-detail", kwargs={"slug": self.slug}) def save(self, *args, **kwargs): + if not self.slug: + self.slug = self.slug_id + "-" + slugify(self.title) + if self.completed and not self.completed_date: self.completed_date = timezone.now().date() @@ -107,10 +109,11 @@ class Task(models.Model): class Document(models.Model): title = models.CharField(verbose_name="Titel", max_length=128) - shortterm = models.CharField(max_length=20, blank=True) - slug = models.SlugField(max_length=20, blank=True) - + slug_id = models.CharField( + default=create_random_id, max_length=8, unique=True, editable=False + ) etherpad_key = models.CharField(max_length=50, blank=True) + date = models.DateField(verbose_name="Datum", default=date.today) task = models.ForeignKey(Task, on_delete=models.CASCADE) @@ -121,19 +124,8 @@ class Document(models.Model): verbose_name = "Dokument" verbose_name_plural = "Dokumente" - constraints = [ - # TODO: include lower/upper case - when Django 4.0, then go for it. - UniqueConstraint( - fields=["title", "date", "task"], name="unique_task_document" - ), - ] - def clean(self): - if not self.shortterm: - self.shortterm = slugify(self.title[:20]) - self.slug = slugify(self.shortterm) - - pad_name = slugify(str(self.date) + "-" + self.task.slug + "-" + self.slug) + pad_name = slugify(str(self.slug_id) + "-" + self.title[:40]) if len(pad_name) > 50: raise ValidationError( _( diff --git a/fet2020/tasks/urls.py b/fet2020/tasks/urls.py index 09d79b04..f0a1d6f5 100644 --- a/fet2020/tasks/urls.py +++ b/fet2020/tasks/urls.py @@ -10,7 +10,7 @@ app_name = apps.TasksConfig.name urlpatterns = [ path("", views.index, name="index"), path("add/", TaskCreate.as_view(), name="task-create"), - path("/update/", TaskUpdate.as_view(), name="task-update"), - path("/detail/", TaskDetail.as_view(), name="task-detail"), - path("/add/", DocumentCreate.as_view(), name="docu-create"), + path("/", TaskDetail.as_view(), name="task-detail"), + path("/update/", TaskUpdate.as_view(), name="task-update"), + path("/add/", DocumentCreate.as_view(), name="docu-create"), ] diff --git a/fet2020/tasks/views.py b/fet2020/tasks/views.py index c43c5842..3a5e957e 100644 --- a/fet2020/tasks/views.py +++ b/fet2020/tasks/views.py @@ -1,6 +1,7 @@ import logging from collections import deque + from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import User from django.shortcuts import render @@ -92,11 +93,11 @@ class TaskCreate(LoginRequiredMixin, CreateView): class TaskUpdate(LoginRequiredMixin, UpdateView): + form_class = TaskUpdateForm model = Task template_name = "tasks/task_update.html" - form_class = TaskUpdateForm - task_id = None + slug = None task_list = None def form_valid(self, form): @@ -114,12 +115,12 @@ class TaskUpdate(LoginRequiredMixin, UpdateView): return kwargs def get_initial(self): - self.task_id = self.kwargs.get("pk") - self.task_list = Task.objects.get(id=self.task_id).task_list + self.slug = self.kwargs.get("slug") + self.task_list = Task.objects.get(slug=self.slug).task_list def get_success_url(self): kwargs = { - "pk": self.task_id, + "slug": self.slug, } return reverse("tasks:task-detail", kwargs=kwargs) @@ -165,24 +166,24 @@ class DocumentCreate(LoginRequiredMixin, CreateView): template_name = "tasks/attachment_create.html" form_class = DocumentCreateForm - task_id = None + slug = None def form_valid(self, form): form.instance.created_by = self.request.user add_log_action(self.request, form, "tasks", "document", True) return super().form_valid(form) - def get_initial(self): - self.task_id = self.kwargs.get("pk") - def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["task"] = Task.objects.get(pk=self.task_id) + context["task"] = Task.objects.get(slug=self.slug) return context + def get_initial(self): + self.slug = self.kwargs.get("slug") + def get_success_url(self): kwargs = { - "pk": self.task_id, + "slug": self.slug, } return reverse("tasks:task-detail", kwargs=kwargs) diff --git a/fet2020/templates/tasks/attachment_create.html b/fet2020/templates/tasks/attachment_create.html index adb2cb4d..830aa08c 100644 --- a/fet2020/templates/tasks/attachment_create.html +++ b/fet2020/templates/tasks/attachment_create.html @@ -28,16 +28,6 @@ - -