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()) | ||||||
|  | @ -14,6 +14,7 @@ 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