import copy import math from datetime import datetime from typing import Any, Union from urllib.parse import quote_plus, urlencode from zoneinfo import ZoneInfo import fastapi import paginate from jinja2 import pass_context import aurweb.models from aurweb import config, l10n from aurweb.templates import register_filter, register_function @register_filter("pager_nav") @pass_context def pager_nav(context: dict[str, Any], page: int, total: int, prefix: str) -> str: page = int(page) # Make sure this is an int. pp = context.get("PP", 50) # Setup a local query string dict, optionally passed by caller. q = context.get("q", dict()) search_by = context.get("SeB", None) if search_by: q["SeB"] = search_by sort_by = context.get("SB", None) if sort_by: q["SB"] = sort_by def create_url(page: int): nonlocal q offset = max(page * pp - pp, 0) qs = to_qs(extend_query(q, ["O", offset])) return f"{prefix}?{qs}" # Use the paginate module to produce our linkage. pager = paginate.Page( [], page=page + 1, items_per_page=pp, item_count=total, url_maker=create_url ) return pager.pager( link_attr={"class": "page"}, curpage_attr={"class": "page"}, separator=" ", format="$link_first $link_previous ~5~ $link_next $link_last", symbol_first="« First", symbol_previous="‹ Previous", symbol_next="Next ›", symbol_last="Last »", ) @register_function("config_getint") def config_getint(section: str, key: str) -> int: return config.getint(section, key) @register_function("round") def do_round(f: float) -> int: return round(f) @register_filter("tr") @pass_context def tr(context: dict[str, Any], value: str): """A translation filter; example: {{ "Hello" | tr("de") }}.""" _ = l10n.get_translator_for_request(context.get("request")) return _(value) @register_filter("tn") @pass_context def tn(context: dict[str, Any], count: int, singular: str, plural: str) -> str: """A singular and plural translation filter. Example: {{ some_integer | tn("singular %d", "plural %d") }} :param context: Response context :param count: The number used to decide singular or plural state :param singular: The singular translation :param plural: The plural translation :return: Translated string """ gettext = l10n.get_raw_translator_for_request(context.get("request")) return gettext.ngettext(singular, plural, count) @register_filter("dt") def timestamp_to_datetime(timestamp: int): return datetime.utcfromtimestamp(int(timestamp)) @register_filter("as_timezone") def as_timezone(dt: datetime, timezone: str): return dt.astimezone(tz=ZoneInfo(timezone)) @register_filter("extend_query") def extend_query(query: dict[str, Any], *additions) -> dict[str, Any]: """Add additional key value pairs to query.""" q = copy.copy(query) for k, v in list(additions): q[k] = v return q @register_filter("urlencode") def to_qs(query: dict[str, Any]) -> str: return urlencode(query, doseq=True) @register_filter("get_vote") def get_vote(voteinfo, request: fastapi.Request): from aurweb.models import TUVote return voteinfo.tu_votes.filter(TUVote.User == request.user).first() @register_filter("number_format") def number_format(value: float, places: int): """A converter function similar to PHP's number_format.""" return f"{value:.{places}f}" @register_filter("account_url") @pass_context def account_url(context: dict[str, Any], user: "aurweb.models.user.User") -> str: base = aurweb.config.get("options", "aur_location") return f"{base}/account/{user.Username}" @register_filter("quote_plus") def _quote_plus(*args, **kwargs) -> str: return quote_plus(*args, **kwargs) @register_filter("ceil") def ceil(*args, **kwargs) -> int: return math.ceil(*args, **kwargs) @register_function("date_strftime") @pass_context def date_strftime(context: dict[str, Any], dt: Union[int, datetime], fmt: str) -> str: if isinstance(dt, int): dt = timestamp_to_datetime(dt) tz = context.get("timezone") return as_timezone(dt, tz).strftime(fmt) @register_function("date_display") @pass_context def date_display(context: dict[str, Any], dt: Union[int, datetime]) -> str: return date_strftime(context, dt, "%Y-%m-%d (%Z)") @register_function("datetime_display") @pass_context def datetime_display(context: dict[str, Any], dt: Union[int, datetime]) -> str: return date_strftime(context, dt, "%Y-%m-%d %H:%M (%Z)")