Move template filters and globals into blueprint (#301)

* Move 8 of 9 template filters and globals into a blueprint

* Rename nyaa.filters -> nyaa.template_utils

* Fix import sorting
This commit is contained in:
Kfir Hadas 2017-07-23 22:30:41 +03:00
parent 50529920bd
commit f3b923ccca
3 changed files with 114 additions and 102 deletions

View File

@ -3,17 +3,15 @@ import math
import os.path import os.path
import re import re
from datetime import datetime, timedelta from datetime import datetime, timedelta
from email.utils import formatdate
from urllib.parse import quote from urllib.parse import quote
import flask import flask
from flask_paginate import Pagination from flask_paginate import Pagination
from werkzeug import url_encode
from werkzeug.datastructures import CombinedMultiDict from werkzeug.datastructures import CombinedMultiDict
from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload
from nyaa import api_handler, app, backend, db, forms, models, torrents, views from nyaa import api_handler, app, backend, db, forms, models, template_utils, torrents, views
from nyaa.search import (DEFAULT_MAX_SEARCH_RESULT, DEFAULT_PER_PAGE, SERACH_PAGINATE_DISPLAY_MSG, from nyaa.search import (DEFAULT_MAX_SEARCH_RESULT, DEFAULT_PER_PAGE, SERACH_PAGINATE_DISPLAY_MSG,
_generate_query_string, search_db, search_elastic) _generate_query_string, search_db, search_elastic)
from nyaa.utils import cached_function, chain_get from nyaa.utils import cached_function, chain_get
@ -21,51 +19,6 @@ from nyaa.utils import cached_function, chain_get
DEBUG_API = False DEBUG_API = False
# For static_cachebuster
_static_cache = {}
@app.template_global()
def static_cachebuster(filename):
''' Adds a ?t=<mtime> cachebuster to the given path, if the file exists.
Results are cached in memory and persist until app restart! '''
# Instead of timestamps, we could use commit hashes (we already load it in __init__)
# But that'd mean every static resource would get cache busted. This lets unchanged items
# stay in the cache.
if app.debug:
# Do not bust cache on debug (helps debugging)
return flask.url_for('static', filename=filename)
# Get file mtime if not already cached.
if filename not in _static_cache:
file_path = os.path.join(app.static_folder, filename)
file_mtime = None
if os.path.exists(file_path):
file_mtime = int(os.path.getmtime(file_path))
_static_cache[filename] = file_mtime
return flask.url_for('static', filename=filename, t=_static_cache[filename])
@app.template_global()
def modify_query(**new_values):
args = flask.request.args.copy()
for key, value in new_values.items():
args[key] = value
return '{}?{}'.format(flask.request.path, url_encode(args))
@app.template_global()
def filter_truthy(input_list):
''' Jinja2 can't into list comprehension so this is for
the search_results.html template '''
return [item for item in input_list if item]
@app.template_global() @app.template_global()
def category_name(cat_id): def category_name(cat_id):
''' Given a category id (eg. 1_2), returns a category name (eg. Anime - English-translated) ''' ''' Given a category id (eg. 1_2), returns a category name (eg. Anime - English-translated) '''
@ -96,18 +49,6 @@ def before_request():
return 'You are banned.', 403 return 'You are banned.', 403
@app.template_filter('utc_time')
def get_utc_timestamp(datetime_str):
''' Returns a UTC POSIX timestamp, as seconds '''
UTC_EPOCH = datetime.utcfromtimestamp(0)
return int((datetime.strptime(datetime_str, '%Y-%m-%dT%H:%M:%S') - UTC_EPOCH).total_seconds())
@app.template_filter('display_time')
def get_display_time(datetime_str):
return datetime.strptime(datetime_str, '%Y-%m-%dT%H:%M:%S').strftime('%Y-%m-%d %H:%M')
@cached_function @cached_function
def get_category_id_map(): def get_category_id_map():
''' Reads database for categories and turns them into a dict with ''' Reads database for categories and turns them into a dict with
@ -261,16 +202,6 @@ def home(rss):
special_results=special_results) special_results=special_results)
@app.template_filter('rfc822')
def _jinja2_filter_rfc822(date, fmt=None):
return formatdate(date.timestamp())
@app.template_filter('rfc822_es')
def _jinja2_filter_rfc822_es(datestr, fmt=None):
return formatdate(datetime.strptime(datestr, '%Y-%m-%dT%H:%M:%S').timestamp())
def render_rss(label, query, use_elastic, magnet_links=False): def render_rss(label, query, use_elastic, magnet_links=False):
rss_xml = flask.render_template('rss.xml', rss_xml = flask.render_template('rss.xml',
use_elastic=use_elastic, use_elastic=use_elastic,
@ -544,40 +475,13 @@ def _get_cached_torrent_file(torrent):
return open(cached_torrent, 'rb'), os.path.getsize(cached_torrent) return open(cached_torrent, 'rb'), os.path.getsize(cached_torrent)
@app.template_filter()
def timesince(dt, default='just now'):
"""
Returns string representing "time since" e.g.
3 minutes ago, 5 hours ago etc.
Date and time (UTC) are returned if older than 1 day.
"""
now = datetime.utcnow()
diff = now - dt
periods = (
(diff.days, 'day', 'days'),
(diff.seconds / 3600, 'hour', 'hours'),
(diff.seconds / 60, 'minute', 'minutes'),
(diff.seconds, 'second', 'seconds'),
)
if diff.days >= 1:
return dt.strftime('%Y-%m-%d %H:%M UTC')
else:
for period, singular, plural in periods:
if period >= 1:
return '%d %s ago' % (period, singular if int(period) == 1 else plural)
return default
# #################################### BLUEPRINTS #################################### # #################################### BLUEPRINTS ####################################
def register_blueprints(flask_app): def register_blueprints(flask_app):
""" Register the blueprints using the flask_app object """ """ Register the blueprints using the flask_app object """
# Template filters and globals
flask_app.register_blueprint(template_utils.bp)
# API routes # API routes
flask_app.register_blueprint(api_handler.api_blueprint, url_prefix='/api') flask_app.register_blueprint(api_handler.api_blueprint, url_prefix='/api')
# Site routes # Site routes

107
nyaa/template_utils.py Normal file
View File

@ -0,0 +1,107 @@
import os.path
from datetime import datetime
from email.utils import formatdate
import flask
from werkzeug.urls import url_encode
from nyaa import app
bp = flask.Blueprint('template-utils', __name__)
_static_cache = {} # For static_cachebuster
# ######################### TEMPLATE GLOBALS #########################
@bp.app_template_global()
def static_cachebuster(filename):
""" Adds a ?t=<mtime> cachebuster to the given path, if the file exists.
Results are cached in memory and persist until app restart! """
# Instead of timestamps, we could use commit hashes (we already load it in __init__)
# But that'd mean every static resource would get cache busted. This lets unchanged items
# stay in the cache.
if app.debug:
# Do not bust cache on debug (helps debugging)
return flask.url_for('static', filename=filename)
# Get file mtime if not already cached.
if filename not in _static_cache:
file_path = os.path.join(app.static_folder, filename)
file_mtime = None
if os.path.exists(file_path):
file_mtime = int(os.path.getmtime(file_path))
_static_cache[filename] = file_mtime
return flask.url_for('static', filename=filename, t=_static_cache[filename])
@bp.app_template_global()
def modify_query(**new_values):
args = flask.request.args.copy()
for key, value in new_values.items():
args[key] = value
return '{}?{}'.format(flask.request.path, url_encode(args))
@bp.app_template_global()
def filter_truthy(input_list):
""" Jinja2 can't into list comprehension so this is for
the search_results.html template """
return [item for item in input_list if item]
# ######################### TEMPLATE FILTERS #########################
@bp.app_template_filter('utc_time')
def get_utc_timestamp(datetime_str):
""" Returns a UTC POSIX timestamp, as seconds """
UTC_EPOCH = datetime.utcfromtimestamp(0)
return int((datetime.strptime(datetime_str, '%Y-%m-%dT%H:%M:%S') - UTC_EPOCH).total_seconds())
@bp.app_template_filter('display_time')
def get_display_time(datetime_str):
return datetime.strptime(datetime_str, '%Y-%m-%dT%H:%M:%S').strftime('%Y-%m-%d %H:%M')
@bp.app_template_filter('rfc822')
def _jinja2_filter_rfc822(date, fmt=None):
return formatdate(date.timestamp())
@bp.app_template_filter('rfc822_es')
def _jinja2_filter_rfc822_es(datestr, fmt=None):
return formatdate(datetime.strptime(datestr, '%Y-%m-%dT%H:%M:%S').timestamp())
@bp.app_template_filter()
def timesince(dt, default='just now'):
"""
Returns string representing "time since" e.g.
3 minutes ago, 5 hours ago etc.
Date and time (UTC) are returned if older than 1 day.
"""
now = datetime.utcnow()
diff = now - dt
periods = (
(diff.days, 'day', 'days'),
(diff.seconds / 3600, 'hour', 'hours'),
(diff.seconds / 60, 'minute', 'minutes'),
(diff.seconds, 'second', 'seconds'),
)
if diff.days >= 1:
return dt.strftime('%Y-%m-%d %H:%M UTC')
else:
for period, singular, plural in periods:
if period >= 1:
return '%d %s ago' % (period, singular if int(period) == 1 else plural)
return default

View File

@ -4,11 +4,12 @@ import datetime
from email.utils import formatdate from email.utils import formatdate
from tests import NyaaTestCase from tests import NyaaTestCase
from nyaa.routes import (_jinja2_filter_rfc822, _jinja2_filter_rfc822_es, get_utc_timestamp, from nyaa.routes import category_name
get_display_time, timesince, filter_truthy, category_name) from nyaa.template_utils import (_jinja2_filter_rfc822, _jinja2_filter_rfc822_es, get_utc_timestamp,
get_display_time, timesince, filter_truthy)
class TestFilters(NyaaTestCase): class TestTemplateUtils(NyaaTestCase):
# def setUp(self): # def setUp(self):
# self.db, nyaa.app.config['DATABASE'] = tempfile.mkstemp() # self.db, nyaa.app.config['DATABASE'] = tempfile.mkstemp()