added gallery and portal informations

This commit is contained in:
2018-04-25 20:51:32 +02:00
parent b4ef6fe9f8
commit 9cc4e09698
25 changed files with 5948 additions and 53 deletions

View File

@@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from parler.admin import TranslatableAdmin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from portal.models import Profile, Information, DownloadSection, DownloadTag, DownloadFile
from portal.models import Profile, Announcement, DownloadSection, DownloadTag, DownloadFile, Information, \
InformationSection
class ProfileInline(admin.StackedInline):
@@ -25,8 +25,8 @@ admin.site.unregister(User)
admin.site.register(User, UserAdmin)
@admin.register(Information)
class InformationAdmin(TranslatableAdmin):
@admin.register(Announcement)
class AnnouncementAdmin(TranslatableAdmin):
list_display = ('title', 'published')
list_filter = ('groups',)
filter_horizontal = ('groups',)
@@ -38,6 +38,18 @@ class InformationAdmin(TranslatableAdmin):
)
@admin.register(Information)
class InformationAdmin(TranslatableAdmin):
list_display = ('title', 'published')
list_filter = ('groups',)
filter_horizontal = ('groups',)
@admin.register(InformationSection)
class InformationSectionAdmin(TranslatableAdmin):
pass
@admin.register(DownloadSection)
class DownloadSectionAdmin(TranslatableAdmin):
list_display = ('title', 'ordering')

View File

@@ -0,0 +1,130 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.8post1 on 2018-04-25 13:34
from __future__ import unicode_literals
import cms.models.fields
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import image_cropping.fields
import parler.models
import project.utils
class Migration(migrations.Migration):
dependencies = [
('cms', '0018_pagenode'),
('auth', '0008_alter_user_username_max_length'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
migrations.swappable_dependency(settings.FILER_IMAGE_MODEL),
('portal', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Announcement',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('cropping', image_cropping.fields.ImageRatioField('image', '1200x800', adapt_rotation=False, allow_fullsize=False, free_crop=True, help_text=None, hide_image_field=False, size_warning=False, verbose_name='cropping')),
('published', models.BooleanField(default=False, verbose_name='Veröffentlicht')),
('updated', models.DateTimeField(auto_now=True, verbose_name='Aktualisiert')),
('groups', models.ManyToManyField(related_name='announcements', to='auth.Group', verbose_name='Mitglieder Gruppe')),
('image', project.utils.CroppableFilerImageField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.FILER_IMAGE_MODEL, verbose_name='Bild')),
('informed_users', models.ManyToManyField(blank=True, null=True, to=settings.AUTH_USER_MODEL, verbose_name='Als gelesen markiert von:')),
('placeholder', cms.models.fields.PlaceholderField(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, slotname='content', to='cms.Placeholder')),
],
options={
'ordering': ['-updated'],
'verbose_name': 'Neuigkeit',
'verbose_name_plural': 'Neuigkeiten',
},
bases=(parler.models.TranslatableModelMixin, models.Model),
),
migrations.CreateModel(
name='AnnouncementTranslation',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('language_code', models.CharField(db_index=True, max_length=15, verbose_name='Language')),
('title', models.CharField(max_length=100, verbose_name='Title')),
('master', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='translations', to='portal.Announcement')),
],
options={
'db_table': 'portal_announcement_translation',
'verbose_name': 'Neuigkeit Translation',
'db_tablespace': '',
'default_permissions': (),
'managed': True,
},
),
migrations.CreateModel(
name='InformationSection',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ordering', models.IntegerField(default=50, verbose_name='Sortierung')),
],
options={
'ordering': ['ordering'],
'verbose_name': 'Information Section',
'verbose_name_plural': 'Information Sections',
},
bases=(parler.models.TranslatableModelMixin, models.Model),
),
migrations.CreateModel(
name='InformationSectionTranslation',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('language_code', models.CharField(db_index=True, max_length=15, verbose_name='Language')),
('title', models.CharField(max_length=100, verbose_name='Title')),
('master', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='translations', to='portal.InformationSection')),
],
options={
'db_table': 'portal_informationsection_translation',
'verbose_name': 'Information Section Translation',
'db_tablespace': '',
'default_permissions': (),
'managed': True,
},
),
migrations.AlterModelOptions(
name='information',
options={'verbose_name': 'Information', 'verbose_name_plural': 'Informationen'},
),
migrations.RemoveField(
model_name='information',
name='informed_users',
),
migrations.RemoveField(
model_name='information',
name='updated',
),
migrations.AddField(
model_name='informationtranslation',
name='description',
field=models.TextField(default='', verbose_name='Beschreibung'),
preserve_default=False,
),
migrations.AddField(
model_name='informationtranslation',
name='tag_list',
field=models.TextField(blank=True, help_text='Mit Komma getrennt', null=True, verbose_name='Tags'),
),
migrations.AlterField(
model_name='information',
name='groups',
field=models.ManyToManyField(related_name='informations', to='auth.Group', verbose_name='Mitglieder Gruppe'),
),
migrations.AddField(
model_name='information',
name='section',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='informations', to='portal.InformationSection', verbose_name='Information Section'),
),
migrations.AlterUniqueTogether(
name='informationsectiontranslation',
unique_together=set([('language_code', 'master')]),
),
migrations.AlterUniqueTogether(
name='announcementtranslation',
unique_together=set([('language_code', 'master')]),
),
]

