manage announcements
This commit is contained in:
parent
fe3bac40c8
commit
56a672cef6
8 changed files with 150 additions and 4 deletions
|
@ -8,7 +8,9 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.translation import ungettext_lazy
|
from django.utils.translation import ungettext_lazy
|
||||||
|
|
||||||
from c3nav.control.models import UserPermissions
|
from c3nav.control.models import UserPermissions
|
||||||
|
from c3nav.mapdata.forms import I18nModelFormMixin
|
||||||
from c3nav.mapdata.models.access import AccessPermissionToken, AccessPermissionTokenItem, AccessRestriction
|
from c3nav.mapdata.models.access import AccessPermissionToken, AccessPermissionTokenItem, AccessRestriction
|
||||||
|
from c3nav.site.models import Announcement
|
||||||
|
|
||||||
|
|
||||||
class UserPermissionsForm(ModelForm):
|
class UserPermissionsForm(ModelForm):
|
||||||
|
@ -108,3 +110,13 @@ class AccessPermissionForm(Form):
|
||||||
return AccessPermissionToken(author=self.author,
|
return AccessPermissionToken(author=self.author,
|
||||||
can_grant=self.cleaned_data.get('can_grant', '0') == '1',
|
can_grant=self.cleaned_data.get('can_grant', '0') == '1',
|
||||||
restrictions=tuple(restrictions))
|
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()
|
||||||
|
|
12
src/c3nav/control/templates/control/announcement.html
Normal file
12
src/c3nav/control/templates/control/announcement.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{% extends 'control/base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block heading %}{% trans 'Edit announcement' %}{% endblock %}
|
||||||
|
|
||||||
|
{% block subcontent %}
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<button type="submit">{% trans 'Save' %}</button>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
34
src/c3nav/control/templates/control/announcements.html
Normal file
34
src/c3nav/control/templates/control/announcements.html
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{% extends 'control/base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block heading %}{% trans 'Users' %}{% endblock %}
|
||||||
|
|
||||||
|
{% block subcontent %}
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'ID' %}</th>
|
||||||
|
<th>{% trans 'Text' %}</th>
|
||||||
|
<th>{% trans 'Author' %}</th>
|
||||||
|
<th>{% trans 'Active' %}</th>
|
||||||
|
<th>{% trans 'Active until' %}</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
{% for announcement in announcements %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ announcement.id }}</td>
|
||||||
|
<td>{{ announcement.text }}</td>
|
||||||
|
<td>{{ announcement.author }}</td>
|
||||||
|
<td>{{ announcement.active }}</td>
|
||||||
|
<td>{{ announcement.active_until }}</td>
|
||||||
|
<td><a href="{% url 'control.announcements.detail' announcement=user.pk %}">{% trans 'Edit' %}</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>{% trans 'Create new announcement' %}</h4>
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<button type="submit">{% trans 'Create new announcement' %}</button>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
|
@ -15,6 +15,9 @@
|
||||||
<a href="{% url 'control.index' %}">{% trans 'Overview' %}</a> ·
|
<a href="{% url 'control.index' %}">{% trans 'Overview' %}</a> ·
|
||||||
<a href="{% url 'control.users' %}">{% trans 'Users' %}</a> ·
|
<a href="{% url 'control.users' %}">{% trans 'Users' %}</a> ·
|
||||||
<a href="{% url 'control.access' %}">{% trans 'Access' %}</a>
|
<a href="{% url 'control.access' %}">{% trans 'Access' %}</a>
|
||||||
|
{% if request.user_permissions.manage_announcements %}
|
||||||
|
· <a href="{% url 'control.announcements' %}">{% trans 'Announcements' %}</a>
|
||||||
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
</nav>
|
</nav>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
from django.conf.urls import url
|
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 = [
|
urlpatterns = [
|
||||||
url(r'^users/$', user_list, name='control.users'),
|
url(r'^users/$', user_list, name='control.users'),
|
||||||
url(r'^users/(?P<user>\d+)/$', user_detail, name='control.users.detail'),
|
url(r'^users/(?P<user>\d+)/$', user_detail, name='control.users.detail'),
|
||||||
url(r'^access/$', grant_access, name='control.access'),
|
url(r'^access/$', grant_access, name='control.access'),
|
||||||
url(r'^access/(?P<token>[^/]+)$', grant_access_qr, name='control.access.qr'),
|
url(r'^access/(?P<token>[^/]+)$', grant_access_qr, name='control.access.qr'),
|
||||||
|
url(r'^announcements/$', announcement_list, name='control.announcements'),
|
||||||
|
url(r'^announcements/(?P<announcement>\d+)/$', announcement_detail, name='control.announcements.detail'),
|
||||||
url(r'^$', main_index, name='control.index'),
|
url(r'^$', main_index, name='control.index'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -11,9 +11,10 @@ from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
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.control.models import UserPermissions
|
||||||
from c3nav.mapdata.models.access import AccessPermission, AccessPermissionToken
|
from c3nav.mapdata.models.access import AccessPermission, AccessPermissionToken
|
||||||
|
from c3nav.site.models import Announcement
|
||||||
|
|
||||||
|
|
||||||
def control_panel_view(func):
|
def control_panel_view(func):
|
||||||
|
@ -170,3 +171,49 @@ def grant_access_qr(request, token):
|
||||||
'url_qr': reverse('site.qr', kwargs={'path': url}),
|
'url_qr': reverse('site.qr', kwargs={'path': url}),
|
||||||
'url_absolute': request.build_absolute_uri(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,
|
||||||
|
})
|
||||||
|
|
33
src/c3nav/site/migrations/0002_announcement_tweaks.py
Normal file
33
src/c3nav/site/migrations/0002_announcement_tweaks.py
Normal file
|
@ -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'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,3 +1,4 @@
|
||||||
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -10,7 +11,8 @@ class Announcement(models.Model):
|
||||||
created = models.DateTimeField(auto_now_add=True, verbose_name=_('created'))
|
created = models.DateTimeField(auto_now_add=True, verbose_name=_('created'))
|
||||||
active_until = models.DateTimeField(null=True, verbose_name=_('active until'))
|
active_until = models.DateTimeField(null=True, verbose_name=_('active until'))
|
||||||
active = models.BooleanField(default=True, verbose_name=_('active'))
|
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:
|
class Meta:
|
||||||
verbose_name = _('Announcement')
|
verbose_name = _('Announcement')
|
||||||
|
@ -22,6 +24,6 @@ class Announcement(models.Model):
|
||||||
def get_current(cls):
|
def get_current(cls):
|
||||||
try:
|
try:
|
||||||
return cls.objects.filter(Q(active=True) & (Q(active_until__isnull=True) |
|
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:
|
except cls.DoesNotExist:
|
||||||
return None
|
return None
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue