First attempt at online permissions.
This commit is contained in:
parent
e78a667ee3
commit
ce30077013
10 changed files with 181 additions and 13 deletions
|
@ -4,29 +4,46 @@ Use etiquette_flask_dev.py or etiquette_flask_prod.py.
|
|||
'''
|
||||
import flask; from flask import request
|
||||
import functools
|
||||
import json
|
||||
import mimetypes
|
||||
import traceback
|
||||
|
||||
from voussoirkit import bytestring
|
||||
from voussoirkit import configlayers
|
||||
from voussoirkit import flasktools
|
||||
from voussoirkit import pathclass
|
||||
from voussoirkit import vlogging
|
||||
|
||||
import etiquette
|
||||
|
||||
from . import client_caching
|
||||
from . import jinja_filters
|
||||
from . import permissions
|
||||
from . import sessions
|
||||
|
||||
log = vlogging.getLogger(__name__)
|
||||
|
||||
# Constants ########################################################################################
|
||||
|
||||
DEFAULT_SERVER_CONFIG = {
|
||||
'anonymous_read': True,
|
||||
'anonymous_write': True,
|
||||
}
|
||||
|
||||
BROWSER_CACHE_DURATION = 180
|
||||
|
||||
# Flask init #######################################################################################
|
||||
|
||||
# __file__ = .../etiquette_flask/backend/common.py
|
||||
# root_dir = .../etiquette_flask
|
||||
root_dir = pathclass.Path(__file__).parent.parent
|
||||
|
||||
P = None
|
||||
|
||||
TEMPLATE_DIR = root_dir.with_child('templates')
|
||||
STATIC_DIR = root_dir.with_child('static')
|
||||
FAVICON_PATH = STATIC_DIR.with_child('favicon.png')
|
||||
BROWSER_CACHE_DURATION = 180
|
||||
SERVER_CONFIG_FILENAME = 'etiquette_flask_config.json'
|
||||
|
||||
site = flask.Flask(
|
||||
__name__,
|
||||
|
@ -37,6 +54,7 @@ site.config.update(
|
|||
SEND_FILE_MAX_AGE_DEFAULT=BROWSER_CACHE_DURATION,
|
||||
TEMPLATES_AUTO_RELOAD=True,
|
||||
)
|
||||
site.server_config = None
|
||||
site.jinja_env.add_extension('jinja2.ext.do')
|
||||
site.jinja_env.trim_blocks = True
|
||||
site.jinja_env.lstrip_blocks = True
|
||||
|
@ -49,6 +67,7 @@ file_etag_manager = client_caching.FileEtagManager(
|
|||
max_filesize=5 * bytestring.MEBIBYTE,
|
||||
max_age=BROWSER_CACHE_DURATION,
|
||||
)
|
||||
permission_manager = permissions.PermissionManager(site)
|
||||
|
||||
# Response wrappers ################################################################################
|
||||
|
||||
|
@ -80,10 +99,18 @@ def before_request():
|
|||
if site.localhost_only and not request.is_localhost:
|
||||
return flask.abort(403)
|
||||
|
||||
# Since we don't define this route, I can't just add this where it belongs.
|
||||
# Sorry.
|
||||
if request.url_rule.rule == '/static/<path:filename>':
|
||||
permission_manager.global_public()
|
||||
|
||||
session_manager._before_request(request)
|
||||
|
||||
@site.after_request
|
||||
def after_request(response):
|
||||
if response.status_code < 400 and not hasattr(request, 'checked_permissions'):
|
||||
log.error('You forgot to set checked_permissions for ' + request.path)
|
||||
return flask.abort(500)
|
||||
response = flasktools.gzip_response(request, response)
|
||||
response = session_manager._after_request(response)
|
||||
return response
|
||||
|
@ -277,3 +304,22 @@ def send_file(filepath, override_mimetype=None):
|
|||
def init_photodb(*args, **kwargs):
|
||||
global P
|
||||
P = etiquette.photodb.PhotoDB.closest_photodb(*args, **kwargs)
|
||||
load_config()
|
||||
|
||||
def load_config() -> None:
|
||||
log.debug('Loading server config file.')
|
||||
config_file = P.data_directory.with_child(SERVER_CONFIG_FILENAME)
|
||||
(config, needs_rewrite) = configlayers.load_file(
|
||||
filepath=config_file,
|
||||
default_config=DEFAULT_SERVER_CONFIG,
|
||||
)
|
||||
site.server_config = config
|
||||
|
||||
if needs_rewrite:
|
||||
save_config()
|
||||
|
||||
def save_config() -> None:
|
||||
log.debug('Saving server config file.')
|
||||
config_file = P.data_directory.with_child(SERVER_CONFIG_FILENAME)
|
||||
with config_file.open('w', encoding='utf-8') as handle:
|
||||
handle.write(json.dumps(site.server_config, indent=4, sort_keys=True))
|
||||
|
|
|
@ -15,8 +15,7 @@ session_manager = common.session_manager
|
|||
|
||||
@site.route('/admin')
|
||||
def get_admin():
|
||||
if not request.is_localhost:
|
||||
flask.abort(403)
|
||||
common.permission_manager.admin()
|
||||
|
||||
counts = dotdict.DotDict({
|
||||
'albums': common.P.get_album_count(),
|
||||
|
@ -36,8 +35,7 @@ def get_admin():
|
|||
|
||||
@site.route('/admin/dbdownload')
|
||||
def get_dbdump():
|
||||
if not request.is_localhost:
|
||||
flask.abort(403)
|
||||
common.permission_manager.admin()
|
||||
|
||||
with common.P.transaction:
|
||||
binary = common.P.database_filepath.read('rb')
|
||||
|
@ -52,24 +50,23 @@ def get_dbdump():
|
|||
|
||||
@site.route('/admin/clear_sessions', methods=['POST'])
|
||||
def post_clear_sessions():
|
||||
if not request.is_localhost:
|
||||
return flasktools.json_response({}, status=403)
|
||||
common.permission_manager.admin()
|
||||
|
||||
session_manager.clear()
|
||||
return flasktools.json_response({})
|
||||
|
||||
@site.route('/admin/reload_config', methods=['POST'])
|
||||
def post_reload_config():
|
||||
if not request.is_localhost:
|
||||
return flasktools.json_response({}, status=403)
|
||||
common.permission_manager.admin()
|
||||
|
||||
common.P.load_config()
|
||||
common.load_config()
|
||||
|
||||
return flasktools.json_response({})
|
||||
|
||||
@site.route('/admin/uncache', methods=['POST'])
|
||||
def post_uncache():
|
||||
if not request.is_localhost:
|
||||
return flasktools.json_response({}, status=403)
|
||||
common.permission_manager.admin()
|
||||
|
||||
with common.P.transaction:
|
||||
for cache in common.P.caches.values():
|
||||
|
|
|
@ -17,6 +17,7 @@ session_manager = common.session_manager
|
|||
|
||||
@site.route('/album/<album_id>')
|
||||
def get_album_html(album_id):
|
||||
common.permission_manager.basic()
|
||||
album = common.P_album(album_id, response_type='html')
|
||||
response = common.render_template(
|
||||
request,
|
||||
|
@ -28,12 +29,14 @@ def get_album_html(album_id):
|
|||
|
||||
@site.route('/album/<album_id>.json')
|
||||
def get_album_json(album_id):
|
||||
common.permission_manager.basic()
|
||||
album = common.P_album(album_id, response_type='json')
|
||||
album = album.jsonify()
|
||||
return flasktools.json_response(album)
|
||||
|
||||
@site.route('/album/<album_id>.zip')
|
||||
def get_album_zip(album_id):
|
||||
common.permission_manager.basic()
|
||||
album = common.P_album(album_id, response_type='html')
|
||||
|
||||
recursive = request.args.get('recursive', True)
|
||||
|
@ -58,6 +61,7 @@ def get_album_zip(album_id):
|
|||
@site.route('/album/<album_id>/add_child', methods=['POST'])
|
||||
@flasktools.required_fields(['child_id'], forbid_whitespace=True)
|
||||
def post_album_add_child(album_id):
|
||||
common.permission_manager.basic()
|
||||
child_ids = stringtools.comma_space_split(request.form['child_id'])
|
||||
with common.P.transaction:
|
||||
album = common.P_album(album_id, response_type='json')
|
||||
|
@ -71,6 +75,7 @@ def post_album_add_child(album_id):
|
|||
@site.route('/album/<album_id>/remove_child', methods=['POST'])
|
||||
@flasktools.required_fields(['child_id'], forbid_whitespace=True)
|
||||
def post_album_remove_child(album_id):
|
||||
common.permission_manager.basic()
|
||||
child_ids = stringtools.comma_space_split(request.form['child_id'])
|
||||
with common.P.transaction:
|
||||
album = common.P_album(album_id, response_type='json')
|
||||
|
@ -81,6 +86,7 @@ def post_album_remove_child(album_id):
|
|||
|
||||
@site.route('/album/<album_id>/remove_thumbnail_photo', methods=['POST'])
|
||||
def post_album_remove_thumbnail_photo(album_id):
|
||||
common.permission_manager.basic()
|
||||
with common.P.transaction:
|
||||
album = common.P_album(album_id, response_type='json')
|
||||
album.set_thumbnail_photo(None)
|
||||
|
@ -88,6 +94,7 @@ def post_album_remove_thumbnail_photo(album_id):
|
|||
|
||||
@site.route('/album/<album_id>/refresh_directories', methods=['POST'])
|
||||
def post_album_refresh_directories(album_id):
|
||||
common.permission_manager.basic()
|
||||
with common.P.transaction:
|
||||
album = common.P_album(album_id, response_type='json')
|
||||
for directory in album.get_associated_directories():
|
||||
|
@ -100,6 +107,7 @@ def post_album_refresh_directories(album_id):
|
|||
@site.route('/album/<album_id>/set_thumbnail_photo', methods=['POST'])
|
||||
@flasktools.required_fields(['photo_id'], forbid_whitespace=True)
|
||||
def post_album_set_thumbnail_photo(album_id):
|
||||
common.permission_manager.basic()
|
||||
with common.P.transaction:
|
||||
album = common.P_album(album_id, response_type='json')
|
||||
photo = common.P_photo(request.form['photo_id'], response_type='json')
|
||||
|
@ -114,7 +122,7 @@ def post_album_add_photo(album_id):
|
|||
'''
|
||||
Add a photo or photos to this album.
|
||||
'''
|
||||
|
||||
common.permission_manager.basic()
|
||||
photo_ids = stringtools.comma_space_split(request.form['photo_id'])
|
||||
with common.P.transaction:
|
||||
album = common.P_album(album_id, response_type='json')
|
||||
|
@ -129,6 +137,7 @@ def post_album_remove_photo(album_id):
|
|||
'''
|
||||
Remove a photo or photos from this album.
|
||||
'''
|
||||
common.permission_manager.basic()
|
||||
photo_ids = stringtools.comma_space_split(request.form['photo_id'])
|
||||
with common.P.transaction:
|
||||
album = common.P_album(album_id, response_type='json')
|
||||
|
@ -144,6 +153,7 @@ def post_album_add_tag(album_id):
|
|||
'''
|
||||
Apply a tag to every photo in the album.
|
||||
'''
|
||||
common.permission_manager.basic()
|
||||
response = {}
|
||||
with common.P.transaction:
|
||||
album = common.P_album(album_id, response_type='json')
|
||||
|
@ -168,6 +178,7 @@ def post_album_edit(album_id):
|
|||
'''
|
||||
Edit the title / description.
|
||||
'''
|
||||
common.permission_manager.basic()
|
||||
title = request.form.get('title', None)
|
||||
description = request.form.get('description', None)
|
||||
|
||||
|
@ -180,6 +191,7 @@ def post_album_edit(album_id):
|
|||
|
||||
@site.route('/album/<album_id>/show_in_folder', methods=['POST'])
|
||||
def post_album_show_in_folder(album_id):
|
||||
common.permission_manager.basic()
|
||||
if not request.is_localhost:
|
||||
flask.abort(403)
|
||||
|
||||
|
@ -199,6 +211,7 @@ def post_album_show_in_folder(album_id):
|
|||
# Album listings ###################################################################################
|
||||
|
||||
@site.route('/all_albums.json')
|
||||
@common.permission_manager.basic_decorator
|
||||
@flasktools.cached_endpoint(max_age=15)
|
||||
def get_all_album_names():
|
||||
all_albums = {album.id: album.display_name for album in common.P.get_albums()}
|
||||
|
@ -207,6 +220,7 @@ def get_all_album_names():
|
|||
|
||||
@site.route('/albums')
|
||||
def get_albums_html():
|
||||
common.permission_manager.basic()
|
||||
albums = list(common.P.get_root_albums())
|
||||
albums.sort(key=lambda x: x.display_name.lower())
|
||||
response = common.render_template(
|
||||
|
@ -219,6 +233,7 @@ def get_albums_html():
|
|||
|
||||
@site.route('/albums.json')
|
||||
def get_albums_json():
|
||||
common.permission_manager.basic()
|
||||
albums = list(common.P.get_albums())
|
||||
albums.sort(key=lambda x: x.display_name.lower())
|
||||
albums = [album.jsonify(include_photos=False) for album in albums]
|
||||
|
@ -228,6 +243,7 @@ def get_albums_json():
|
|||
|
||||
@site.route('/albums/create_album', methods=['POST'])
|
||||
def post_albums_create():
|
||||
common.permission_manager.basic()
|
||||
title = request.form.get('title', None)
|
||||
description = request.form.get('description', None)
|
||||
parent_id = request.form.get('parent_id', None)
|
||||
|
@ -246,6 +262,7 @@ def post_albums_create():
|
|||
|
||||
@site.route('/album/<album_id>/delete', methods=['POST'])
|
||||
def post_album_delete(album_id):
|
||||
common.permission_manager.basic()
|
||||
with common.P.transaction:
|
||||
album = common.P_album(album_id, response_type='json')
|
||||
album.delete()
|
||||
|
|
|
@ -10,10 +10,12 @@ session_manager = common.session_manager
|
|||
|
||||
@site.route('/')
|
||||
def root():
|
||||
common.permission_manager.global_public()
|
||||
motd = random.choice(common.P.config['motd_strings'])
|
||||
return common.render_template(request, 'root.html', motd=motd)
|
||||
|
||||
@site.route('/favicon.ico')
|
||||
@site.route('/favicon.png')
|
||||
def favicon():
|
||||
common.permission_manager.global_public()
|
||||
return flask.send_file(common.FAVICON_PATH.absolute_path)
|
||||
|
|
|
@ -13,12 +13,14 @@ session_manager = common.session_manager
|
|||
|
||||
@site.route('/bookmark/<bookmark_id>.json')
|
||||
def get_bookmark_json(bookmark_id):
|
||||
common.permission_manager.basic()
|
||||
bookmark = common.P_bookmark(bookmark_id, response_type='json')
|
||||
response = bookmark.jsonify()
|
||||
return flasktools.json_response(response)
|
||||
|
||||
@site.route('/bookmark/<bookmark_id>/edit', methods=['POST'])
|
||||
def post_bookmark_edit(bookmark_id):
|
||||
common.permission_manager.basic()
|
||||
with common.P.transaction:
|
||||
bookmark = common.P_bookmark(bookmark_id, response_type='json')
|
||||
# Emptystring is okay for titles, but not for URL.
|
||||
|
@ -34,6 +36,7 @@ def post_bookmark_edit(bookmark_id):
|
|||
|
||||
@site.route('/bookmarks.atom')
|
||||
def get_bookmarks_atom():
|
||||
common.permission_manager.basic()
|
||||
bookmarks = common.P.get_bookmarks()
|
||||
response = etiquette.helpers.make_atom_feed(
|
||||
bookmarks,
|
||||
|
@ -45,11 +48,13 @@ def get_bookmarks_atom():
|
|||
|
||||
@site.route('/bookmarks')
|
||||
def get_bookmarks_html():
|
||||
common.permission_manager.basic()
|
||||
bookmarks = list(common.P.get_bookmarks())
|
||||
return common.render_template(request, 'bookmarks.html', bookmarks=bookmarks)
|
||||
|
||||
@site.route('/bookmarks.json')
|
||||
def get_bookmarks_json():
|
||||
common.permission_manager.basic()
|
||||
bookmarks = [b.jsonify() for b in common.P.get_bookmarks()]
|
||||
return flasktools.json_response(bookmarks)
|
||||
|
||||
|
@ -58,6 +63,7 @@ def get_bookmarks_json():
|
|||
@site.route('/bookmarks/create_bookmark', methods=['POST'])
|
||||
@flasktools.required_fields(['url'], forbid_whitespace=True)
|
||||
def post_bookmark_create():
|
||||
common.permission_manager.basic()
|
||||
url = request.form['url']
|
||||
title = request.form.get('title', None)
|
||||
user = session_manager.get(request).user
|
||||
|
@ -69,6 +75,7 @@ def post_bookmark_create():
|
|||
|
||||
@site.route('/bookmark/<bookmark_id>/delete', methods=['POST'])
|
||||
def post_bookmark_delete(bookmark_id):
|
||||
common.permission_manager.basic()
|
||||
with common.P.transaction:
|
||||
bookmark = common.P_bookmark(bookmark_id, response_type='json')
|
||||
bookmark.delete()
|
||||
|
|
|
@ -25,11 +25,13 @@ photo_download_zip_tokens = cacheclass.Cache(maxlen=100)
|
|||
|
||||
@site.route('/photo/<photo_id>')
|
||||
def get_photo_html(photo_id):
|
||||
common.permission_manager.basic()
|
||||
photo = common.P_photo(photo_id, response_type='html')
|
||||
return common.render_template(request, 'photo.html', photo=photo)
|
||||
|
||||
@site.route('/photo/<photo_id>.json')
|
||||
def get_photo_json(photo_id):
|
||||
common.permission_manager.basic()
|
||||
photo = common.P_photo(photo_id, response_type='json')
|
||||
photo = photo.jsonify()
|
||||
photo = flasktools.json_response(photo)
|
||||
|
@ -38,6 +40,7 @@ def get_photo_json(photo_id):
|
|||
@site.route('/photo/<photo_id>/download')
|
||||
@site.route('/photo/<photo_id>/download/<basename>')
|
||||
def get_file(photo_id, basename=None):
|
||||
common.permission_manager.basic()
|
||||
photo_id = photo_id.split('.')[0]
|
||||
photo = common.P.get_photo(photo_id)
|
||||
|
||||
|
@ -63,6 +66,7 @@ def get_file(photo_id, basename=None):
|
|||
|
||||
@site.route('/photo/<photo_id>/thumbnail')
|
||||
@site.route('/photo/<photo_id>/thumbnail/<basename>')
|
||||
@common.permission_manager.basic_decorator
|
||||
@flasktools.cached_endpoint(max_age=common.BROWSER_CACHE_DURATION)
|
||||
def get_thumbnail(photo_id, basename=None):
|
||||
photo_id = photo_id.split('.')[0]
|
||||
|
@ -90,6 +94,7 @@ def get_thumbnail(photo_id, basename=None):
|
|||
|
||||
@site.route('/photo/<photo_id>/delete', methods=['POST'])
|
||||
def post_photo_delete(photo_id):
|
||||
common.permission_manager.basic()
|
||||
delete_file = request.form.get('delete_file', False)
|
||||
delete_file = stringtools.truthystring(delete_file)
|
||||
with common.P.transaction:
|
||||
|
@ -122,6 +127,7 @@ def post_photo_add_tag(photo_id):
|
|||
'''
|
||||
Add a tag to this photo.
|
||||
'''
|
||||
common.permission_manager.basic()
|
||||
response = post_photo_add_remove_tag_core(
|
||||
photo_ids=photo_id,
|
||||
tagname=request.form['tagname'],
|
||||
|
@ -135,6 +141,7 @@ def post_photo_copy_tags(photo_id):
|
|||
'''
|
||||
Copy the tags from another photo.
|
||||
'''
|
||||
common.permission_manager.basic()
|
||||
with common.P.transaction:
|
||||
photo = common.P_photo(photo_id, response_type='json')
|
||||
other = common.P_photo(request.form['other_photo'], response_type='json')
|
||||
|
@ -147,6 +154,7 @@ def post_photo_remove_tag(photo_id):
|
|||
'''
|
||||
Remove a tag from this photo.
|
||||
'''
|
||||
common.permission_manager.basic()
|
||||
response = post_photo_add_remove_tag_core(
|
||||
photo_ids=photo_id,
|
||||
tagname=request.form['tagname'],
|
||||
|
@ -157,6 +165,7 @@ def post_photo_remove_tag(photo_id):
|
|||
@site.route('/batch/photos/add_tag', methods=['POST'])
|
||||
@flasktools.required_fields(['photo_ids', 'tagname'], forbid_whitespace=True)
|
||||
def post_batch_photos_add_tag():
|
||||
common.permission_manager.basic()
|
||||
response = post_photo_add_remove_tag_core(
|
||||
photo_ids=request.form['photo_ids'],
|
||||
tagname=request.form['tagname'],
|
||||
|
@ -167,6 +176,7 @@ def post_batch_photos_add_tag():
|
|||
@site.route('/batch/photos/remove_tag', methods=['POST'])
|
||||
@flasktools.required_fields(['photo_ids', 'tagname'], forbid_whitespace=True)
|
||||
def post_batch_photos_remove_tag():
|
||||
common.permission_manager.basic()
|
||||
response = post_photo_add_remove_tag_core(
|
||||
photo_ids=request.form['photo_ids'],
|
||||
tagname=request.form['tagname'],
|
||||
|
@ -178,6 +188,7 @@ def post_batch_photos_remove_tag():
|
|||
|
||||
@site.route('/photo/<photo_id>/generate_thumbnail', methods=['POST'])
|
||||
def post_photo_generate_thumbnail(photo_id):
|
||||
common.permission_manager.basic()
|
||||
special = request.form.to_dict()
|
||||
|
||||
with common.P.transaction:
|
||||
|
@ -212,17 +223,20 @@ def post_photo_refresh_metadata_core(photo_ids):
|
|||
|
||||
@site.route('/photo/<photo_id>/refresh_metadata', methods=['POST'])
|
||||
def post_photo_refresh_metadata(photo_id):
|
||||
common.permission_manager.basic()
|
||||
response = post_photo_refresh_metadata_core(photo_ids=photo_id)
|
||||
return response
|
||||
|
||||
@site.route('/batch/photos/refresh_metadata', methods=['POST'])
|
||||
@flasktools.required_fields(['photo_ids'], forbid_whitespace=True)
|
||||
def post_batch_photos_refresh_metadata():
|
||||
common.permission_manager.basic()
|
||||
response = post_photo_refresh_metadata_core(photo_ids=request.form['photo_ids'])
|
||||
return response
|
||||
|
||||
@site.route('/photo/<photo_id>/set_searchhidden', methods=['POST'])
|
||||
def post_photo_set_searchhidden(photo_id):
|
||||
common.permission_manager.basic()
|
||||
with common.P.transaction:
|
||||
photo = common.P_photo(photo_id, response_type='json')
|
||||
photo.set_searchhidden(True)
|
||||
|
@ -230,6 +244,7 @@ def post_photo_set_searchhidden(photo_id):
|
|||
|
||||
@site.route('/photo/<photo_id>/unset_searchhidden', methods=['POST'])
|
||||
def post_photo_unset_searchhidden(photo_id):
|
||||
common.permission_manager.basic()
|
||||
with common.P.transaction:
|
||||
photo = common.P_photo(photo_id, response_type='json')
|
||||
photo.set_searchhidden(False)
|
||||
|
@ -249,6 +264,7 @@ def post_batch_photos_searchhidden_core(photo_ids, searchhidden):
|
|||
|
||||
@site.route('/photo/<photo_id>/show_in_folder', methods=['POST'])
|
||||
def post_photo_show_in_folder(photo_id):
|
||||
common.permission_manager.basic()
|
||||
if not request.is_localhost:
|
||||
flask.abort(403)
|
||||
|
||||
|
@ -267,6 +283,7 @@ def post_photo_show_in_folder(photo_id):
|
|||
@site.route('/batch/photos/set_searchhidden', methods=['POST'])
|
||||
@flasktools.required_fields(['photo_ids'], forbid_whitespace=True)
|
||||
def post_batch_photos_set_searchhidden():
|
||||
common.permission_manager.basic()
|
||||
photo_ids = request.form['photo_ids']
|
||||
response = post_batch_photos_searchhidden_core(photo_ids=photo_ids, searchhidden=True)
|
||||
return response
|
||||
|
@ -274,6 +291,7 @@ def post_batch_photos_set_searchhidden():
|
|||
@site.route('/batch/photos/unset_searchhidden', methods=['POST'])
|
||||
@flasktools.required_fields(['photo_ids'], forbid_whitespace=True)
|
||||
def post_batch_photos_unset_searchhidden():
|
||||
common.permission_manager.basic()
|
||||
photo_ids = request.form['photo_ids']
|
||||
response = post_batch_photos_searchhidden_core(photo_ids=photo_ids, searchhidden=False)
|
||||
return response
|
||||
|
@ -282,6 +300,7 @@ def post_batch_photos_unset_searchhidden():
|
|||
|
||||
@site.route('/clipboard')
|
||||
def get_clipboard_page():
|
||||
common.permission_manager.basic()
|
||||
return common.render_template(request, 'clipboard.html')
|
||||
|
||||
@site.route('/batch/photos', methods=['POST'])
|
||||
|
@ -290,6 +309,7 @@ def post_batch_photos():
|
|||
'''
|
||||
Return a list of photo.jsonify() for each requested photo id.
|
||||
'''
|
||||
common.permission_manager.basic()
|
||||
photo_ids = request.form['photo_ids']
|
||||
|
||||
photo_ids = stringtools.comma_space_split(photo_ids)
|
||||
|
@ -302,6 +322,7 @@ def post_batch_photos():
|
|||
@site.route('/batch/photos/photo_card', methods=['POST'])
|
||||
@flasktools.required_fields(['photo_ids'], forbid_whitespace=True)
|
||||
def post_batch_photos_photo_cards():
|
||||
common.permission_manager.basic()
|
||||
photo_ids = request.form['photo_ids']
|
||||
|
||||
photo_ids = stringtools.comma_space_split(photo_ids)
|
||||
|
@ -333,6 +354,7 @@ def get_batch_photos_download_zip(zip_token):
|
|||
After the user has generated their zip token, they can retrieve
|
||||
that zip file.
|
||||
'''
|
||||
common.permission_manager.basic()
|
||||
zip_token = zip_token.split('.')[0]
|
||||
try:
|
||||
photo_ids = photo_download_zip_tokens[zip_token]
|
||||
|
@ -362,6 +384,7 @@ def post_batch_photos_download_zip():
|
|||
so the way this works is we generate a token representing the photoset
|
||||
that they want, and then they can retrieve the zip itself via GET.
|
||||
'''
|
||||
common.permission_manager.basic()
|
||||
photo_ids = request.form['photo_ids']
|
||||
photo_ids = stringtools.comma_space_split(photo_ids)
|
||||
|
||||
|
@ -436,6 +459,7 @@ def get_search_core():
|
|||
|
||||
@site.route('/search_embed')
|
||||
def get_search_embed():
|
||||
common.permission_manager.basic()
|
||||
search = get_search_core()
|
||||
response = common.render_template(
|
||||
request,
|
||||
|
@ -447,6 +471,8 @@ def get_search_embed():
|
|||
|
||||
@site.route('/search')
|
||||
def get_search_html():
|
||||
common.permission_manager.basic()
|
||||
|
||||
search = get_search_core()
|
||||
search.kwargs.view = request.args.get('view', 'grid')
|
||||
|
||||
|
@ -496,6 +522,7 @@ def get_search_html():
|
|||
|
||||
@site.route('/search.atom')
|
||||
def get_search_atom():
|
||||
common.permission_manager.basic()
|
||||
search = get_search_core()
|
||||
soup = etiquette.helpers.make_atom_feed(
|
||||
search.results,
|
||||
|
@ -508,6 +535,7 @@ def get_search_atom():
|
|||
|
||||
@site.route('/search.json')
|
||||
def get_search_json():
|
||||
common.permission_manager.basic()
|
||||
search = get_search_core()
|
||||
response = search.jsonify()
|
||||
return flasktools.json_response(response)
|
||||
|
@ -516,5 +544,6 @@ def get_search_json():
|
|||
|
||||
@site.route('/swipe')
|
||||
def get_swipe():
|
||||
common.permission_manager.basic()
|
||||
response = common.render_template(request, 'swipe.html')
|
||||
return response
|
||||
|
|
|
@ -15,11 +15,13 @@ session_manager = common.session_manager
|
|||
@site.route('/tags/<specific_tag>')
|
||||
@site.route('/tags/<specific_tag>.json')
|
||||
def get_tags_specific_redirect(specific_tag):
|
||||
common.permission_manager.basic()
|
||||
return flask.redirect(request.url.replace('/tags/', '/tag/'))
|
||||
|
||||
@site.route('/tagid/<tag_id>')
|
||||
@site.route('/tagid/<tag_id>.json')
|
||||
def get_tag_id_redirect(tag_id):
|
||||
common.permission_manager.basic()
|
||||
if request.path.endswith('.json'):
|
||||
tag = common.P_tag_id(tag_id, response_type='json')
|
||||
else:
|
||||
|
@ -31,6 +33,7 @@ def get_tag_id_redirect(tag_id):
|
|||
|
||||
@site.route('/tag/<specific_tag_name>.json')
|
||||
def get_tag_json(specific_tag_name):
|
||||
common.permission_manager.basic()
|
||||
specific_tag = common.P_tag(specific_tag_name, response_type='json')
|
||||
if specific_tag.name != specific_tag_name:
|
||||
new_url = f'/tag/{specific_tag.name}.json' + request.query_string.decode('utf-8')
|
||||
|
@ -44,6 +47,7 @@ def get_tag_json(specific_tag_name):
|
|||
|
||||
@site.route('/tag/<tagname>/edit', methods=['POST'])
|
||||
def post_tag_edit(tagname):
|
||||
common.permission_manager.basic()
|
||||
with common.P.transaction:
|
||||
tag = common.P_tag(tagname, response_type='json')
|
||||
name = request.form.get('name', '').strip()
|
||||
|
@ -59,6 +63,7 @@ def post_tag_edit(tagname):
|
|||
@site.route('/tag/<tagname>/add_child', methods=['POST'])
|
||||
@flasktools.required_fields(['child_name'], forbid_whitespace=True)
|
||||
def post_tag_add_child(tagname):
|
||||
common.permission_manager.basic()
|
||||
with common.P.transaction:
|
||||
parent = common.P_tag(tagname, response_type='json')
|
||||
child = common.P_tag(request.form['child_name'], response_type='json')
|
||||
|
@ -69,6 +74,7 @@ def post_tag_add_child(tagname):
|
|||
@site.route('/tag/<tagname>/add_synonym', methods=['POST'])
|
||||
@flasktools.required_fields(['syn_name'], forbid_whitespace=True)
|
||||
def post_tag_add_synonym(tagname):
|
||||
common.permission_manager.basic()
|
||||
syn_name = request.form['syn_name']
|
||||
|
||||
with common.P.transaction:
|
||||
|
@ -81,6 +87,7 @@ def post_tag_add_synonym(tagname):
|
|||
@site.route('/tag/<tagname>/remove_child', methods=['POST'])
|
||||
@flasktools.required_fields(['child_name'], forbid_whitespace=True)
|
||||
def post_tag_remove_child(tagname):
|
||||
common.permission_manager.basic()
|
||||
with common.P.transaction:
|
||||
parent = common.P_tag(tagname, response_type='json')
|
||||
child = common.P_tag(request.form['child_name'], response_type='json')
|
||||
|
@ -91,6 +98,7 @@ def post_tag_remove_child(tagname):
|
|||
@site.route('/tag/<tagname>/remove_synonym', methods=['POST'])
|
||||
@flasktools.required_fields(['syn_name'], forbid_whitespace=True)
|
||||
def post_tag_remove_synonym(tagname):
|
||||
common.permission_manager.basic()
|
||||
syn_name = request.form['syn_name']
|
||||
|
||||
with common.P.transaction:
|
||||
|
@ -103,6 +111,7 @@ def post_tag_remove_synonym(tagname):
|
|||
# Tag listings #####################################################################################
|
||||
|
||||
@site.route('/all_tags.json')
|
||||
@common.permission_manager.basic_decorator
|
||||
@flasktools.cached_endpoint(max_age=15)
|
||||
def get_all_tag_names():
|
||||
all_tags = list(common.P.get_all_tag_names())
|
||||
|
@ -113,6 +122,7 @@ def get_all_tag_names():
|
|||
@site.route('/tag/<specific_tag_name>')
|
||||
@site.route('/tags')
|
||||
def get_tags_html(specific_tag_name=None):
|
||||
common.permission_manager.basic()
|
||||
if specific_tag_name is None:
|
||||
specific_tag = None
|
||||
else:
|
||||
|
@ -151,6 +161,7 @@ def get_tags_html(specific_tag_name=None):
|
|||
|
||||
@site.route('/tags.json')
|
||||
def get_tags_json():
|
||||
common.permission_manager.basic()
|
||||
include_synonyms = request.args.get('synonyms')
|
||||
include_synonyms = include_synonyms is None or stringtools.truthystring(include_synonyms)
|
||||
|
||||
|
@ -164,6 +175,7 @@ def get_tags_json():
|
|||
@site.route('/tags/create_tag', methods=['POST'])
|
||||
@flasktools.required_fields(['name'], forbid_whitespace=True)
|
||||
def post_tag_create():
|
||||
common.permission_manager.basic()
|
||||
name = request.form['name']
|
||||
description = request.form.get('description', None)
|
||||
|
||||
|
@ -175,6 +187,7 @@ def post_tag_create():
|
|||
@site.route('/tags/easybake', methods=['POST'])
|
||||
@flasktools.required_fields(['easybake_string'], forbid_whitespace=True)
|
||||
def post_tag_easybake():
|
||||
common.permission_manager.basic()
|
||||
easybake_string = request.form['easybake_string']
|
||||
|
||||
with common.P.transaction:
|
||||
|
@ -184,6 +197,7 @@ def post_tag_easybake():
|
|||
|
||||
@site.route('/tag/<tagname>/delete', methods=['POST'])
|
||||
def post_tag_delete(tagname):
|
||||
common.permission_manager.basic()
|
||||
with common.P.transaction:
|
||||
tag = common.P_tag(tagname, response_type='json')
|
||||
tag.delete()
|
||||
|
|
|
@ -14,11 +14,13 @@ session_manager = common.session_manager
|
|||
|
||||
@site.route('/user/<username>')
|
||||
def get_user_html(username):
|
||||
common.permission_manager.basic()
|
||||
user = common.P_user(username, response_type='html')
|
||||
return common.render_template(request, 'user.html', user=user)
|
||||
|
||||
@site.route('/user/<username>.json')
|
||||
def get_user_json(username):
|
||||
common.permission_manager.basic()
|
||||
user = common.P_user(username, response_type='json')
|
||||
user = user.jsonify()
|
||||
return flasktools.json_response(user)
|
||||
|
@ -26,6 +28,7 @@ def get_user_json(username):
|
|||
@site.route('/userid/<user_id>')
|
||||
@site.route('/userid/<user_id>.json')
|
||||
def get_user_id_redirect(user_id):
|
||||
common.permission_manager.basic()
|
||||
if request.path.endswith('.json'):
|
||||
user = common.P_user_id(user_id, response_type='json')
|
||||
else:
|
||||
|
@ -37,6 +40,7 @@ def get_user_id_redirect(user_id):
|
|||
|
||||
@site.route('/user/<username>/edit', methods=['POST'])
|
||||
def post_user_edit(username):
|
||||
common.permission_manager.basic()
|
||||
if not request.session:
|
||||
return flasktools.json_response(etiquette.exceptions.Unauthorized().jsonify(), status=403)
|
||||
user = common.P_user(username, response_type='json')
|
||||
|
@ -54,6 +58,7 @@ def post_user_edit(username):
|
|||
|
||||
@site.route('/login', methods=['GET'])
|
||||
def get_login():
|
||||
common.permission_manager.global_public()
|
||||
response = common.render_template(
|
||||
request,
|
||||
'login.html',
|
||||
|
@ -66,6 +71,7 @@ def get_login():
|
|||
@site.route('/login', methods=['POST'])
|
||||
@flasktools.required_fields(['username', 'password'])
|
||||
def post_login():
|
||||
common.permission_manager.global_public()
|
||||
if request.session.user:
|
||||
exc = etiquette.exceptions.AlreadySignedIn()
|
||||
response = exc.jsonify()
|
||||
|
@ -96,6 +102,7 @@ def post_login():
|
|||
|
||||
@site.route('/logout', methods=['POST'])
|
||||
def post_logout():
|
||||
common.permission_manager.basic()
|
||||
session_manager.remove(request)
|
||||
response = flasktools.json_response({})
|
||||
return response
|
||||
|
@ -104,11 +111,13 @@ def post_logout():
|
|||
|
||||
@site.route('/register', methods=['GET'])
|
||||
def get_register():
|
||||
common.permission_manager.global_public()
|
||||
return flask.redirect('/login')
|
||||
|
||||
@site.route('/register', methods=['POST'])
|
||||
@flasktools.required_fields(['username', 'password_1', 'password_2'])
|
||||
def post_register():
|
||||
common.permission_manager.global_public()
|
||||
if request.session.user:
|
||||
exc = etiquette.exceptions.AlreadySignedIn()
|
||||
response = exc.jsonify()
|
||||
|
|
43
frontends/etiquette_flask/backend/permissions.py
Normal file
43
frontends/etiquette_flask/backend/permissions.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
import flask; from flask import request
|
||||
import functools
|
||||
|
||||
from voussoirkit import vlogging
|
||||
|
||||
log = vlogging.getLogger(__name__)
|
||||
|
||||
class PermissionManager:
|
||||
def __init__(self, site):
|
||||
self.site = site
|
||||
|
||||
def admin(self):
|
||||
if request.is_localhost:
|
||||
request.checked_permissions = True
|
||||
return True
|
||||
else:
|
||||
return flask.abort(403)
|
||||
|
||||
def basic(self):
|
||||
if request.method not in {'GET', 'POST'}:
|
||||
return flask.abort(405)
|
||||
elif request.is_localhost:
|
||||
request.checked_permissions = True
|
||||
return True
|
||||
elif request.method == 'GET' and self.site.server_config['anonymous_read'] or request.session.user:
|
||||
request.checked_permissions = True
|
||||
return True
|
||||
elif request.method == 'POST' and self.site.server_config['anonymous_write'] or request.session.user:
|
||||
request.checked_permissions = True
|
||||
return True
|
||||
else:
|
||||
return flask.abort(403)
|
||||
|
||||
def basic_decorator(self, endpoint):
|
||||
log.debug('Decorating %s with basic_decorator.', endpoint)
|
||||
@functools.wraps(endpoint)
|
||||
def wrapped(*args, **kwargs):
|
||||
self.basic()
|
||||
return endpoint(*args, **kwargs)
|
||||
return wrapped
|
||||
|
||||
def global_public(self):
|
||||
request.checked_permissions = True
|
|
@ -1,6 +1,9 @@
|
|||
'''
|
||||
This file is the gevent launcher for local / development use.
|
||||
'''
|
||||
from voussoirkit import vlogging
|
||||
vlogging.earlybird_config()
|
||||
|
||||
import gevent.monkey; gevent.monkey.patch_all()
|
||||
import werkzeug.middleware.proxy_fix
|
||||
|
||||
|
@ -11,6 +14,7 @@ import sys
|
|||
|
||||
from voussoirkit import betterhelp
|
||||
from voussoirkit import pathclass
|
||||
from voussoirkit import operatornotify
|
||||
from voussoirkit import vlogging
|
||||
|
||||
log = vlogging.getLogger(__name__, 'etiquette_flask_dev')
|
||||
|
@ -79,7 +83,7 @@ def etiquette_flask_launch_argparse(args):
|
|||
use_https=args.use_https,
|
||||
)
|
||||
|
||||
@vlogging.main_decorator
|
||||
@operatornotify.main_decorator(subject='etiquette_flask_dev', notify_every_line=True)
|
||||
def main(argv):
|
||||
parser = argparse.ArgumentParser(
|
||||
description='''
|
||||
|
|
Loading…
Reference in a new issue