View File

@@ -35,8 +35,8 @@ class Profile(models.Model):
return '{} {}'.format(self.first_name, self.last_name)
class Information(TranslatableModel):
groups = models.ManyToManyField(Group, verbose_name='Mitglieder Gruppe', related_name='tasks')
class Announcement(TranslatableModel):
groups = models.ManyToManyField(Group, verbose_name='Mitglieder Gruppe', related_name='announcements')
image = CroppableFilerImageField(verbose_name='Bild', blank=True, null=True)
cropping = ImageRatioField('image', '1200x800', free_crop=True)
@@ -50,10 +50,52 @@ class Information(TranslatableModel):
title=models.CharField(max_length=100, verbose_name='Title'),
)
class Meta:
verbose_name = 'Neuigkeit'
verbose_name_plural = 'Neuigkeiten'
ordering = ['-updated']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse_lazy('portal:announcement', args=[self.pk])
class InformationSection(TranslatableModel):
translations = TranslatedFields(
title=models.CharField(max_length=100, verbose_name='Title')
)
ordering = models.IntegerField(default=50, verbose_name='Sortierung')
class Meta:
verbose_name = 'Information Section'
verbose_name_plural = 'Information Sections'
ordering = ['ordering']
def __str__(self):
return self.title
class Information(TranslatableModel):
section = models.ForeignKey(InformationSection, verbose_name='Information Section', related_name='informations',
null=True, blank=True)
groups = models.ManyToManyField(Group, verbose_name='Mitglieder Gruppe', related_name='informations')
image = CroppableFilerImageField(verbose_name='Bild', blank=True, null=True)
cropping = ImageRatioField('image', '1200x800', free_crop=True)
placeholder = PlaceholderField('content')
published = models.BooleanField(verbose_name='Veröffentlicht', default=False)
translations = TranslatedFields(
title=models.CharField(max_length=100, verbose_name='Title'),
description=models.TextField(verbose_name='Beschreibung'),
tag_list=models.TextField(verbose_name='Tags', help_text='Mit Komma getrennt', null=True, blank=True)
)
class Meta:
verbose_name = 'Information'
verbose_name_plural = 'Informationen'
ordering = ['-updated']
def __str__(self):
return self.title

View File

@@ -10,7 +10,8 @@ from boto.s3.connection import (
class PrivateS3MediaStorage(S3MediaStorage):
def __init__(self):
def __init__(self, base_url=None):
self.base_url = base_url
bucket_name = settings.AWS_MEDIA_STORAGE_BUCKET_NAME
if '.' in bucket_name:

View File

@@ -33,7 +33,7 @@
<span class="button__icon">{% include 'project/assets/arrow-left-long.svg' %}</span>
<span class="button__text">{% trans 'Zurück zur Übersicht' %}</span>
</a>
{% if not request.user in object.informed_users.all %}
{% if not information and not request.user in object.informed_users.all %}
<button class="button">
<span class="button__icon">{% include 'project/assets/tick.svg' %}</span>
<span class="button__text">{% trans 'Als gelesen markieren' %}</span>

View File

@@ -92,13 +92,53 @@
</div>
</div>
<div id="information" class="downloads__frame">
<h2 class="reveal_self reveal reveal_animation">{% trans 'Informationen' %}</h2>
<form class="downloads__filter reveal_self reveal reveal_animation"
action="{{ request.path }}#information" method="get">
<div class="form__field form__field--icon">
<input name="information"
{% if request.GET.information %}value="{{ request.GET.information }}"{% endif %}
class="downloads_search"
type="text" placeholder="{% trans 'Suchbegriff eingeben' %}">
<button>{% trans 'Suchen' %}{% include 'project/assets/search.svg' %}</button>
</div>
</form>
{% for section in information_sections %}
<div class="downloads__section reveal_container">
<div class="downloads__section__title{% if flat %} downloads__section__title--flat{% endif %} reveal reveal_animation">
<h3>{{ section.title }}</h3>
</div>
<ul class="downloads">
{% for item in section.items %}
<li class="reveal_self reveal reveal_animation data_delay_{{ forloop.counter0 }}">
<a href="{{ item.get_absolute_url }}" class="download__item download__item--page">
<span class="download__item__title">{{ item.title }}</span>
<span class="download__item__description">
{% if item.description %}{{ item.description }}{% endif %}
</span>
<span class="downloads__item__tags">
{% if item.tag_list %}{{ item.tag_list }}{% endif %}</span>
<span class="download__item__icon">
{% include 'project/assets/arrow-right.svg' %}
</span>
</a>
</li>
{% endfor %}
</ul>
</div>
{% endfor %}
{% trans 'Informationen' as information_section_title %}
{% include 'project/plugins/content/section_title.html' with section_title=information_section_title %}
</div>
<div id="downloads" class="downloads__frame">
<h2 class="reveal_self reveal reveal_animation">{% trans 'Downloads' %}</h2>
<form class="downloads__filter reveal_self reveal reveal_animation"
action="{{ request.path }}#downloads" method="get">
<div class="form__field form__field--icon">
<input name="q" {% if request.GET.q %}value="{{ request.GET.q }}"{% endif %}
id="downloads_search"
class="downloads_search"
type="text" placeholder="{% trans 'Suchbegriff eingeben' %}">
<button>{% trans 'Suchen' %}{% include 'project/assets/search.svg' %}</button>
</div>

View File

@@ -7,7 +7,7 @@ from django.views.generic import TemplateView
from django.contrib.auth import views as auth_views
from portal.forms import LoginForm
from portal.views import ProfileEditView, OverviewView, InformationDetailView
from portal.views import ProfileEditView, OverviewView, AnnouncementDetailView, InformationDetailView
urlpatterns = [
url(_(r'^login/$'), auth_views.login, {'authentication_form': LoginForm}, name='login'),
@@ -30,8 +30,12 @@ urlpatterns = [
template_name='portal/edit_success.html'
), login_url=reverse_lazy('portal:login')), name='edit_profile_success'),
url(_(r'^announcement/(?P<pk>\d+)/$'),
login_required(AnnouncementDetailView.as_view(), login_url=reverse_lazy('portal:login')), name='announcement'),
url(_(r'^information/(?P<pk>\d+)/$'),
login_required(InformationDetailView.as_view(), login_url=reverse_lazy('portal:login')), name='information'),
login_required(InformationDetailView.as_view(), login_url=reverse_lazy('portal:login')),
kwargs={'information': True}, name='information'),
url(_(r'^$'), login_required(OverviewView.as_view(), login_url=reverse_lazy('portal:login')), name='overview'),
]

