remove the banner
[wolnelektury.git] / src / catalogue / models / tag.py
index 31da256..a5c96d5 100644 (file)
@@ -1,6 +1,5 @@
-# -*- coding: utf-8 -*-
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+# This file is part of Wolne Lektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
 #
 from django.conf import settings
 from django.contrib.contenttypes.fields import GenericForeignKey
 #
 from django.conf import settings
 from django.contrib.contenttypes.fields import GenericForeignKey
@@ -9,32 +8,29 @@ from django.core.cache import caches
 from django.contrib.auth.models import User
 from django.core.exceptions import ObjectDoesNotExist
 from django.db import models
 from django.contrib.auth.models import User
 from django.core.exceptions import ObjectDoesNotExist
 from django.db import models
-from django.db.models import permalink
 from django.db.models.query import Prefetch
 from django.dispatch import Signal
 from django.db.models.query import Prefetch
 from django.dispatch import Signal
-from django.utils.translation import ugettext_lazy as _
+from django.urls import reverse
+from django.utils.translation import gettext_lazy as _
 
 from newtagging.models import TagManager, TaggedItemManager
 
 from newtagging.models import TagManager, TaggedItemManager
-from ssify import flush_ssi_includes
 
 
 
 
-# Those are hard-coded here so that makemessages sees them.
 TAG_CATEGORIES = (
 TAG_CATEGORIES = (
-    ('author', _('author')),
-    ('epoch', _('epoch')),
-    ('kind', _('kind')),
-    ('genre', _('genre')),
-    ('theme', _('theme')),
-    ('set', _('set')),
-    ('thing', _('thing')),  # things shown on pictures
+    ('author', _('autor')),
+    ('epoch', _('epoka')),
+    ('kind', _('rodzaj')),
+    ('genre', _('gatunek')),
+    ('theme', _('motyw')),
+    ('set', _('półka')),
+    ('thing', _('obiekt')),  # things shown on pictures
 )
 
 
 class TagRelation(models.Model):
 )
 
 
 class TagRelation(models.Model):
-
-    tag = models.ForeignKey('Tag', verbose_name=_('tag'), related_name='items')
-    content_type = models.ForeignKey(ContentType, verbose_name=_('content type'))
-    object_id = models.PositiveIntegerField(_('object id'), db_index=True)
+    tag = models.ForeignKey('Tag', models.CASCADE, verbose_name='tag', related_name='items')
+    content_type = models.ForeignKey(ContentType, models.CASCADE, verbose_name='typ obiektu')
+    object_id = models.PositiveIntegerField('id obiektu', db_index=True)
     content_object = GenericForeignKey('content_type', 'object_id')
 
     objects = TaggedItemManager()
     content_object = GenericForeignKey('content_type', 'object_id')
 
     objects = TaggedItemManager()
@@ -43,11 +39,11 @@ class TagRelation(models.Model):
         db_table = 'catalogue_tag_relation'
         unique_together = (('tag', 'content_type', 'object_id'),)
 
         db_table = 'catalogue_tag_relation'
         unique_together = (('tag', 'content_type', 'object_id'),)
 
-    def __unicode__(self):
+    def __str__(self):
         try:
         try:
-            return u'%s [%s]' % (self.content_type.get_object_for_this_type(pk=self.object_id), self.tag)
+            return '%s [%s]' % (self.content_type.get_object_for_this_type(pk=self.object_id), self.tag)
         except ObjectDoesNotExist:
         except ObjectDoesNotExist:
-            return u'<deleted> [%s]' % self.tag
+            return '<deleted> [%s]' % self.tag
 
 
 class Tag(models.Model):
 
 
 class Tag(models.Model):
@@ -55,25 +51,52 @@ class Tag(models.Model):
 
     Used to represent searchable metadata (authors, epochs, genres, kinds),
     fragment themes (motifs) and some book hierarchy related kludges."""
 
     Used to represent searchable metadata (authors, epochs, genres, kinds),
     fragment themes (motifs) and some book hierarchy related kludges."""
-    name = models.CharField(_('name'), max_length=120, db_index=True)
-    slug = models.SlugField(_('slug'), max_length=120, db_index=True)
-    sort_key = models.CharField(_('sort key'), max_length=120, db_index=True)
+    name = models.CharField('nazwa', max_length=120, db_index=True)
+    slug = models.SlugField('slug', max_length=120, db_index=True)
+    sort_key = models.CharField('klucz sortowania', max_length=120, db_index=True)
     category = models.CharField(
     category = models.CharField(
-        _('category'), max_length=50, blank=False, null=False, db_index=True, choices=TAG_CATEGORIES)
-    description = models.TextField(_('description'), blank=True)
+        'kategoria', max_length=50, blank=False, null=False, db_index=True, choices=TAG_CATEGORIES)
+    description = models.TextField('opis', blank=True)
 
     for_books = models.BooleanField(default=False)
     for_pictures = models.BooleanField(default=False)
 
 
     for_books = models.BooleanField(default=False)
     for_pictures = models.BooleanField(default=False)
 
