~homeworkprod/byceps

4ef91f3154b04e150b06bd5d3f94ec5aef1bc4bb — Jochen Kupperschmidt 1 year, 7 months ago 1db908c
Move news image HTML rendering to separate service
M byceps/blueprints/admin/news/views.py => byceps/blueprints/admin/news/views.py +2 -1
@@ 13,6 13,7 @@ from flask import abort, g, request
from ....services.brand import service as brand_service
from ....services.image import service as image_service
from ....services.news import channel_service as news_channel_service
from ....services.news import html_service as news_html_service
from ....services.news import image_service as news_image_service
from ....services.news import service as news_item_service
from ....services.news.transfer.models import Channel


@@ 277,7 278,7 @@ def _render_item_version(version, item):
    }

    try:
        rendered_body = news_item_service.render_body(
        rendered_body = news_html_service.render_body(
            version.body, channel.id, item.images
        )


M byceps/blueprints/news/views.py => byceps/blueprints/news/views.py +2 -1
@@ 10,6 10,7 @@ import dataclasses

from flask import abort, g

from ...services.news import html_service as news_html_service
from ...services.news import service as news_service
from ...services.site import settings_service as site_settings_service
from ...util.framework.blueprint import create_blueprint


@@ 101,7 102,7 @@ def _may_view_drafts(user):

def _replace_body_with_rendered_body(item):
    try:
        rendered_body = news_service.render_body(
        rendered_body = news_html_service.render_body(
            item.body, item.channel.id, item.images
        )
    except Exception as e:

A byceps/services/news/html_service.py => byceps/services/news/html_service.py +81 -0
@@ 0,0 1,81 @@
"""
byceps.services.news.html_service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Render HTML fragments from news items and images.

:Copyright: 2006-2020 Jochen Kupperschmidt
:License: Modified BSD, see LICENSE for details.
"""

from functools import partial
from typing import List, Optional

from jinja2 import Markup

from ...util.iterables import find
from ...util.templating import load_template

from .transfer.models import ChannelID, Image


def render_body(
    raw_body: str, channel_id: ChannelID, images: List[Image]
) -> str:
    """Render item's raw body to HTML."""
    template = load_template(raw_body)
    render_image = partial(_render_image, channel_id, images)
    return template.render(render_image=render_image)


def _render_image(
    channel_id: ChannelID,
    images: List[Image],
    number: int,
    *,
    width: Optional[int] = None,
    height: Optional[int] = None,
) -> str:
    """Render HTML for image."""
    image = find(lambda image: image.number == number, images)

    if image is None:
        raise Exception(f'Unknown image number "{number}"')

    img_src = image.url_path

    figure_attrs = ''
    img_attrs = ''
    figcaption_attrs = ''

    if image.alt_text:
        img_attrs += f' alt="{image.alt_text}"'

    if width:
        img_attrs += f' width="{width}"'
        figcaption_attrs += f' style="max-width: {width}px;"'
    if height:
        img_attrs += f' height="{height}"'

    caption = image.caption
    if caption is None:
        caption = ''

    if image.attribution:
        if caption:
            caption += ' '
        caption += f'<small>Bild: {image.attribution}</small>'

    caption_elem = (
        f'<figcaption{figcaption_attrs}>{caption}</figcaption>'
        if caption
        else ''
    )

    html = f"""\
<figure{figure_attrs}>
  <img src="{img_src}"{img_attrs}>
  {caption_elem}
</figure>"""

    return Markup(html)

M byceps/services/news/service.py => byceps/services/news/service.py +2 -69
@@ 7,16 7,11 @@ byceps.services.news.service
"""

from datetime import datetime
from functools import partial
from typing import Dict, List, Optional, Sequence

from jinja2 import Markup
from typing import Dict, Optional, Sequence

from ...database import db, paginate, Pagination, Query
from ...events.news import NewsItemPublished
from ...typing import BrandID, UserID
from ...util.iterables import find
from ...util.templating import load_template

from ..brand.models.brand import Brand as DbBrand



@@ 28,7 23,7 @@ from .models.item import (
    ItemVersion as DbItemVersion,
)
from . import image_service
from .transfer.models import ChannelID, Image, Item, ItemID, ItemVersionID
from .transfer.models import ChannelID, Item, ItemID, ItemVersionID


def create_item(


@@ 283,65 278,3 @@ def _assemble_image_url_path(item: DbItem) -> Optional[str]:
        return None

    return f'/data/global/news_channels/{item.channel_id}/{url_path}'


def render_body(
    raw_body: str, channel_id: ChannelID, images: List[Image]
) -> str:
    """Render item's raw body to HTML."""
    template = load_template(raw_body)
    render_image = partial(_render_image, channel_id, images)
    return template.render(render_image=render_image)


def _render_image(
    channel_id: ChannelID,
    images: List[Image],
    number: int,
    *,
    width: Optional[int] = None,
    height: Optional[int] = None,
) -> str:
    """Render HTML for image."""
    image = find(lambda image: image.number == number, images)

    if image is None:
        raise Exception(f'Unknown image number "{number}"')

    img_src = image.url_path

    figure_attrs = ''
    img_attrs = ''
    figcaption_attrs = ''

    if image.alt_text:
        img_attrs += f' alt="{image.alt_text}"'

    if width:
        img_attrs += f' width="{width}"'
        figcaption_attrs += f' style="max-width: {width}px;"'
    if height:
        img_attrs += f' height="{height}"'

    caption = image.caption
    if caption is None:
        caption = ''

    if image.attribution:
        if caption:
            caption += ' '
        caption += f'<small>Bild: {image.attribution}</small>'

    caption_elem = (
        f'<figcaption{figcaption_attrs}>{caption}</figcaption>'
        if caption
        else ''
    )

    html = f"""\
<figure{figure_attrs}>
  <img src="{img_src}"{img_attrs}>
  {caption_elem}
</figure>"""

    return Markup(html)