View File

@@ -5,22 +5,39 @@ from django.utils.translation import ugettext_lazy as _
from django.views.generic import UpdateView, ListView, DetailView
from portal.forms import ProfileEditForm
from portal.models import Information, DownloadFile
from portal.models import DownloadFile, Announcement, Information
class InformationQuerysetMixin(object):
class ContentQuerysetMixin(object):
def get_queryset(self):
queryset = Information.objects.all()
queryset = self.model.objects.all()
if not self.request.user.is_superuser:
queryset = queryset.filter(groups__in=self.request.user.groups.all())
queryset = queryset.filter(published=True)
return queryset
class OverviewView(InformationQuerysetMixin, ListView):
class OverviewView(ContentQuerysetMixin, ListView):
template_name = 'portal/overview.html'
open_tasks = None
paginate_by = 5
model = Announcement
def get_information_sections(self):
informations = Information.objects.filter(section__isnull=False, groups__in=self.request.user.groups.all())
sections = {}
for information in informations:
if not sections.get(information.section_id, None):
sections[information.section_id] = {
'section': information.section,
'items': []
}
sections[information.section_id]['items'].append(information)
sections_list = [{'title': x['section'].title, 'items': x['items'], 'ordering': x['section'].ordering} for x in
sections.values()]
return sorted(sections_list, key=lambda x: x['ordering'])
def get_download_sections(self):
file_list = DownloadFile.objects.filter(groups__in=self.request.user.groups.all())
@@ -43,7 +60,7 @@ class OverviewView(InformationQuerysetMixin, ListView):
return queryset.filter(informed_users__in=[self.request.user])
def get_open_tasks(self):
queryset = InformationQuerysetMixin.get_queryset(self).exclude(informed_users__in=[self.request.user])
queryset = ContentQuerysetMixin.get_queryset(self).exclude(informed_users__in=[self.request.user])
return queryset
def get_settings(self):
@@ -56,6 +73,7 @@ class OverviewView(InformationQuerysetMixin, ListView):
def get_context_data(self, **kwargs):
context = super(OverviewView, self).get_context_data(**kwargs)
context.update({
'information_sections': self.get_information_sections(),
'download_sections': self.get_download_sections(),
'settings': self.get_settings()
})
@@ -68,14 +86,20 @@ class OverviewView(InformationQuerysetMixin, ListView):
return context
class InformationDetailView(InformationQuerysetMixin, DetailView):
template_name = 'portal/information.html'
class AnnouncementDetailView(ContentQuerysetMixin, DetailView):
template_name = 'portal/content.html'
model = Announcement
def post(self, request, *args, **kwargs):
self.get_object().informed_users.add(self.request.user)
return redirect('portal:overview')
class InformationDetailView(ContentQuerysetMixin, DetailView):
template_name = 'portal/content.html'
model = Information
class ProfileEditView(UpdateView):
form_class = ProfileEditForm
template_name = 'portal/edit_form.html'