From dfb2e3d0274ada1ef171effced19ed8d91c19838 Mon Sep 17 00:00:00 2001 From: rr- Date: Tue, 7 Jun 2016 11:16:25 +0200 Subject: [PATCH] server/posts: add getting posts around id Leave undocumented since it add almost no value for the client applications. --- server/szurubooru/api/__init__.py | 3 +- server/szurubooru/api/post_api.py | 12 ++++++++ server/szurubooru/app.py | 1 + .../search/configs/base_search_config.py | 4 +++ .../search/configs/post_search_config.py | 4 +++ server/szurubooru/search/executor.py | 28 +++++++++++++++++++ 6 files changed, 51 insertions(+), 1 deletion(-) diff --git a/server/szurubooru/api/__init__.py b/server/szurubooru/api/__init__.py index 3f0c7e2..59b8d6b 100644 --- a/server/szurubooru/api/__init__.py +++ b/server/szurubooru/api/__init__.py @@ -20,7 +20,8 @@ from szurubooru.api.post_api import ( PostDetailApi, PostFeatureApi, PostScoreApi, - PostFavoriteApi) + PostFavoriteApi, + PostsAroundApi) from szurubooru.api.snapshot_api import SnapshotListApi from szurubooru.api.info_api import InfoApi from szurubooru.api.context import Context, Request diff --git a/server/szurubooru/api/post_api.py b/server/szurubooru/api/post_api.py index 1fc38a2..147faab 100644 --- a/server/szurubooru/api/post_api.py +++ b/server/szurubooru/api/post_api.py @@ -152,3 +152,15 @@ class PostFavoriteApi(BaseApi): favorites.unset_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()) + + 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)) diff --git a/server/szurubooru/app.py b/server/szurubooru/app.py index 93245e7..ac9f11d 100644 --- a/server/szurubooru/app.py +++ b/server/szurubooru/app.py @@ -109,6 +109,7 @@ def create_app(): app.add_route('/post/{post_id}', api.PostDetailApi()) app.add_route('/post/{post_id}/score', api.PostScoreApi()) app.add_route('/post/{post_id}/favorite', api.PostFavoriteApi()) + app.add_route('/post/{post_id}/around', api.PostsAroundApi()) app.add_route('/comments/', api.CommentListApi()) app.add_route('/comment/{comment_id}', api.CommentDetailApi()) diff --git a/server/szurubooru/search/configs/base_search_config.py b/server/szurubooru/search/configs/base_search_config.py index 1dc9d4b..bb2cc0b 100644 --- a/server/szurubooru/search/configs/base_search_config.py +++ b/server/szurubooru/search/configs/base_search_config.py @@ -13,6 +13,10 @@ class BaseSearchConfig(object): def create_count_query(self): return self.create_filter_query() + @property + def id_column(self): + return None + @property def anonymous_filter(self): return None diff --git a/server/szurubooru/search/configs/post_search_config.py b/server/szurubooru/search/configs/post_search_config.py index 0f4adaf..2cd381c 100644 --- a/server/szurubooru/search/configs/post_search_config.py +++ b/server/szurubooru/search/configs/post_search_config.py @@ -105,6 +105,10 @@ class PostSearchConfig(BaseSearchConfig): def finalize_query(self, query): return query.order_by(db.Post.creation_time.desc()) + @property + def id_column(self): + return db.Post.post_id + @property def anonymous_filter(self): return search_util.create_subquery_filter( diff --git a/server/szurubooru/search/executor.py b/server/szurubooru/search/executor.py index c024d94..6df508a 100644 --- a/server/szurubooru/search/executor.py +++ b/server/szurubooru/search/executor.py @@ -27,6 +27,34 @@ class Executor(object): self.config = search_config self.parser = parser.Parser() + def get_around(self, query_text, entity_id): + search_query = self.parser.parse(query_text) + self.config.on_search_query_parsed(search_query) + filter_query = self.config \ + .create_filter_query() \ + .options(sqlalchemy.orm.lazyload('*')) + filter_query = self._prepare_db_query(filter_query, search_query, False) + prev_filter_query = filter_query \ + .filter(self.config.id_column < entity_id) \ + .order_by(None) \ + .order_by(sqlalchemy.func.abs(self.config.id_column - entity_id).asc()) \ + .limit(1) + next_filter_query = filter_query \ + .filter(self.config.id_column > entity_id) \ + .order_by(None) \ + .order_by(sqlalchemy.func.abs(self.config.id_column - entity_id).asc()) \ + .limit(1) + return [ + next_filter_query.one_or_none(), + prev_filter_query.one_or_none()] + + def get_around_and_serialize(self, ctx, entity_id, serializer): + entities = self.get_around(ctx.get_param_as_string('query'), entity_id) + return { + 'next': serializer(entities[0]), + 'prev': serializer(entities[1]), + } + def execute(self, query_text, page, page_size): ''' Parse input and return tuple containing total record count and filtered