the racalc cronjob reports erronous partly recalculations now. A lot of code cleanups
310 lines
9.9 KiB
Python
310 lines
9.9 KiB
Python
import os
|
|
|
|
import django_comments as comments
|
|
from csp.decorators import csp_update
|
|
from django.conf import settings
|
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
|
from django.http import HttpResponse, Http404
|
|
from django.utils.translation import ugettext as _
|
|
from django.views import generic
|
|
|
|
from . import models, forms
|
|
|
|
|
|
class WYSIWYGEditorMixin(PermissionRequiredMixin):
|
|
"""
|
|
A view to update the Content-Security-Policy for the WYSIWYG editor.
|
|
Since it is only used in edit forms, it extends the PermissionRequiredMixin.
|
|
"""
|
|
|
|
@csp_update(SCRIPT_SRC="'unsafe-eval'")
|
|
def dispatch(self, request, *args, **kwargs):
|
|
"""Add "unsafe-eval" to the Content-Secuirty-Policy HTTP Headers for the
|
|
WYSIWYG Editor.
|
|
|
|
:param request: the HTTP Request Object
|
|
:param args: args for the super dispatch
|
|
:param kwargs: kwargs for the super dispatch
|
|
:return: django HTTPResponse object
|
|
"""
|
|
return super(WYSIWYGEditorMixin, self).dispatch(
|
|
request, *args, **kwargs)
|
|
|
|
|
|
class ArticleArchiveMixin(object):
|
|
"""Mixin to add common context data to Views of the news archive."""
|
|
category = None
|
|
|
|
def get_category(self, queryset):
|
|
"""
|
|
Filter the queryset by category if one has been specified in the URL
|
|
|
|
:param queryset: an model.Article.objects Queryset
|
|
:return: an model.Article.objects Queryset filterd by category
|
|
"""
|
|
|
|
category_slug = self.kwargs.get('category')
|
|
if not category_slug:
|
|
self.category = None
|
|
return queryset
|
|
try:
|
|
self.category = models.Category.objects.get(slug=category_slug)
|
|
except models.Category.DoesNotExist:
|
|
raise Http404(_("This Category does not exist."))
|
|
return queryset.filter(category=self.category)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""
|
|
Adds the categories and the active category to the template context.
|
|
|
|
:return: an django.template.context
|
|
"""
|
|
|
|
context = super(ArticleArchiveMixin, self).get_context_data(**kwargs)
|
|
context['categories'] = models.Category.objects.all()
|
|
context['active_category'] = self.category
|
|
return context
|
|
|
|
|
|
class ArticleArchiveIndex(ArticleArchiveMixin, generic.ArchiveIndexView):
|
|
"""
|
|
Displays the latest news and the filters to browse the archives.
|
|
"""
|
|
|
|
queryset = models.Article.objects.filter(status=models.STATUS_PUBLISHED)
|
|
date_field = 'date_created'
|
|
paginate_by = 5
|
|
context_object_name = 'article_list'
|
|
allow_empty = True
|
|
|
|
def get_queryset(self):
|
|
"""
|
|
Filter the Queryset by category.
|
|
|
|
:return: models.Article.objects queryset
|
|
"""
|
|
return self.get_category(
|
|
super(ArticleArchiveIndex, self).get_queryset()
|
|
)
|
|
|
|
|
|
class ArticleYearArchive(ArticleArchiveMixin, generic.YearArchiveView):
|
|
"""
|
|
Displays the Articles filterd by a specific year
|
|
"""
|
|
|
|
queryset = models.Article.objects.filter(status=models.STATUS_PUBLISHED)
|
|
date_field = 'date_created'
|
|
paginate_by = 5
|
|
year_format = '%Y'
|
|
make_object_list = True
|
|
allow_empty = True
|
|
|
|
def get_queryset(self):
|
|
"""
|
|
Filter the Queryset by category.
|
|
|
|
:return: models.Article.objects queryset
|
|
"""
|
|
return self.get_category(
|
|
super(ArticleYearArchive, self).get_queryset()
|
|
)
|
|
|
|
|
|
class ArticleMonthArchive(ArticleArchiveMixin, generic.MonthArchiveView):
|
|
"""
|
|
Displays the Articles filterd by a specific month
|
|
"""
|
|
|
|
queryset = models.Article.objects.filter(status=models.STATUS_PUBLISHED)
|
|
date_field = 'date_created'
|
|
month_format = '%m'
|
|
paginate_by = 5
|
|
make_object_list = True
|
|
allow_empty = True
|
|
|
|
def get_queryset(self):
|
|
"""
|
|
Filter the Queryset by category.
|
|
|
|
:return: models.Article.objects queryset
|
|
"""
|
|
return self.get_category(
|
|
super(ArticleMonthArchive, self).get_queryset()
|
|
)
|
|
|
|
|
|
class ArticleDetail(generic.DetailView):
|
|
"""
|
|
Render the news Article, but only if it got published.
|
|
"""
|
|
|
|
queryset = models.Article.objects.filter(status=models.STATUS_PUBLISHED)
|
|
|
|
|
|
class ArticleForm(WYSIWYGEditorMixin, generic.UpdateView):
|
|
"""
|
|
View to add or edit an Article
|
|
"""
|
|
model = models.Article
|
|
form_class = forms.ArticleForm
|
|
permission_required = 'content.change_article'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Set the title variable to create/or edit article."""
|
|
context = super(ArticleForm, self).get_context_data(**kwargs)
|
|
context['title'] = _("Edit Article") if self.kwargs.get('pk') else \
|
|
_("Create Article")
|
|
return context
|
|
|
|
def get_object(self, queryset=None):
|
|
"""Get the Article or create a new one if no id has been provided.
|
|
|
|
:param queryset: Get the single item from this filtered queryset.
|
|
:return:
|
|
"""
|
|
queryset = queryset or self.get_queryset()
|
|
if self.kwargs.get('pk'):
|
|
return queryset.get(pk=self.kwargs['pk'])
|
|
return models.Article(author=self.request.user)
|
|
|
|
|
|
class PageAddForm(WYSIWYGEditorMixin, generic.CreateView):
|
|
""" Renders an Form to create a new page for users with conforming
|
|
permissions."""
|
|
|
|
form_class = forms.PageForm
|
|
template_name = 'content/page_form.html'
|
|
permission_required = 'content.add_page'
|
|
|
|
def get_initial(self):
|
|
"""Try to get the path of the parent page as initial data."""
|
|
path = os.path.splitext(self.kwargs['path'])[0]
|
|
if path.startswith('/'):
|
|
path = path[1:]
|
|
if path.endswith('/'):
|
|
path = path[:-1]
|
|
parent = models.Page.objects.get(path=path)
|
|
return {'parent': parent}
|
|
|
|
|
|
class PageEditForm(WYSIWYGEditorMixin, generic.UpdateView):
|
|
"""Renders an Form to edit a page for users with conforming permissions."""
|
|
|
|
form_class = forms.PageForm
|
|
model = models.Page
|
|
permission_required = 'content.change_page'
|
|
|
|
def get_object(self, queryset=None):
|
|
""" Get the path from the URL and fetch the corresponding page.
|
|
|
|
First get the path wihout fileextentsion leading or trailing slashes,
|
|
then search in the database if such a page exists.
|
|
|
|
:param queryset: Get the single item from this filtered queryset.
|
|
:return:
|
|
"""
|
|
path = os.path.splitext(self.kwargs['path'])[0]
|
|
queryset = queryset or self.get_queryset()
|
|
if path.startswith('/'):
|
|
path = path[1:]
|
|
if path.endswith('/'):
|
|
path = path[:-1]
|
|
return queryset.get(path=path)
|
|
|
|
|
|
class PageHtml(generic.DetailView):
|
|
"""Display static HTML content from the database."""
|
|
|
|
model = models.Page
|
|
|
|
def get_object(self, queryset=None):
|
|
"""Get the page content from the db that equals the given URL.
|
|
|
|
:param queryset: Get the single item from this filtered queryset.
|
|
:return:
|
|
"""
|
|
queryset = queryset or self.get_queryset()
|
|
try:
|
|
return queryset.get(path=self.kwargs['path'],
|
|
content_type=models.HTML_PAGE)
|
|
except models.Page.DoesNotExist:
|
|
raise Http404(
|
|
_("No Page found matching the Path %s") % self.request.path
|
|
)
|
|
|
|
def get_template_names(self):
|
|
"""Each static page can define its own template, so return the template
|
|
name that has been stored in the dataset.
|
|
|
|
:return: filename of the template to render.
|
|
"""
|
|
return self.object.template
|
|
|
|
|
|
class PagePdf(generic.DeleteView):
|
|
"""Deliver an static PDF File under this given URL."""
|
|
|
|
model = models.Page
|
|
|
|
def get_object(self, queryset=None):
|
|
"""Get the PDF page from the db that equals the given URL.
|
|
|
|
:param queryset: Get the single item from this filtered queryset.
|
|
:return: models.Page object or raise a 404 if not found.
|
|
"""
|
|
queryset = queryset or self.get_queryset()
|
|
try:
|
|
return queryset.get(path=self.kwargs['path'],
|
|
content_type=models.PDF_PAGE)
|
|
except models.Page.DoesNotExist:
|
|
raise Http404(
|
|
_("No PDF Document found matching the Path %s") %
|
|
self.request.path
|
|
)
|
|
|
|
def render_to_response(self, context, **response_kwargs):
|
|
"""Stream the PDF File to the client and set the right content headers.
|
|
|
|
:param context: useless only for compatility
|
|
:param response_kwargs: will be added to the HttpResponse kwargs.
|
|
:return: an HTTPResponse with PDF Content or an Http404 exception
|
|
"""
|
|
try:
|
|
with open(self.object.pdf_file.path, 'rb') as pdf_file:
|
|
response = HttpResponse(
|
|
content=pdf_file.read(),
|
|
content_type='application/pdf',
|
|
**response_kwargs
|
|
)
|
|
return response
|
|
except:
|
|
raise Http404('File not Found %s.pdf' % self.kwargs['path'])
|
|
|
|
|
|
class StartPage(generic.TemplateView):
|
|
"""The Frontpage, a page with the latest infos and some static content."""
|
|
template_name = 'index.html'
|
|
|
|
def get_context_data(self):
|
|
""" Adds recent ariticles and recent comments to the context.
|
|
|
|
:return: array() with the context data
|
|
"""
|
|
page = models.Page.objects.get(slug='index')
|
|
recent_comment_list = comments.get_model().objects.filter(
|
|
site__pk=settings.SITE_ID,
|
|
is_public=True,
|
|
is_removed=False,
|
|
)
|
|
recent_comment_list = recent_comment_list.order_by('-submit_date')[:10]
|
|
context = {
|
|
'title': page.title,
|
|
'content': page.content,
|
|
'recent_article_list': models.Article.objects.published()[:3],
|
|
'recent_comment_list': recent_comment_list,
|
|
}
|
|
return context
|
|
|
|
queryset = models.Article.objects.filter(status=models.STATUS_PUBLISHED)
|