server/comments: add comment search
This commit is contained in:
parent
b75cfff8f7
commit
0b47957bb9
71
API.md
71
API.md
|
@ -39,7 +39,7 @@
|
|||
- [Getting featured post](#getting-featured-post)
|
||||
- [Featuring post](#featuring-post)
|
||||
- Comments
|
||||
- ~~Listing comments~~
|
||||
- [Listing comments](#listing-comments)
|
||||
- [Creating comment](#creating-comment)
|
||||
- [Updating comment](#updating-comment)
|
||||
- [Getting comment](#getting-comment)
|
||||
|
@ -673,6 +673,75 @@ data.
|
|||
Features a post on the main page in web client.
|
||||
|
||||
|
||||
## Listing comments
|
||||
- **Request**
|
||||
|
||||
`GET /comments/?page=<page>&pageSize=<page-size>&query=<query>`
|
||||
|
||||
- **Output**
|
||||
|
||||
```json5
|
||||
{
|
||||
"query": <query>, // same as in input
|
||||
"page": <page>, // same as in input
|
||||
"pageSize": <page-size>,
|
||||
"total": <total-count>,
|
||||
"comments": [
|
||||
<comment>,
|
||||
<comment>,
|
||||
<comment>
|
||||
]
|
||||
}
|
||||
```
|
||||
...where `<comment>` is a [comment resource](#comment) and `query` contains
|
||||
standard [search query](#search).
|
||||
|
||||
- **Errors**
|
||||
|
||||
- privileges are too low
|
||||
|
||||
- **Description**
|
||||
|
||||
Searches for comments.
|
||||
|
||||
**Anonymous tokens**
|
||||
|
||||
Same as `text` token.
|
||||
|
||||
**Named tokens**
|
||||
|
||||
| `<value>` | Description |
|
||||
| ---------------- | ---------------------------------------------- |
|
||||
| `id` | specific comment ID |
|
||||
| `post` | specific post ID |
|
||||
| `user` | created by given user (accepts wildcards) |
|
||||
| `text` | containing given text (accepts wildcards) |
|
||||
| `creation-date` | created at given date |
|
||||
| `creation-time` | alias of `creation-date` |
|
||||
| `last-edit-date` | whose most recent edit date matches given date |
|
||||
| `last-edit-time` | alias of `last-edit-date` |
|
||||
| `edit-date` | alias of `last-edit-date` |
|
||||
| `edit-time` | alias of `last-edit-date` |
|
||||
|
||||
**Sort style tokens**
|
||||
|
||||
| `<value>` | Description |
|
||||
| ---------------- | ------------------------- |
|
||||
| `random` | as random as it can get |
|
||||
| `user` | author name, A to Z |
|
||||
| `post` | post ID, newest to oldest |
|
||||
| `creation-date` | newest to oldest |
|
||||
| `creation-time` | alias of `creation-date` |
|
||||
| `last-edit-date` | recently edited first |
|
||||
| `last-edit-time` | alias of `last-edit-date` |
|
||||
| `edit-date` | alias of `last-edit-date` |
|
||||
| `edit-time` | alias of `last-edit-date` |
|
||||
|
||||
**Special tokens**
|
||||
|
||||
None.
|
||||
|
||||
|
||||
## Creating comment
|
||||
- **Request**
|
||||
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
import datetime
|
||||
from szurubooru import search
|
||||
from szurubooru.api.base_api import BaseApi
|
||||
from szurubooru.func import auth, comments, posts
|
||||
|
||||
class CommentListApi(BaseApi):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._search_executor = search.SearchExecutor(
|
||||
search.CommentSearchConfig())
|
||||
|
||||
def get(self, ctx):
|
||||
raise NotImplementedError()
|
||||
auth.verify_privilege(ctx.user, 'comments:list')
|
||||
return self._search_executor.execute_and_serialize(
|
||||
ctx,
|
||||
lambda comment: comments.serialize_comment(comment, ctx.user),
|
||||
'comments')
|
||||
|
||||
def post(self, ctx):
|
||||
auth.verify_privilege(ctx.user, 'comments:create')
|
||||
|
|
|
@ -4,3 +4,4 @@ from szurubooru.search.search_executor import SearchExecutor
|
|||
from szurubooru.search.user_search_config import UserSearchConfig
|
||||
from szurubooru.search.snapshot_search_config import SnapshotSearchConfig
|
||||
from szurubooru.search.tag_search_config import TagSearchConfig
|
||||
from szurubooru.search.comment_search_config import CommentSearchConfig
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
from sqlalchemy.sql.expression import func
|
||||
from szurubooru import db
|
||||
from szurubooru.search.base_search_config import BaseSearchConfig
|
||||
|
||||
class CommentSearchConfig(BaseSearchConfig):
|
||||
def create_query(self):
|
||||
return db.session.query(db.Comment).join(db.User)
|
||||
|
||||
def finalize_query(self, query):
|
||||
return query.order_by(db.Comment.creation_time.desc())
|
||||
|
||||
@property
|
||||
def anonymous_filter(self):
|
||||
return self._create_str_filter(db.Comment.text)
|
||||
|
||||
@property
|
||||
def named_filters(self):
|
||||
return {
|
||||
'id': self._create_num_filter(db.Comment.comment_id),
|
||||
'post': self._create_num_filter(db.Comment.post_id),
|
||||
'user': self._create_str_filter(db.User.name),
|
||||
'text': self._create_str_filter(db.Comment.text),
|
||||
'creation-date': self._create_date_filter(db.Comment.creation_time),
|
||||
'creation-time': self._create_date_filter(db.Comment.creation_time),
|
||||
'last-edit-date': self._create_date_filter(db.Comment.last_edit_time),
|
||||
'last-edit-time': self._create_date_filter(db.Comment.last_edit_time),
|
||||
'edit-date': self._create_date_filter(db.Comment.last_edit_time),
|
||||
'edit-time': self._create_date_filter(db.Comment.last_edit_time),
|
||||
}
|
||||
|
||||
@property
|
||||
def sort_columns(self):
|
||||
return {
|
||||
'random': (func.random(), None),
|
||||
'user': (db.User.name, self.SORT_ASC),
|
||||
'post': (db.Comment.post_id, self.SORT_DESC),
|
||||
'creation-date': (db.Comment.creation_time, self.SORT_DESC),
|
||||
'creation-time': (db.Comment.creation_time, self.SORT_DESC),
|
||||
'last-edit-date': (db.Comment.last_edit_time, self.SORT_DESC),
|
||||
'last-edit-time': (db.Comment.last_edit_time, self.SORT_DESC),
|
||||
'edit-date': (db.Comment.last_edit_time, self.SORT_DESC),
|
||||
'edit-time': (db.Comment.last_edit_time, self.SORT_DESC),
|
||||
}
|
|
@ -14,7 +14,7 @@ class SnapshotSearchConfig(BaseSearchConfig):
|
|||
'type': self._create_str_filter(db.Snapshot.resource_type),
|
||||
'id': self._create_str_filter(db.Snapshot.resource_repr),
|
||||
'date': self._create_date_filter(db.Snapshot.creation_time),
|
||||
'time': self._create_str_filter(db.Snapshot.creation_time),
|
||||
'time': self._create_date_filter(db.Snapshot.creation_time),
|
||||
'operation': self._create_str_filter(db.Snapshot.operation),
|
||||
'user': self._create_str_filter(db.User.name),
|
||||
}
|
||||
|
|
|
@ -18,9 +18,31 @@ def test_ctx(context_factory, config_injector, user_factory, comment_factory):
|
|||
ret.context_factory = context_factory
|
||||
ret.user_factory = user_factory
|
||||
ret.comment_factory = comment_factory
|
||||
ret.list_api = api.CommentListApi()
|
||||
ret.detail_api = api.CommentDetailApi()
|
||||
return ret
|
||||
|
||||
def test_retrieving_multiple(test_ctx):
|
||||
comment1 = test_ctx.comment_factory(text='text 1')
|
||||
comment2 = test_ctx.comment_factory(text='text 2')
|
||||
db.session.add_all([comment1, comment2])
|
||||
result = test_ctx.list_api.get(
|
||||
test_ctx.context_factory(
|
||||
input={'query': '', 'page': 1},
|
||||
user=test_ctx.user_factory(rank='regular_user')))
|
||||
assert result['query'] == ''
|
||||
assert result['page'] == 1
|
||||
assert result['pageSize'] == 100
|
||||
assert result['total'] == 2
|
||||
assert [c['text'] for c in result['comments']] == ['text 1', 'text 2']
|
||||
|
||||
def test_trying_to_retrieve_multiple_without_privileges(test_ctx):
|
||||
with pytest.raises(errors.AuthError):
|
||||
test_ctx.list_api.get(
|
||||
test_ctx.context_factory(
|
||||
input={'query': '', 'page': 1},
|
||||
user=test_ctx.user_factory(rank='anonymous')))
|
||||
|
||||
def test_retrieving_single(test_ctx):
|
||||
comment = test_ctx.comment_factory(text='dummy text')
|
||||
db.session.add(comment)
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
import datetime
|
||||
import pytest
|
||||
from szurubooru import db, errors, search
|
||||
|
||||
@pytest.fixture
|
||||
def executor():
|
||||
search_config = search.CommentSearchConfig()
|
||||
return search.SearchExecutor(search_config)
|
||||
|
||||
@pytest.fixture
|
||||
def verify_unpaged(executor):
|
||||
def verify(input, expected_comment_text):
|
||||
actual_count, actual_comments = executor.execute(
|
||||
input, page=1, page_size=100)
|
||||
print(actual_comments)
|
||||
actual_comment_text = [c.text for c in actual_comments]
|
||||
assert actual_count == len(expected_comment_text)
|
||||
assert actual_comment_text == expected_comment_text
|
||||
return verify
|
||||
|
||||
@pytest.mark.parametrize('input,expected_comment_text', [
|
||||
('creation-time:2014', ['t2', 't1']),
|
||||
('creation-date:2014', ['t2', 't1']),
|
||||
])
|
||||
def test_filter_by_creation_time(
|
||||
verify_unpaged, comment_factory, input, expected_comment_text):
|
||||
comment1 = comment_factory(text='t1')
|
||||
comment2 = comment_factory(text='t2')
|
||||
comment3 = comment_factory(text='t3')
|
||||
comment1.creation_time = datetime.datetime(2014, 1, 1)
|
||||
comment2.creation_time = datetime.datetime(2014, 6, 1)
|
||||
comment3.creation_time = datetime.datetime(2015, 1, 1)
|
||||
db.session.add_all([comment1, comment2, comment3])
|
||||
verify_unpaged(input, expected_comment_text)
|
||||
|
||||
@pytest.mark.parametrize('input,expected_comment_text', [
|
||||
('text:t1', ['t1']),
|
||||
('text:t2', ['t2']),
|
||||
('text:t1,t2', ['t1', 't2']),
|
||||
('text:t*', ['t1', 't2']),
|
||||
])
|
||||
def test_filter_by_text(
|
||||
verify_unpaged, comment_factory, input, expected_comment_text):
|
||||
comment1 = comment_factory(text='t1')
|
||||
comment2 = comment_factory(text='t2')
|
||||
db.session.add_all([comment1, comment2])
|
||||
verify_unpaged(input, expected_comment_text)
|
||||
|
||||
@pytest.mark.parametrize('input,expected_comment_text', [
|
||||
('user:u1', ['t1']),
|
||||
('user:u2', ['t2']),
|
||||
('user:u1,u2', ['t2', 't1']),
|
||||
])
|
||||
def test_filter_by_user(
|
||||
verify_unpaged, comment_factory, user_factory, input, expected_comment_text):
|
||||
db.session.add(comment_factory(text='t2', user=user_factory(name='u2')))
|
||||
db.session.add(comment_factory(text='t1', user=user_factory(name='u1')))
|
||||
verify_unpaged(input, expected_comment_text)
|
||||
|
||||
@pytest.mark.parametrize('input,expected_comment_text', [
|
||||
('post:1', ['t1']),
|
||||
('post:2', ['t2']),
|
||||
('post:1,2', ['t1', 't2']),
|
||||
])
|
||||
def test_filter_by_post(
|
||||
verify_unpaged, comment_factory, post_factory, input, expected_comment_text):
|
||||
db.session.add(comment_factory(text='t1', post=post_factory(id=1)))
|
||||
db.session.add(comment_factory(text='t2', post=post_factory(id=2)))
|
||||
verify_unpaged(input, expected_comment_text)
|
||||
|
||||
@pytest.mark.parametrize('input,expected_comment_text', [
|
||||
('', ['t1', 't2']),
|
||||
('t1', ['t1']),
|
||||
('t2', ['t2']),
|
||||
('t1,t2', ['t1', 't2']),
|
||||
])
|
||||
def test_anonymous(verify_unpaged, comment_factory, input, expected_comment_text):
|
||||
db.session.add(comment_factory(text='t1'))
|
||||
db.session.add(comment_factory(text='t2'))
|
||||
verify_unpaged(input, expected_comment_text)
|
||||
|
||||
@pytest.mark.parametrize('input,expected_comment_text', [
|
||||
('sort:user', ['t1', 't2']),
|
||||
])
|
||||
def test_sort_by_user(
|
||||
verify_unpaged, comment_factory, user_factory, input, expected_comment_text):
|
||||
db.session.add(comment_factory(text='t2', user=user_factory(name='u2')))
|
||||
db.session.add(comment_factory(text='t1', user=user_factory(name='u1')))
|
||||
verify_unpaged(input, expected_comment_text)
|
||||
|
||||
@pytest.mark.parametrize('input,expected_comment_text', [
|
||||
('sort:post', ['t2', 't1']),
|
||||
])
|
||||
def test_sort_by_post(
|
||||
verify_unpaged, comment_factory, post_factory, input, expected_comment_text):
|
||||
db.session.add(comment_factory(text='t1', post=post_factory(id=1)))
|
||||
db.session.add(comment_factory(text='t2', post=post_factory(id=2)))
|
||||
verify_unpaged(input, expected_comment_text)
|
||||
|
||||
@pytest.mark.parametrize('input,expected_comment_text', [
|
||||
('', ['t3', 't2', 't1']),
|
||||
('sort:creation-date', ['t3', 't2', 't1']),
|
||||
('sort:creation-time', ['t3', 't2', 't1']),
|
||||
])
|
||||
def test_sort_by_creation_time(
|
||||
verify_unpaged, comment_factory, input, expected_comment_text):
|
||||
comment1 = comment_factory(text='t1')
|
||||
comment2 = comment_factory(text='t2')
|
||||
comment3 = comment_factory(text='t3')
|
||||
comment1.creation_time = datetime.datetime(1991, 1, 1)
|
||||
comment2.creation_time = datetime.datetime(1991, 1, 2)
|
||||
comment3.creation_time = datetime.datetime(1991, 1, 3)
|
||||
db.session.add_all([comment3, comment1, comment2])
|
||||
verify_unpaged(input, expected_comment_text)
|
||||
|
||||
@pytest.mark.parametrize('input,expected_comment_text', [
|
||||
('sort:last-edit-date', ['t3', 't2', 't1']),
|
||||
('sort:last-edit-time', ['t3', 't2', 't1']),
|
||||
('sort:edit-date', ['t3', 't2', 't1']),
|
||||
('sort:edit-time', ['t3', 't2', 't1']),
|
||||
])
|
||||
def test_sort_by_last_edit_time(
|
||||
verify_unpaged, comment_factory, input, expected_comment_text):
|
||||
comment1 = comment_factory(text='t1')
|
||||
comment2 = comment_factory(text='t2')
|
||||
comment3 = comment_factory(text='t3')
|
||||
comment1.last_edit_time = datetime.datetime(1991, 1, 1)
|
||||
comment2.last_edit_time = datetime.datetime(1991, 1, 2)
|
||||
comment3.last_edit_time = datetime.datetime(1991, 1, 3)
|
||||
db.session.add_all([comment3, comment1, comment2])
|
||||
verify_unpaged(input, expected_comment_text)
|
|
@ -102,13 +102,13 @@ def test_sort_by_name(verify_unpaged, tag_factory, input, expected_tag_names):
|
|||
db.session.add(tag_factory(names=['t1']))
|
||||
verify_unpaged(input, expected_tag_names)
|
||||
|
||||
@pytest.mark.parametrize('input,expected_user_names', [
|
||||
@pytest.mark.parametrize('input,expected_tag_names', [
|
||||
('', ['t1', 't2', 't3']),
|
||||
('sort:creation-date', ['t3', 't2', 't1']),
|
||||
('sort:creation-time', ['t3', 't2', 't1']),
|
||||
])
|
||||
def test_sort_by_creation_time(
|
||||
verify_unpaged, tag_factory, input, expected_user_names):
|
||||
verify_unpaged, tag_factory, input, expected_tag_names):
|
||||
tag1 = tag_factory(names=['t1'])
|
||||
tag2 = tag_factory(names=['t2'])
|
||||
tag3 = tag_factory(names=['t3'])
|
||||
|
@ -116,7 +116,7 @@ def test_sort_by_creation_time(
|
|||
tag2.creation_time = datetime.datetime(1991, 1, 2)
|
||||
tag3.creation_time = datetime.datetime(1991, 1, 3)
|
||||
db.session.add_all([tag3, tag1, tag2])
|
||||
verify_unpaged(input, expected_user_names)
|
||||
verify_unpaged(input, expected_tag_names)
|
||||
|
||||
@pytest.mark.parametrize('input,expected_tag_names', [
|
||||
('sort:suggestion-count', ['t1', 't2', 'sug1', 'sug2', 'sug3']),
|
||||
|
|
Loading…
Reference in New Issue