# -*- coding: utf-8 -*- from os import path from django.conf import settings from django.utils.timezone import now from django.core.urlresolvers import reverse from django.core.cache import cache from django.db import models from django.template.defaultfilters import slugify from django.utils.safestring import mark_safe from django.utils.translation import get_language, ugettext as _ from django.core.exceptions import ValidationError from kasu.image_models import ImageModel from utils import STATUS_CHOICES, STATUS_WAITING, STATUS_PUBLISHED, \ cleaner CONTENT_CHOICES = ( (0, u'Django View'), (1, u'HTML'), (2, u'PDF') ) def get_upload_path(instance, filename): """ Generates the desired file path and filename for an uploaded Image. With this function Django can save the uploaded images to subfolders that also have a meaning for humans. @param instance: an Django Object for which the Image has been uploaded. @type instance: a instace of an models.Model sub-class. @param filename: The filename of the uploaded image. @type filename: String """ extension = filename[filename.rfind('.') + 1:] if isinstance(instance, Category): return "categories/%s.%s" % (instance.slug, extension) class ArticleManager(models.Manager): def published(self): return self.filter(status=STATUS_PUBLISHED, date_created__lte=now()) class Article(ImageModel): headline_de = models.CharField(_('Headline'), max_length=255) headline_en = models.CharField('Headline', max_length=255, blank=True) content_de = models.TextField(_('Content')) content_en = models.TextField('Content', blank=True) category = models.ForeignKey('Category', verbose_name=_('Category')) image = models.ImageField(_('Image'), upload_to='news/', blank=True, null=True) slug = models.SlugField(_('Slug'), unique_for_month='date_created') author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_('Author')) status = models.SmallIntegerField(_('Status'), choices=STATUS_CHOICES, default=STATUS_PUBLISHED) date_created = models.DateTimeField(_('Created'), blank=True) date_modified = models.DateTimeField(_('Modified'), auto_now=True) objects = ArticleManager() class Meta(object): verbose_name = _('Article') verbose_name_plural = _('Articles') ordering = ('-date_created',) def clean(self): if not self.date_created: self.date_created = now() if not self.slug: self.slug = slugify(self.headline_de)[:50] self.content_de = cleaner.clean_html(self.content_de) self.content_en = cleaner.clean_html(self.content_en) def __unicode__(self): return self.headline @property def posting_image(self): if self.image: return self.article else: return self.category.article def get_absolute_url(self): kwargs = { 'year': self.date_created.strftime('%Y'), 'month': self.date_created.strftime('%m'), 'slug': self.slug, } return reverse('show-article', kwargs=kwargs) @property def headline(self): headline = getattr(self, "headline_%s" % get_language()) if not headline: return mark_safe(self.headline_de) else: return mark_safe(headline) @property def content(self): content = getattr(self, "content_%s" % get_language(), self.content_de) if not content: return mark_safe(self.content_de) else: return mark_safe(content) class Page(models.Model): """ Eine Seite auf der Homepage. Sie kann eine "statische" HTML Seite, die URL einer dynamische Django View, oder ein PDF Dokument sein. Jede Seite kann neben Deutsch auch auf Englisch angeboten werden. Ist keine englische Übersetzung vorhanden, wird die deutsche Version angeboten. """ menu_name_de = models.CharField( 'Menü Name', max_length=255, help_text=_('The short name for the menu-entry of this page') ) menu_name_en = models.CharField( 'Menu Name', max_length=255, blank=True, help_text=_('The short name for the menu-entry of this page') ) title_de = models.CharField('Titel', max_length=255, help_text=_( 'This title appears in the HTML header')) title_en = models.CharField('Title', max_length=255, blank=True, help_text=_( 'This title appears in the HTML header')) slug = models.SlugField(_('slug')) path = models.CharField(_('Path'), max_length=100, db_index=True, editable=False, unique=True) parent = models.ForeignKey('self', blank=True, null=True, related_name='subpages', on_delete=models.SET_NULL) position = models.PositiveSmallIntegerField(_('Position'), blank=True, null=True) status = models.SmallIntegerField(_('status'), choices=STATUS_CHOICES, default=STATUS_WAITING) content_type = models.IntegerField(choices=CONTENT_CHOICES) content_de = models.TextField('Inhalt', blank=True) content_en = models.TextField('Content', blank=True) enable_comments = models.BooleanField(_('enable comments'), default=True) template = models.CharField(_('Template'), max_length=100, default="content/page.html") pdf_de = models.FileField(upload_to='pdf/de/', blank=True, null=True) pdf_en = models.FileField(upload_to='pdf/en/', blank=True, null=True) def __unicode__(self): return u'%s' % self.title @property def content(self): cont = getattr(self, "content_%s" % get_language()) or self.content_de return mark_safe(cont) @property def css_class(self): return CONTENT_CHOICES[self.content_type][1].lower().replace(' ', '_') @property def menu_name(self): return getattr(self, "menu_name_%s" % get_language()) or self.menu_name_de @property def pdf_file(self): return getattr(self, "pdf_%s" % get_language()) or self.pdf_de @property def title(self): return getattr(self, "title_%s" % get_language()) or self.title_de def clean(self): if self.parent is None: self.path = self.slug else: self.path = path.join(self.parent.path, self.slug) if self.content_type is None: if self.pdf_de: self.content_type = 2 if self.content_de: self.content_type = 1 else: self.content_type = 0 if self.content_type == 1: self.content_de = cleaner.clean_html(self.content_de) self.content_en = cleaner.clean_html(self.content_en) elif self.content_type == 2 and not self.pdf_de.name: raise ValidationError( _(u'Please upload a PDF-File to this PDF-Page.')) def get_absolute_url(self): aboslute_url = '/' + self.path if self.content_type == 1: aboslute_url += '.html' elif self.content_type == 2: aboslute_url += '.pdf' else: aboslute_url += '/' return aboslute_url class Meta(object): ordering = ['parent__id', 'position'] unique_together = (('slug', 'parent'),) verbose_name = _('Page') verbose_name_plural = _('Pages') class Category(ImageModel): name_de = models.CharField(_('Name'), max_length=80) name_en = models.CharField(_('Name'), max_length=80, blank=True) description_de = models.TextField(_('Description')) description_en = models.TextField(_('Description'), blank=True) image = models.ImageField(_('Image'), upload_to='news/categories/', blank=True, null=True) slug = models.SlugField(_('Slug'), unique=True, db_index=True) class Meta(object): ordering = ('slug',) verbose_name = _('Category') verbose_name_plural = _('Categories') @property def name(self): return getattr(self, "name_%s" % get_language(), self.name_de) @property def description(self): return getattr(self, "description_%s" % get_language(), self.description_de) def get_absolute_url(self): return reverse('article-archive', kwargs={'category': self.slug}) def __unicode__(self): return self.name def force_cache_update(sender, instance, **kwargs): for page in instance.subpages.all(): page.clean() page.save() cache.delete('all_pages') cache.delete('top_level_pages') models.signals.post_delete.connect(force_cache_update, sender=Page) models.signals.post_save.connect(force_cache_update, sender=Page)