Skip to content
Snippets Groups Projects
Commit f75031e3 authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Merge branch '1-not-mensa-specific' into 'master'

Resolve "Not mensa-specific"

Closes #1 and #2

See merge request AlekSIS/onboarding/AlekSIS-App-Resint!14
parents a41e41c2 691131e7
No related branches found
No related tags found
1 merge request!14Resolve "Not mensa-specific"
Pipeline #24567 passed
Showing
with 564 additions and 104 deletions
......@@ -2,6 +2,10 @@ include:
- project: "AlekSIS/official/AlekSIS"
file: /ci/general.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test.yml
file: /ci/test/lint.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/build_dist.yml
file: /ci/test/security.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/build/dist.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/publish/pypi.yml
......@@ -18,9 +18,9 @@ Licence
::
Copyright © 2018, 2019, 2020 Jonathan Weth <wethjo@katharineum.de>
Copyright © 2018, 2019, 2020, 2021 Jonathan Weth <dev@jonathanweth.de>
Copyright © 2020, 2021 Frank Poetzsch-Heffter <p-h@katharineum.de>
Copyright © 2019 Julian Leucker <leuckeju@katharineum.de>
Copyright © 2020 Frank Poetzsch-Heffter <p-h@katharineum.de>
Licenced under the EUPL, version 1.2 or later
......
from django.contrib import admin
from .models import Poster
from .models import Poster, PosterGroup
admin.site.register(PosterGroup)
admin.site.register(Poster)
......@@ -6,11 +6,11 @@ class ResintConfig(AppConfig):
verbose_name = "AlekSIS – Resint (Public poster)"
urls = {
"Repository": "https://edugit.org/AlekSIS/official/AlekSIS-App-Resint/",
"Repository": "https://edugit.org/AlekSIS/onboarding/AlekSIS-App-Resint/",
}
licence = "EUPL-1.2+"
copyright = (
([2018, 2019, 2020], "Jonathan Weth", "wethjo@katharineum.de"),
copyright_info = (
([2018, 2019, 2020, 2021], "Jonathan Weth", "dev@jonathanweth.de"),
([2020, 2021], "Frank Poetzsch-Heffter", "p-h@katharineum.de"),
([2019], "Julian Leucker", "leuckeju@katharineum.de"),
([2020], "Frank Poetzsch-Heffter", "p-h@katharineum.de"),
)
File deleted
File deleted
from django import forms
from django.core.validators import FileExtensionValidator
from django.utils import timezone
from django.http import HttpRequest
from guardian.shortcuts import get_objects_for_user
from material import Layout, Row
from .models import Poster
from .models import Poster, PosterGroup
current_year = timezone.datetime.now().year
options_for_year = [(current_year, current_year), (current_year + 1, current_year + 1)]
calendar_weeks = [(cw, str(cw)) for cw in range(1, 53)]
class PosterUploadForm(forms.ModelForm):
calendar_week = forms.ChoiceField(choices=calendar_weeks, initial=timezone.datetime.now().isocalendar()[1])
year = forms.ChoiceField(
initial=timezone.datetime.now().year, choices=options_for_year
)
pdf = forms.FileField(
validators=[FileExtensionValidator(allowed_extensions=["pdf"])],
)
class PosterGroupForm(forms.ModelForm):
"""Form to manage poster groups."""
layout = Layout(
Row("calendar_week", "year"),
Row("pdf")
Row("slug"),
Row("name"),
Row("publishing_day", "publishing_time"),
Row("default_pdf"),
Row("show_in_menu", "public"),
)
class Meta:
model = PosterGroup
fields = [
"slug",
"name",
"publishing_day",
"publishing_time",
"default_pdf",
"show_in_menu",
"public",
]
class PosterUploadForm(forms.ModelForm):
"""Form for uploading new posters."""
class Meta:
model = Poster
fields = ("calendar_week", "year", "pdf")
fields = ["group", "week", "year", "pdf"]
def __init__(self, request: HttpRequest, *args, **kwargs):
super().__init__(*args, **kwargs)
qs = PosterGroup.objects.all()
if not request.user.has_perm("resint.view_postergroup"):
qs = get_objects_for_user(request.user, "resint.add_poster_to_group", qs)
self.fields["group"].queryset = qs
from typing import Any, Dict, List
from django.apps import apps
from django.urls import reverse
from django.utils.functional import lazy
from django.utils.translation import ugettext_lazy as _
def _get_menu_entries() -> List[Dict[str, Any]]:
"""Build menu entries for all poster groups.
This will include only poster groups where ``show_in_menu`` is enabled.
"""
PosterGroup = apps.get_model("resint", "PosterGroup")
return [
{
"name": group.name,
"url": reverse("poster_show_current", args=[group.slug]),
"icon": "picture_as_pdf",
"validators": [
(
"aleksis.apps.resint.rules.permission_validator",
"resint.view_poster_pdf_menu",
group,
),
],
}
for group in PosterGroup.objects.all()
]
get_menu_entries_lazy = lazy(_get_menu_entries, list)
MENUS = {
"NAV_MENU_CORE": [
{
......@@ -8,22 +39,33 @@ MENUS = {
"icon": "open_in_browser",
"root": True,
"validators": [
"menu_generator.validators.is_authenticated",
("aleksis.core.util.predicates.permission_validator", "resint.view_poster_menu",),
],
"submenu": [
{
"name": _("Current poster"),
"url": "poster_show_current",
"icon": "picture_as_pdf",
"validators": ["menu_generator.validators.is_authenticated"],
},
{
"name": _("Upload poster"),
"name": _("Manage posters"),
"url": "poster_index",
"icon": "file_upload",
"validators": ["menu_generator.validators.is_authenticated"],
"validators": [
(
"aleksis.core.util.predicates.permission_validator",
"resint.view_posters_rule",
),
],
},
{
"name": _("Poster groups"),
"url": "poster_group_list",
"icon": "topic",
"validators": [
(
"aleksis.core.util.predicates.permission_validator",
"resint.view_postergroups_rule",
),
],
},
],
}
]
+ get_menu_entries_lazy(),
}
# Generated by Django 3.0.4 on 2020-03-29 16:02
# Generated by Django 3.2.4 on 2021-06-30 18:23
import aleksis.apps.resint.models
import django.contrib.postgres.fields.jsonb
import calendarweek.calendarweek
import django.contrib.sites.managers
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
......@@ -10,22 +13,61 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('sites', '0002_alter_domain_unique'),
]
operations = [
migrations.CreateModel(
name='PosterGroup',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extended_data', models.JSONField(default=dict, editable=False)),
('slug', models.SlugField(help_text="If you use 'example', the filename will be 'example.pdf'.", verbose_name='Slug used in URL name')),
('name', models.CharField(max_length=255, verbose_name='Name')),
('publishing_day', models.PositiveSmallIntegerField(choices=[(0, 'Montag'), (1, 'Dienstag'), (2, 'Mittwoch'), (3, 'Donnerstag'), (4, 'Freitag'), (5, 'Samstag'), (6, 'Sonntag')], verbose_name='Publishing weekday')),
('publishing_time', models.TimeField(verbose_name='Publishing time')),
('default_pdf', models.FileField(help_text='This PDF file will be shown if there is no current PDF.', upload_to='default_posters/', validators=[django.core.validators.FileExtensionValidator(allowed_extensions=['pdf'])], verbose_name='Default PDF')),
('show_in_menu', models.BooleanField(default=True, verbose_name='Show in menu')),
('public', models.BooleanField(default=False, verbose_name='Show for not logged-in users')),
('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.site')),
],
options={
'verbose_name': 'Poster group',
'verbose_name_plural': 'Poster groups',
},
managers=[
('objects', django.contrib.sites.managers.CurrentSiteManager()),
],
),
migrations.CreateModel(
name='Poster',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
('calendar_week', models.IntegerField(verbose_name='CW')),
('year', models.IntegerField(verbose_name='Year')),
('pdf', models.FileField(upload_to=aleksis.apps.resint.models.path_and_rename_poster, verbose_name='PDF')),
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extended_data', models.JSONField(default=dict, editable=False)),
('week', models.PositiveSmallIntegerField(choices=[(1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'), (10, '10'), (11, '11'), (12, '12'), (13, '13'), (14, '14'), (15, '15'), (16, '16'), (17, '17'), (18, '18'), (19, '19'), (20, '20'), (21, '21'), (22, '22'), (23, '23'), (24, '24'), (25, '25'), (26, '26'), (27, '27'), (28, '28'), (29, '29'), (30, '30'), (31, '31'), (32, '32'), (33, '33'), (34, '34'), (35, '35'), (36, '36'), (37, '37'), (38, '38'), (39, '39'), (40, '40'), (41, '41'), (42, '42'), (43, '43'), (44, '44'), (45, '45'), (46, '46'), (47, '47'), (48, '48'), (49, '49'), (50, '50'), (51, '51'), (52, '52')], default=calendarweek.calendarweek.CalendarWeek.current_week, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(53)], verbose_name='Calendar week')),
('year', models.PositiveSmallIntegerField(default=aleksis.apps.resint.models._get_current_year, verbose_name='Year')),
('pdf', models.FileField(upload_to='posters/', validators=[django.core.validators.FileExtensionValidator(allowed_extensions=['pdf'])], verbose_name='PDF')),
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='posters', to='resint.postergroup', verbose_name='Poster group')),
('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.site')),
],
options={
'verbose_name': 'Poster',
'verbose_name_plural': 'Posters',
'unique_together': {('calendar_week', 'year')},
},
managers=[
('objects', django.contrib.sites.managers.CurrentSiteManager()),
],
),
migrations.AddConstraint(
model_name='postergroup',
constraint=models.UniqueConstraint(fields=('site_id', 'name'), name='unique_site_name'),
),
migrations.AddConstraint(
model_name='postergroup',
constraint=models.UniqueConstraint(fields=('site_id', 'slug'), name='unique_site_slug'),
),
migrations.AddConstraint(
model_name='poster',
constraint=models.UniqueConstraint(fields=('site_id', 'week', 'year'), name='unique_site_week_year'),
),
]
# Generated by Django 3.2.5 on 2021-07-03 09:20
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('resint', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='postergroup',
options={'permissions': [('view_poster_of_group', 'Can view all posters of this group'), ('upload_poster_to_group', 'Can upload new posters to this group'), ('delete_poster_of_group', 'Can delete all posters of this group')], 'verbose_name': 'Poster group', 'verbose_name_plural': 'Poster groups'},
),
]
# Generated by Django 3.2.5 on 2021-07-04 16:07
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('resint', '0002_permissions'),
]
operations = [
migrations.RemoveConstraint(
model_name='poster',
name='unique_site_week_year',
),
migrations.AddConstraint(
model_name='poster',
constraint=models.UniqueConstraint(fields=('site_id', 'week', 'year', 'group'), name='unique_site_week_year'),
),
]
# Generated by Django 3.2.5 on 2021-07-14 10:49
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('resint', '0003_group_in_unique_constraint'),
]
operations = [
migrations.AlterModelOptions(
name='postergroup',
options={'permissions': [('view_poster_of_group', 'Can view all posters of this group'), ('upload_poster_to_group', 'Can upload new posters to this group'), ('change_poster_to_group', 'Can change all posters of this group'), ('delete_poster_of_group', 'Can delete all posters of this group')], 'verbose_name': 'Poster group', 'verbose_name_plural': 'Poster groups'},
),
]
from datetime import datetime
from typing import Optional
from django.core.validators import FileExtensionValidator, MaxValueValidator, MinValueValidator
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from calendarweek import CalendarWeek
from calendarweek.django import i18n_day_name_choices_lazy
from aleksis.core.mixins import ExtensibleModel
from aleksis.core.util.core_helpers import path_and_rename
def path_and_rename_poster(instance, filename: str) -> str:
return path_and_rename(instance, filename, upload_to="poster")
class PosterGroup(ExtensibleModel):
"""Group for time-based documents, called posters."""
slug = models.SlugField(
verbose_name=_("Slug used in URL name"),
help_text=_("If you use 'example', the filename will be 'example.pdf'."),
)
name = models.CharField(max_length=255, verbose_name=_("Name"))
publishing_day = models.PositiveSmallIntegerField(
verbose_name=_("Publishing weekday"), choices=i18n_day_name_choices_lazy()
)
publishing_time = models.TimeField(verbose_name=_("Publishing time"))
default_pdf = models.FileField(
upload_to="default_posters/",
verbose_name=_("Default PDF"),
help_text=_("This PDF file will be shown if there is no current PDF."),
validators=[FileExtensionValidator(allowed_extensions=["pdf"])],
)
show_in_menu = models.BooleanField(default=True, verbose_name=_("Show in menu"))
public = models.BooleanField(default=False, verbose_name=_("Show for not logged-in users"))
class Meta:
verbose_name = _("Poster group")
verbose_name_plural = _("Poster groups")
constraints = [
models.UniqueConstraint(fields=["site_id", "name"], name="unique_site_name"),
models.UniqueConstraint(fields=["site_id", "slug"], name="unique_site_slug"),
]
permissions = [
("view_poster_of_group", _("Can view all posters of this group")),
("upload_poster_to_group", _("Can upload new posters to this group")),
("change_poster_to_group", _("Can change all posters of this group")),
("delete_poster_of_group", _("Can delete all posters of this group")),
]
def __str__(self) -> str:
return f"{self.name} ({self.publishing_day_name}, {self.publishing_time})"
@property
def publishing_day_name(self) -> str:
"""Return the full name of the publishing day (e. g. Monday)."""
return i18n_day_name_choices_lazy()[self.publishing_day][1]
@property
def filename(self) -> str:
"""Return the filename for the currently valid PDF file."""
return f"{self.slug}.pdf"
@property
def current_poster(self) -> Optional["Poster"]:
"""Get the currently valid poster."""
# Get current date with year and calendar week
current = timezone.datetime.now()
cw = CalendarWeek.from_date(current)
# Create datetime with the friday of the week and the toggle time
day = cw[self.publishing_day]
day_and_time = timezone.datetime.combine(day, self.publishing_time)
# Check whether to show the poster of the next week or the current week
if current > day_and_time:
cw += 1
# Look for matching PDF in DB
try:
obj = self.posters.get(year=cw.year, week=cw.week)
return obj
# Or show the default PDF
except Poster.DoesNotExist:
return None
def _get_current_year() -> int:
"""Get the current year."""
return timezone.now().year
calendar_weeks = [(cw, str(cw)) for cw in range(1, 53)]
class Poster(ExtensibleModel):
calendar_week = models.IntegerField(verbose_name=_("CW"))
year = models.IntegerField(verbose_name=_("Year"))
pdf = models.FileField(upload_to=path_and_rename_poster, verbose_name=_("PDF"))
"""A time-based document."""
group = models.ForeignKey(
to=PosterGroup,
related_name="posters",
on_delete=models.CASCADE,
verbose_name=_("Poster group"),
)
week = models.PositiveSmallIntegerField(
verbose_name=_("Calendar week"),
validators=[MinValueValidator(1), MaxValueValidator(53)],
default=CalendarWeek.current_week,
choices=calendar_weeks,
)
year = models.PositiveSmallIntegerField(verbose_name=_("Year"), default=_get_current_year)
pdf = models.FileField(
upload_to="posters/",
verbose_name=_("PDF"),
validators=[FileExtensionValidator(allowed_extensions=["pdf"])],
)
class Meta:
unique_together = ("calendar_week", "year")
constraints = [
models.UniqueConstraint(
fields=["site_id", "week", "year", "group"], name="unique_site_week_year"
)
]
verbose_name = _("Poster")
verbose_name_plural = _("Posters")
def __str__(self):
return "{} {}/{}".format(_("CW"), self.calendar_week, self.year)
def __str__(self) -> str:
return f"{self.group.name}: {self.week}/{self.year}"
@property
def valid_from(self) -> datetime:
"""Return the time this poster is valid from."""
cw = CalendarWeek(week=self.week, year=self.year) - 1
day = cw[self.group.publishing_day]
return timezone.datetime.combine(day, self.group.publishing_time)
@property
def valid_to(self) -> datetime:
"""Return the time this poster is valid to."""
cw = CalendarWeek(week=self.week, year=self.year)
day = cw[self.group.publishing_day]
return timezone.datetime.combine(day, self.group.publishing_time)
from django.contrib.auth.models import User
from django.http import HttpRequest
from rules import add_perm, predicate
from aleksis.apps.resint.models import Poster, PosterGroup
from aleksis.core.util.predicates import (
check_object_permission,
has_any_object,
has_global_perm,
has_object_perm,
has_person,
)
def has_poster_group_object_perm(perm: str):
name = f"has_poster_group_object_perm:{perm}"
@predicate(name)
def fn(user: User, obj: Poster) -> bool:
return check_object_permission(user, perm, obj.group, checker_obj=obj)
return fn
def permission_validator(request: HttpRequest, perm: str, obj) -> bool:
"""Check whether the request user has a permission."""
if request.user:
return request.user.has_perm(perm, obj)
return False
@predicate
def is_public_poster_group(user: User, obj: PosterGroup):
return obj.public
@predicate
def show_poster_group_in_menu(user: User, obj: PosterGroup):
return obj.show_in_menu
# View poster group list
view_poster_groups_predicate = has_person & (
has_global_perm("resint.view_postergroup")
| has_any_object("resint.view_postergroup", PosterGroup)
)
add_perm("resint.view_postergroups_rule", view_poster_groups_predicate)
# Add poster group
add_poster_group_predicate = view_poster_groups_predicate & has_global_perm(
"resint.add_postergroup"
)
add_perm("resint.add_postergroup_rule", add_poster_group_predicate)
# Edit poster group
edit_poster_group_predicate = view_poster_groups_predicate & (
has_global_perm("resint.change_postergroup") | has_object_perm("resint.change_postergroup")
)
add_perm("resint.edit_postergroup_rule", edit_poster_group_predicate)
# Delete poster group
delete_poster_group_predicate = view_poster_groups_predicate & (
has_global_perm("resint.delete_postergroup") | has_object_perm("resint.delete_postergroup")
)
add_perm("resint.delete_postergroup_rule", delete_poster_group_predicate)
view_posters_predicate = has_person & (
has_global_perm("resint.view_poster")
| has_any_object("resint.view_poster", Poster)
| has_any_object("resint.view_poster_of_group", PosterGroup)
)
add_perm("resint.view_posters_rule", view_posters_predicate)
# Upload poster
upload_poster_predicate = view_posters_predicate & (
has_global_perm("resint.add_poster") | has_any_object("resint.add_poster_to_group", PosterGroup)
)
add_perm("resint.upload_poster_rule", upload_poster_predicate)
# Edit poster
edit_poster_predicate = view_posters_predicate & (
has_global_perm("resint.change_poster")
| has_object_perm("resint.change_poster")
| has_poster_group_object_perm("resint.change_poster_of_group")
)
add_perm("resint.edit_poster_rule", edit_poster_predicate)
# Delete poster
delete_poster_predicate = view_posters_predicate & (
has_global_perm("resint.delete_poster")
| has_object_perm("resint.delete_poster")
| has_poster_group_object_perm("resint.delete_poster_of_group")
)
add_perm("resint.delete_poster_rule", delete_poster_predicate)
# View poster PDF file
view_poster_pdf_predicate = is_public_poster_group | (
has_person
& (has_global_perm("resint.view_postergroup") | has_global_perm("resint.view_poster"))
)
add_perm("resint.view_poster_pdf", view_poster_pdf_predicate)
# View menu entry for single posters
view_poster_pdf_menu_predicate = show_poster_group_in_menu & view_poster_pdf_predicate
add_perm("resint.view_poster_pdf_menu", view_poster_pdf_menu_predicate)
# Show the poster manage menu
view_poster_menu_predicate = view_posters_predicate | view_poster_groups_predicate
add_perm("resint.view_poster_menu", view_poster_menu_predicate)
import os
from datetime import time
from django.utils.translation import gettext_lazy as _
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
CONSTANCE_CONFIG = {
"RESINT_NEW_WEEK_DAY": (4, _("Weekday at which the poster of the next week is to be shown"), "weekday_field"),
"RESINT_NEW_WEEK_TIME": (time(14, 00), _("Time at which the poster of the next week is to be shown"), time)
}
CONSTANCE_CONFIG_FIELDSETS = {
"Resint settings": ("RESINT_NEW_WEEK_DAY", "RESINT_NEW_WEEK_TIME"),
}
{% extends 'core/base.html' %}
{% load material_form i18n %}
{% block browser_title %}
{% blocktrans %}Create poster group{% endblocktrans %}
{% endblock %}
{% block page_title %}
{% blocktrans %}Create poster group{% endblocktrans %}
{% endblock %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% form form=form %}{% endform %}
{% include "core/partials/save_button.html" %}
</form>
{% endblock %}
{% extends 'core/base.html' %}
{% load material_form i18n %}
{% block page_title %}
{% trans "Edit poster group" %}
{% endblock %}
{% block browser_title %}
{% trans "Edit poster group" %}
{% endblock %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% form form=form %}{% endform %}
{% include "core/partials/save_button.html" %}
</form>
{% endblock %}
{% extends 'core/base.html' %}
{% load material_form i18n rules %}
{% block browser_title %}{% blocktrans %}Poster groups{% endblocktrans %}{% endblock %}
{% block content %}
{% has_perm "resint.add_postergroup_rule" user as can_add_poster_group %}
{% if can_add_poster_group %}
<a class="waves-effect waves-light btn green modal-trigger right" href="{% url "create_poster_group" %}">
<i class="material-icons left">add</i>{% blocktrans %}Create new poster group{% endblocktrans %}
</a>
{% endif %}
<h1>{% blocktrans %}Poster groups{% endblocktrans %}</h1>
<table>
<thead>
<tr>
<th>{% blocktrans %}Name{% endblocktrans %}</th>
<th>{% blocktrans %}Filename{% endblocktrans %}</th>
<th>{% blocktrans %}Publishing day{% endblocktrans %}</th>
<th>{% blocktrans %}Publishing time{% endblocktrans %}</th>
<th>{% blocktrans %}Default PDF file{% endblocktrans %}</th>
<th>{% blocktrans %}Actions{% endblocktrans %}</th>
</tr>
</thead>
<tbody>
{% for poster_group in postergroup_list %}
<tr>
<td>{{ poster_group.name }}</td>
<td>
<a href="{% url "poster_show_current" poster_group.slug %}" target="_blank">
<code>{{ poster_group.filename }}</code></a>
</td>
<td>{{ poster_group.publishing_day_name }}</td>
<td>{{ poster_group.publishing_time }}</td>
<td>
<a href="{{ poster_group.default_pdf.url }}" class="btn-flat" target="_blank">
<i class="material-icons left">picture_as_pdf</i>
{% trans "Open" %}
</a>
</td>
<td>
{% has_perm "resint.edit_postergroup_rule" user poster_group as can_edit_poster_group %}
{% if can_edit_poster_group %}
<a href="{% url 'edit_poster_group' poster_group.id %}"
class="waves-effect waves-light btn-flat orange-text">
<i class="material-icons left">edit</i>
{% trans "Edit" %}
</a>
{% endif %}
{% has_perm "resint.delete_postergroup_rule" user poster_group as can_delete_poster_group %}
{% if can_delete_poster_group %}
<a href="{% url 'delete_poster_group' poster_group.id %}"
class="waves-effect waves-light btn-flat red-text">
<i class="material-icons left">delete</i>
{% trans "Delete" %}
</a>
{% endif %}
</td>
</tr>
{% empty %}
<tr>
<td colspan="4">{% blocktrans %}There are no poster groups available.{% endblocktrans %}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% extends "core/base.html" %}
{% load msg_box static i18n %}
{% block content %}
<a class="waves-effect waves-light btn green" href="{% url "poster_upload" %}"><i class="material-icons left">add</i>
{% trans "Upload new poster" %}
</a>
<a class="waves-effect waves-light btn orange" href="{% url "poster_show_current" %}"><i class="material-icons left">picture_as_pdf</i>
{% trans "Show current poster" %}
</a>
<h5>{% trans "All uploaded posters" %}</h5>
<ul class="collection">
{% for poster in posters %}
<li class="collection-item ">
<span class="title">{{ poster }}</span>
<p>
<a class="btn-flat waves-effect waves-green" href="{% get_media_prefix %}{{ poster.pdf }}" target="_blank">
<i class="material-icons left">picture_as_pdf</i> {% trans "Show" %}
</a>
<a class="btn-flat delete-poster waves-effect waves-red" href="{% url "poster_delete" poster.id %}">
<i class="material-icons left">delete</i> {% trans "Delete" %}
</a>
</p>
</li>
{% endfor %}
</ul>
<script type="text/javascript">
$(".delete-poster").click(function (e) {
if (!confirm("Wirklich löschen?")) {
e.preventDefault();
}
})
</script>
{% endblock %}
{% extends 'core/base.html' %}
{% load material_form i18n %}
{% block page_title %}
{% trans "Edit poster" %}
{% endblock %}
{% block browser_title %}
{% trans "Edit poster" %}
{% endblock %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% form form=form %}{% endform %}
{% include "core/partials/save_button.html" %}
</form>
{% endblock %}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment