From 56a672cef605487426bb76cdb045793d8b829d83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laura=20Kl=C3=BCnder?=
Date: Sun, 10 Dec 2017 15:23:53 +0100
Subject: [PATCH] manage announcements
---
src/c3nav/control/forms.py | 12 +++++
.../templates/control/announcement.html | 12 +++++
.../templates/control/announcements.html | 34 +++++++++++++
src/c3nav/control/templates/control/base.html | 3 ++
src/c3nav/control/urls.py | 5 +-
src/c3nav/control/views.py | 49 ++++++++++++++++++-
.../migrations/0002_announcement_tweaks.py | 33 +++++++++++++
src/c3nav/site/models.py | 6 ++-
8 files changed, 150 insertions(+), 4 deletions(-)
create mode 100644 src/c3nav/control/templates/control/announcement.html
create mode 100644 src/c3nav/control/templates/control/announcements.html
create mode 100644 src/c3nav/site/migrations/0002_announcement_tweaks.py
diff --git a/src/c3nav/control/forms.py b/src/c3nav/control/forms.py
index 39fad030..98da4143 100644
--- a/src/c3nav/control/forms.py
+++ b/src/c3nav/control/forms.py
@@ -8,7 +8,9 @@ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext_lazy
from c3nav.control.models import UserPermissions
+from c3nav.mapdata.forms import I18nModelFormMixin
from c3nav.mapdata.models.access import AccessPermissionToken, AccessPermissionTokenItem, AccessRestriction
+from c3nav.site.models import Announcement
class UserPermissionsForm(ModelForm):
@@ -108,3 +110,13 @@ class AccessPermissionForm(Form):
return AccessPermissionToken(author=self.author,
can_grant=self.cleaned_data.get('can_grant', '0') == '1',
restrictions=tuple(restrictions))
+
+
+class AnnouncementForm(I18nModelFormMixin, ModelForm):
+ class Meta:
+ model = Announcement
+ fields = ('text', 'active', 'active_until')
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.fields['active_until'].initial = timezone.now()
diff --git a/src/c3nav/control/templates/control/announcement.html b/src/c3nav/control/templates/control/announcement.html
new file mode 100644
index 00000000..1ecd2edf
--- /dev/null
+++ b/src/c3nav/control/templates/control/announcement.html
@@ -0,0 +1,12 @@
+{% extends 'control/base.html' %}
+{% load i18n %}
+
+{% block heading %}{% trans 'Edit announcement' %}{% endblock %}
+
+{% block subcontent %}
+
+{% endblock %}
diff --git a/src/c3nav/control/templates/control/announcements.html b/src/c3nav/control/templates/control/announcements.html
new file mode 100644
index 00000000..9d36a99c
--- /dev/null
+++ b/src/c3nav/control/templates/control/announcements.html
@@ -0,0 +1,34 @@
+{% extends 'control/base.html' %}
+{% load i18n %}
+
+{% block heading %}{% trans 'Users' %}{% endblock %}
+
+{% block subcontent %}
+
+
+ {% trans 'ID' %} |
+ {% trans 'Text' %} |
+ {% trans 'Author' %} |
+ {% trans 'Active' %} |
+ {% trans 'Active until' %} |
+ |
+
+ {% for announcement in announcements %}
+
+ {{ announcement.id }} |
+ {{ announcement.text }} |
+ {{ announcement.author }} |
+ {{ announcement.active }} |
+ {{ announcement.active_until }} |
+ {% trans 'Edit' %} |
+
+ {% endfor %}
+
+
+ {% trans 'Create new announcement' %}
+
+{% endblock %}
diff --git a/src/c3nav/control/templates/control/base.html b/src/c3nav/control/templates/control/base.html
index d9a0316b..038298f8 100644
--- a/src/c3nav/control/templates/control/base.html
+++ b/src/c3nav/control/templates/control/base.html
@@ -15,6 +15,9 @@
{% trans 'Overview' %} ·
{% trans 'Users' %} ·
{% trans 'Access' %}
+ {% if request.user_permissions.manage_announcements %}
+ · {% trans 'Announcements' %}
+ {% endif %}
{% endblock %}
diff --git a/src/c3nav/control/urls.py b/src/c3nav/control/urls.py
index 97a12d96..f6a220d9 100644
--- a/src/c3nav/control/urls.py
+++ b/src/c3nav/control/urls.py
@@ -1,11 +1,14 @@
from django.conf.urls import url
-from c3nav.control.views import grant_access, grant_access_qr, main_index, user_detail, user_list
+from c3nav.control.views import (announcement_detail, announcement_list, grant_access, grant_access_qr, main_index,
+ user_detail, user_list)
urlpatterns = [
url(r'^users/$', user_list, name='control.users'),
url(r'^users/(?P\d+)/$', user_detail, name='control.users.detail'),
url(r'^access/$', grant_access, name='control.access'),
url(r'^access/(?P[^/]+)$', grant_access_qr, name='control.access.qr'),
+ url(r'^announcements/$', announcement_list, name='control.announcements'),
+ url(r'^announcements/(?P\d+)/$', announcement_detail, name='control.announcements.detail'),
url(r'^$', main_index, name='control.index'),
]
diff --git a/src/c3nav/control/views.py b/src/c3nav/control/views.py
index e2b29ca4..200b388f 100644
--- a/src/c3nav/control/views.py
+++ b/src/c3nav/control/views.py
@@ -11,9 +11,10 @@ from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
-from c3nav.control.forms import AccessPermissionForm, UserPermissionsForm
+from c3nav.control.forms import AccessPermissionForm, AnnouncementForm, UserPermissionsForm
from c3nav.control.models import UserPermissions
from c3nav.mapdata.models.access import AccessPermission, AccessPermissionToken
+from c3nav.site.models import Announcement
def control_panel_view(func):
@@ -170,3 +171,49 @@ def grant_access_qr(request, token):
'url_qr': reverse('site.qr', kwargs={'path': url}),
'url_absolute': request.build_absolute_uri(url),
})
+
+
+@login_required
+@control_panel_view
+def announcement_list(request):
+ if not request.user_permissions.manage_announcements:
+ raise PermissionDenied
+
+ announcements = Announcement.objects.order_by('id')
+
+ if request.method == 'POST':
+ form = AnnouncementForm(data=request.POST)
+ if form.is_valid():
+ announcement = form.instance
+ announcement = request.user
+ announcement.save()
+ return redirect('control.announcements')
+ else:
+ form = AnnouncementForm()
+
+ return render(request, 'control/announcements.html', {
+ 'form': form,
+ 'announcements': announcements,
+ })
+
+
+@login_required
+@control_panel_view
+def announcement_detail(request, announcement):
+ if not request.user_permissions.manage_announcements:
+ raise PermissionDenied
+
+ announcement = get_object_or_404(Announcement, pk=announcement)
+
+ if request.method == 'POST':
+ form = AnnouncementForm(instance=announcement, data=request.POST)
+ if form.is_valid():
+ form.save()
+ return redirect('control.announcements')
+ else:
+ form = AnnouncementForm(instance=announcement)
+
+ return render(request, 'control/announcement.html', {
+ 'form': form,
+ 'announcement': announcement,
+ })
diff --git a/src/c3nav/site/migrations/0002_announcement_tweaks.py b/src/c3nav/site/migrations/0002_announcement_tweaks.py
new file mode 100644
index 00000000..b92dcfdc
--- /dev/null
+++ b/src/c3nav/site/migrations/0002_announcement_tweaks.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.6 on 2017-12-10 14:14
+from __future__ import unicode_literals
+
+import c3nav.mapdata.fields
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('site', '0001_announcement'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='announcement',
+ name='message',
+ ),
+ migrations.AddField(
+ model_name='announcement',
+ name='author',
+ field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='announcements', to=settings.AUTH_USER_MODEL, verbose_name='author'),
+ ),
+ migrations.AddField(
+ model_name='announcement',
+ name='text',
+ field=c3nav.mapdata.fields.I18nField(fallback_any=True, verbose_name='Text'),
+ ),
+ ]
diff --git a/src/c3nav/site/models.py b/src/c3nav/site/models.py
index 841b4321..fb6fd608 100644
--- a/src/c3nav/site/models.py
+++ b/src/c3nav/site/models.py
@@ -1,3 +1,4 @@
+from django.conf import settings
from django.db import models
from django.db.models import Q
from django.utils import timezone
@@ -10,7 +11,8 @@ class Announcement(models.Model):
created = models.DateTimeField(auto_now_add=True, verbose_name=_('created'))
active_until = models.DateTimeField(null=True, verbose_name=_('active until'))
active = models.BooleanField(default=True, verbose_name=_('active'))
- message = I18nField(_('Message'))
+ author = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.PROTECT, verbose_name=_('author'))
+ text = I18nField(_('Text'), fallback_any=True)
class Meta:
verbose_name = _('Announcement')
@@ -22,6 +24,6 @@ class Announcement(models.Model):
def get_current(cls):
try:
return cls.objects.filter(Q(active=True) & (Q(active_until__isnull=True) |
- Q(active_until__isnull=timezone.now()))).latest()
+ Q(active_until__gt=timezone.now()))).latest()
except cls.DoesNotExist:
return None