Route for getting previous/next posts in pool
This commit is contained in:
parent
748f0e16eb
commit
8e8b15a1d8
9 changed files with 194 additions and 6 deletions
|
@ -16,6 +16,14 @@ class PostMainController extends BasePostController {
|
|||
constructor(ctx, editMode) {
|
||||
super(ctx);
|
||||
|
||||
let poolPostsAround = Promise.resolve({results: [], activePool: null})
|
||||
if (api.hasPrivilege("pools.list") && api.hasPrivilege("pools.view")) {
|
||||
poolPostsAround = PostList.getPoolPostsAround(
|
||||
ctxt.parameters.id,
|
||||
parameters ? parameters.query : null
|
||||
);
|
||||
}
|
||||
|
||||
let parameters = ctx.parameters;
|
||||
Promise.all([
|
||||
Post.get(ctx.parameters.id),
|
||||
|
@ -23,9 +31,10 @@ class PostMainController extends BasePostController {
|
|||
ctx.parameters.id,
|
||||
parameters ? parameters.query : null
|
||||
),
|
||||
poolPostsAround
|
||||
]).then(
|
||||
(responses) => {
|
||||
const [post, aroundResponse] = responses;
|
||||
const [post, aroundResponse, poolPostsAroundResponse] = responses;
|
||||
|
||||
// remove junk from query, but save it into history so that it can
|
||||
// be still accessed after history navigation / page refresh
|
||||
|
@ -44,6 +53,8 @@ class PostMainController extends BasePostController {
|
|||
this._post = post;
|
||||
this._view = new PostMainView({
|
||||
post: post,
|
||||
poolPostsAround: poolPostsAroundResponse.results,
|
||||
activePool: poolPostsAroundResponse.activePool,
|
||||
editMode: editMode,
|
||||
prevPostId: aroundResponse.prev
|
||||
? aroundResponse.prev.id
|
||||
|
|
|
@ -7,7 +7,7 @@ const PoolNavigatorControl = require("../controls/pool_navigator_control.js");
|
|||
const template = views.getTemplate("pool-navigator-list");
|
||||
|
||||
class PoolNavigatorListControl extends events.EventTarget {
|
||||
constructor(hostNode, a) {
|
||||
constructor(hostNode, pools) {
|
||||
super();
|
||||
this._hostNode = hostNode;
|
||||
|
||||
|
|
|
@ -16,6 +16,15 @@ class PostList extends AbstractList {
|
|||
);
|
||||
}
|
||||
|
||||
static getPoolPostsAround(id, searchQuery) {
|
||||
return api.get(
|
||||
uri.formatApiLink("post", id, "pool-posts-around", {
|
||||
query: PostList._decorateSearchQuery(searchQuery || ""),
|
||||
fields: "id",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
static search(text, offset, limit, fields) {
|
||||
return api
|
||||
.get(
|
||||
|
|
|
@ -9,4 +9,5 @@ pillow>=4.3.0
|
|||
pynacl>=1.2.1
|
||||
pytz>=2018.3
|
||||
pyRFC3339>=1.0
|
||||
alembic_utils>=0.5.6
|
||||
youtube_dl
|
||||
|
|
|
@ -284,6 +284,19 @@ def get_posts_around(
|
|||
)
|
||||
|
||||
|
||||
@rest.routes.get("/post/(?P<post_id>[^/]+)/pool-posts-around/?")
|
||||
def get_pool_posts_around(
|
||||
ctx: rest.Context, params: Dict[str, str]
|
||||
) -> rest.Response:
|
||||
auth.verify_privilege(ctx.user, "posts:list")
|
||||
auth.verify_privilege(ctx.user, "pools:list")
|
||||
auth.verify_privilege(ctx.user, "pools:view")
|
||||
_search_executor_config.user = ctx.user
|
||||
post = _get_post(params)
|
||||
results = posts.get_pool_posts_around(post)
|
||||
return posts.serialize_pool_posts_around(results)
|
||||
|
||||
|
||||
@rest.routes.post("/posts/reverse-search/?")
|
||||
def get_posts_by_image(
|
||||
ctx: rest.Context, _params: Dict[str, str] = {}
|
||||
|
|
|
@ -2,6 +2,7 @@ import hmac
|
|||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple
|
||||
from collections import namedtuple
|
||||
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
@ -134,12 +135,16 @@ def get_post_content_path(post: model.Post) -> str:
|
|||
)
|
||||
|
||||
|
||||
def get_post_thumbnail_path_from_id(post_id: int) -> str:
|
||||
return "generated-thumbnails/%d_%s.jpg" % (
|
||||
post_id,
|
||||
get_post_security_hash(post_id),
|
||||
)
|
||||
|
||||
|
||||
def get_post_thumbnail_path(post: model.Post) -> str:
|
||||
assert post
|
||||
return "generated-thumbnails/%d_%s.jpg" % (
|
||||
post.post_id,
|
||||
get_post_security_hash(post.post_id),
|
||||
)
|
||||
return get_post_thumbnail_path_from_id(post.post_id)
|
||||
|
||||
|
||||
def get_post_thumbnail_backup_path(post: model.Post) -> str:
|
||||
|
@ -967,3 +972,69 @@ def search_by_image(image_content: bytes) -> List[Tuple[float, model.Post]]:
|
|||
]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
PoolPostsAround = namedtuple('PoolPostsAround', 'pool prev_post next_post')
|
||||
|
||||
def get_pool_posts_around(post: model.Post) -> List[PoolPostsAround]:
|
||||
around = dict()
|
||||
pool_ids = set()
|
||||
post_ids = set()
|
||||
|
||||
dbquery = """
|
||||
SELECT around.ord, around.pool_id, around.post_id, around.delta
|
||||
FROM pool_post pp,
|
||||
LATERAL get_pool_posts_around(pp.pool_id, pp.post_id) around
|
||||
WHERE pp.post_id = :post_id;
|
||||
"""
|
||||
|
||||
for order, pool_id, post_id, delta in db.session.execute(dbquery, {"post_id": post.post_id}):
|
||||
if pool_id not in around:
|
||||
around[pool_id] = [None, None]
|
||||
if delta < 0:
|
||||
around[pool_id][0] = post_id
|
||||
elif delta > 0:
|
||||
around[pool_id][1] = post_id
|
||||
pool_ids.add(pool_id)
|
||||
post_ids.add(post_id)
|
||||
|
||||
pools = dict()
|
||||
posts = dict()
|
||||
|
||||
for pool in db.session.query(model.Pool).filter(model.Pool.pool_id.in_(pool_ids)).all():
|
||||
pools[pool.pool_id] = pool
|
||||
|
||||
for result in db.session.query(model.Post.post_id).filter(model.Post.post_id.in_(post_ids)).all():
|
||||
post_id = result[0]
|
||||
posts[post_id] = { "id": post_id, "thumbnailUrl": get_post_thumbnail_path_from_id(post_id) }
|
||||
|
||||
results = []
|
||||
|
||||
for pool_id, entry in around.items():
|
||||
prev_post = None
|
||||
next_post = None
|
||||
if entry[0] is not None:
|
||||
prev_post = posts[entry[0]]
|
||||
if entry[1] is not None:
|
||||
next_post = posts[entry[1]]
|
||||
results.append(PoolPostsAround(pools[pool_id], prev_post, next_post))
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def sort_pool_posts_around(around: List[PoolPostsAround]) -> List[PoolPostsAround]:
|
||||
return sorted(
|
||||
around,
|
||||
key=lambda entry: entry.pool.pool_id,
|
||||
)
|
||||
|
||||
|
||||
def serialize_pool_posts_around(around: List[PoolPostsAround]) -> Optional[rest.Response]:
|
||||
return [
|
||||
{
|
||||
"pool": pools.serialize_micro_pool(entry.pool),
|
||||
"prev_post": entry.prev_post,
|
||||
"next_post": entry.next_post
|
||||
}
|
||||
for entry in sort_pool_posts_around(around)
|
||||
]
|
||||
|
|
|
@ -11,6 +11,7 @@ import sys
|
|||
from time import sleep
|
||||
|
||||
import alembic
|
||||
from alembic_utils.replaceable_entity import register_entities
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
|
@ -21,6 +22,9 @@ sys.path.append(os.path.join(dir_to_self, *[os.pardir] * 2))
|
|||
|
||||
import szurubooru.config # noqa: E402
|
||||
import szurubooru.model.base # noqa: E402
|
||||
|
||||
from szurubooru.migrations.functions import get_pool_posts_around # noqa: E402
|
||||
register_entities([get_pool_posts_around])
|
||||
# fmt: on
|
||||
|
||||
|
||||
|
|
46
server/szurubooru/migrations/functions.py
Normal file
46
server/szurubooru/migrations/functions.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
from alembic_utils.pg_function import PGFunction
|
||||
|
||||
get_pool_posts_around = PGFunction.from_sql("""
|
||||
CREATE OR REPLACE FUNCTION public.get_pool_posts_around(
|
||||
P_POOL_ID int,
|
||||
P_POST_ID int
|
||||
)
|
||||
RETURNS TABLE (
|
||||
ORD int,
|
||||
POOL_ID int,
|
||||
POST_ID int,
|
||||
DELTA int
|
||||
)
|
||||
LANGUAGE PLPGSQL
|
||||
AS $$
|
||||
BEGIN
|
||||
RETURN QUERY WITH main AS (
|
||||
SELECT * FROM pool_post WHERE pool_post.pool_id = P_POOL_ID AND pool_post.post_id = P_POST_ID
|
||||
),
|
||||
around AS (
|
||||
(SELECT pool_post.ord,
|
||||
pool_post.pool_id,
|
||||
pool_post.post_id,
|
||||
1 as delta,
|
||||
main.ord AS target_ord,
|
||||
main.pool_id AS target_pool_id
|
||||
FROM pool_post, main
|
||||
WHERE pool_post.ord > main.ord
|
||||
AND pool_post.pool_id = main.pool_id
|
||||
ORDER BY pool_post.ord ASC LIMIT 1)
|
||||
UNION
|
||||
(SELECT pool_post.ord,
|
||||
pool_post.pool_id,
|
||||
pool_post.post_id,
|
||||
-1 as delta,
|
||||
main.ord AS target_ord,
|
||||
main.pool_id AS target_pool_id
|
||||
FROM pool_post, main
|
||||
WHERE pool_post.ord < main.ord
|
||||
AND pool_post.pool_id = main.pool_id
|
||||
ORDER BY pool_post.ord DESC LIMIT 1)
|
||||
)
|
||||
SELECT around.ord, around.pool_id, around.post_id, around.delta FROM around;
|
||||
END
|
||||
$$
|
||||
""")
|
|
@ -0,0 +1,33 @@
|
|||
'''
|
||||
add get pool posts around function
|
||||
|
||||
Revision ID: f0b8a4298dc7
|
||||
Created at: 2021-05-08 21:23:48.782025
|
||||
'''
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
from alembic_utils.pg_function import PGFunction
|
||||
from sqlalchemy import text as sql_text
|
||||
|
||||
revision = 'f0b8a4298dc7'
|
||||
down_revision = 'adcd63ff76a2'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
def upgrade():
|
||||
public_get_pool_posts_around = PGFunction(
|
||||
schema="public",
|
||||
signature="get_pool_posts_around( P_POOL_ID int, P_POST_ID int )",
|
||||
definition='returns TABLE (\n ORD int,\n POOL_ID int,\n POST_ID int,\n DELTA int\n )\n LANGUAGE PLPGSQL\nAS $$\nBEGIN\n RETURN QUERY WITH main AS (\n SELECT * FROM pool_post WHERE pool_post.pool_id = P_POOL_ID AND pool_post.post_id = P_POST_ID\n ),\n around AS (\n (SELECT pool_post.ord,\n pool_post.pool_id,\n pool_post.post_id,\n 1 as delta,\n main.ord AS target_ord,\n main.pool_id AS target_pool_id\n FROM pool_post, main\n WHERE pool_post.ord > main.ord\n AND pool_post.pool_id = main.pool_id\n ORDER BY pool_post.ord ASC LIMIT 1)\n UNION\n (SELECT pool_post.ord,\n pool_post.pool_id,\n pool_post.post_id,\n -1 as delta,\n main.ord AS target_ord,\n main.pool_id AS target_pool_id\n FROM pool_post, main\n WHERE pool_post.ord < main.ord\n AND pool_post.pool_id = main.pool_id\n ORDER BY pool_post.ord DESC LIMIT 1)\n )\n SELECT around.ord, around.pool_id, around.post_id, around.delta FROM around;\nEND\n$$'
|
||||
)
|
||||
op.create_entity(public_get_pool_posts_around)
|
||||
|
||||
def downgrade():
|
||||
public_get_pool_posts_around = PGFunction(
|
||||
schema="public",
|
||||
signature="get_pool_posts_around( P_POOL_ID int, P_POST_ID int )",
|
||||
definition='returns TABLE (\n ORD int,\n POOL_ID int,\n POST_ID int,\n DELTA int\n )\n LANGUAGE PLPGSQL\nAS $$\nBEGIN\n RETURN QUERY WITH main AS (\n SELECT * FROM pool_post WHERE pool_post.pool_id = P_POOL_ID AND pool_post.post_id = P_POST_ID\n ),\n around AS (\n (SELECT pool_post.ord,\n pool_post.pool_id,\n pool_post.post_id,\n 1 as delta,\n main.ord AS target_ord,\n main.pool_id AS target_pool_id\n FROM pool_post, main\n WHERE pool_post.ord > main.ord\n AND pool_post.pool_id = main.pool_id\n ORDER BY pool_post.ord ASC LIMIT 1)\n UNION\n (SELECT pool_post.ord,\n pool_post.pool_id,\n pool_post.post_id,\n -1 as delta,\n main.ord AS target_ord,\n main.pool_id AS target_pool_id\n FROM pool_post, main\n WHERE pool_post.ord < main.ord\n AND pool_post.pool_id = main.pool_id\n ORDER BY pool_post.ord DESC LIMIT 1)\n )\n SELECT around.ord, around.pool_id, around.post_id, around.delta FROM around;\nEND\n$$'
|
||||
)
|
||||
op.drop_entity(public_get_pool_posts_around)
|
Loading…
Reference in a new issue