|
@@ -3,31 +3,16 @@
|
|
|
# All rights reserved
|
|
|
#
|
|
|
# THIS SOFTWARE IS PROVIDED AS IS WITHOUT WARRANTY
|
|
|
-from typing import Iterable
|
|
|
import os
|
|
|
-from urllib.parse import urlencode
|
|
|
-from bottle import (
|
|
|
- route,
|
|
|
- request,
|
|
|
- response,
|
|
|
- FormsDict,
|
|
|
- redirect,
|
|
|
- template,
|
|
|
- static_file,
|
|
|
-)
|
|
|
+from bottle import route, request, response, template, static_file
|
|
|
from psycopg import connect
|
|
|
from threading import Thread
|
|
|
|
|
|
+from .route_decorators import normalize, poison, cursor
|
|
|
from .query_to_xml import get_categories, get_groups, get_products, get_tags
|
|
|
-
|
|
|
-from ..data.filter import(
|
|
|
- get_filter,
|
|
|
- get_query_param,
|
|
|
-)
|
|
|
-from . import trend as worker
|
|
|
-from . import PARAMS
|
|
|
from .CachedLoadingPage import CachedLoadingPage
|
|
|
from .Cache import Cache
|
|
|
+from . import trend as worker
|
|
|
|
|
|
host = f"host={os.getenv('HOST')}"
|
|
|
db = f"dbname={os.getenv('DB', 'grocery')}"
|
|
@@ -39,66 +24,28 @@ conn = connect(f"{host} {db} {user} {password}")
|
|
|
|
|
|
CACHE = Cache(10)
|
|
|
|
|
|
-def normalize_query(query: FormsDict, allow: Iterable[str] = None) -> str:
|
|
|
- param = get_filter(query, allow=allow)
|
|
|
- return urlencode([
|
|
|
- (k, get_query_param(*param[k])) for k in sorted(param) if param[k]
|
|
|
- ])
|
|
|
-
|
|
|
-def _normalize_decorator(func, poison_on_reload=False):
|
|
|
- def wrap(*args, **kwargs):
|
|
|
- _, _, path, *_ = request.urlparts
|
|
|
- normalized = normalize_query(request.query, allow=PARAMS)
|
|
|
- if poison_on_reload and request.params.get('reload') == 'true':
|
|
|
- CACHE.remove(normalized)
|
|
|
- if request.query_string != normalized:
|
|
|
- return redirect(f'{path}?{normalized}')
|
|
|
- return func(*args, **kwargs)
|
|
|
- return wrap
|
|
|
-
|
|
|
-def normalize(*args, **kwargs):
|
|
|
- if not len(args):
|
|
|
- return lambda f: _normalize_decorator(f, **kwargs)
|
|
|
-
|
|
|
- return _normalize_decorator(*args)
|
|
|
-
|
|
|
-def cursor(func):
|
|
|
- def wrap(*args, **kwargs):
|
|
|
- try:
|
|
|
- with conn.cursor() as cur:
|
|
|
- return func(cur, *args, **kwargs)
|
|
|
- finally:
|
|
|
- conn.commit()
|
|
|
- return wrap
|
|
|
-
|
|
|
-
|
|
|
@route('/grocery/static/<filename:path>')
|
|
|
def send_static(filename):
|
|
|
return static_file(filename, root='app/rest/static')
|
|
|
|
|
|
+
|
|
|
@route('/grocery/trend')
|
|
|
-@normalize(poison_on_reload=True)
|
|
|
+@poison(cache=CACHE)
|
|
|
+@normalize
|
|
|
def trend():
|
|
|
+ page = CACHE.get(request.query_string)
|
|
|
_, _, path, *_ = request.urlparts
|
|
|
- normalized = normalize_query(request.query, allow=PARAMS)
|
|
|
- if request.params.get('reload') == 'true':
|
|
|
- CACHE.remove(normalized)
|
|
|
-
|
|
|
- if request.query_string != normalized:
|
|
|
- return redirect(f'{path}?{normalized}')
|
|
|
-
|
|
|
- page = CACHE.get(normalized)
|
|
|
-
|
|
|
- return page if page else CACHE.add(normalized, CachedLoadingPage(
|
|
|
+ return page if page else CACHE.add(request.query_string, CachedLoadingPage(
|
|
|
template("loading", progress=[]),
|
|
|
lambda queue: Thread(target=worker.trend, args=(
|
|
|
queue, conn, path, request.query
|
|
|
)).start()
|
|
|
))
|
|
|
|
|
|
+
|
|
|
@route('/grocery/groups')
|
|
|
@normalize
|
|
|
-@cursor
|
|
|
+@cursor(connection=conn)
|
|
|
def groups(cur):
|
|
|
response.content_type = 'application/xhtml+xml; charset=utf-8'
|
|
|
return get_groups(cur, request.query)
|
|
@@ -106,14 +53,15 @@ def groups(cur):
|
|
|
|
|
|
@route('/grocery/categories')
|
|
|
@normalize
|
|
|
-@cursor
|
|
|
+@cursor(connection=conn)
|
|
|
def categories(cur):
|
|
|
response.content_type = 'application/xhtml+xml; charset=utf-8'
|
|
|
return get_categories(cur, request.query)
|
|
|
|
|
|
+
|
|
|
@route('/grocery/products')
|
|
|
@normalize
|
|
|
-@cursor
|
|
|
+@cursor(connection=conn)
|
|
|
def products(cur):
|
|
|
response.content_type = 'application/xhtml+xml; charset=utf-8'
|
|
|
return get_products(cur, request.query)
|
|
@@ -121,7 +69,7 @@ def products(cur):
|
|
|
|
|
|
@route('/grocery/tags')
|
|
|
@normalize
|
|
|
-@cursor
|
|
|
+@cursor(connection=conn)
|
|
|
def tags(cur):
|
|
|
response.content_type = 'application/xhtml+xml; charset=utf-8'
|
|
|
return get_tags(cur, request.query)
|