diff --git a/forums/forms.py b/forums/forms.py index 76c774e4e7223a788676ac7af3fc969dad089cd9..7274759967491868e8333467c11cbc4c3f984e00 100644 --- a/forums/forms.py +++ b/forums/forms.py @@ -6,7 +6,7 @@ from django import forms from ajax_select.fields import AutoCompleteSelectField -from .models import Forum, Post +from .models import Forum, Meeting, Post class ForumForm(forms.ModelForm): @@ -22,6 +22,15 @@ class ForumForm(forms.ModelForm): self.fields['parent_object_id'].widget = forms.HiddenInput() +class MeetingForm(ForumForm): + class Meta: + model = Meeting + fields = ['name', 'slug', 'description', + 'publicly_visible', 'moderators', + 'parent_content_type', 'parent_object_id', + 'date_from', 'date_until', 'preamble'] + + class ForumGroupPermissionsForm(forms.ModelForm): """ Used for granting a specific Group access to a given Forum. diff --git a/forums/migrations/0006_meeting.py b/forums/migrations/0006_meeting.py new file mode 100644 index 0000000000000000000000000000000000000000..02cf93d9f53e582bd87c52e03995d939f1ef2b9c --- /dev/null +++ b/forums/migrations/0006_meeting.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2019-03-09 08:56 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('forums', '0005_forum_description'), + ] + + operations = [ + migrations.CreateModel( + name='Meeting', + fields=[ + ('forum', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='forums.Forum')), + ('date_from', models.DateField()), + ('date_until', models.DateField()), + ('preamble', models.TextField(help_text='Explanatory notes for the meeting.\nYou can use ReStructuredText, see a <a href="https://devguide.python.org/documenting/#restructuredtext-primer" target="_blank">primer on python.org</a>')), + ('minutes', models.TextField(blank=True, help_text='To be filled in after completion of the meeting.\nYou can use ReStructuredText, see a <a href="https://devguide.python.org/documenting/#restructuredtext-primer" target="_blank">primer on python.org</a>', null=True)), + ], + bases=('forums.forum',), + ), + ] diff --git a/forums/models.py b/forums/models.py index ae15f3a8e2cd5da606e193fe82e1e3d2bea22514..ef03914f29c8739bffb8fd7794356079d19560cf 100644 --- a/forums/models.py +++ b/forums/models.py @@ -2,6 +2,8 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" +import datetime + from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.models import ContentType from django.core.urlresolvers import reverse @@ -92,6 +94,54 @@ class Forum(models.Model): return None +class Meeting(Forum): + """ + A Meeting is a Forum but with fixed start and end dates, + and with additional descriptor fields (preamble, minutes). + + By definition, adding new Posts is allowed up to and including + the date specified in ``date_until``. The Meeting can however + be viewed in perpetuity by users who have viewing rights. + """ + forum = models.OneToOneField('forums.Forum', on_delete=models.CASCADE, + parent_link=True) + date_from = models.DateField() + date_until = models.DateField() + preamble = models.TextField( + help_text=( + 'Explanatory notes for the meeting.\n' + 'You can use ReStructuredText, see a ' + '<a href="https://devguide.python.org/documenting/#restructuredtext-primer" ' + 'target="_blank">primer on python.org</a>') + ) + minutes = models.TextField( + blank=True, null=True, + help_text=( + 'To be filled in after completion of the meeting.\n' + 'You can use ReStructuredText, see a ' + '<a href="https://devguide.python.org/documenting/#restructuredtext-primer" ' + 'target="_blank">primer on python.org</a>') + ) + + def __str__(self): + return '%s, [%s to %s]' % (self.forum, + self.date_from.strftime('%Y-%m-%d'), + self.date_until.strftime('%Y-%m-%d')) + + @property + def context_color(self): + """If meeting is future: primary; ongoing: green; voting: orange; finished: info.""" + today = datetime.date.today() + if today < self.date_from: + return 'primary' + elif today <= self.date_until: + return 'success' + elif today < self.date_until + datetime.timedelta(days=8): + return 'warning' + else: + return 'info' + + class Post(models.Model): """ A comment, feedback, question or similar, with a specified parent object. diff --git a/forums/templates/forums/forum_list.html b/forums/templates/forums/forum_list.html index b4a815c4b91411c33b0cef62ce2da8b3de2fb17f..f7806ccea9ef9d01e0e5cc724bacfd711fe1f96b 100644 --- a/forums/templates/forums/forum_list.html +++ b/forums/templates/forums/forum_list.html @@ -21,6 +21,7 @@ {% if perms.forums.can_add_forum %} <ul> <li><a href="{% url 'forums:forum_create' %}">Create a new Forum</a></li> + <li><a href="{% url 'forums:meeting_create' %}">Create a new Meeting</a></li> </ul> {% endif %} @@ -28,6 +29,9 @@ {% for forum in object_list %} <div class="card"> <div class="card-header d-flex justify-content-between"> + {% if forum.meeting %} + <span class="badge badge-{{ forum.meeting.context_color }}">Meeting:</span> + {% endif %} <a href="{{ forum.get_absolute_url }}">{{ forum }}</a> <span class="badge badge-primary badge-pill">{{ forum.nr_posts }} post{{ forum.nr_posts|pluralize }}</span> </div> diff --git a/forums/urls.py b/forums/urls.py index 989b3229c9a40e266205309076b0b33bf23675c9..8975463c8cba2feb6e2572642b4ec6a813bdd9a8 100644 --- a/forums/urls.py +++ b/forums/urls.py @@ -17,6 +17,11 @@ urlpatterns = [ views.ForumCreateView.as_view(), name='forum_create' ), + url( + r'^meeting/add/$', + views.MeetingCreateView.as_view(), + name='meeting_create' + ), url( r'^(?P<slug>[\w-]+)/$', views.ForumDetailView.as_view(), diff --git a/forums/views.py b/forums/views.py index 5716fbd208fa352b86d064d494e77c6993a7c409..2607f47a45a77e46c0ac9b87d927b52ade5c8166 100644 --- a/forums/views.py +++ b/forums/views.py @@ -20,9 +20,9 @@ from guardian.mixins import PermissionRequiredMixin from guardian.shortcuts import (assign_perm, remove_perm, get_objects_for_user, get_perms, get_users_with_perms, get_groups_with_perms) -from .models import Forum, Post +from .models import Forum, Meeting, Post from .forms import (ForumForm, ForumGroupPermissionsForm, ForumOrganizationPermissionsForm, - PostForm) + MeetingForm, PostForm) from scipost.mixins import PermissionsMixin @@ -49,6 +49,11 @@ class ForumCreateView(PermissionsMixin, CreateView): return initial +class MeetingCreateView(ForumCreateView): + model = Meeting + form_class = MeetingForm + + class ForumUpdateView(PermissionRequiredMixin, UpdateView): permission_required = 'forums.update_forum' model = Forum