rename things
This commit is contained in:
0
src/portal/__init__.py
Normal file
0
src/portal/__init__.py
Normal file
60
src/portal/admin.py
Normal file
60
src/portal/admin.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from aldryn_forms.utils import get_user_model
|
||||
from django.contrib import admin
|
||||
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
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class ProfileInline(admin.StackedInline):
|
||||
model = Profile
|
||||
can_delete = False
|
||||
|
||||
|
||||
class UserAdmin(BaseUserAdmin):
|
||||
inlines = [ProfileInline]
|
||||
fieldsets = (
|
||||
(None, {'fields': ('username', 'password')}),
|
||||
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups')}),
|
||||
)
|
||||
|
||||
|
||||
admin.site.unregister(User)
|
||||
admin.site.register(User, UserAdmin)
|
||||
|
||||
|
||||
@admin.register(Information)
|
||||
class InformationAdmin(TranslatableAdmin):
|
||||
list_display = ('title', 'published', 'publish_date')
|
||||
list_filter = ('groups',)
|
||||
filter_horizontal = ('groups',)
|
||||
readonly_fields = ('informed_users',)
|
||||
fieldsets = (
|
||||
(None, {'fields': ('title', 'published', 'image', 'cropping')}),
|
||||
(_('Permissions'), {'fields': ('groups',)}),
|
||||
(_('Veröffentlichung'), {'fields': ('publish_date',)}),
|
||||
(_('Information'), {'fields': ('informed_users',)}),
|
||||
)
|
||||
|
||||
|
||||
@admin.register(DownloadSection)
|
||||
class DownloadSectionAdmin(TranslatableAdmin):
|
||||
list_display = ('title', 'ordering')
|
||||
list_editable = ['ordering']
|
||||
|
||||
|
||||
@admin.register(DownloadTag)
|
||||
class DownloadTagAdmin(TranslatableAdmin):
|
||||
pass
|
||||
|
||||
|
||||
@admin.register(DownloadFile)
|
||||
class DownloadFileAdmin(TranslatableAdmin):
|
||||
list_display = ('label', 'ordering')
|
||||
list_editable = ['ordering']
|
||||
list_filter = ('section', 'groups')
|
||||
filter_horizontal = ('groups', 'tags')
|
||||
22
src/portal/forms.py
Normal file
22
src/portal/forms.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from django import forms
|
||||
from django.contrib.auth.forms import AuthenticationForm
|
||||
|
||||
from portal.models import Profile
|
||||
|
||||
|
||||
class LoginForm(AuthenticationForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(LoginForm, self).__init__(*args, **kwargs)
|
||||
for _, value in self.fields.items():
|
||||
value.widget.attrs['placeholder'] = value.label
|
||||
|
||||
|
||||
class ProfileEditForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Profile
|
||||
fields = ['first_name', 'last_name', 'street', 'zip', 'place', 'email']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ProfileEditForm, self).__init__(*args, **kwargs)
|
||||
self.fields['zip'].widget = forms.TextInput()
|
||||
0
src/portal/migrations/__init__.py
Normal file
0
src/portal/migrations/__init__.py
Normal file
142
src/portal/models.py
Normal file
142
src/portal/models.py
Normal file
@@ -0,0 +1,142 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from cms.models.fields import PlaceholderField
|
||||
import os
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import Group
|
||||
from django.core.files.storage import default_storage
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from image_cropping import ImageRatioField
|
||||
from parler.models import TranslatableModel, TranslatedFields
|
||||
|
||||
from portal.storage import PrivateS3MediaStorage
|
||||
from project.utils import CroppableFilerImageField
|
||||
|
||||
|
||||
class Profile(models.Model):
|
||||
user = models.OneToOneField(get_user_model(), related_name='profile', on_delete=models.CASCADE)
|
||||
first_name = models.CharField(verbose_name=_('Vorname'), max_length=255)
|
||||
last_name = models.CharField(verbose_name=_('Nachname'), max_length=255)
|
||||
street = models.CharField(verbose_name=_('Strasse'), max_length=255, null=True, blank=True)
|
||||
zip = models.IntegerField(verbose_name=_('PLZ'), null=True, blank=True)
|
||||
place = models.CharField(verbose_name=_('Ort'), max_length=255, null=True, blank=True)
|
||||
email = models.EmailField(verbose_name=_('E-Mail'), null=True, blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'User Profil'
|
||||
verbose_name_plural = 'User Profile'
|
||||
|
||||
def __str__(self):
|
||||
return self.full_name
|
||||
|
||||
@property
|
||||
def full_name(self):
|
||||
return '{} {}'.format(self.first_name, self.last_name)
|
||||
|
||||
|
||||
class Information(TranslatableModel):
|
||||
groups = models.ManyToManyField(Group, verbose_name='Mitglieder Gruppe', related_name='tasks')
|
||||
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)
|
||||
publish_date = models.DateTimeField(verbose_name='Veröffentlichungsdatum', default=timezone.now)
|
||||
|
||||
informed_users = models.ManyToManyField(get_user_model(), verbose_name='Als gelesen markiert von:',
|
||||
null=True, blank=True)
|
||||
|
||||
translations = TranslatedFields(
|
||||
title=models.CharField(max_length=100, verbose_name=_('Title')),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Mitglieder Aufgabe'
|
||||
verbose_name_plural = 'Mitglieder Aufgaben'
|
||||
ordering = ['-publish_date']
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse_lazy('portal:information', args=[self.pk])
|
||||
|
||||
|
||||
class DownloadSection(TranslatableModel):
|
||||
translations = TranslatedFields(
|
||||
title=models.CharField(max_length=100, verbose_name='Title')
|
||||
)
|
||||
ordering = models.IntegerField(default=50, verbose_name='Sortierung')
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Download Section'
|
||||
verbose_name_plural = 'Download Sections'
|
||||
ordering = ['ordering']
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
|
||||
class DownloadTag(TranslatableModel):
|
||||
translations = TranslatedFields(
|
||||
name=models.CharField(max_length=100, verbose_name='Name')
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Download Tag'
|
||||
verbose_name_plural = 'Download Tags'
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
if getattr(settings, 'DEFAULT_STORAGE_DSN', None):
|
||||
protected_file_storage = PrivateS3MediaStorage()
|
||||
else:
|
||||
protected_file_storage = default_storage
|
||||
|
||||
|
||||
class DownloadFile(TranslatableModel):
|
||||
section = models.ForeignKey(DownloadSection, verbose_name='Download Section', related_name='files')
|
||||
groups = models.ManyToManyField(Group, verbose_name='Mitgliedergruppen', related_name='files')
|
||||
tags = models.ManyToManyField(DownloadTag, verbose_name='Suchbegriffe', related_name='files',
|
||||
blank=True, null=True)
|
||||
|
||||
translations = TranslatedFields(
|
||||
name=models.CharField(max_length=512, verbose_name='Name', blank=True, null=True),
|
||||
description=models.TextField(verbose_name='Beschreibung', blank=True, null=True),
|
||||
file=models.FileField(upload_to='protected_files', max_length=512, storage=protected_file_storage)
|
||||
)
|
||||
|
||||
ordering = models.IntegerField(default=50, verbose_name='Sortierung')
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Download File'
|
||||
verbose_name_plural = 'Download Files'
|
||||
ordering = ['ordering']
|
||||
|
||||
def __str__(self):
|
||||
return self.label
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
return self.file.url
|
||||
|
||||
@property
|
||||
def extension(self):
|
||||
return self.file.name.split('.')[-1]
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
if self.name:
|
||||
return self.name
|
||||
else:
|
||||
return os.path.basename(self.file.name)
|
||||
|
||||
@property
|
||||
def tag_list(self):
|
||||
return ', '.join(list(self.tags.values_list('translations__name', flat=True)))
|
||||
57
src/portal/storage.py
Normal file
57
src/portal/storage.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
from aldryn_django.storage import S3MediaStorage
|
||||
from django.conf import settings
|
||||
|
||||
from boto.s3.connection import (
|
||||
SubdomainCallingFormat,
|
||||
OrdinaryCallingFormat,
|
||||
)
|
||||
|
||||
|
||||
class PrivateS3MediaStorage(S3MediaStorage):
|
||||
def __init__(self):
|
||||
bucket_name = settings.AWS_MEDIA_STORAGE_BUCKET_NAME
|
||||
|
||||
if '.' in bucket_name:
|
||||
calling_format = OrdinaryCallingFormat()
|
||||
else:
|
||||
calling_format = SubdomainCallingFormat()
|
||||
|
||||
# We cannot use a function call or a partial here. Instead, we have to
|
||||
# create a subclass because django tries to recreate a new object by
|
||||
# calling the __init__ of the returned object (with no arguments).
|
||||
super(S3MediaStorage, self).__init__(
|
||||
access_key=settings.AWS_MEDIA_ACCESS_KEY_ID,
|
||||
secret_key=settings.AWS_MEDIA_SECRET_ACCESS_KEY,
|
||||
bucket_name=bucket_name,
|
||||
location=settings.AWS_MEDIA_BUCKET_PREFIX,
|
||||
host=settings.AWS_MEDIA_STORAGE_HOST,
|
||||
custom_domain=settings.AWS_MEDIA_DOMAIN,
|
||||
calling_format=calling_format,
|
||||
# Setting an ACL requires us to grant the user the PutObjectAcl
|
||||
# permission as well, even if it matches the default bucket ACL.
|
||||
# XXX: Ideally we would thus set it to `None`, but due to how
|
||||
# easy_thumbnails works internally, that causes thumbnail
|
||||
# generation to fail...
|
||||
default_acl='private',
|
||||
querystring_auth=True,
|
||||
)
|
||||
# MEDIA_HEADERS is a list of tuples containing a regular expression
|
||||
# to match against a path, and a dictionary of HTTP headers to be
|
||||
# returned with the resource identified by the path when it is
|
||||
# requested.
|
||||
# The headers are applied in the order they where declared, and
|
||||
# processing stops at the first match.
|
||||
# E.g.:
|
||||
#
|
||||
# MEDIA_HEADERS = [
|
||||
# (r'media/cache/.*', {
|
||||
# 'Cache-Control': 'max-age={}'.format(3600 * 24 * 365),
|
||||
# })
|
||||
# ]
|
||||
#
|
||||
media_headers = getattr(settings, 'MEDIA_HEADERS', [])
|
||||
self.media_headers = [
|
||||
(re.compile(r), headers) for r, headers in media_headers
|
||||
]
|
||||
13
src/portal/templates/portal/edit_form.html
Normal file
13
src/portal/templates/portal/edit_form.html
Normal file
@@ -0,0 +1,13 @@
|
||||
{% load i18n %}
|
||||
<form action="{{ request.path }}" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="control__item__fields">
|
||||
{% for field in form %}
|
||||
{% include 'project/includes/field.html' with field=field label=True %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<button class="button button--small">
|
||||
<span class="button__icon">{% include 'project/assets/tick.svg' %}</span>
|
||||
<span class="button__text">{% trans 'Speichern' %}</span>
|
||||
</button>
|
||||
</form>
|
||||
8
src/portal/templates/portal/edit_success.html
Normal file
8
src/portal/templates/portal/edit_success.html
Normal file
@@ -0,0 +1,8 @@
|
||||
{% load i18n %}
|
||||
<div class="control__item__success">
|
||||
<p>{% trans 'Ihre Informationen wurden erfolgreich angepasst.' %}</p>
|
||||
<a href="#" class="button button--small control__item__close">
|
||||
<span class="button__icon">{% include 'project/assets/close.svg' %}</span>
|
||||
<span class="button__text">{% trans 'Schliessen' %}</span>
|
||||
</a>
|
||||
</div>
|
||||
44
src/portal/templates/portal/information.html
Normal file
44
src/portal/templates/portal/information.html
Normal file
@@ -0,0 +1,44 @@
|
||||
{% extends 'project/content.html' %}
|
||||
{% load i18n thumbnail cms_tags %}
|
||||
|
||||
{% block title %}{{ object.title }}{% endblock %}
|
||||
|
||||
{% block content_intro %}
|
||||
<div class="content__intro reveal_container reveal_self reveal reveal_animation{% if object.image %} image{% endif %}">
|
||||
<div class="content__intro__content reveal reveal_animation">
|
||||
<h1>{{ object.title }}</h1>
|
||||
<a href="{% url 'portal:overview' %}" class="button">
|
||||
<span class="button__icon">{% include 'project/assets/arrow-left-long.svg' %}</span>
|
||||
<span class="button__text">{% trans 'Zurück zur Übersicht' %}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% if object.image %}
|
||||
{% thumbnail object.image 1600x800 box=object.cropping crop detail as thumb %}
|
||||
<div class="content__intro__image scroll reveal reveal_animation" data-ease-multiplier="-2"
|
||||
style="background-image: url({{ thumb.url }})"></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block navigation_title %}{{ object.title }}{% endblock %}
|
||||
|
||||
{% block content_main %}
|
||||
{% render_placeholder object.placeholder language LANGUAGE_CODE %}
|
||||
|
||||
<form action="{{ request.path }}" method="post" class="information__form reveal_self reveal reveal_animation">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="form__submit">
|
||||
<a href="{% url 'portal:overview' %}" class="button button--ghost">
|
||||
<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 %}
|
||||
<button class="button">
|
||||
<span class="button__icon">{% include 'project/assets/tick.svg' %}</span>
|
||||
<span class="button__text">{% trans 'Als gelesen markieren' %}</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
117
src/portal/templates/portal/overview.html
Normal file
117
src/portal/templates/portal/overview.html
Normal file
@@ -0,0 +1,117 @@
|
||||
{% extends 'main.html' %}
|
||||
{% load i18n static %}
|
||||
|
||||
{% block title %}{% trans 'Mitgliederbereich' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="content__frame">
|
||||
<div class="content__intro reveal_container reveal_self reveal reveal_animation image">
|
||||
<div class="content__intro__content reveal reveal_animation">
|
||||
<h1>{% trans 'Grüezi, ' %}{{ request.user.profile.full_name }}</h1>
|
||||
<p>{% trans 'Willkommen in Ihrem persönlichen Portal der Tagesschule Elementa' %}</p>
|
||||
<a href="{% url 'portal:logout' %}" class="button">
|
||||
<span class="button__icon">{% include 'project/assets/arrow-left-long.svg' %}</span>
|
||||
<span class="button__text">{% trans 'Logout' %}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="content__intro__image scroll reveal reveal_animation" data-ease-multiplier="-2"
|
||||
style="background-image: url({% static 'img/portal_background.jpg' %})"></div>
|
||||
</div>
|
||||
<div class="content__container">
|
||||
<div class="content__main">
|
||||
<div class="control_panel reveal_self reveal reveal_animation">
|
||||
<div class="control_panel__content">
|
||||
<div class="control_panel__content__item">
|
||||
<h2 class="reveal_self reveal reveal_animation">{% trans 'Aktuell' %}</h2>
|
||||
<div id="todo" class="load__frame">
|
||||
<div class="load__main">
|
||||
<ul class="control__list reveal_container">
|
||||
{% for object in object_list %}
|
||||
<li class="data_id_{{ forloop.counter0 }} reveal reveal_animation">
|
||||
<a href="{{ object.get_absolute_url }}"
|
||||
class="p control__item control__item--arrow control__item--status {% if request.user in object.informed_users.all %}control__item--status--active{% endif %}">
|
||||
<span class="control__item__title">
|
||||
<span class="control__item__status">
|
||||
{% if object.is_expired %}
|
||||
{% include 'project/assets/close.svg' %}
|
||||
{% else %}
|
||||
{% include 'project/assets/tick.svg' %}
|
||||
{% endif %}
|
||||
</span>
|
||||
{{ object.title }}
|
||||
<span class="control__item__arrow">
|
||||
{% include 'project/assets/arrow-right.svg' %}
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% if page_obj.has_next or paginator.count > 0 and open_object_list %}
|
||||
<div class="load__replace data_id_3 reveal_self reveal reveal_animation">
|
||||
<a href="{% spaceless %}{% url 'portal:overview' %}?page=
|
||||
{% if open_object_list %}{{ page_obj.start_index }}{% else %}{{ page_obj.next_page_number }}{% endif %}{% endspaceless %}"
|
||||
class="button button--load list__button button--small">
|
||||
<span class="button__icon">{% include 'project/assets/dots.svg' %}</span>
|
||||
<span class="button__text">{% trans 'Ältere laden' %}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control_panel__content__item">
|
||||
<h2 class="reveal_self reveal reveal_animation">{% trans 'Einstellungen' %}</h2>
|
||||
<ul class="control__list reveal_container">
|
||||
{% for settings_title, settings_url in settings %}
|
||||
<li class="reveal reveal_animation data_delay_{{ forloop.counter0 }}">
|
||||
<div class="control__item control__item--button">
|
||||
<span class="control__item__title">
|
||||
{{ settings_title }}
|
||||
<a href="#" data-href="{{ settings_url }}"
|
||||
class="button button--small control__item__open">
|
||||
<span class="button__icon">{% include 'project/assets/dots.svg' %}</span>
|
||||
<span class="button__text">{% trans 'Ändern' %}</span>
|
||||
</a>
|
||||
<a href="#"
|
||||
class="button button--small button--ghost control__item__close">
|
||||
<span class="button__icon">{% include 'project/assets/close.svg' %}</span>
|
||||
<span class="button__text">{% trans 'Abbrechen' %}</span>
|
||||
</a>
|
||||
</span>
|
||||
<div class="control__item__content">
|
||||
<div class="control__item__content__main">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="downloads" class="downloads__frame reveal_self reveal reveal_animation">
|
||||
<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"
|
||||
type="text" placeholder="{% trans 'Suchbegriff eingeben' %}">
|
||||
<button>{% trans 'Suchen' %}{% include 'project/assets/search.svg' %}</button>
|
||||
</div>
|
||||
</form>
|
||||
{% for section in download_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>
|
||||
{% include 'project/plugins/content/download_section.html' with instance=section %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
36
src/portal/templates/registration/login.html
Normal file
36
src/portal/templates/registration/login.html
Normal file
@@ -0,0 +1,36 @@
|
||||
{% extends 'project/dialog.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans 'Mitgliederbereich' %}{% endblock %}
|
||||
|
||||
{% block extra_meta %}
|
||||
<meta name="robots" content="noindex, nofollow"/>
|
||||
{% endblock %}
|
||||
|
||||
{% block dialog %}
|
||||
<h2 class="reveal_self reveal reveal_animation">{% trans 'Login' %}</h2>
|
||||
<p class="reveal_self reveal reveal_animation section__text">
|
||||
Lorem ipsum dolor sit amet, consetetur sadipscing elitr.
|
||||
</p>
|
||||
<form class="reveal_self reveal reveal_animation" method="post" action=".">
|
||||
{% if form.non_field_errors %}
|
||||
{% for error in form.non_field_errors %}
|
||||
<p class="form__errors reveal_self reveal reveal_animation">{{ error }}</p>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% csrf_token %}
|
||||
|
||||
{% for field in form %}
|
||||
{% include 'project/includes/field.html' with field=field %}
|
||||
{% endfor %}
|
||||
|
||||
<div class="form__submit reveal_self reveal reveal_animation">
|
||||
<button type="submit" class="button">
|
||||
<span class="button__icon">{% include 'project/assets/arrow-right-long.svg' %}</span>
|
||||
<span class="button__text">{% trans 'Login' %}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
37
src/portal/urls.py
Normal file
37
src/portal/urls.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from django.conf.urls import url
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.views import LoginView, LogoutView, PasswordChangeView
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from portal.forms import LoginForm
|
||||
from portal.views import ProfileEditView, OverviewView, InformationDetailView
|
||||
|
||||
urlpatterns = [
|
||||
url(_(r'^login/$'), LoginView.as_view(form_class=LoginForm), name='login'),
|
||||
|
||||
url(_(r'^logout/$'), LogoutView.as_view(next_page=reverse_lazy('portal:overview')), name='logout'),
|
||||
|
||||
url(_(r'^account/change/password/$'), login_required(PasswordChangeView.as_view(
|
||||
template_name='portal/edit_form.html',
|
||||
success_url=reverse_lazy('portal:change_password_success')
|
||||
), login_url=reverse_lazy('portal:login')), name='change_password'),
|
||||
|
||||
url(_(r'^account/change/password/success/$'), login_required(TemplateView.as_view(
|
||||
template_name='portal/edit_success.html'
|
||||
), login_url=reverse_lazy('portal:login')), name='change_password_success'),
|
||||
|
||||
url(_(r'^account/edit/profile/$'), login_required(ProfileEditView.as_view(
|
||||
), login_url=reverse_lazy('portal:login')), name='edit_profile'),
|
||||
|
||||
url(_(r'^account/edit/profile/success/$'), login_required(TemplateView.as_view(
|
||||
template_name='portal/edit_success.html'
|
||||
), login_url=reverse_lazy('portal:login')), name='edit_profile_success'),
|
||||
|
||||
url(_(r'^info/(?P<pk>\d+)/$'),
|
||||
login_required(InformationDetailView.as_view(), login_url=reverse_lazy('portal:login')), name='information'),
|
||||
|
||||
url(_(r'^$'), login_required(OverviewView.as_view(), login_url=reverse_lazy('portal:login')), name='overview'),
|
||||
]
|
||||
84
src/portal/views.py
Normal file
84
src/portal/views.py
Normal file
@@ -0,0 +1,84 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from django.shortcuts import redirect
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
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
|
||||
|
||||
|
||||
class InformationQuerysetMixin(object):
|
||||
def get_queryset(self):
|
||||
queryset = Information.objects.filter(groups__in=self.request.user.groups.all())
|
||||
if not self.request.user.is_superuser:
|
||||
queryset = queryset.filter(published=True)
|
||||
return queryset
|
||||
|
||||
|
||||
class OverviewView(InformationQuerysetMixin, ListView):
|
||||
template_name = 'portal/overview.html'
|
||||
open_tasks = None
|
||||
paginate_by = 5
|
||||
|
||||
def get_download_sections(self):
|
||||
file_list = DownloadFile.objects.filter(groups__in=self.request.user.groups.all())
|
||||
sections = {}
|
||||
for file in file_list:
|
||||
if not sections.get(file.section_id, None):
|
||||
sections[file.section_id] = {
|
||||
'section': file.section,
|
||||
'items': []
|
||||
}
|
||||
sections[file.section_id]['items'].append(file)
|
||||
|
||||
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_queryset(self):
|
||||
queryset = super(OverviewView, self).get_queryset()
|
||||
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])
|
||||
return queryset
|
||||
|
||||
def get_settings(self):
|
||||
settings = (
|
||||
(_('Benutzerdaten'), reverse_lazy('portal:edit_profile')),
|
||||
(_('Passwort'), reverse_lazy('portal:change_password')),
|
||||
)
|
||||
return settings
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(OverviewView, self).get_context_data(**kwargs)
|
||||
context.update({
|
||||
'download_sections': self.get_download_sections(),
|
||||
'settings': self.get_settings()
|
||||
})
|
||||
self.open_tasks = self.get_open_tasks()
|
||||
if not self.request.GET.get(self.page_kwarg, None) and self.open_tasks.count() > 0:
|
||||
context.update({
|
||||
'object_list': self.open_tasks,
|
||||
'open_object_list': True
|
||||
})
|
||||
return context
|
||||
|
||||
|
||||
class InformationDetailView(InformationQuerysetMixin, DetailView):
|
||||
template_name = 'portal/information.html'
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.get_object().informed_users.add(self.request.user)
|
||||
return redirect('portal:overview')
|
||||
|
||||
|
||||
class ProfileEditView(UpdateView):
|
||||
form_class = ProfileEditForm
|
||||
template_name = 'portal/edit_form.html'
|
||||
success_url = reverse_lazy('portal:edit_profile_success')
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
return self.request.user.profile
|
||||
Reference in New Issue
Block a user