Source code for org.pdf.directory_entry

from __future__ import annotations

from html import escape
from io import BytesIO
from markupsafe import Markup

from onegov.form.fields import UploadField, UploadMultipleField
from onegov.org import _
from onegov.org.layout import DefaultMailLayout
from onegov.org.pdf.core import OrgPdf
from onegov.pdf import page_fn_footer, page_fn_header_and_footer


from typing import Any, TYPE_CHECKING
if TYPE_CHECKING:
    from collections.abc import Callable
    from datetime import datetime
    from onegov.org.models import ExtendedDirectoryEntry
    from onegov.org.request import OrgRequest
    from onegov.pdf.templates import Template
    from reportlab.pdfgen.canvas import Canvas


[docs] class DirectoryEntryPdf(OrgPdf): """ Certifies the publication of a directory entry, attached to the admin notifications sent when a publication starts or ends. """ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) # our footer already prefixes a copyright, so skip OrgPdf's 'Source:' self.doc.author = kwargs.get('author', '') @property
[docs] def page_fn(self) -> Callable[[Canvas, Template], None]: # the title is already part of the story, no header on the first page return page_fn_footer
@property
[docs] def page_fn_later(self) -> Callable[[Canvas, Template], None]: return page_fn_header_and_footer
[docs] def add_title( self, entry: ExtendedDirectoryEntry, request: OrgRequest, ended: bool = False ) -> None: title = escape(entry.title) self.h(title) link = ( f'<a href="{request.link(entry)}" color="{self.link_color}">' f'<u>{title}</u></a>' ) if ended: intro = _( 'The publication "${title}" has ended.', mapping={'title': link}, ) else: intro = _( 'This document certifies the publication "${title}" as ' 'follows.', mapping={'title': link}, ) self.p_markup(intro)
[docs] def add_fields( self, entry: ExtendedDirectoryEntry, layout: DefaultMailLayout ) -> None: self.h2(_('Publication')) form = entry.directory.form_class(data=entry.values) self.mini_html(Markup('<ul>{}</ul>').format(Markup('').join( Markup('<li><strong>{}</strong>: {}').format( escape(field.label.text), form.render_display(field) ) for field in form if not isinstance(field, (UploadField, UploadMultipleField)) )))
[docs] def add_attachments( self, entry: ExtendedDirectoryEntry, layout: DefaultMailLayout ) -> None: self.h2(_('Attachments')) if not entry.files: self.mini_html(f'<p>{self.translate(_("None"))}</p>') return size_label = self.translate(_('Size')) date_label = self.translate(_('Date')) hash_label = self.translate(_('Hash')) bytes_label = self.translate(_('Bytes')) # bullet-less bold filename tight above its list, spaced between files name_style = self.style.normal.clone( 'attachment_name', spaceBefore=12, spaceAfter=2 ) for file in entry.files: self.p_markup(f'<strong>{escape(file.name)}</strong>', name_style) self.mini_html( f'<ul>' f'<li>{size_label}: {file.reference.file.content_length} ' f'{bytes_label}</li>' f'<li>{date_label}: ' f'{layout.format_date(file.created, "datetime")}</li>' f'<li>{hash_label}: {file.checksum or file.id}</li>' f'</ul>' )
[docs] def add_publication_details( self, entry: ExtendedDirectoryEntry, layout: DefaultMailLayout ) -> None: self.h2(_('Publication details')) not_set = self.translate(_('Not set')) start = ( layout.format_date(entry.publication_start, 'datetime') if entry.publication_start else not_set ) end = ( layout.format_date(entry.publication_end, 'datetime') if entry.publication_end else not_set ) details = '\n'.join([ ( f'<li><strong>{self.translate(_("Publication start:"))}' f'</strong> {start}</li>' ), ( f'<li><strong>{self.translate(_("Publication end:"))}' f'</strong> {end}</li>' ), ( f'<li><strong>{self.translate(_("Access"))}:</strong> ' f'{layout.access_label(entry.access)}</li>' ), ( f'<li><strong>{self.translate(_("Entry checksum"))}:</strong> ' f'{entry.content_hash}</li>' ), ]) self.mini_html(f'<ul>{details}</ul>')
[docs] def add_generated_note( self, layout: DefaultMailLayout, generated_at: datetime ) -> None: text = _( 'Email automatically generated by ${org} at ${timestamp}', mapping={ 'org': layout.org.title, 'timestamp': layout.format_date( generated_at, 'datetime'), }, ) self.p_markup( text, self.style.paragraph.clone('generated_footer', spaceBefore=20) )
@classmethod
[docs] def from_entry( cls, request: OrgRequest, entry: ExtendedDirectoryEntry, generated_at: datetime, ended: bool = False ) -> BytesIO: """ Creates a PDF representation of the published entry. """ app = request.app layout = DefaultMailLayout(entry, request) result = BytesIO() pdf = cls( result, title=entry.title, author=app.org.title, locale=request.locale, translations=app.translations, ) pdf.init_a4_portrait( page_fn=pdf.page_fn, page_fn_later=pdf.page_fn_later ) pdf.add_title(entry, request, ended) pdf.add_fields(entry, layout) pdf.add_attachments(entry, layout) pdf.add_publication_details(entry, layout) pdf.add_generated_note(layout, generated_at) pdf.generate() result.seek(0) return result