-    user = models.ForeignKey(User, blank=True, null=True)
+    user = models.ForeignKey(User, models.CASCADE, blank=True, null=True)
     gazeta_link = models.CharField(blank=True, max_length=240)
     culturepl_link = models.CharField(blank=True, max_length=240)
     wiki_link = models.CharField(blank=True, max_length=240)
     gazeta_link = models.CharField(blank=True, max_length=240)
     culturepl_link = models.CharField(blank=True, max_length=240)
     wiki_link = models.CharField(blank=True, max_length=240)
-
-    created_at = models.DateTimeField(_('creation date'), auto_now_add=True, db_index=True)
-    changed_at = models.DateTimeField(_('creation date'), auto_now=True, db_index=True)
-
-    after_change = Signal(providing_args=['instance', 'languages'])
+    photo = models.FileField(blank=True, null=True, upload_to='catalogue/tag/')
+    photo_attribution = models.CharField(max_length=255, blank=True)
+
+    created_at = models.DateTimeField('data utworzenia', auto_now_add=True, db_index=True)
+    changed_at = models.DateTimeField('data modyfikacji', auto_now=True, db_index=True)
+
+    plural = models.CharField(
+        'liczba mnoga', max_length=255, blank=True,
+        help_text='dotyczy gatunków'
+    )
+    genre_epoch_specific = models.BooleanField(
+        default=False,
+        help_text='Po wskazaniu tego gatunku, dodanie epoki byłoby nadmiarowe, np. „dramat romantyczny”'
+    )
+    adjective_feminine_singular = models.CharField(
+        'przymiotnik pojedynczy żeński', max_length=255, blank=True,
+        help_text='twórczość … Adama Mickiewicza; dotyczy epok'
+    )
+    adjective_nonmasculine_plural = models.CharField(
+        'przymiotnik mnogi niemęskoosobowy', max_length=255, blank=True,
+        help_text='utwory … Adama Mickiewicza; dotyczy epok'
+    )
+    genitive = models.CharField(
+        'dopełniacz', max_length=255, blank=True,
+        help_text='utwory … (czyje?); dotyczy autorów'
+    )
+    collective_noun = models.CharField(
+        'określenie zbiorowe', max_length=255, blank=True,
+        help_text='np. „Liryka” albo „Twórczość dramatyczna”; dotyczy rodzajów'
+    )
+
+    after_change = Signal()
 
     intermediary_table_model = TagRelation
     objects = TagManager()
 
     intermediary_table_model = TagRelation
     objects = TagManager()
@@ -92,70 +115,23 @@ class Tag(models.Model):
         'polka': 'set',
         'obiekt': 'thing',
     }
         'polka': 'set',
         'obiekt': 'thing',
     }
-    categories_dict = dict((item[::-1] for item in categories_rev.iteritems()))
+    categories_dict = dict((item[::-1] for item in categories_rev.items()))
 
     class Meta:
         ordering = ('sort_key',)
 
     class Meta:
         ordering = ('sort_key',)
-        verbose_name = _('tag')
-        verbose_name_plural = _('tags')
+        verbose_name = 'tag'
+        verbose_name_plural = 'tagi'
         unique_together = (("slug", "category"),)
         app_label = 'catalogue'
 
         unique_together = (("slug", "category"),)
         app_label = 'catalogue'
 
-    def save(self, *args, **kwargs):
-        flush_cache = flush_all_includes = False
-        if self.pk and self.category != 'set':
-            # Flush the whole views cache.
-            # Seem a little harsh, but changed tag names, descriptions
-            # and links come up at any number of places.
-            flush_cache = True
-
-            # Find in which languages we need to flush related includes.
-            old_self = type(self).objects.get(pk=self.pk)
-            # Category shouldn't normally be changed, but just in case.
-            if self.category != old_self.category:
-                flush_all_includes = True
-            languages_changed = self.languages_changed(old_self)
-
+    def save(self, *args, quick=False, **kwargs):
+        existing = self.pk and self.category != 'set'
         ret = super(Tag, self).save(*args, **kwargs)
         ret = super(Tag, self).save(*args, **kwargs)
-
-        if flush_cache:
-            caches[settings.CACHE_MIDDLEWARE_ALIAS].clear()
-            if flush_all_includes:
-                flush_ssi_includes()
-            else:
-                self.flush_includes()
-            self.after_change.send(sender=type(self), instance=self, languages=languages_changed)
-
+        if existing and not quick:
+            self.after_change.send(sender=type(self), instance=self)
         return ret
 
         return ret
 
-    def languages_changed(self, old):
-        all_langs = [lc for (lc, _ln) in settings.LANGUAGES]
-        if (old.category, old.slug) != (self.category, self.slug):
-            return all_langs
-        languages = set()
-        for lang in all_langs:
-            name_field = 'name_%s' % lang
-            if getattr(old, name_field) != getattr(self, name_field):
-                languages.add(lang)
-        return languages
-
-    def flush_includes(self, languages=True):
-        if not languages:
-            return
-        if languages is True:
-            languages = [lc for (lc, _ln) in settings.LANGUAGES]
-        flush_ssi_includes([
-            template % (self.pk, lang)
-            for template in [
-                '/api/include/tag/%d.%s.json',
-                '/api/include/tag/%d.%s.xml',
-                ]
-            for lang in languages
-            ])
-        flush_ssi_includes([
-            '/katalog/%s.json' % lang for lang in languages])
-
-    def __unicode__(self):
+    def __str__(self):
         return self.name
 
     def __repr__(self):
         return self.name
 
     def __repr__(self):
@@ -173,17 +149,24 @@ class Tag(models.Model):
     def category_plural(self):
         return self.category + 's'
 
     def category_plural(self):
         return self.category + 's'
 
-    @permalink
     def get_absolute_url(self):
     def get_absolute_url(self):
-        return 'tagged_object_list', [self.url_chunk]
+        return reverse('tagged_object_list', args=[self.url_chunk])
 
 
-    @permalink
     def get_absolute_gallery_url(self):
     def get_absolute_gallery_url(self):
-        return 'tagged_object_list_gallery', [self.url_chunk]
+        return reverse('tagged_object_list_gallery', args=[self.url_chunk])
+
+    def get_absolute_catalogue_url(self):
+        # TODO: remove magic.
+        if self.category == 'set':
+            return reverse('social_my_shelf')
+        elif self.category == 'thing':
+            return ''
+        else:
+            return reverse(f'{self.category}_catalogue')
 
     def has_description(self):
         return len(self.description) > 0
 
     def has_description(self):
         return len(self.description) > 0
-    has_description.short_description = _('description')
+    has_description.short_description = 'opis'
     has_description.boolean = True
 
     @staticmethod
     has_description.boolean = True
 
     @staticmethod
@@ -230,41 +213,43 @@ class Tag(models.Model):
         from slugify import slugify
         from sortify import sortify
         meta_tags = []
         from slugify import slugify
         from sortify import sortify
         meta_tags = []
-        categories = (('kinds', 'kind'), ('genres', 'genre'), ('authors', 'author'), ('epochs', 'epoch'))
-        for field_name, category in categories:
+        categories = (
+            # BookInfo field names, Tag category, relationship
+            ('kinds', 'kind', None),
+            ('genres', 'genre', None),
+            ('epochs', 'epoch', None),
+            ('authors', 'author', None),
+            ('translators', 'author', 'translator'),
+        )
+        for field_name, category, relationship in categories:
             try:
                 tag_names = getattr(info, field_name)
             try:
                 tag_names = getattr(info, field_name)
-            except KeyError:
-                try:
-                    tag_names = [getattr(info, category)]
-                except KeyError:
-                    # For instance, Pictures do not have 'genre' field.
-                    continue
+            except (AttributeError, KeyError):  # TODO: shouldn't be KeyError here at all.
+                # For instance, Pictures do not have 'genre' field.
+                continue
             for tag_name in tag_names:
             for tag_name in tag_names:
-                lang = getattr(tag_name, 'lang', settings.LANGUAGE_CODE)
+                lang = getattr(tag_name, 'lang', None) or settings.LANGUAGE_CODE
                 tag_sort_key = tag_name
                 if category == 'author':
                     tag_sort_key = ' '.join((tag_name.last_name,) + tag_name.first_names)
                     tag_name = tag_name.readable()
                 tag_sort_key = tag_name
                 if category == 'author':
                     tag_sort_key = ' '.join((tag_name.last_name,) + tag_name.first_names)
                     tag_name = tag_name.readable()
-                if lang == settings.LANGUAGE_CODE:
-                    # Allow creating new tag, if it's in default language.
-                    tag, created = Tag.objects.get_or_create(slug=slugify(tag_name), category=category)
-                    if created:
-                        tag_name = unicode(tag_name)
-                        tag.name = tag_name
-                        setattr(tag, "name_%s" % lang, tag_name)
-                        tag.sort_key = sortify(tag_sort_key.lower())
-                        tag.save()
-
-                    meta_tags.append(tag)
+
+                try:
+                    tag = Tag.objects.get(category=category, **{"name_%s" % lang: tag_name})
+                except Tag.DoesNotExist:
+                    if lang == settings.LANGUAGE_CODE:
+                        # Allow creating new tag, if it's in default language.
+                        tag, created = Tag.objects.get_or_create(slug=slugify(tag_name), category=category)
+                        if created:
+                            tag_name = str(tag_name)
+                            tag.name = tag_name
+                            setattr(tag, "name_%s" % lang, tag_name)
+                            tag.sort_key = sortify(tag_sort_key.lower())
+                            tag.save()
+
+                        meta_tags.append((tag, relationship))
                 else:
                 else:
-                    # Ignore unknown tags in non-default languages.
-                    try:
-                        tag = Tag.objects.get(category=category, **{"name_%s" % lang: tag_name})
-                    except Tag.DoesNotExist:
-                        pass
-                    else:
-                        meta_tags.append(tag)
+                    meta_tags.append((tag, relationship))
         return meta_tags
 
 
         return meta_tags