X-Git-Url: https://git.mdrn.pl/redakcja.git/blobdiff_plain/391d6cbc649f387a731f724cd4cf7dbcb02e26c2..94da7eb2739d91e80607681bc61672ef769ca90c:/src/catalogue/models.py?ds=sidebyside diff --git a/src/catalogue/models.py b/src/catalogue/models.py index ea7bf54b..6f4fa1e9 100644 --- a/src/catalogue/models.py +++ b/src/catalogue/models.py @@ -1,6 +1,10 @@ from collections import Counter +from datetime import date, timedelta import decimal +import re +from urllib.request import urlopen from django.apps import apps +from django.conf import settings from django.db import models from django.template.loader import render_to_string from django.urls import reverse @@ -16,6 +20,10 @@ class Author(WikidataModel): slug = models.SlugField(max_length=255, null=True, blank=True, unique=True) first_name = models.CharField(_("first name"), max_length=255, blank=True) last_name = models.CharField(_("last name"), max_length=255, blank=True) + genitive = models.CharField( + 'dopełniacz', max_length=255, blank=True, + help_text='utwory … (czyje?)' + ) name_de = models.CharField(_("name (de)"), max_length=255, blank=True) name_lt = models.CharField(_("name (lt)"), max_length=255, blank=True) @@ -130,6 +138,7 @@ class NotableBook(OrderableModel): class Category(WikidataModel): name = models.CharField(_("name"), max_length=255) slug = models.SlugField(max_length=255, unique=True) + description = models.TextField(_("description"), blank=True, help_text=_('for publication')) class Meta: abstract = True @@ -137,19 +146,43 @@ class Category(WikidataModel): def __str__(self): return self.name + class Epoch(Category): + adjective_feminine_singular = models.CharField( + 'przymiotnik pojedynczy żeński', max_length=255, blank=True, + help_text='twórczość … Adama Mickiewicza' + ) + adjective_nonmasculine_plural = models.CharField( + 'przymiotnik mnogi niemęskoosobowy', max_length=255, blank=True, + help_text='utwory … Adama Mickiewicza' + ) + class Meta: verbose_name = _('epoch') verbose_name_plural = _('epochs') class Genre(Category): + plural = models.CharField( + 'liczba mnoga', max_length=255, blank=True, + help_text='dotyczy gatunków' + ) + is_epoch_specific = models.BooleanField( + default=False, + help_text='Po wskazaniu tego gatunku, dodanie epoki byłoby nadmiarowe, np. „dramat romantyczny”' + ) + class Meta: verbose_name = _('genre') verbose_name_plural = _('genres') class Kind(Category): + collective_noun = models.CharField( + 'określenie zbiorowe', max_length=255, blank=True, + help_text='np. „Liryka” albo „Twórczość dramatyczna”' + ) + class Meta: verbose_name = _('kind') verbose_name_plural = _('kinds') @@ -193,6 +226,9 @@ class Book(WikidataModel): free_license = models.BooleanField(_('free license'), default=False) polona_missing = models.BooleanField(_('missing on Polona'), default=False) + monthly_views_reader = models.IntegerField(default=0) + monthly_views_page = models.IntegerField(default=0) + class Meta: ordering = ("title",) verbose_name = _('book') @@ -252,12 +288,68 @@ class Book(WikidataModel): def translators_last_names(self): return ', '.join(a.last_name for a in self.translators.all()) + def document_book__project(self): + b = self.document_books.first() + if b is None: return '' + if b.project is None: return '' + return b.project.name + + def audience(self): + try: + return self.document_books.first().wldocument().book_info.audience or '' + except: + return '' + def get_estimated_costs(self): return { work_type: work_type.calculate(self) for work_type in WorkType.objects.all() } + def update_monthly_stats(self): + # Find publication date. + # By default, get previous 12 months. + this_month = date.today().replace(day=1) + cutoff = this_month.replace(year=this_month.year - 1) + months = 12 + + # If the book was published later, + # find out the denominator. + pbr = apps.get_model('documents', 'BookPublishRecord').objects.filter( + book__catalogue_book=self).order_by('timestamp').first() + if pbr is not None and pbr.timestamp.date() > cutoff: + months = (this_month - pbr.timestamp.date()).days / 365 * 12 + + if not months: + return + + stats = self.bookmonthlystats_set.filter(date__gte=cutoff).aggregate( + views_page=models.Sum('views_page'), + views_reader=models.Sum('views_reader') + ) + self.monthly_views_page = stats['views_page'] / months + self.monthly_views_reader = stats['views_reader'] / months + self.save(update_fields=['monthly_views_page', 'monthly_views_reader']) + + @property + def content_stats(self): + if hasattr(self, '_content_stats'): + return self._content_stats + try: + stats = self.document_books.first().wldocument().get_statistics()['total'] + except Exception as e: + stats = {} + self._content_stats = stats + return stats + + chars = lambda self: self.content_stats.get('chars', '') + chars_with_fn = lambda self: self.content_stats.get('chars_with_fn', '') + words = lambda self: self.content_stats.get('words', '') + words_with_fn = lambda self: self.content_stats.get('words_with_fn', '') + verses = lambda self: self.content_stats.get('verses', '') + verses_with_fn = lambda self: self.content_stats.get('verses_with_fn', '') + chars_out_verse = lambda self: self.content_stats.get('chars_out_verse', '') + chars_out_verse_with_fn = lambda self: self.content_stats.get('chars_out_verse_with_fn', '') class CollectionCategory(models.Model): name = models.CharField(_("name"), max_length=255) @@ -376,3 +468,42 @@ class Place(WikidataModel): def __str__(self): return self.name + + +class BookMonthlyStats(models.Model): + book = models.ForeignKey('catalogue.Book', models.CASCADE) + date = models.DateField() + views_reader = models.IntegerField(default=0) + views_page = models.IntegerField(default=0) + + @classmethod + def build_for_month(cls, date): + date = date.replace(day=1) + period = 'month' + + date = date.isoformat() + url = f'{settings.PIWIK_URL}?date={date}&filter_limit=-1&format=CSV&idSite={settings.PIWIK_WL_SITE_ID}&language=pl&method=Actions.getPageUrls&module=API&period={period}&segment=&token_auth={settings.PIWIK_TOKEN}&flat=1' + data = urlopen(url).read().decode('utf-16') + lines = data.split('\n')[1:] + for line in lines: + m = re.match('^/katalog/lektura/([^,./]+)\.html,', line) + if m is not None: + which = 'views_reader' + else: + m = re.match('^/katalog/lektura/([^,./]+)/,', line) + if m is not None: + which = 'views_page' + if m is not None: + slug = m.group(1) + _url, _uviews, views, _rest = line.split(',', 3) + views = int(views) + try: + book = Book.objects.get(slug=slug) + except Book.DoesNotExist: + continue + else: + cls.objects.update_or_create( + book=book, date=date, + defaults={which: views} + ) + book.update_monthly_stats()