Improve separation between front & back with etiquette_flask package
Move flask-specific operations out of etiquette's files and into new etiquette_flask. In etiquette_site.py, etiquette calls are fully qualified.
This commit is contained in:
parent
83b9adbd61
commit
a9c7ad6993
8 changed files with 151 additions and 137 deletions
|
@ -1 +1,8 @@
|
||||||
pass
|
from . import constants
|
||||||
|
from . import decorators
|
||||||
|
from . import exceptions
|
||||||
|
from . import helpers
|
||||||
|
from . import jsonify
|
||||||
|
from . import objects
|
||||||
|
from . import photodb
|
||||||
|
from . import searchhelpers
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
import flask
|
|
||||||
from flask import request
|
|
||||||
import functools
|
import functools
|
||||||
import time
|
import time
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from . import jsonify
|
|
||||||
|
|
||||||
|
|
||||||
def required_feature(features):
|
def required_feature(features):
|
||||||
'''
|
'''
|
||||||
|
@ -31,35 +27,6 @@ def required_feature(features):
|
||||||
return wrapped
|
return wrapped
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
def required_fields(fields, forbid_whitespace=False):
|
|
||||||
'''
|
|
||||||
Declare that the endpoint requires certain POST body fields. Without them,
|
|
||||||
we respond with 400 and a message.
|
|
||||||
|
|
||||||
forbid_whitespace:
|
|
||||||
If True, then providing the field is not good enough. It must also
|
|
||||||
contain at least some non-whitespace characters.
|
|
||||||
'''
|
|
||||||
def wrapper(function):
|
|
||||||
@functools.wraps(function)
|
|
||||||
def wrapped(*args, **kwargs):
|
|
||||||
for requirement in fields:
|
|
||||||
missing = (
|
|
||||||
requirement not in request.form or
|
|
||||||
(forbid_whitespace and request.form[requirement].strip() == '')
|
|
||||||
)
|
|
||||||
if missing:
|
|
||||||
response = {
|
|
||||||
'error_type': 'MISSING_FIELDS',
|
|
||||||
'error_message': 'Required fields: %s' % ', '.join(fields),
|
|
||||||
}
|
|
||||||
response = jsonify.make_json_response(response, status=400)
|
|
||||||
return response
|
|
||||||
|
|
||||||
return function(*args, **kwargs)
|
|
||||||
return wrapped
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
def not_implemented(function):
|
def not_implemented(function):
|
||||||
'''
|
'''
|
||||||
Decorator to remember what needs doing.
|
Decorator to remember what needs doing.
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
import flask
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
def make_json_response(j, *args, **kwargs):
|
|
||||||
dumped = json.dumps(j)
|
|
||||||
response = flask.Response(dumped, *args, **kwargs)
|
|
||||||
response.headers['Content-Type'] = 'application/json;charset=utf-8'
|
|
||||||
return response
|
|
||||||
|
|
||||||
def album(a, minimal=False):
|
def album(a, minimal=False):
|
||||||
j = {
|
j = {
|
||||||
|
|
3
etiquette_flask/__init__.py
Normal file
3
etiquette_flask/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from . import decorators
|
||||||
|
from . import jsonify
|
||||||
|
from . import sessions
|
35
etiquette_flask/decorators.py
Normal file
35
etiquette_flask/decorators.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import flask
|
||||||
|
from flask import request
|
||||||
|
import functools
|
||||||
|
|
||||||
|
from etiquette import jsonify
|
||||||
|
|
||||||
|
|
||||||
|
def required_fields(fields, forbid_whitespace=False):
|
||||||
|
'''
|
||||||
|
Declare that the endpoint requires certain POST body fields. Without them,
|
||||||
|
we respond with 400 and a message.
|
||||||
|
|
||||||
|
forbid_whitespace:
|
||||||
|
If True, then providing the field is not good enough. It must also
|
||||||
|
contain at least some non-whitespace characters.
|
||||||
|
'''
|
||||||
|
def wrapper(function):
|
||||||
|
@functools.wraps(function)
|
||||||
|
def wrapped(*args, **kwargs):
|
||||||
|
for requirement in fields:
|
||||||
|
missing = (
|
||||||
|
requirement not in request.form or
|
||||||
|
(forbid_whitespace and request.form[requirement].strip() == '')
|
||||||
|
)
|
||||||
|
if missing:
|
||||||
|
response = {
|
||||||
|
'error_type': 'MISSING_FIELDS',
|
||||||
|
'error_message': 'Required fields: %s' % ', '.join(fields),
|
||||||
|
}
|
||||||
|
response = jsonify.make_json_response(response, status=400)
|
||||||
|
return response
|
||||||
|
|
||||||
|
return function(*args, **kwargs)
|
||||||
|
return wrapped
|
||||||
|
return wrapper
|
9
etiquette_flask/jsonify.py
Normal file
9
etiquette_flask/jsonify.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import flask
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def make_json_response(j, *args, **kwargs):
|
||||||
|
dumped = json.dumps(j)
|
||||||
|
response = flask.Response(dumped, *args, **kwargs)
|
||||||
|
response.headers['Content-Type'] = 'application/json;charset=utf-8'
|
||||||
|
return response
|
|
@ -3,7 +3,7 @@ from flask import request
|
||||||
import functools
|
import functools
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from . import helpers
|
from etiquette import helpers
|
||||||
|
|
||||||
def _generate_token():
|
def _generate_token():
|
||||||
token = str(uuid.uuid4())
|
token = str(uuid.uuid4())
|
||||||
|
@ -13,7 +13,8 @@ def _generate_token():
|
||||||
def _normalize_token(token):
|
def _normalize_token(token):
|
||||||
if isinstance(token, flask.Request):
|
if isinstance(token, flask.Request):
|
||||||
token = token.cookies.get('etiquette_session', None)
|
token = token.cookies.get('etiquette_session', None)
|
||||||
|
|
||||||
|
|
||||||
class SessionManager:
|
class SessionManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sessions = {}
|
self.sessions = {}
|
|
@ -9,24 +9,22 @@ import urllib.parse
|
||||||
import warnings
|
import warnings
|
||||||
import zipstream
|
import zipstream
|
||||||
|
|
||||||
from etiquette import constants
|
import etiquette
|
||||||
from etiquette import decorators
|
import etiquette_flask
|
||||||
from etiquette import exceptions
|
|
||||||
from etiquette import helpers
|
from voussoirkit import pathclass
|
||||||
from etiquette import jsonify
|
|
||||||
from etiquette import objects
|
|
||||||
from etiquette import photodb
|
|
||||||
from etiquette import searchhelpers
|
|
||||||
from etiquette import sessions
|
|
||||||
|
|
||||||
|
|
||||||
TEMPLATE_DIR = 'C:\\git\\Etiquette\\templates'
|
root_dir = pathclass.Path(__file__).parent
|
||||||
STATIC_DIR = 'C:\\git\\Etiquette\\static'
|
|
||||||
|
TEMPLATE_DIR = root_dir.with_child('templates')
|
||||||
|
STATIC_DIR = root_dir.with_child('static')
|
||||||
|
FAVICON_PATH = STATIC_DIR.with_child('favicon.png')
|
||||||
|
|
||||||
site = flask.Flask(
|
site = flask.Flask(
|
||||||
__name__,
|
__name__,
|
||||||
template_folder=TEMPLATE_DIR,
|
template_folder=TEMPLATE_DIR.absolute_path,
|
||||||
static_folder=STATIC_DIR,
|
static_folder=STATIC_DIR.absolute_path,
|
||||||
)
|
)
|
||||||
site.config.update(
|
site.config.update(
|
||||||
SEND_FILE_MAX_AGE_DEFAULT=180,
|
SEND_FILE_MAX_AGE_DEFAULT=180,
|
||||||
|
@ -37,9 +35,9 @@ site.jinja_env.trim_blocks = True
|
||||||
site.jinja_env.lstrip_blocks = True
|
site.jinja_env.lstrip_blocks = True
|
||||||
site.debug = True
|
site.debug = True
|
||||||
|
|
||||||
P = photodb.PhotoDB()
|
P = etiquette.photodb.PhotoDB()
|
||||||
|
|
||||||
session_manager = sessions.SessionManager()
|
session_manager = etiquette_flask.sessions.SessionManager()
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
@ -67,8 +65,8 @@ def delete_synonym(synonym):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
master_tag = P.get_tag(synonym)
|
master_tag = P.get_tag(synonym)
|
||||||
except exceptions.NoSuchTag as e:
|
except etiquette.exceptions.NoSuchTag as e:
|
||||||
raise exceptions.NoSuchSynonym(*e.given_args, **e.given_kwargs)
|
raise etiquette.exceptions.NoSuchSynonym(*e.given_args, **e.given_kwargs)
|
||||||
master_tag.remove_synonym(synonym)
|
master_tag.remove_synonym(synonym)
|
||||||
|
|
||||||
return {'action':'delete_synonym', 'synonym': synonym}
|
return {'action':'delete_synonym', 'synonym': synonym}
|
||||||
|
@ -78,8 +76,8 @@ def P_wrapper(function):
|
||||||
try:
|
try:
|
||||||
return function(thingid)
|
return function(thingid)
|
||||||
|
|
||||||
except exceptions.EtiquetteException as e:
|
except etiquette.exceptions.EtiquetteException as e:
|
||||||
if isinstance(e, exceptions.NoSuch):
|
if isinstance(e, etiquette.exceptions.NoSuch):
|
||||||
status = 404
|
status = 404
|
||||||
else:
|
else:
|
||||||
status = 400
|
status = 400
|
||||||
|
@ -87,8 +85,8 @@ def P_wrapper(function):
|
||||||
if response_type == 'html':
|
if response_type == 'html':
|
||||||
flask.abort(status, e.error_message)
|
flask.abort(status, e.error_message)
|
||||||
else:
|
else:
|
||||||
response = jsonify.exception(e)
|
response = etiquette.jsonify.exception(e)
|
||||||
response = jsonify.make_json_response(response, status=status)
|
response = etiquette_flask.jsonify.make_json_response(response, status=status)
|
||||||
flask.abort(response)
|
flask.abort(response)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -96,7 +94,7 @@ def P_wrapper(function):
|
||||||
if response_type == 'html':
|
if response_type == 'html':
|
||||||
flask.abort(500)
|
flask.abort(500)
|
||||||
else:
|
else:
|
||||||
flask.abort(jsonify.make_response({}, status=500))
|
flask.abort(etiquette.jsonify.make_json_response({}, status=500))
|
||||||
|
|
||||||
return P_wrapped
|
return P_wrapped
|
||||||
|
|
||||||
|
@ -175,7 +173,7 @@ def send_file(filepath, override_mimetype=None):
|
||||||
if request.method == 'HEAD':
|
if request.method == 'HEAD':
|
||||||
outgoing_data = bytes()
|
outgoing_data = bytes()
|
||||||
else:
|
else:
|
||||||
outgoing_data = helpers.read_filebytes(
|
outgoing_data = etiquette.helpers.read_filebytes(
|
||||||
filepath,
|
filepath,
|
||||||
range_min=range_min,
|
range_min=range_min,
|
||||||
range_max=range_max,
|
range_max=range_max,
|
||||||
|
@ -215,12 +213,12 @@ def get_register():
|
||||||
|
|
||||||
@site.route('/login', methods=['POST'])
|
@site.route('/login', methods=['POST'])
|
||||||
@session_manager.give_token
|
@session_manager.give_token
|
||||||
@decorators.required_fields(['username', 'password'])
|
@etiquette_flask.decorators.required_fields(['username', 'password'])
|
||||||
def post_login():
|
def post_login():
|
||||||
if session_manager.get(request):
|
if session_manager.get(request):
|
||||||
e = exceptions.AlreadySignedIn()
|
e = etiquette.exceptions.AlreadySignedIn()
|
||||||
response = jsonify.exception(e)
|
response = etiquette.jsonify.exception(e)
|
||||||
return jsonify.make_json_response(response, status=403)
|
return etiquette_flask.jsonify.make_json_response(response, status=403)
|
||||||
|
|
||||||
username = request.form['username']
|
username = request.form['username']
|
||||||
password = request.form['password']
|
password = request.form['password']
|
||||||
|
@ -231,22 +229,22 @@ def post_login():
|
||||||
# page 404s anyway.
|
# page 404s anyway.
|
||||||
user = P.get_user(username=username)
|
user = P.get_user(username=username)
|
||||||
user = P.login(user.id, password)
|
user = P.login(user.id, password)
|
||||||
except (exceptions.NoSuchUser, exceptions.WrongLogin):
|
except (etiquette.exceptions.NoSuchUser, etiquette.exceptions.WrongLogin):
|
||||||
e = exceptions.WrongLogin()
|
e = etiquette.exceptions.WrongLogin()
|
||||||
response = jsonify.exception(e)
|
response = etiquette.jsonify.exception(e)
|
||||||
return jsonify.make_json_response(response, status=422)
|
return etiquette_flask.jsonify.make_json_response(response, status=422)
|
||||||
session = sessions.Session(request, user)
|
session = etiquette_flask.sessions.Session(request, user)
|
||||||
session_manager.add(session)
|
session_manager.add(session)
|
||||||
return jsonify.make_json_response({})
|
return etiquette_flask.jsonify.make_json_response({})
|
||||||
|
|
||||||
@site.route('/register', methods=['POST'])
|
@site.route('/register', methods=['POST'])
|
||||||
@session_manager.give_token
|
@session_manager.give_token
|
||||||
@decorators.required_fields(['username', 'password_1', 'password_2'])
|
@etiquette_flask.decorators.required_fields(['username', 'password_1', 'password_2'])
|
||||||
def post_register():
|
def post_register():
|
||||||
if session_manager.get(request):
|
if session_manager.get(request):
|
||||||
e = exceptions.AlreadySignedIn()
|
e = etiquette.exceptions.AlreadySignedIn()
|
||||||
response = jsonify.exception(e)
|
response = etiquette.jsonify.exception(e)
|
||||||
return jsonify.make_json_response(response, status=403)
|
return etiquette_flask.jsonify.make_json_response(response, status=403)
|
||||||
|
|
||||||
username = request.form['username']
|
username = request.form['username']
|
||||||
password_1 = request.form['password_1']
|
password_1 = request.form['password_1']
|
||||||
|
@ -257,17 +255,17 @@ def post_register():
|
||||||
'error_type': 'PASSWORDS_DONT_MATCH',
|
'error_type': 'PASSWORDS_DONT_MATCH',
|
||||||
'error_message': 'Passwords do not match.',
|
'error_message': 'Passwords do not match.',
|
||||||
}
|
}
|
||||||
return jsonify.make_json_response(response, status=422)
|
return etiquette_flask.jsonify.make_json_response(response, status=422)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user = P.register_user(username, password_1)
|
user = P.register_user(username, password_1)
|
||||||
except exceptions.EtiquetteException as e:
|
except etiquette.exceptions.EtiquetteException as e:
|
||||||
response = jsonify.exception(e)
|
response = etiquette.jsonify.exception(e)
|
||||||
return jsonify.make_json_response(response, status=400)
|
return etiquette_flask.jsonify.make_json_response(response, status=400)
|
||||||
|
|
||||||
session = sessions.Session(request, user)
|
session = etiquette_flask.sessions.Session(request, user)
|
||||||
session_manager.add(session)
|
session_manager.add(session)
|
||||||
return jsonify.make_json_response({})
|
return etiquette_flask.jsonify.make_json_response({})
|
||||||
|
|
||||||
@site.route('/logout', methods=['GET', 'POST'])
|
@site.route('/logout', methods=['GET', 'POST'])
|
||||||
@session_manager.give_token
|
@session_manager.give_token
|
||||||
|
@ -280,8 +278,7 @@ def logout():
|
||||||
@site.route('/favicon.ico')
|
@site.route('/favicon.ico')
|
||||||
@site.route('/favicon.png')
|
@site.route('/favicon.png')
|
||||||
def favicon():
|
def favicon():
|
||||||
filename = os.path.join(STATIC_DIR, 'favicon.png')
|
return flask.send_file(FAVICON_PATH.absolute_path)
|
||||||
return flask.send_file(filename)
|
|
||||||
|
|
||||||
|
|
||||||
def get_album_core(albumid):
|
def get_album_core(albumid):
|
||||||
|
@ -305,11 +302,11 @@ def get_album_html(albumid):
|
||||||
@session_manager.give_token
|
@session_manager.give_token
|
||||||
def get_album_json(albumid):
|
def get_album_json(albumid):
|
||||||
album = get_album_core(albumid)
|
album = get_album_core(albumid)
|
||||||
album = jsonify.album(album)
|
album = etiquette.jsonify.album(album)
|
||||||
album['sub_albums'] = [P_album(x) for x in album['sub_albums']]
|
album['sub_albums'] = [P_album(x) for x in album['sub_albums']]
|
||||||
album['sub_albums'].sort(key=lambda x: (x.title or x.id).lower())
|
album['sub_albums'].sort(key=lambda x: (x.title or x.id).lower())
|
||||||
album['sub_albums'] = [jsonify.album(x, minimal=True) for x in album['sub_albums']]
|
album['sub_albums'] = [etiquette.jsonify.album(x, minimal=True) for x in album['sub_albums']]
|
||||||
return jsonify.make_json_response(album)
|
return etiquette_flask.jsonify.make_json_response(album)
|
||||||
|
|
||||||
|
|
||||||
@site.route('/album/<albumid>.zip')
|
@site.route('/album/<albumid>.zip')
|
||||||
|
@ -317,16 +314,16 @@ def get_album_zip(albumid):
|
||||||
album = P_album(albumid)
|
album = P_album(albumid)
|
||||||
|
|
||||||
recursive = request.args.get('recursive', True)
|
recursive = request.args.get('recursive', True)
|
||||||
recursive = helpers.truthystring(recursive)
|
recursive = etiquette.helpers.truthystring(recursive)
|
||||||
|
|
||||||
arcnames = helpers.album_zip_filenames(album, recursive=recursive)
|
arcnames = etiquette.helpers.album_zip_filenames(album, recursive=recursive)
|
||||||
|
|
||||||
streamed_zip = zipstream.ZipFile()
|
streamed_zip = zipstream.ZipFile()
|
||||||
for (real_filepath, arcname) in arcnames.items():
|
for (real_filepath, arcname) in arcnames.items():
|
||||||
streamed_zip.write(real_filepath, arcname=arcname)
|
streamed_zip.write(real_filepath, arcname=arcname)
|
||||||
|
|
||||||
# Add the album metadata as an {id}.txt file within each directory.
|
# Add the album metadata as an {id}.txt file within each directory.
|
||||||
directories = helpers.album_zip_directories(album, recursive=recursive)
|
directories = etiquette.helpers.album_zip_directories(album, recursive=recursive)
|
||||||
for (inner_album, directory) in directories.items():
|
for (inner_album, directory) in directories.items():
|
||||||
text = []
|
text = []
|
||||||
if inner_album.title:
|
if inner_album.title:
|
||||||
|
@ -346,7 +343,7 @@ def get_album_zip(albumid):
|
||||||
else:
|
else:
|
||||||
download_as = 'album %s.zip' % album.id
|
download_as = 'album %s.zip' % album.id
|
||||||
|
|
||||||
download_as = helpers.normalize_filepath(download_as)
|
download_as = etiquette.helpers.normalize_filepath(download_as)
|
||||||
download_as = urllib.parse.quote(download_as)
|
download_as = urllib.parse.quote(download_as)
|
||||||
outgoing_headers = {
|
outgoing_headers = {
|
||||||
'Content-Type': 'application/octet-stream',
|
'Content-Type': 'application/octet-stream',
|
||||||
|
@ -372,8 +369,8 @@ def get_albums_html():
|
||||||
@session_manager.give_token
|
@session_manager.give_token
|
||||||
def get_albums_json():
|
def get_albums_json():
|
||||||
albums = get_albums_core()
|
albums = get_albums_core()
|
||||||
albums = [jsonify.album(album, minimal=True) for album in albums]
|
albums = [etiquette.jsonify.album(album, minimal=True) for album in albums]
|
||||||
return jsonify.make_json_response(albums)
|
return etiquette_flask.jsonify.make_json_response(albums)
|
||||||
|
|
||||||
|
|
||||||
@site.route('/bookmarks')
|
@site.route('/bookmarks')
|
||||||
|
@ -390,10 +387,10 @@ def get_file(photoid):
|
||||||
photo = P.get_photo(photoid)
|
photo = P.get_photo(photoid)
|
||||||
|
|
||||||
do_download = request.args.get('download', False)
|
do_download = request.args.get('download', False)
|
||||||
do_download = helpers.truthystring(do_download)
|
do_download = etiquette.helpers.truthystring(do_download)
|
||||||
|
|
||||||
use_original_filename = request.args.get('original_filename', False)
|
use_original_filename = request.args.get('original_filename', False)
|
||||||
use_original_filename = helpers.truthystring(use_original_filename)
|
use_original_filename = etiquette.helpers.truthystring(use_original_filename)
|
||||||
|
|
||||||
if do_download:
|
if do_download:
|
||||||
if use_original_filename:
|
if use_original_filename:
|
||||||
|
@ -401,7 +398,7 @@ def get_file(photoid):
|
||||||
else:
|
else:
|
||||||
download_as = photo.id + photo.dot_extension
|
download_as = photo.id + photo.dot_extension
|
||||||
|
|
||||||
download_as = helpers.normalize_filepath(download_as)
|
download_as = etiquette.helpers.normalize_filepath(download_as)
|
||||||
download_as = urllib.parse.quote(download_as)
|
download_as = urllib.parse.quote(download_as)
|
||||||
response = flask.make_response(send_file(photo.real_filepath))
|
response = flask.make_response(send_file(photo.real_filepath))
|
||||||
response.headers['Content-Disposition'] = 'attachment; filename*=UTF-8\'\'%s' % download_as
|
response.headers['Content-Disposition'] = 'attachment; filename*=UTF-8\'\'%s' % download_as
|
||||||
|
@ -421,12 +418,12 @@ def get_photo_html(photoid):
|
||||||
@session_manager.give_token
|
@session_manager.give_token
|
||||||
def get_photo_json(photoid):
|
def get_photo_json(photoid):
|
||||||
photo = P_photo(photoid, response_type='json')
|
photo = P_photo(photoid, response_type='json')
|
||||||
photo = jsonify.photo(photo)
|
photo = etiquette.jsonify.photo(photo)
|
||||||
photo = jsonify.make_json_response(photo)
|
photo = etiquette_flask.jsonify.make_json_response(photo)
|
||||||
return photo
|
return photo
|
||||||
|
|
||||||
def get_search_core():
|
def get_search_core():
|
||||||
warning_bag = objects.WarningBag()
|
warning_bag = etiquette.objects.WarningBag()
|
||||||
|
|
||||||
has_tags = request.args.get('has_tags')
|
has_tags = request.args.get('has_tags')
|
||||||
tag_musts = request.args.get('tag_musts')
|
tag_musts = request.args.get('tag_musts')
|
||||||
|
@ -442,7 +439,7 @@ def get_search_core():
|
||||||
limit = request.args.get('limit')
|
limit = request.args.get('limit')
|
||||||
# This is being pre-processed because the site enforces a maximum value
|
# This is being pre-processed because the site enforces a maximum value
|
||||||
# which the PhotoDB api does not.
|
# which the PhotoDB api does not.
|
||||||
limit = searchhelpers.normalize_limit(limit, warning_bag=warning_bag)
|
limit = etiquette.searchhelpers.normalize_limit(limit, warning_bag=warning_bag)
|
||||||
|
|
||||||
if limit is None:
|
if limit is None:
|
||||||
limit = 50
|
limit = 50
|
||||||
|
@ -515,7 +512,7 @@ def get_search_core():
|
||||||
warnings = set()
|
warnings = set()
|
||||||
photos = []
|
photos = []
|
||||||
for item in search_results:
|
for item in search_results:
|
||||||
if isinstance(item, objects.WarningBag):
|
if isinstance(item, etiquette.objects.WarningBag):
|
||||||
warnings.update(item.warnings)
|
warnings.update(item.warnings)
|
||||||
else:
|
else:
|
||||||
photos.append(item)
|
photos.append(item)
|
||||||
|
@ -534,7 +531,7 @@ def get_search_core():
|
||||||
if len(photos) == limit:
|
if len(photos) == limit:
|
||||||
next_params = original_params.copy()
|
next_params = original_params.copy()
|
||||||
next_params['offset'] = offset + limit
|
next_params['offset'] = offset + limit
|
||||||
next_params = helpers.dict_to_params(next_params)
|
next_params = etiquette.helpers.dict_to_params(next_params)
|
||||||
next_page_url = '/search' + next_params
|
next_page_url = '/search' + next_params
|
||||||
else:
|
else:
|
||||||
next_page_url = None
|
next_page_url = None
|
||||||
|
@ -542,7 +539,7 @@ def get_search_core():
|
||||||
if offset > 0:
|
if offset > 0:
|
||||||
prev_params = original_params.copy()
|
prev_params = original_params.copy()
|
||||||
prev_params['offset'] = max(0, offset - limit)
|
prev_params['offset'] = max(0, offset - limit)
|
||||||
prev_params = helpers.dict_to_params(prev_params)
|
prev_params = etiquette.helpers.dict_to_params(prev_params)
|
||||||
prev_page_url = '/search' + prev_params
|
prev_page_url = '/search' + prev_params
|
||||||
else:
|
else:
|
||||||
prev_page_url = None
|
prev_page_url = None
|
||||||
|
@ -565,7 +562,7 @@ def get_search_core():
|
||||||
def get_search_html():
|
def get_search_html():
|
||||||
search_results = get_search_core()
|
search_results = get_search_core()
|
||||||
search_kwargs = search_results['search_kwargs']
|
search_kwargs = search_results['search_kwargs']
|
||||||
qualname_map = P.export_tags(exporter=photodb.tag_export_qualname_map)
|
qualname_map = P.export_tags(exporter=etiquette.photodb.tag_export_qualname_map)
|
||||||
session = session_manager.get(request)
|
session = session_manager.get(request)
|
||||||
response = flask.render_template(
|
response = flask.render_template(
|
||||||
'search.html',
|
'search.html',
|
||||||
|
@ -585,9 +582,9 @@ def get_search_html():
|
||||||
def get_search_json():
|
def get_search_json():
|
||||||
search_results = get_search_core()
|
search_results = get_search_core()
|
||||||
search_results['photos'] = [
|
search_results['photos'] = [
|
||||||
jsonify.photo(photo, include_albums=False) for photo in search_results['photos']
|
etiquette.jsonify.photo(photo, include_albums=False) for photo in search_results['photos']
|
||||||
]
|
]
|
||||||
return jsonify.make_json_response(search_results)
|
return etiquette_flask.jsonify.make_json_response(search_results)
|
||||||
|
|
||||||
|
|
||||||
def get_tags_core(specific_tag=None):
|
def get_tags_core(specific_tag=None):
|
||||||
|
@ -608,7 +605,7 @@ def get_tags_html(specific_tag=None):
|
||||||
tags = get_tags_core(specific_tag)
|
tags = get_tags_core(specific_tag)
|
||||||
session = session_manager.get(request)
|
session = session_manager.get(request)
|
||||||
include_synonyms = request.args.get('synonyms')
|
include_synonyms = request.args.get('synonyms')
|
||||||
include_synonyms = include_synonyms is None or helpers.truthystring(include_synonyms)
|
include_synonyms = include_synonyms is None or etiquette.helpers.truthystring(include_synonyms)
|
||||||
response = flask.render_template(
|
response = flask.render_template(
|
||||||
'tags.html',
|
'tags.html',
|
||||||
include_synonyms=include_synonyms,
|
include_synonyms=include_synonyms,
|
||||||
|
@ -625,9 +622,9 @@ def get_tags_json(specific_tag=None):
|
||||||
specific_tag = P_tag(specific_tag, response_type='json')
|
specific_tag = P_tag(specific_tag, response_type='json')
|
||||||
tags = get_tags_core(specific_tag)
|
tags = get_tags_core(specific_tag)
|
||||||
include_synonyms = request.args.get('synonyms')
|
include_synonyms = request.args.get('synonyms')
|
||||||
include_synonyms = include_synonyms is None or helpers.truthystring(include_synonyms)
|
include_synonyms = include_synonyms is None or etiquette.helpers.truthystring(include_synonyms)
|
||||||
tags = [jsonify.tag(tag, include_synonyms=include_synonyms) for tag in tags]
|
tags = [etiquette.jsonify.tag(tag, include_synonyms=include_synonyms) for tag in tags]
|
||||||
return jsonify.make_json_response(tags)
|
return etiquette_flask.jsonify.make_json_response(tags)
|
||||||
|
|
||||||
|
|
||||||
@site.route('/thumbnail/<photoid>')
|
@site.route('/thumbnail/<photoid>')
|
||||||
|
@ -656,8 +653,8 @@ def get_user_html(username):
|
||||||
@session_manager.give_token
|
@session_manager.give_token
|
||||||
def get_user_json(username):
|
def get_user_json(username):
|
||||||
user = get_user_core(username)
|
user = get_user_core(username)
|
||||||
user = jsonify.user(user)
|
user = etiquette.jsonify.user(user)
|
||||||
user = jsonify.make_json_response(user)
|
user = etiquette_flask.jsonify.make_json_response(user)
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
@ -673,15 +670,15 @@ def post_album_add_tag(albumid):
|
||||||
tag = request.form['tagname'].strip()
|
tag = request.form['tagname'].strip()
|
||||||
try:
|
try:
|
||||||
tag = P_tag(tag)
|
tag = P_tag(tag)
|
||||||
except exceptions.NoSuchTag as e:
|
except etiquette.exceptions.NoSuchTag as e:
|
||||||
response = jsonify.exception(e)
|
response = etiquette.jsonify.exception(e)
|
||||||
return jsonify.make_json_response(response, status=404)
|
return etiquette_flask.jsonify.make_json_response(response, status=404)
|
||||||
recursive = request.form.get('recursive', False)
|
recursive = request.form.get('recursive', False)
|
||||||
recursive = helpers.truthystring(recursive)
|
recursive = etiquette.helpers.truthystring(recursive)
|
||||||
album.add_tag_to_all(tag, nested_children=recursive)
|
album.add_tag_to_all(tag, nested_children=recursive)
|
||||||
response['action'] = 'add_tag'
|
response['action'] = 'add_tag'
|
||||||
response['tagname'] = tag.name
|
response['tagname'] = tag.name
|
||||||
return jsonify.make_json_response(response)
|
return etiquette_flask.jsonify.make_json_response(response)
|
||||||
|
|
||||||
|
|
||||||
@site.route('/album/<albumid>/edit', methods=['POST'])
|
@site.route('/album/<albumid>/edit', methods=['POST'])
|
||||||
|
@ -696,7 +693,7 @@ def post_album_edit(albumid):
|
||||||
description = request.form.get('description', None)
|
description = request.form.get('description', None)
|
||||||
album.edit(title=title, description=description)
|
album.edit(title=title, description=description)
|
||||||
response = {'title': album.title, 'description': album.description}
|
response = {'title': album.title, 'description': album.description}
|
||||||
return jsonify.make_json_response(response)
|
return etiquette_flask.jsonify.make_json_response(response)
|
||||||
|
|
||||||
|
|
||||||
def post_photo_add_remove_tag_core(photoid, tagname, add_or_remove):
|
def post_photo_add_remove_tag_core(photoid, tagname, add_or_remove):
|
||||||
|
@ -708,16 +705,16 @@ def post_photo_add_remove_tag_core(photoid, tagname, add_or_remove):
|
||||||
photo.add_tag(tag)
|
photo.add_tag(tag)
|
||||||
elif add_or_remove == 'remove':
|
elif add_or_remove == 'remove':
|
||||||
photo.remove_tag(tag)
|
photo.remove_tag(tag)
|
||||||
except exceptions.EtiquetteException as e:
|
except etiquette.exceptions.EtiquetteException as e:
|
||||||
response = jsonify.exception(e)
|
response = etiquette.jsonify.exception(e)
|
||||||
response = jsonify.make_json_response(response, status=400)
|
response = etiquette_flask.jsonify.make_json_response(response, status=400)
|
||||||
flask.abort(response)
|
flask.abort(response)
|
||||||
|
|
||||||
response = {'tagname': tag.name}
|
response = {'tagname': tag.name}
|
||||||
return jsonify.make_json_response(response)
|
return etiquette_flask.jsonify.make_json_response(response)
|
||||||
|
|
||||||
@site.route('/photo/<photoid>/add_tag', methods=['POST'])
|
@site.route('/photo/<photoid>/add_tag', methods=['POST'])
|
||||||
@decorators.required_fields(['tagname'], forbid_whitespace=True)
|
@etiquette_flask.decorators.required_fields(['tagname'], forbid_whitespace=True)
|
||||||
def post_photo_add_tag(photoid):
|
def post_photo_add_tag(photoid):
|
||||||
'''
|
'''
|
||||||
Add a tag to this photo.
|
Add a tag to this photo.
|
||||||
|
@ -725,7 +722,7 @@ def post_photo_add_tag(photoid):
|
||||||
return post_photo_add_remove_tag_core(photoid, request.form['tagname'], 'add')
|
return post_photo_add_remove_tag_core(photoid, request.form['tagname'], 'add')
|
||||||
|
|
||||||
@site.route('/photo/<photoid>/remove_tag', methods=['POST'])
|
@site.route('/photo/<photoid>/remove_tag', methods=['POST'])
|
||||||
@decorators.required_fields(['tagname'], forbid_whitespace=True)
|
@etiquette_flask.decorators.required_fields(['tagname'], forbid_whitespace=True)
|
||||||
def post_photo_remove_tag(photoid):
|
def post_photo_remove_tag(photoid):
|
||||||
'''
|
'''
|
||||||
Remove a tag from this photo.
|
Remove a tag from this photo.
|
||||||
|
@ -737,29 +734,30 @@ def post_photo_refresh_metadata(photoid):
|
||||||
'''
|
'''
|
||||||
Refresh the file metadata.
|
Refresh the file metadata.
|
||||||
'''
|
'''
|
||||||
|
P.caches['photo'].remove(photoid)
|
||||||
photo = P_photo(photoid, response_type='json')
|
photo = P_photo(photoid, response_type='json')
|
||||||
try:
|
try:
|
||||||
photo.reload_metadata()
|
photo.reload_metadata()
|
||||||
except exceptions.EtiquetteException as e:
|
except etiquette.exceptions.EtiquetteException as e:
|
||||||
response = jsonify.exception(e)
|
response = etiquette.jsonify.exception(e)
|
||||||
response = jsonify.make_json_response(response, status=400)
|
response = etiquette_flask.jsonify.make_json_response(response, status=400)
|
||||||
flask.abort(response)
|
flask.abort(response)
|
||||||
return jsonify.make_json_response({})
|
return etiquette_flask.jsonify.make_json_response({})
|
||||||
|
|
||||||
|
|
||||||
def post_tag_create_delete_core(tagname, function):
|
def post_tag_create_delete_core(tagname, function):
|
||||||
try:
|
try:
|
||||||
response = function(tagname)
|
response = function(tagname)
|
||||||
status = 200
|
status = 200
|
||||||
except exceptions.EtiquetteException as e:
|
except etiquette.exceptions.EtiquetteException as e:
|
||||||
response = jsonify.exception(e)
|
response = etiquette.jsonify.exception(e)
|
||||||
status = 400
|
status = 400
|
||||||
#print(response)
|
#print(response)
|
||||||
|
|
||||||
return jsonify.make_json_response(response, status=status)
|
return etiquette_flask.jsonify.make_json_response(response, status=status)
|
||||||
|
|
||||||
@site.route('/tags/create_tag', methods=['POST'])
|
@site.route('/tags/create_tag', methods=['POST'])
|
||||||
@decorators.required_fields(['tagname'], forbid_whitespace=True)
|
@etiquette_flask.decorators.required_fields(['tagname'], forbid_whitespace=True)
|
||||||
def post_tag_create():
|
def post_tag_create():
|
||||||
'''
|
'''
|
||||||
Create a tag.
|
Create a tag.
|
||||||
|
@ -767,7 +765,7 @@ def post_tag_create():
|
||||||
return post_tag_create_delete_core(request.form['tagname'], create_tag)
|
return post_tag_create_delete_core(request.form['tagname'], create_tag)
|
||||||
|
|
||||||
@site.route('/tags/delete_tag', methods=['POST'])
|
@site.route('/tags/delete_tag', methods=['POST'])
|
||||||
@decorators.required_fields(['tagname'], forbid_whitespace=True)
|
@etiquette_flask.decorators.required_fields(['tagname'], forbid_whitespace=True)
|
||||||
def post_tag_delete():
|
def post_tag_delete():
|
||||||
'''
|
'''
|
||||||
Delete a tag.
|
Delete a tag.
|
||||||
|
@ -775,7 +773,7 @@ def post_tag_delete():
|
||||||
return post_tag_create_delete_core(request.form['tagname'], delete_tag)
|
return post_tag_create_delete_core(request.form['tagname'], delete_tag)
|
||||||
|
|
||||||
@site.route('/tags/delete_synonym', methods=['POST'])
|
@site.route('/tags/delete_synonym', methods=['POST'])
|
||||||
@decorators.required_fields(['tagname'], forbid_whitespace=True)
|
@etiquette_flask.decorators.required_fields(['tagname'], forbid_whitespace=True)
|
||||||
def post_tag_delete_synonym():
|
def post_tag_delete_synonym():
|
||||||
'''
|
'''
|
||||||
Delete a synonym.
|
Delete a synonym.
|
||||||
|
|
Loading…
Reference in a new issue