X-Git-Url: https://git.mdrn.pl/redakcja.git/blobdiff_plain/57a3ad0520284210f945b0e2f91f67233e49d07e..b9166b62220208f49bfd3521e547d60d377ab7c1:/src/wlxml/models.py diff --git a/src/wlxml/models.py b/src/wlxml/models.py new file mode 100644 index 00000000..0b910a83 --- /dev/null +++ b/src/wlxml/models.py @@ -0,0 +1,164 @@ +from io import BytesIO +from django.apps import apps +from django.core.files import File +from django.db import models +from django.urls import reverse +from django.utils.translation import gettext_lazy as _ +from librarian import DocProvider +from librarian.parser import WLDocument as LegacyWLDocument +from librarian.builders import StandaloneHtmlBuilder, TxtBuilder +from librarian.document import WLDocument + + +class Tag(models.Model): + name = models.CharField(max_length=255, unique=True, db_index=True) + type = models.CharField(max_length=255, choices=[ + ('section', _('Section, contains blocks')), + ('div', _('Block element, like a paragraph')), + ('span', _('Inline element, like an emphasis')), + ('sep', _('Separator, has no content')), + ('aside', _('Aside content, like a footnote')), + ('verse', _('Verse element')), + ], blank=True) + similar_to = models.ForeignKey('self', models.PROTECT, null=True, blank=True) + description = models.TextField(blank=True) + example = models.TextField(blank=True) + + example_html = models.FileField(upload_to='wlxml/tag/example/html/', blank=True) + example_pdf = models.FileField(upload_to='wlxml/tag/example/pdf/', blank=True) + example_txt = models.FileField(upload_to='wlxml/tag/example/txt/', blank=True) + + # border_radius? + editor_css = models.TextField(blank=True) + editor_css_after = models.TextField(blank=True) + + class Meta: + verbose_name = _('tag') + verbose_name_plural = _('tags') + + def __str__(self): + return self.name + + def get_absolute_url(self): + return reverse('wlxml_tag', args=[self.name]) + ### allowed tags? + + def save(self, **kwargs): + docbytes = b''' + + + + +pol +test +test +test +test +test +test + + + + +''' + self.example.encode('utf-8') + b'' + + + doc = WLDocument(filename=BytesIO(docbytes)) + + self.example_html.save( + self.name + '.html', + File( + StandaloneHtmlBuilder().build(doc).get_file()), + save=False) + self.example_txt.save( + self.name + '.txt', + File( + TxtBuilder().build(doc).get_file()), + save=False) + + provider=DocProvider() + legacy_doc = LegacyWLDocument.from_bytes(docbytes, provider=provider) + + self.example_pdf.save( + self.name + '.pdf', + File(legacy_doc.as_pdf().get_file()), + save=False) + + + super().save(**kwargs) + + + +class Attribute(models.Model): + tag = models.ForeignKey(Tag, models.CASCADE) + name = models.CharField(max_length=255) + + class Meta: + verbose_name = _('attribute') + verbose_name_plural = _('attribute') + + unique_together = [ + ('tag', 'name'), + ] + + def __str__(self): + return self.name + + +class TagUsage(models.Model): + tag = models.ForeignKey(Tag, models.CASCADE) + chunk = models.ForeignKey('documents.Chunk', models.CASCADE) + + class Meta: + verbose_name = _('tag usage') + verbose_name_plural = _('tags usage') + + def __str__(self): + return f'{self.tag.name} @ {self.chunk.slug}' + + + @classmethod + def update_chunk(cls, chunk): + tag_names = set() + attribute_items = {} + doc = WLDocument.from_bytes(chunk.materialize().encode('utf-8')) + for element in doc.edoc.iter(): + tag_names.add(element.tag) + for k, v in element.attrib.iteritems(): + attribute_items.setdefault(element.tag, set()).add((k, v)) + + cls.objects.filter(chunk=chunk).exclude(tag__name__in=tag_names).delete() + for tag_name in tag_names: + tag, create = Tag.objects.get_or_create(name=tag_name) + tu, created = cls.objects.get_or_create(tag=tag, chunk=chunk) + + new_attributes = attribute_items.get(tag_name, []) + + for attr in tu.attributeusage_set.all(): + key = (attr.attribute.name, value) + if key not in new_attributes: + attr.delete() + else: + new_attributes.delete(key) + + for k, v in new_attributes: + attribute, created = tag.attribute_set.get_or_create(name=k) + tu.attributeusage_set.create(attribute=attribute, value=v) + + + @classmethod + def update_all_chunks(cls): + Chunk = apps.get_model('documents', 'Chunk') + for chunk in Chunk.objects.all(): + cls.update_chunk(chunk) + + +class AttributeUsage(models.Model): + tag_usage = models.ForeignKey(TagUsage, models.CASCADE) + attribute = models.ForeignKey(Attribute, models.CASCADE) + value = models.CharField(max_length=2048, blank=True) + + class Meta: + verbose_name = _('attribute usage') + verbose_name_plural = _('attributes usage') +