aboutsummaryrefslogtreecommitdiff
path: root/server/szurubooru/api/post_api.py
diff options
context:
space:
mode:
authorrr-2016-08-14 12:35:14 +0200
committerrr-2016-08-14 16:43:35 +0200
commitaf62f8c45ac8986342a56d41f176435ada1a1a9b (patch)
tree5bb920cff28c4ac74f2ca1c292ac007d2fcc5c76 /server/szurubooru/api/post_api.py
parentd102c9bdbafe503952c306abb55d430db2c75718 (diff)
server/general: ditch falcon for in-house WSGI app
For quite some time, I hated Falcon's class maps approach that caused more chaos than good for Szurubooru. I've taken a look at the other frameworks (hug, flask, etc) again, but they all looked too bloated/over-engineered. I decided to just talk to WSGI myself. Regex-based routing may not be the fastest in the world, but I'm fine with response time of 10 ms for cached /posts.
Diffstat (limited to 'server/szurubooru/api/post_api.py')
-rw-r--r--server/szurubooru/api/post_api.py298
1 files changed, 148 insertions, 150 deletions
diff --git a/server/szurubooru/api/post_api.py b/server/szurubooru/api/post_api.py
index 68a9835..b75f40b 100644
--- a/server/szurubooru/api/post_api.py
+++ b/server/szurubooru/api/post_api.py
@@ -1,7 +1,9 @@
import datetime
from szurubooru import search
-from szurubooru.api.base_api import BaseApi
from szurubooru.func import auth, tags, posts, snapshots, favorites, scores, util
+from szurubooru.rest import routes
+
+_search_executor = search.Executor(search.configs.PostSearchConfig())
def _serialize_post(ctx, post):
return posts.serialize_post(
@@ -9,165 +11,161 @@ def _serialize_post(ctx, post):
ctx.user,
options=util.get_serialization_options(ctx))
-class PostListApi(BaseApi):
- def __init__(self):
- super().__init__()
- self._search_executor = search.Executor(
- search.configs.PostSearchConfig())
+@routes.get('/posts/?')
+def get_posts(ctx, _params=None):
+ auth.verify_privilege(ctx.user, 'posts:list')
+ _search_executor.config.user = ctx.user
+ return _search_executor.execute_and_serialize(
+ ctx, lambda post: _serialize_post(ctx, post))
+
+@routes.post('/posts/?')
+def create_post(ctx, _params=None):
+ anonymous = ctx.get_param_as_bool('anonymous', default=False)
+ if anonymous:
+ auth.verify_privilege(ctx.user, 'posts:create:anonymous')
+ else:
+ auth.verify_privilege(ctx.user, 'posts:create:identified')
+ content = ctx.get_file('content', required=True)
+ tag_names = ctx.get_param_as_list('tags', required=True)
+ safety = ctx.get_param_as_string('safety', required=True)
+ source = ctx.get_param_as_string('source', required=False, default=None)
+ if ctx.has_param('contentUrl') and not source:
+ source = ctx.get_param_as_string('contentUrl')
+ relations = ctx.get_param_as_list('relations', required=False) or []
+ notes = ctx.get_param_as_list('notes', required=False) or []
+ flags = ctx.get_param_as_list('flags', required=False) or []
- def get(self, ctx):
- auth.verify_privilege(ctx.user, 'posts:list')
- self._search_executor.config.user = ctx.user
- return self._search_executor.execute_and_serialize(
- ctx, lambda post: _serialize_post(ctx, post))
+ post, new_tags = posts.create_post(
+ content, tag_names, None if anonymous else ctx.user)
+ if len(new_tags):
+ auth.verify_privilege(ctx.user, 'tags:create')
+ posts.update_post_safety(post, safety)
+ posts.update_post_source(post, source)
+ posts.update_post_relations(post, relations)
+ posts.update_post_notes(post, notes)
+ posts.update_post_flags(post, flags)
+ if ctx.has_file('thumbnail'):
+ posts.update_post_thumbnail(post, ctx.get_file('thumbnail'))
+ ctx.session.add(post)
+ snapshots.save_entity_creation(post, ctx.user)
+ ctx.session.commit()
+ tags.export_to_json()
+ return _serialize_post(ctx, post)
- def post(self, ctx):
- anonymous = ctx.get_param_as_bool('anonymous', default=False)
- if anonymous:
- auth.verify_privilege(ctx.user, 'posts:create:anonymous')
- else:
- auth.verify_privilege(ctx.user, 'posts:create:identified')
- content = ctx.get_file('content', required=True)
- tag_names = ctx.get_param_as_list('tags', required=True)
- safety = ctx.get_param_as_string('safety', required=True)
- source = ctx.get_param_as_string('source', required=False, default=None)
- if ctx.has_param('contentUrl') and not source:
- source = ctx.get_param_as_string('contentUrl')
- relations = ctx.get_param_as_list('relations', required=False) or []
- notes = ctx.get_param_as_list('notes', required=False) or []
- flags = ctx.get_param_as_list('flags', required=False) or []
+@routes.get('/post/(?P<post_id>[^/]+)/?')
+def get_post(ctx, params):
+ auth.verify_privilege(ctx.user, 'posts:view')
+ post = posts.get_post_by_id(params['post_id'])
+ return _serialize_post(ctx, post)
- post, new_tags = posts.create_post(
- content, tag_names, None if anonymous else ctx.user)
+@routes.put('/post/(?P<post_id>[^/]+)/?')
+def update_post(ctx, params):
+ post = posts.get_post_by_id(params['post_id'])
+ util.verify_version(post, ctx)
+ if ctx.has_file('content'):
+ auth.verify_privilege(ctx.user, 'posts:edit:content')
+ posts.update_post_content(post, ctx.get_file('content'))
+ if ctx.has_param('tags'):
+ auth.verify_privilege(ctx.user, 'posts:edit:tags')
+ new_tags = posts.update_post_tags(post, ctx.get_param_as_list('tags'))
if len(new_tags):
auth.verify_privilege(ctx.user, 'tags:create')
- posts.update_post_safety(post, safety)
- posts.update_post_source(post, source)
- posts.update_post_relations(post, relations)
- posts.update_post_notes(post, notes)
- posts.update_post_flags(post, flags)
- if ctx.has_file('thumbnail'):
- posts.update_post_thumbnail(post, ctx.get_file('thumbnail'))
- ctx.session.add(post)
- snapshots.save_entity_creation(post, ctx.user)
- ctx.session.commit()
- tags.export_to_json()
- return _serialize_post(ctx, post)
-
-class PostDetailApi(BaseApi):
- def get(self, ctx, post_id):
- auth.verify_privilege(ctx.user, 'posts:view')
- post = posts.get_post_by_id(post_id)
- return _serialize_post(ctx, post)
-
- def put(self, ctx, post_id):
- post = posts.get_post_by_id(post_id)
- util.verify_version(post, ctx)
- if ctx.has_file('content'):
- auth.verify_privilege(ctx.user, 'posts:edit:content')
- posts.update_post_content(post, ctx.get_file('content'))
- if ctx.has_param('tags'):
- auth.verify_privilege(ctx.user, 'posts:edit:tags')
- new_tags = posts.update_post_tags(post, ctx.get_param_as_list('tags'))
- if len(new_tags):
- auth.verify_privilege(ctx.user, 'tags:create')
- if ctx.has_param('safety'):
- auth.verify_privilege(ctx.user, 'posts:edit:safety')
- posts.update_post_safety(post, ctx.get_param_as_string('safety'))
- if ctx.has_param('source'):
- auth.verify_privilege(ctx.user, 'posts:edit:source')
- posts.update_post_source(post, ctx.get_param_as_string('source'))
- elif ctx.has_param('contentUrl'):
- posts.update_post_source(post, ctx.get_param_as_string('contentUrl'))
- if ctx.has_param('relations'):
- auth.verify_privilege(ctx.user, 'posts:edit:relations')
- posts.update_post_relations(post, ctx.get_param_as_list('relations'))
- if ctx.has_param('notes'):
- auth.verify_privilege(ctx.user, 'posts:edit:notes')
- posts.update_post_notes(post, ctx.get_param_as_list('notes'))
- if ctx.has_param('flags'):
- auth.verify_privilege(ctx.user, 'posts:edit:flags')
- posts.update_post_flags(post, ctx.get_param_as_list('flags'))
- if ctx.has_file('thumbnail'):
- auth.verify_privilege(ctx.user, 'posts:edit:thumbnail')
- posts.update_post_thumbnail(post, ctx.get_file('thumbnail'))
- util.bump_version(post)
- post.last_edit_time = datetime.datetime.utcnow()
- ctx.session.flush()
- snapshots.save_entity_modification(post, ctx.user)
- ctx.session.commit()
- tags.export_to_json()
- return _serialize_post(ctx, post)
-
- def delete(self, ctx, post_id):
- auth.verify_privilege(ctx.user, 'posts:delete')
- post = posts.get_post_by_id(post_id)
- util.verify_version(post, ctx)
- snapshots.save_entity_deletion(post, ctx.user)
- posts.delete(post)
- ctx.session.commit()
- tags.export_to_json()
- return {}
+ if ctx.has_param('safety'):
+ auth.verify_privilege(ctx.user, 'posts:edit:safety')
+ posts.update_post_safety(post, ctx.get_param_as_string('safety'))
+ if ctx.has_param('source'):
+ auth.verify_privilege(ctx.user, 'posts:edit:source')
+ posts.update_post_source(post, ctx.get_param_as_string('source'))
+ elif ctx.has_param('contentUrl'):
+ posts.update_post_source(post, ctx.get_param_as_string('contentUrl'))
+ if ctx.has_param('relations'):
+ auth.verify_privilege(ctx.user, 'posts:edit:relations')
+ posts.update_post_relations(post, ctx.get_param_as_list('relations'))
+ if ctx.has_param('notes'):
+ auth.verify_privilege(ctx.user, 'posts:edit:notes')
+ posts.update_post_notes(post, ctx.get_param_as_list('notes'))
+ if ctx.has_param('flags'):
+ auth.verify_privilege(ctx.user, 'posts:edit:flags')
+ posts.update_post_flags(post, ctx.get_param_as_list('flags'))
+ if ctx.has_file('thumbnail'):
+ auth.verify_privilege(ctx.user, 'posts:edit:thumbnail')
+ posts.update_post_thumbnail(post, ctx.get_file('thumbnail'))
+ util.bump_version(post)
+ post.last_edit_time = datetime.datetime.utcnow()
+ ctx.session.flush()
+ snapshots.save_entity_modification(post, ctx.user)
+ ctx.session.commit()
+ tags.export_to_json()
+ return _serialize_post(ctx, post)
-class PostFeatureApi(BaseApi):
- def post(self, ctx):
- auth.verify_privilege(ctx.user, 'posts:feature')
- post_id = ctx.get_param_as_int('id', required=True)
- post = posts.get_post_by_id(post_id)
- featured_post = posts.try_get_featured_post()
- if featured_post and featured_post.post_id == post.post_id:
- raise posts.PostAlreadyFeaturedError(
- 'Post %r is already featured.' % post_id)
- posts.feature_post(post, ctx.user)
- if featured_post:
- snapshots.save_entity_modification(featured_post, ctx.user)
- snapshots.save_entity_modification(post, ctx.user)
- ctx.session.commit()
- return _serialize_post(ctx, post)
+@routes.delete('/post/(?P<post_id>[^/]+)/?')
+def delete_post(ctx, params):
+ auth.verify_privilege(ctx.user, 'posts:delete')
+ post = posts.get_post_by_id(params['post_id'])
+ util.verify_version(post, ctx)
+ snapshots.save_entity_deletion(post, ctx.user)
+ posts.delete(post)
+ ctx.session.commit()
+ tags.export_to_json()
+ return {}
- def get(self, ctx):
- post = posts.try_get_featured_post()
- return _serialize_post(ctx, post)
+@routes.get('/featured-post/?')
+def get_featured_post(ctx, _params=None):
+ post = posts.try_get_featured_post()
+ return _serialize_post(ctx, post)
-class PostScoreApi(BaseApi):
- def put(self, ctx, post_id):
- auth.verify_privilege(ctx.user, 'posts:score')
- post = posts.get_post_by_id(post_id)
- score = ctx.get_param_as_int('score', required=True)
- scores.set_score(post, ctx.user, score)
- ctx.session.commit()
- return _serialize_post(ctx, post)
+@routes.post('/featured-post/?')
+def set_featured_post(ctx, _params=None):
+ auth.verify_privilege(ctx.user, 'posts:feature')
+ post_id = ctx.get_param_as_int('id', required=True)
+ post = posts.get_post_by_id(post_id)
+ featured_post = posts.try_get_featured_post()
+ if featured_post and featured_post.post_id == post.post_id:
+ raise posts.PostAlreadyFeaturedError(
+ 'Post %r is already featured.' % post_id)
+ posts.feature_post(post, ctx.user)
+ if featured_post:
+ snapshots.save_entity_modification(featured_post, ctx.user)
+ snapshots.save_entity_modification(post, ctx.user)
+ ctx.session.commit()
+ return _serialize_post(ctx, post)
- def delete(self, ctx, post_id):
- auth.verify_privilege(ctx.user, 'posts:score')
- post = posts.get_post_by_id(post_id)
- scores.delete_score(post, ctx.user)
- ctx.session.commit()
- return _serialize_post(ctx, post)
+@routes.put('/post/(?P<post_id>[^/]+)/score/?')
+def set_post_score(ctx, params):
+ auth.verify_privilege(ctx.user, 'posts:score')
+ post = posts.get_post_by_id(params['post_id'])
+ score = ctx.get_param_as_int('score', required=True)
+ scores.set_score(post, ctx.user, score)
+ ctx.session.commit()
+ return _serialize_post(ctx, post)
-class PostFavoriteApi(BaseApi):
- def post(self, ctx, post_id):
- auth.verify_privilege(ctx.user, 'posts:favorite')
- post = posts.get_post_by_id(post_id)
- favorites.set_favorite(post, ctx.user)
- ctx.session.commit()
- return _serialize_post(ctx, post)
+@routes.delete('/post/(?P<post_id>[^/]+)/score/?')
+def delete_post_score(ctx, params):
+ auth.verify_privilege(ctx.user, 'posts:score')
+ post = posts.get_post_by_id(params['post_id'])
+ scores.delete_score(post, ctx.user)
+ ctx.session.commit()
+ return _serialize_post(ctx, post)
- def delete(self, ctx, post_id):
- auth.verify_privilege(ctx.user, 'posts:favorite')
- post = posts.get_post_by_id(post_id)
- favorites.unset_favorite(post, ctx.user)
- ctx.session.commit()
- return _serialize_post(ctx, post)
+@routes.post('/post/(?P<post_id>[^/]+)/favorite/?')
+def add_post_to_favorites(ctx, params):
+ auth.verify_privilege(ctx.user, 'posts:favorite')
+ post = posts.get_post_by_id(params['post_id'])
+ favorites.set_favorite(post, ctx.user)
+ ctx.session.commit()
+ return _serialize_post(ctx, post)
-class PostsAroundApi(BaseApi):
- def __init__(self):
- super().__init__()
- self._search_executor = search.Executor(
- search.configs.PostSearchConfig())
+@routes.delete('/post/(?P<post_id>[^/]+)/favorite/?')
+def delete_post_from_favorites(ctx, params):
+ auth.verify_privilege(ctx.user, 'posts:favorite')
+ post = posts.get_post_by_id(params['post_id'])
+ favorites.unset_favorite(post, ctx.user)
+ ctx.session.commit()
+ return _serialize_post(ctx, post)
- def get(self, ctx, post_id):
- auth.verify_privilege(ctx.user, 'posts:list')
- self._search_executor.config.user = ctx.user
- return self._search_executor.get_around_and_serialize(
- ctx, post_id, lambda post: _serialize_post(ctx, post))
+@routes.get('/post/(?P<post_id>[^/]+)/around/?')
+def get_posts_around(ctx, params):
+ auth.verify_privilege(ctx.user, 'posts:list')
+ _search_executor.config.user = ctx.user
+ return _search_executor.get_around_and_serialize(
+ ctx, params['post_id'], lambda post: _serialize_post(ctx, post))

© 2015 - 2026 Jakob L. Kreuze