diff --git a/client/html/help_search_posts.tpl b/client/html/help_search_posts.tpl index 30a986f0..e6cb707b 100644 --- a/client/html/help_search_posts.tpl +++ b/client/html/help_search_posts.tpl @@ -44,7 +44,7 @@ pool - belonging to given pool ID + belonging to the pool with the given ID tag-count diff --git a/doc/API.md b/doc/API.md index 528b665c..51084c06 100644 --- a/doc/API.md +++ b/doc/API.md @@ -44,6 +44,20 @@ - [Getting featured post](#getting-featured-post) - [Featuring post](#featuring-post) - [Reverse image search](#reverse-image-search) + - Pool categories + - [Listing pool categories](#listing-pool-categories) + - [Creating pool category](#creating-pool-category) + - [Updating pool category](#updating-pool-category) + - [Getting pool category](#getting-pool-category) + - [Deleting pool category](#deleting-pool-category) + - [Setting default pool category](#setting-default-pool-category) + - Pools + - [Listing pools](#listing-pool) + - [Creating pool](#creating-pool) + - [Updating pool](#updating-pool) + - [Getting pool](#getting-pool) + - [Deleting pool](#deleting-pool) + - [Merging pools](#merging-pools) - Comments - [Listing comments](#listing-comments) - [Creating comment](#creating-comment) @@ -82,6 +96,8 @@ - [Micro tag](#micro-tag) - [Post](#post) - [Micro post](#micro-post) + - [Pool category](#pool-category) + - [Pool](#pool) - [Note](#note) - [Comment](#comment) - [Snapshot](#snapshot) @@ -724,6 +740,7 @@ data. | `submit` | alias of upload | | `comment` | commented by given user (accepts wildcards) | | `fav` | favorited by given user (accepts wildcards) | + | `pool` | belonging to the pool with the given ID | | `tag-count` | having given number of tags | | `comment-count` | having given number of comments | | `fav-count` | favorited by given number of users | @@ -1118,6 +1135,383 @@ data. Retrieves posts that look like the input image. +## Listing pool categories +- **Request** + + `GET /pool-categories` + +- **Output** + + An [unpaged search result](#unpaged-search-result), for which `` + is a [pool category resource](#pool-category). + +- **Errors** + + - privileges are too low + +- **Description** + + Lists all pool categories. Doesn't use paging. + +## Creating pool category +- **Request** + + `POST /pool-categories` + +- **Input** + + ```json5 + { + "name": , + "color": + } + ``` + +- **Output** + + A [pool category resource](#pool-category). + +- **Errors** + + - the name is used by an existing pool category (names are case insensitive) + - the name is invalid or missing + - the color is invalid or missing + - privileges are too low + +- **Description** + + Creates a new pool category using specified parameters. Name must match + `pool_category_name_regex` from server's configuration. First category + created becomes the default category. + +## Updating pool category +- **Request** + + `PUT /pool-category/` + +- **Input** + + ```json5 + { + "version": , + "name": , // optional + "color": , // optional + } + ``` + +- **Output** + + A [pool category resource](#pool-category). + +- **Errors** + + - the version is outdated + - the pool category does not exist + - the name is used by an existing pool category (names are case insensitive) + - the name is invalid + - the color is invalid + - privileges are too low + +- **Description** + + Updates an existing pool category using specified parameters. Name must + match `pool_category_name_regex` from server's configuration. All fields + except the [`version`](#versioning) are optional - update concerns only + provided fields. + +## Getting pool category +- **Request** + + `GET /pool-category/` + +- **Output** + + A [pool category resource](#pool-category). + +- **Errors** + + - the pool category does not exist + - privileges are too low + +- **Description** + + Retrieves information about an existing pool category. + +## Deleting pool category +- **Request** + + `DELETE /pool-category/` + +- **Input** + + ```json5 + { + "version": + } + ``` + +- **Output** + + ```json5 + {} + ``` + +- **Errors** + + - the version is outdated + - the pool category does not exist + - the pool category is used by some pools + - the pool category is the last pool category available + - privileges are too low + +- **Description** + + Deletes existing pool category. The pool category to be deleted must have no + usages. + +## Setting default pool category +- **Request** + + `PUT /pool-category//default` + +- **Input** + + ```json5 + {} + ``` + +- **Output** + + A [pool category resource](#pool-category). + +- **Errors** + + - the pool category does not exist + - privileges are too low + +- **Description** + + Sets given pool category as default. All new pools created manually or + automatically will have this category. + +## Listing pools +- **Request** + + `GET /pools/?offset=&limit=&query=` + +- **Output** + + A [paged search result resource](#paged-search-result), for which + `` is a [pool resource](#pool). + +- **Errors** + + - privileges are too low + +- **Description** + + Searches for pools. + + **Anonymous tokens** + + Same as `name` token. + + **Named tokens** + + | `` | Description | + | ------------------- | ----------------------------------------- | + | `name` | having given name (accepts wildcards) | + | `category` | having given category (accepts wildcards) | + | `creation-date` | created at given date | + | `creation-time` | alias of `creation-date` | + | `last-edit-date` | edited at given date | + | `last-edit-time` | alias of `last-edit-date` | + | `edit-date` | alias of `last-edit-date` | + | `edit-time` | alias of `last-edit-date` | + | `post-count` | used in given number of posts | + + **Sort style tokens** + + | `` | Description | + | ------------------- | ---------------------------- | + | `random` | as random as it can get | + | `name` | A to Z | + | `category` | category (A to Z) | + | `creation-date` | recently created first | + | `creation-time` | alias of `creation-date` | + | `last-edit-date` | recently edited first | + | `last-edit-time` | alias of `creation-time` | + | `edit-date` | alias of `creation-time` | + | `edit-time` | alias of `creation-time` | + | `post-count` | used in most posts first | + + **Special tokens** + + None. + +## Creating pool +- **Request** + + `POST /pools/create` + +- **Input** + + ```json5 + { + "names": [, , ...], + "category": , + "description": , // optional + "posts": [, , ...], // optional + } + ``` + +- **Output** + + A [pool resource](#pool). + +- **Errors** + + - any name is invalid + - category is invalid + - no name was specified + - there is at least one duplicate post + - at least one post ID does not exist + - privileges are too low + +- **Description** + + Creates a new pool using specified parameters. Names, suggestions and + implications must match `pool_name_regex` from server's configuration. + Category must exist and is the same as `name` field within + [`` resource](#pool-category). `posts` is an optional list of + integer post IDs. If the specified posts do not exist, an error will be + thrown. + +## Updating pool +- **Request** + + `PUT /pool/` + +- **Input** + + ```json5 + { + "version": , + "names": [, , ...], // optional + "category": , // optional + "description": , // optional + "posts": [, , ...], // optional + } + ``` + +- **Output** + + A [pool resource](#pool). + +- **Errors** + + - the version is outdated + - the pool does not exist + - any name is invalid + - category is invalid + - no name was specified + - there is at least one duplicate post + - at least one post ID does not exist + - privileges are too low + +- **Description** + + Updates an existing pool using specified parameters. Names, suggestions and + implications must match `pool_name_regex` from server's configuration. + Category must exist and is the same as `name` field within + [`` resource](#pool-category). `posts` is an optional list of + integer post IDs. If the specified posts do not exist yet, an error will be + thrown. The full list of post IDs must be provided if they are being + updated, and the previous list of posts will be replaced with the new one. + All fields except the [`version`](#versioning) are optional - update + concerns only provided fields. + +## Getting pool +- **Request** + + `GET /pool/` + +- **Output** + + A [pool resource](#pool). + +- **Errors** + + - the pool does not exist + - privileges are too low + +- **Description** + + Retrieves information about an existing pool. + +## Deleting pool +- **Request** + + `DELETE /pool/` + +- **Input** + + ```json5 + { + "version": + } + ``` + +- **Output** + + ```json5 + {} + ``` + +- **Errors** + + - the version is outdated + - the pool does not exist + - privileges are too low + +- **Description** + + Deletes existing pool. All posts in the pool will only have their relation + to the pool removed. + +## Merging pools +- **Request** + + `POST /pool-merge/` + +- **Input** + + ```json5 + { + "removeVersion": , + "remove": , + "mergeToVersion": , + "mergeTo": + } + ``` + +- **Output** + + A [pool resource](#pool) containing the merged pool. + +- **Errors** + + - the version of either pool is outdated + - the source or target pool does not exist + - the source pool is the same as the target pool + - privileges are too low + +- **Description** + + Removes source pool and merges all of its posts with the target pool. Other + pool properties such as category and aliases do not get transferred and are + discarded. + ## Listing comments - **Request** @@ -2073,6 +2467,68 @@ A text annotation rendered on top of the post. will draw it inside the post's upper left quarter. - ``: the annotation text. The client should render is as Markdown. +## Pool category +**Description** + +A single pool category. The primary purpose of pool categories is to distinguish +certain pool types (such as series, relations etc.), which improves user +experience. + +**Structure** + +```json5 +{ + "version": , + "name": , + "color": , + "usages": + "default": +} +``` + +**Field meaning** + +- ``: resource version. See [versioning](#versioning). +- ``: the category name. +- ``: the category color. +- ``: how many pools is the given category used with. +- ``: whether the pool category is the default one. + +## Pool +**Description** + +An ordered list of posts, with a description and category. + +**Structure** + +```json5 +{ + "version": , + "id": + "names": , + "category": , + "posts": , + "creationTime": , + "lastEditTime": , + "postCount": , + "description": +} +``` + +**Field meaning** + +- ``: resource version. See [versioning](#versioning). +- ``: the pool identifier. +- ``: a list of pool names (aliases). +- ``: the name of the category the given pool belongs to. +- ``: an ordered list of posts, serialized as [micro + post resource](#micro-post). Posts are ordered by insertion by default. +- ``: time the pool was created, formatted as per RFC 3339. +- ``: time the pool was edited, formatted as per RFC 3339. +- ``: the number of posts the pool has. +- ``: the pool description (instructions how to use, history etc.) + The client should render it as Markdown. + ## Comment **Description** @@ -2144,6 +2600,7 @@ A snapshot is a version of a database resource. | `"tag"` | first tag name at given time | | `"tag_category"` | tag category name at given time | | `"post"` | post ID | + | `"pool"` | pool ID | - ``: a [micro user resource](#micro-user) representing the user who has made the change. diff --git a/server/szurubooru/func/pools.py b/server/szurubooru/func/pools.py index 27574eee..1d279296 100644 --- a/server/szurubooru/func/pools.py +++ b/server/szurubooru/func/pools.py @@ -3,7 +3,7 @@ from typing import Any, Optional, Tuple, List, Dict, Callable from datetime import datetime import sqlalchemy as sa from szurubooru import config, db, model, errors, rest -from szurubooru.func import util, pool_categories, serialization, posts +from szurubooru.func import util, pool_categories, posts, serialization class PoolNotFoundError(errors.NotFoundError): @@ -130,11 +130,9 @@ class PoolSerializer(serialization.BaseSerializer): return self.pool.post_count def serialize_posts(self) -> Any: - return [ - { - 'id': post.post_id - } - for post in self.pool.posts] + return [post for post in + [posts.serialize_micro_post(rel, None) + for rel in self.pool.posts]] def serialize_pool( diff --git a/server/szurubooru/tests/func/test_posts.py b/server/szurubooru/tests/func/test_posts.py index e785ea56..b429491f 100644 --- a/server/szurubooru/tests/func/test_posts.py +++ b/server/szurubooru/tests/func/test_posts.py @@ -209,7 +209,12 @@ def test_serialize_post( 'description': 'desc', 'category': 'test-cat1', 'postCount': 1, - 'posts': [{'id': 1}], + 'posts': [ + { + 'id': 1, + 'thumbnailUrl': 'http://example.com/generated-thumbnails/1_244c8840887984c4.jpg', + } + ], 'version': 1, 'creationTime': datetime(1996, 1, 1), 'lastEditTime': datetime(1998, 1, 1), @@ -220,7 +225,12 @@ def test_serialize_post( 'description': 'desc2', 'category': 'test-cat2', 'postCount': 1, - 'posts': [{'id': 1}], + 'posts': [ + { + 'id': 1, + 'thumbnailUrl': 'http://example.com/generated-thumbnails/1_244c8840887984c4.jpg', + } + ], 'version': 1, 'creationTime': datetime(1996, 1, 1), 'lastEditTime': datetime(1998, 1, 1),