--- /dev/null
+from django.contrib import admin
+from .models import Alert
+
+
+admin.site.register(Alert)
--- /dev/null
+from django.apps import AppConfig
+
+
+class AlertsConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'alerts'
--- /dev/null
+# Generated by Django 3.2.12 on 2022-05-23 11:14
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('documents', '0008_book_legimi_id'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Alert',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('tag', models.CharField(max_length=32)),
+ ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='documents.book')),
+ ],
+ ),
+ ]
--- /dev/null
+from django.db import models
+from django.dispatch import receiver
+from dvcs.models import post_commit
+from .rules import rules, rules_by_tag
+
+
+class Alert(models.Model):
+ book = models.ForeignKey('documents.Book', models.CASCADE)
+ tag = models.CharField(max_length=32)
+
+ @property
+ def rule(self):
+ return rules_by_tag[self.tag]
+
+ @classmethod
+ def validate_book(cls, book):
+ cls.objects.filter(book=book).delete()
+ try:
+ wlbook = book.wldocument(publishable=False, librarian2=True)
+ except:
+ cls.objects.create(book=book, tag='parse')
+ return
+
+ for rule in rules:
+ if rule.check_meta(wlbook.meta):
+ print(rule.tag, book)
+ cls.objects.create(book=book, tag=rule.tag)
+
+
+@receiver(post_commit)
+def validate_post_commit(sender, **kwargs):
+ Alert.validate_book(sender.tree.book)
--- /dev/null
+import re
+from django.utils.translation import gettext_lazy as _
+
+
+class Check:
+ def check_meta(self, meta):
+ return False
+
+
+class CheckParse(Check):
+ tag = 'parse'
+ description = _('Book parse error.')
+
+
+class CheckCoverLocal(Check):
+ tag = 'cover-local'
+ description = _('Cover is not local')
+
+ def check_meta(self, meta):
+ print(meta)
+ if meta.cover_source is None:
+ print('no cover_source')
+ return False
+ return not re.match(r'https?://redakcja.wolnelektury.pl/cover/image/', meta.cover_source)
+
+
+rules = [
+ CheckParse(),
+ CheckCoverLocal(),
+]
+
+rules_by_tag = {
+ r.tag: r
+ for r in rules
+}
--- /dev/null
+from django.template import Library
+from ..models import Alert
+
+
+register = Library()
+
+@register.simple_tag
+def get_alerts():
+ return {
+ 'count': Alert.objects.all().count(),
+ 'items': Alert.objects.all()[:20],
+ }
--- /dev/null
+from django.test import TestCase
+
+# Create your tests here.
--- /dev/null
+from django.shortcuts import render
+
+# Create your views here.
{% load pipeline i18n %}
{% load static %}
{% load documents %}
+{% load alerts %}
<!DOCTYPE html>
<html>
<head lang="{{ LANGUAGE_CODE }}">
</ul>
<ul class="navbar-nav">
- {% include "registration/head_login.html" %}
+
+ {% get_alerts as alerts %}
+ {% if alerts.count %}
+ <div class="nav-item dropdown">
+ <a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" title="Alert">
+ 🔔
+ <span class="badge badge-danger">{{ alerts.count }}</span>
+ </a>
+ <div class="dropdown-menu dropdown-menu-right">
+ {% for alert in alerts.items %}
+ <a class="dropdown-item" href="{{ alert.book.get_absolute_url }}">
+ {{ alert.book }}<br>
+ {{ alert.rule.description }}
+ </a>
+ {% endfor %}
+ </div>
+ </div>
+ {% endif %}
+ {% include "registration/head_login.html" %}
</ul>
</nav>
'apiclient',
'email_mangler',
'wlxml.apps.WlxmlConfig',
+ 'alerts',
)
if DEBUG: