server/comments+posts: add rating
This commit is contained in:
parent
8fb536c8f0
commit
52f4018bee
84
API.md
84
API.md
|
@ -33,7 +33,7 @@
|
||||||
- ~~Updating post~~
|
- ~~Updating post~~
|
||||||
- ~~Getting post~~
|
- ~~Getting post~~
|
||||||
- ~~Deleting post~~
|
- ~~Deleting post~~
|
||||||
- ~~Rating post~~
|
- [Rating post](#rating-post)
|
||||||
- ~~Adding post to favorites~~
|
- ~~Adding post to favorites~~
|
||||||
- ~~Removing post from favorites~~
|
- ~~Removing post from favorites~~
|
||||||
- [Getting featured post](#getting-featured-post)
|
- [Getting featured post](#getting-featured-post)
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
- [Updating comment](#updating-comment)
|
- [Updating comment](#updating-comment)
|
||||||
- [Getting comment](#getting-comment)
|
- [Getting comment](#getting-comment)
|
||||||
- [Deleting comment](#deleting-comment)
|
- [Deleting comment](#deleting-comment)
|
||||||
- ~~Rating comment~~
|
- [Rating comment](#rating-comment)
|
||||||
- Users
|
- Users
|
||||||
- [Listing users](#listing-users)
|
- [Listing users](#listing-users)
|
||||||
- [Creating user](#creating-user)
|
- [Creating user](#creating-user)
|
||||||
|
@ -612,6 +612,40 @@ data.
|
||||||
list is truncated to the first 50 elements. Doesn't use paging.
|
list is truncated to the first 50 elements. Doesn't use paging.
|
||||||
|
|
||||||
|
|
||||||
|
## Rating post
|
||||||
|
- **Request**
|
||||||
|
|
||||||
|
`PUT /post/<id>/score`
|
||||||
|
|
||||||
|
- **Input**
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"score": <score>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Output**
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"post": <post>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
...where `<post>` is a [post resource](#post).
|
||||||
|
|
||||||
|
- **Errors**
|
||||||
|
|
||||||
|
- post does not exist
|
||||||
|
- score is invalid
|
||||||
|
- privileges are too low
|
||||||
|
|
||||||
|
- **Description**
|
||||||
|
|
||||||
|
Updates score of authenticated user for given post. Valid scores are -1, 0
|
||||||
|
and 1.
|
||||||
|
|
||||||
|
|
||||||
## Getting featured post
|
## Getting featured post
|
||||||
- **Request**
|
- **Request**
|
||||||
|
|
||||||
|
@ -854,6 +888,40 @@ data.
|
||||||
Deletes existing comment.
|
Deletes existing comment.
|
||||||
|
|
||||||
|
|
||||||
|
## Rating comment
|
||||||
|
- **Request**
|
||||||
|
|
||||||
|
`PUT /comment/<id>/score`
|
||||||
|
|
||||||
|
- **Input**
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"score": <score>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Output**
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"comment": <comment>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
...where `<comment>` is a [comment resource](#comment).
|
||||||
|
|
||||||
|
- **Errors**
|
||||||
|
|
||||||
|
- comment does not exist
|
||||||
|
- score is invalid
|
||||||
|
- privileges are too low
|
||||||
|
|
||||||
|
- **Description**
|
||||||
|
|
||||||
|
Updates score of authenticated user for given comment. Valid scores are -1,
|
||||||
|
0 and 1.
|
||||||
|
|
||||||
|
|
||||||
## Listing users
|
## Listing users
|
||||||
- **Request**
|
- **Request**
|
||||||
|
|
||||||
|
@ -1317,6 +1385,7 @@ One file together with its metadata posted to the site.
|
||||||
"lastEditTime": <last-edit-time>,
|
"lastEditTime": <last-edit-time>,
|
||||||
"user": <user>,
|
"user": <user>,
|
||||||
"score": <score>,
|
"score": <score>,
|
||||||
|
"ownScore": <own-score>,
|
||||||
"favoritedBy": <favorited-by>,
|
"favoritedBy": <favorited-by>,
|
||||||
"featureCount": <feature-count>,
|
"featureCount": <feature-count>,
|
||||||
"lastFeatureTime": <last-feature-time>,
|
"lastFeatureTime": <last-feature-time>,
|
||||||
|
@ -1357,7 +1426,9 @@ One file together with its metadata posted to the site.
|
||||||
- `<creation-time>`: time the tag was created, formatted as per RFC 3339.
|
- `<creation-time>`: time the tag was created, formatted as per RFC 3339.
|
||||||
- `<last-edit-time>`: time the tag was edited, formatted as per RFC 3339.
|
- `<last-edit-time>`: time the tag was edited, formatted as per RFC 3339.
|
||||||
- `<user>`: who created the post, serialized as [user resource](#user).
|
- `<user>`: who created the post, serialized as [user resource](#user).
|
||||||
- `<score>`: the score (+1/-1 rating) of the given post.
|
- `<score>`: the collective score (+1/-1 rating) of the given post.
|
||||||
|
- `<own-score>`: the score (+1/-1 rating) of the given post by the
|
||||||
|
authenticated user.
|
||||||
- `<favorited-by>`: list of users, serialized as [user resources](#user).
|
- `<favorited-by>`: list of users, serialized as [user resources](#user).
|
||||||
- `<feature-count>`: how many times has the post been featured.
|
- `<feature-count>`: how many times has the post been featured.
|
||||||
- `<last-feature-time>`: the last time the post was featured, formatted as per
|
- `<last-feature-time>`: the last time the post was featured, formatted as per
|
||||||
|
@ -1377,7 +1448,9 @@ A comment under a post.
|
||||||
"user": <author>
|
"user": <author>
|
||||||
"text": <text>,
|
"text": <text>,
|
||||||
"creationTime": <creation-time>,
|
"creationTime": <creation-time>,
|
||||||
"lastEditTime": <last-edit-time>
|
"lastEditTime": <last-edit-time>,
|
||||||
|
"score": <score>,
|
||||||
|
"ownScore": <own-score>
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1387,6 +1460,9 @@ A comment under a post.
|
||||||
- `<author>`: a user resource the post is created by.
|
- `<author>`: a user resource the post is created by.
|
||||||
- `<creation-time>`: time the comment was created, formatted as per RFC 3339.
|
- `<creation-time>`: time the comment was created, formatted as per RFC 3339.
|
||||||
- `<last-edit-time>`: time the comment was edited, formatted as per RFC 3339.
|
- `<last-edit-time>`: time the comment was edited, formatted as per RFC 3339.
|
||||||
|
- `<score>`: the collective score (+1/-1 rating) of the given comment.
|
||||||
|
- `<own-score>`: the score (+1/-1 rating) of the given comment by the
|
||||||
|
authenticated user.
|
||||||
|
|
||||||
|
|
||||||
## Snapshot
|
## Snapshot
|
||||||
|
|
|
@ -93,6 +93,7 @@ privileges:
|
||||||
'posts:edit:thumbnail': power_user
|
'posts:edit:thumbnail': power_user
|
||||||
'posts:feature': mod
|
'posts:feature': mod
|
||||||
'posts:delete': mod
|
'posts:delete': mod
|
||||||
|
'posts:score': regular_user
|
||||||
|
|
||||||
'tags:create': regular_user
|
'tags:create': regular_user
|
||||||
'tags:edit:names': power_user
|
'tags:edit:names': power_user
|
||||||
|
@ -119,5 +120,6 @@ privileges:
|
||||||
'comments:edit:own': regular_user
|
'comments:edit:own': regular_user
|
||||||
'comments:list': regular_user
|
'comments:list': regular_user
|
||||||
'comments:view': regular_user
|
'comments:view': regular_user
|
||||||
|
'comments:score': regular_user
|
||||||
|
|
||||||
'snapshots:list': power_user
|
'snapshots:list': power_user
|
||||||
|
|
|
@ -12,8 +12,11 @@ from szurubooru.api.tag_category_api import (
|
||||||
TagCategoryDetailApi)
|
TagCategoryDetailApi)
|
||||||
from szurubooru.api.comment_api import (
|
from szurubooru.api.comment_api import (
|
||||||
CommentListApi,
|
CommentListApi,
|
||||||
CommentDetailApi)
|
CommentDetailApi,
|
||||||
from szurubooru.api.post_api import PostFeatureApi
|
CommentScoreApi)
|
||||||
|
from szurubooru.api.post_api import (
|
||||||
|
PostFeatureApi,
|
||||||
|
PostScoreApi)
|
||||||
from szurubooru.api.snapshot_api import SnapshotListApi
|
from szurubooru.api.snapshot_api import SnapshotListApi
|
||||||
from szurubooru.api.info_api import InfoApi
|
from szurubooru.api.info_api import InfoApi
|
||||||
from szurubooru.api.context import Context, Request
|
from szurubooru.api.context import Context, Request
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import datetime
|
import datetime
|
||||||
from szurubooru import search
|
from szurubooru import search
|
||||||
from szurubooru.api.base_api import BaseApi
|
from szurubooru.api.base_api import BaseApi
|
||||||
from szurubooru.func import auth, comments, posts
|
from szurubooru.func import auth, comments, posts, scores
|
||||||
|
|
||||||
class CommentListApi(BaseApi):
|
class CommentListApi(BaseApi):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -49,3 +49,19 @@ class CommentDetailApi(BaseApi):
|
||||||
ctx.session.delete(comment)
|
ctx.session.delete(comment)
|
||||||
ctx.session.commit()
|
ctx.session.commit()
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
class CommentScoreApi(BaseApi):
|
||||||
|
def put(self, ctx, comment_id):
|
||||||
|
auth.verify_privilege(ctx.user, 'comments:score')
|
||||||
|
score = ctx.get_param_as_int('score', required=True)
|
||||||
|
comment = comments.get_comment_by_id(comment_id)
|
||||||
|
scores.set_score(comment, ctx.user, score)
|
||||||
|
ctx.session.commit()
|
||||||
|
return {'comment': comments.serialize_comment(comment, ctx.user)}
|
||||||
|
|
||||||
|
def delete(self, ctx, comment_id):
|
||||||
|
auth.verify_privilege(ctx.user, 'comments:score')
|
||||||
|
comment = comments.get_comment_by_id(comment_id)
|
||||||
|
scores.delete_score(comment, ctx.user)
|
||||||
|
ctx.session.commit()
|
||||||
|
return {'comment': comments.serialize_comment(comment, ctx.user)}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from szurubooru.api.base_api import BaseApi
|
from szurubooru.api.base_api import BaseApi
|
||||||
from szurubooru.func import auth, posts, snapshots
|
from szurubooru.func import auth, posts, snapshots, scores
|
||||||
|
|
||||||
class PostFeatureApi(BaseApi):
|
class PostFeatureApi(BaseApi):
|
||||||
def post(self, ctx):
|
def post(self, ctx):
|
||||||
|
@ -20,3 +20,19 @@ class PostFeatureApi(BaseApi):
|
||||||
def get(self, ctx):
|
def get(self, ctx):
|
||||||
post = posts.try_get_featured_post()
|
post = posts.try_get_featured_post()
|
||||||
return posts.serialize_post_with_details(post, ctx.user)
|
return posts.serialize_post_with_details(post, ctx.user)
|
||||||
|
|
||||||
|
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 {'post': posts.serialize_post(post, ctx.user)}
|
||||||
|
|
||||||
|
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 {'post': posts.serialize_post(post, ctx.user)}
|
||||||
|
|
|
@ -47,21 +47,6 @@ def create_app():
|
||||||
middleware.Authenticator(),
|
middleware.Authenticator(),
|
||||||
])
|
])
|
||||||
|
|
||||||
user_list_api = api.UserListApi()
|
|
||||||
user_detail_api = api.UserDetailApi()
|
|
||||||
tag_category_list_api = api.TagCategoryListApi()
|
|
||||||
tag_category_detail_api = api.TagCategoryDetailApi()
|
|
||||||
tag_list_api = api.TagListApi()
|
|
||||||
tag_detail_api = api.TagDetailApi()
|
|
||||||
tag_merge_api = api.TagMergeApi()
|
|
||||||
tag_siblings_api = api.TagSiblingsApi()
|
|
||||||
post_feature_api = api.PostFeatureApi()
|
|
||||||
password_reset_api = api.PasswordResetApi()
|
|
||||||
snapshot_list_api = api.SnapshotListApi()
|
|
||||||
comment_list_api = api.CommentListApi()
|
|
||||||
comment_detail_api = api.CommentDetailApi()
|
|
||||||
info_api = api.InfoApi()
|
|
||||||
|
|
||||||
app.add_error_handler(errors.AuthError, _on_auth_error)
|
app.add_error_handler(errors.AuthError, _on_auth_error)
|
||||||
app.add_error_handler(errors.IntegrityError, _on_integrity_error)
|
app.add_error_handler(errors.IntegrityError, _on_integrity_error)
|
||||||
app.add_error_handler(errors.ValidationError, _on_validation_error)
|
app.add_error_handler(errors.ValidationError, _on_validation_error)
|
||||||
|
@ -69,19 +54,25 @@ def create_app():
|
||||||
app.add_error_handler(errors.NotFoundError, _on_not_found_error)
|
app.add_error_handler(errors.NotFoundError, _on_not_found_error)
|
||||||
app.add_error_handler(errors.ProcessingError, _on_processing_error)
|
app.add_error_handler(errors.ProcessingError, _on_processing_error)
|
||||||
|
|
||||||
app.add_route('/users/', user_list_api)
|
app.add_route('/users/', api.UserListApi())
|
||||||
app.add_route('/user/{user_name}', user_detail_api)
|
app.add_route('/user/{user_name}', api.UserDetailApi())
|
||||||
app.add_route('/tag-categories/', tag_category_list_api)
|
app.add_route('/password-reset/{user_name}', api.PasswordResetApi())
|
||||||
app.add_route('/tag-category/{category_name}', tag_category_detail_api)
|
|
||||||
app.add_route('/tags/', tag_list_api)
|
app.add_route('/tag-categories/', api.TagCategoryListApi())
|
||||||
app.add_route('/tag/{tag_name}', tag_detail_api)
|
app.add_route('/tag-category/{category_name}', api.TagCategoryDetailApi())
|
||||||
app.add_route('/tag-merge/', tag_merge_api)
|
app.add_route('/tags/', api.TagListApi())
|
||||||
app.add_route('/tag-siblings/{tag_name}', tag_siblings_api)
|
app.add_route('/tag/{tag_name}', api.TagDetailApi())
|
||||||
app.add_route('/password-reset/{user_name}', password_reset_api)
|
app.add_route('/tag-merge/', api.TagMergeApi())
|
||||||
app.add_route('/snapshots/', snapshot_list_api)
|
app.add_route('/tag-siblings/{tag_name}', api.TagSiblingsApi())
|
||||||
app.add_route('/info/', info_api)
|
|
||||||
app.add_route('/featured-post/', post_feature_api)
|
app.add_route('/post/{post_id}/score', api.PostScoreApi())
|
||||||
app.add_route('/comments/', comment_list_api)
|
|
||||||
app.add_route('/comment/{comment_id}', comment_detail_api)
|
app.add_route('/comments/', api.CommentListApi())
|
||||||
|
app.add_route('/comment/{comment_id}', api.CommentDetailApi())
|
||||||
|
app.add_route('/comment/{comment_id}/score', api.CommentScoreApi())
|
||||||
|
|
||||||
|
app.add_route('/info/', api.InfoApi())
|
||||||
|
app.add_route('/featured-post/', api.PostFeatureApi())
|
||||||
|
app.add_route('/snapshots/', api.SnapshotListApi())
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from sqlalchemy import Column, Integer, DateTime, Text, ForeignKey
|
from sqlalchemy import Column, Integer, DateTime, Text, ForeignKey
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship, object_session
|
||||||
|
from sqlalchemy.sql.expression import func
|
||||||
from szurubooru.db.base import Base
|
from szurubooru.db.base import Base
|
||||||
|
|
||||||
class CommentScore(Base):
|
class CommentScore(Base):
|
||||||
|
@ -27,3 +28,10 @@ class Comment(Base):
|
||||||
post = relationship('Post')
|
post = relationship('Post')
|
||||||
scores = relationship(
|
scores = relationship(
|
||||||
'CommentScore', cascade='all, delete-orphan', lazy='joined')
|
'CommentScore', cascade='all, delete-orphan', lazy='joined')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def score(self):
|
||||||
|
return object_session(self) \
|
||||||
|
.query(func.sum(CommentScore.score)) \
|
||||||
|
.filter(CommentScore.comment_id == self.comment_id) \
|
||||||
|
.one()[0] or 0
|
||||||
|
|
|
@ -120,17 +120,30 @@ class Post(Base):
|
||||||
.first()
|
.first()
|
||||||
return featured_post and featured_post.post_id == self.post_id
|
return featured_post and featured_post.post_id == self.post_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def score(self):
|
||||||
|
return object_session(self) \
|
||||||
|
.query(func.sum(PostScore.score)) \
|
||||||
|
.filter(PostScore.post_id == self.post_id) \
|
||||||
|
.one()[0] or 0
|
||||||
|
|
||||||
|
feature_count = column_property(
|
||||||
|
select([func.count(PostFeature.post_id)]) \
|
||||||
|
.where(PostFeature.post_id == post_id) \
|
||||||
|
.correlate_except(PostFeature))
|
||||||
|
|
||||||
|
last_feature_time = column_property(
|
||||||
|
select([func.max(PostFeature.time)]) \
|
||||||
|
.where(PostFeature.post_id == post_id) \
|
||||||
|
.correlate_except(PostFeature))
|
||||||
|
|
||||||
# TODO: wire these
|
# TODO: wire these
|
||||||
favorite_count = Column('auto_fav_count', Integer, nullable=False, default=0)
|
#favorite_count = Column('auto_fav_count', Integer, nullable=False, default=0)
|
||||||
score = Column('auto_score', Integer, nullable=False, default=0)
|
#comment_count = Column('auto_comment_count', Integer, nullable=False, default=0)
|
||||||
feature_count = Column('auto_feature_count', Integer, nullable=False, default=0)
|
#note_count = Column('auto_note_count', Integer, nullable=False, default=0)
|
||||||
comment_count = Column('auto_comment_count', Integer, nullable=False, default=0)
|
#last_fav_time = Column(
|
||||||
note_count = Column('auto_note_count', Integer, nullable=False, default=0)
|
# 'auto_fav_time', Integer, nullable=False, default=0)
|
||||||
last_fav_time = Column(
|
#last_comment_edit_time = Column(
|
||||||
'auto_fav_time', Integer, nullable=False, default=0)
|
# 'auto_comment_creation_time', Integer, nullable=False, default=0)
|
||||||
last_feature_time = Column(
|
#last_comment_creation_time = Column(
|
||||||
'auto_feature_time', Integer, nullable=False, default=0)
|
# 'auto_comment_edit_time', Integer, nullable=False, default=0)
|
||||||
last_comment_edit_time = Column(
|
|
||||||
'auto_comment_creation_time', Integer, nullable=False, default=0)
|
|
||||||
last_comment_creation_time = Column(
|
|
||||||
'auto_comment_edit_time', Integer, nullable=False, default=0)
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import datetime
|
import datetime
|
||||||
from szurubooru import db, errors
|
from szurubooru import db, errors
|
||||||
from szurubooru.func import users, posts
|
from szurubooru.func import users, posts, scores
|
||||||
|
|
||||||
class CommentNotFoundError(errors.NotFoundError): pass
|
class CommentNotFoundError(errors.NotFoundError): pass
|
||||||
class EmptyCommentTextError(errors.ValidationError): pass
|
class EmptyCommentTextError(errors.ValidationError): pass
|
||||||
|
|
||||||
def serialize_comment(comment, authenticated_user):
|
def serialize_comment(comment, authenticated_user):
|
||||||
return {
|
ret = {
|
||||||
'id': comment.comment_id,
|
'id': comment.comment_id,
|
||||||
'user': users.serialize_user(comment.user, authenticated_user),
|
'user': users.serialize_user(comment.user, authenticated_user),
|
||||||
'post': posts.serialize_post(comment.post, authenticated_user),
|
'post': posts.serialize_post(comment.post, authenticated_user),
|
||||||
|
@ -14,6 +14,9 @@ def serialize_comment(comment, authenticated_user):
|
||||||
'creationTime': comment.creation_time,
|
'creationTime': comment.creation_time,
|
||||||
'lastEditTime': comment.last_edit_time,
|
'lastEditTime': comment.last_edit_time,
|
||||||
}
|
}
|
||||||
|
if authenticated_user:
|
||||||
|
ret['ownScore'] = scores.get_score(comment, authenticated_user)
|
||||||
|
return ret
|
||||||
|
|
||||||
def try_get_comment_by_id(comment_id):
|
def try_get_comment_by_id(comment_id):
|
||||||
return db.session \
|
return db.session \
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import datetime
|
import datetime
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
from szurubooru import db, errors
|
from szurubooru import db, errors
|
||||||
from szurubooru.func import users, snapshots
|
from szurubooru.func import users, snapshots, scores
|
||||||
|
|
||||||
class PostNotFoundError(errors.NotFoundError): pass
|
class PostNotFoundError(errors.NotFoundError): pass
|
||||||
class PostAlreadyFeaturedError(errors.ValidationError): pass
|
class PostAlreadyFeaturedError(errors.ValidationError): pass
|
||||||
|
@ -36,7 +36,8 @@ def serialize_post(post, authenticated_user):
|
||||||
for rel in post.favorited_by],
|
for rel in post.favorited_by],
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO: fetch own score if needed
|
if authenticated_user:
|
||||||
|
ret['ownScore'] = scores.get_score(post, authenticated_user)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import datetime
|
||||||
|
from szurubooru import db, errors
|
||||||
|
from szurubooru.func import util
|
||||||
|
|
||||||
|
class InvalidScoreError(errors.ValidationError): pass
|
||||||
|
|
||||||
|
def _get_table_info(entity):
|
||||||
|
resource_type, _, _ = util.get_resource_info(entity)
|
||||||
|
if resource_type == 'post':
|
||||||
|
return db.PostScore, lambda table: table.post_id
|
||||||
|
elif resource_type == 'comment':
|
||||||
|
return db.CommentScore, lambda table: table.comment_id
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
|
def _get_score_entity(entity, user):
|
||||||
|
table, get_column = _get_table_info(entity)
|
||||||
|
return db.session \
|
||||||
|
.query(table) \
|
||||||
|
.filter(get_column(table) == get_column(entity)) \
|
||||||
|
.filter(table.user_id == user.user_id) \
|
||||||
|
.one_or_none()
|
||||||
|
|
||||||
|
def delete_score(entity, user):
|
||||||
|
score_entity = _get_score_entity(entity, user)
|
||||||
|
if score_entity:
|
||||||
|
db.session.delete(score_entity)
|
||||||
|
|
||||||
|
def get_score(entity, user):
|
||||||
|
score_entity = _get_score_entity(entity, user)
|
||||||
|
if score_entity:
|
||||||
|
return score_entity.score
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def set_score(entity, user, score):
|
||||||
|
if not score:
|
||||||
|
delete_score(entity, user)
|
||||||
|
return
|
||||||
|
if score not in (-1, 1):
|
||||||
|
raise InvalidScoreError(
|
||||||
|
'Score %r is invalid. Valid scores: %r.' % (score, (-1, 1)))
|
||||||
|
score_entity = _get_score_entity(entity, user)
|
||||||
|
if score_entity:
|
||||||
|
score_entity.score = score
|
||||||
|
else:
|
||||||
|
table, get_column = _get_table_info(entity)
|
||||||
|
score_entity = table()
|
||||||
|
setattr(score_entity, get_column(table).name, get_column(entity))
|
||||||
|
score_entity.score = score
|
||||||
|
score_entity.user = user
|
||||||
|
score_entity.time = datetime.datetime.now()
|
||||||
|
db.session.add(score_entity)
|
|
@ -1,6 +1,6 @@
|
||||||
import datetime
|
import datetime
|
||||||
from sqlalchemy.inspection import inspect
|
|
||||||
from szurubooru import db
|
from szurubooru import db
|
||||||
|
from szurubooru.func import util
|
||||||
|
|
||||||
def get_tag_snapshot(tag):
|
def get_tag_snapshot(tag):
|
||||||
return {
|
return {
|
||||||
|
@ -33,33 +33,11 @@ def get_tag_category_snapshot(category):
|
||||||
|
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
serializers = {
|
serializers = {
|
||||||
'tag': (
|
'tag': get_tag_snapshot,
|
||||||
get_tag_snapshot,
|
'tag_category': get_tag_category_snapshot,
|
||||||
lambda tag: tag.first_name),
|
'post': get_post_snapshot,
|
||||||
'tag_category': (
|
|
||||||
get_tag_category_snapshot,
|
|
||||||
lambda category: category.name),
|
|
||||||
'post': (
|
|
||||||
get_post_snapshot,
|
|
||||||
lambda post: post.post_id),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_resource_info(entity):
|
|
||||||
resource_type = entity.__table__.name
|
|
||||||
assert resource_type in serializers
|
|
||||||
|
|
||||||
primary_key = inspect(entity).identity
|
|
||||||
assert primary_key is not None
|
|
||||||
assert len(primary_key) == 1
|
|
||||||
|
|
||||||
resource_repr = serializers[resource_type][1](entity)
|
|
||||||
assert resource_repr
|
|
||||||
|
|
||||||
resource_id = primary_key[0]
|
|
||||||
assert resource_id
|
|
||||||
|
|
||||||
return (resource_type, resource_id, resource_repr)
|
|
||||||
|
|
||||||
def get_previous_snapshot(snapshot):
|
def get_previous_snapshot(snapshot):
|
||||||
return db.session \
|
return db.session \
|
||||||
.query(db.Snapshot) \
|
.query(db.Snapshot) \
|
||||||
|
@ -71,7 +49,7 @@ def get_previous_snapshot(snapshot):
|
||||||
.first()
|
.first()
|
||||||
|
|
||||||
def get_snapshots(entity):
|
def get_snapshots(entity):
|
||||||
resource_type, resource_id, _ = get_resource_info(entity)
|
resource_type, resource_id, _ = util.get_resource_info(entity)
|
||||||
return db.session \
|
return db.session \
|
||||||
.query(db.Snapshot) \
|
.query(db.Snapshot) \
|
||||||
.filter(db.Snapshot.resource_type == resource_type) \
|
.filter(db.Snapshot.resource_type == resource_type) \
|
||||||
|
@ -103,7 +81,7 @@ def get_serialized_history(entity):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def save(operation, entity, auth_user):
|
def save(operation, entity, auth_user):
|
||||||
resource_type, resource_id, resource_repr = get_resource_info(entity)
|
resource_type, resource_id, resource_repr = util.get_resource_info(entity)
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
|
|
||||||
snapshot = db.Snapshot()
|
snapshot = db.Snapshot()
|
||||||
|
@ -112,7 +90,7 @@ def save(operation, entity, auth_user):
|
||||||
snapshot.resource_type = resource_type
|
snapshot.resource_type = resource_type
|
||||||
snapshot.resource_id = resource_id
|
snapshot.resource_id = resource_id
|
||||||
snapshot.resource_repr = resource_repr
|
snapshot.resource_repr = resource_repr
|
||||||
snapshot.data = serializers[resource_type][0](entity)
|
snapshot.data = serializers[resource_type](entity)
|
||||||
snapshot.user = auth_user
|
snapshot.user = auth_user
|
||||||
|
|
||||||
earlier_snapshots = get_snapshots(entity)
|
earlier_snapshots = get_snapshots(entity)
|
||||||
|
|
|
@ -1,7 +1,31 @@
|
||||||
import datetime
|
import datetime
|
||||||
import re
|
import re
|
||||||
|
from sqlalchemy.inspection import inspect
|
||||||
from szurubooru.errors import ValidationError
|
from szurubooru.errors import ValidationError
|
||||||
|
|
||||||
|
def get_resource_info(entity):
|
||||||
|
serializers = {
|
||||||
|
'tag': lambda tag: tag.first_name,
|
||||||
|
'tag_category': lambda category: category.name,
|
||||||
|
'comment': lambda comment: comment.comment_id,
|
||||||
|
'post': lambda post: post.post_id,
|
||||||
|
}
|
||||||
|
|
||||||
|
resource_type = entity.__table__.name
|
||||||
|
assert resource_type in serializers
|
||||||
|
|
||||||
|
primary_key = inspect(entity).identity
|
||||||
|
assert primary_key is not None
|
||||||
|
assert len(primary_key) == 1
|
||||||
|
|
||||||
|
resource_repr = serializers[resource_type](entity)
|
||||||
|
assert resource_repr
|
||||||
|
|
||||||
|
resource_id = primary_key[0]
|
||||||
|
assert resource_id
|
||||||
|
|
||||||
|
return (resource_type, resource_id, resource_repr)
|
||||||
|
|
||||||
def is_valid_email(email):
|
def is_valid_email(email):
|
||||||
''' Return whether given email address is valid or empty. '''
|
''' Return whether given email address is valid or empty. '''
|
||||||
return not email or re.match(r'^[^@]*@[^@]*\.[^@]*$', email)
|
return not email or re.match(r'^[^@]*@[^@]*\.[^@]*$', email)
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
'''
|
||||||
|
Delete post columns
|
||||||
|
|
||||||
|
Revision ID: ed6dd16a30f3
|
||||||
|
Created at: 2016-04-24 16:29:25.309154
|
||||||
|
'''
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
revision = 'ed6dd16a30f3'
|
||||||
|
down_revision = '46df355634dc'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.drop_column('post', 'auto_comment_edit_time')
|
||||||
|
op.drop_column('post', 'auto_fav_count')
|
||||||
|
op.drop_column('post', 'auto_comment_creation_time')
|
||||||
|
op.drop_column('post', 'auto_feature_count')
|
||||||
|
op.drop_column('post', 'auto_comment_count')
|
||||||
|
op.drop_column('post', 'auto_score')
|
||||||
|
op.drop_column('post', 'auto_fav_time')
|
||||||
|
op.drop_column('post', 'auto_feature_time')
|
||||||
|
op.drop_column('post', 'auto_note_count')
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.add_column('post', sa.Column('auto_note_count', sa.INTEGER(), autoincrement=False, nullable=False))
|
||||||
|
op.add_column('post', sa.Column('auto_feature_time', sa.INTEGER(), autoincrement=False, nullable=False))
|
||||||
|
op.add_column('post', sa.Column('auto_fav_time', sa.INTEGER(), autoincrement=False, nullable=False))
|
||||||
|
op.add_column('post', sa.Column('auto_score', sa.INTEGER(), autoincrement=False, nullable=False))
|
||||||
|
op.add_column('post', sa.Column('auto_comment_count', sa.INTEGER(), autoincrement=False, nullable=False))
|
||||||
|
op.add_column('post', sa.Column('auto_feature_count', sa.INTEGER(), autoincrement=False, nullable=False))
|
||||||
|
op.add_column('post', sa.Column('auto_comment_creation_time', sa.INTEGER(), autoincrement=False, nullable=False))
|
||||||
|
op.add_column('post', sa.Column('auto_fav_count', sa.INTEGER(), autoincrement=False, nullable=False))
|
||||||
|
op.add_column('post', sa.Column('auto_comment_edit_time', sa.INTEGER(), autoincrement=False, nullable=False))
|
|
@ -0,0 +1,150 @@
|
||||||
|
import datetime
|
||||||
|
import pytest
|
||||||
|
from szurubooru import api, db, errors
|
||||||
|
from szurubooru.func import util, comments, scores
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def test_ctx(config_injector, context_factory, user_factory, comment_factory):
|
||||||
|
config_injector({
|
||||||
|
'ranks': ['anonymous', 'regular_user'],
|
||||||
|
'rank_names': {'anonymous': 'Peasant', 'regular_user': 'Lord'},
|
||||||
|
'privileges': {'comments:score': 'regular_user'},
|
||||||
|
'thumbnails': {'avatar_width': 200},
|
||||||
|
})
|
||||||
|
db.session.flush()
|
||||||
|
ret = util.dotdict()
|
||||||
|
ret.context_factory = context_factory
|
||||||
|
ret.user_factory = user_factory
|
||||||
|
ret.comment_factory = comment_factory
|
||||||
|
ret.api = api.CommentScoreApi()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def test_simple_rating(test_ctx, fake_datetime):
|
||||||
|
user = test_ctx.user_factory(rank='regular_user')
|
||||||
|
comment = test_ctx.comment_factory(user=user)
|
||||||
|
db.session.add(comment)
|
||||||
|
db.session.commit()
|
||||||
|
with fake_datetime('1997-12-01'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': 1}, user=user),
|
||||||
|
comment.comment_id)
|
||||||
|
assert 'comment' in result
|
||||||
|
assert 'text' in result['comment']
|
||||||
|
comment = db.session.query(db.Comment).one()
|
||||||
|
assert db.session.query(db.CommentScore).count() == 1
|
||||||
|
assert comment is not None
|
||||||
|
assert comment.score == 1
|
||||||
|
|
||||||
|
def test_updating_rating(test_ctx, fake_datetime):
|
||||||
|
user = test_ctx.user_factory(rank='regular_user')
|
||||||
|
comment = test_ctx.comment_factory(user=user)
|
||||||
|
db.session.add(comment)
|
||||||
|
db.session.commit()
|
||||||
|
with fake_datetime('1997-12-01'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': 1}, user=user),
|
||||||
|
comment.comment_id)
|
||||||
|
with fake_datetime('1997-12-02'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': -1}, user=user),
|
||||||
|
comment.comment_id)
|
||||||
|
comment = db.session.query(db.Comment).one()
|
||||||
|
assert db.session.query(db.CommentScore).count() == 1
|
||||||
|
assert comment.score == -1
|
||||||
|
|
||||||
|
def test_updating_rating_to_zero(test_ctx, fake_datetime):
|
||||||
|
user = test_ctx.user_factory(rank='regular_user')
|
||||||
|
comment = test_ctx.comment_factory(user=user)
|
||||||
|
db.session.add(comment)
|
||||||
|
db.session.commit()
|
||||||
|
with fake_datetime('1997-12-01'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': 1}, user=user),
|
||||||
|
comment.comment_id)
|
||||||
|
with fake_datetime('1997-12-02'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': 0}, user=user),
|
||||||
|
comment.comment_id)
|
||||||
|
comment = db.session.query(db.Comment).one()
|
||||||
|
assert db.session.query(db.CommentScore).count() == 0
|
||||||
|
assert comment.score == 0
|
||||||
|
|
||||||
|
def test_deleting_rating(test_ctx, fake_datetime):
|
||||||
|
user = test_ctx.user_factory(rank='regular_user')
|
||||||
|
comment = test_ctx.comment_factory(user=user)
|
||||||
|
db.session.add(comment)
|
||||||
|
db.session.commit()
|
||||||
|
with fake_datetime('1997-12-01'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': 1}, user=user),
|
||||||
|
comment.comment_id)
|
||||||
|
with fake_datetime('1997-12-02'):
|
||||||
|
result = test_ctx.api.delete(
|
||||||
|
test_ctx.context_factory(user=user), comment.comment_id)
|
||||||
|
comment = db.session.query(db.Comment).one()
|
||||||
|
assert db.session.query(db.CommentScore).count() == 0
|
||||||
|
assert comment.score == 0
|
||||||
|
|
||||||
|
def test_ratings_from_multiple_users(test_ctx, fake_datetime):
|
||||||
|
user1 = test_ctx.user_factory(rank='regular_user')
|
||||||
|
user2 = test_ctx.user_factory(rank='regular_user')
|
||||||
|
comment = test_ctx.comment_factory()
|
||||||
|
db.session.add_all([user1, user2, comment])
|
||||||
|
db.session.commit()
|
||||||
|
with fake_datetime('1997-12-01'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': 1}, user=user1),
|
||||||
|
comment.comment_id)
|
||||||
|
with fake_datetime('1997-12-02'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': -1}, user=user2),
|
||||||
|
comment.comment_id)
|
||||||
|
comment = db.session.query(db.Comment).one()
|
||||||
|
assert db.session.query(db.CommentScore).count() == 2
|
||||||
|
assert comment.score == 0
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('input,expected_exception', [
|
||||||
|
({'score': None}, errors.ValidationError),
|
||||||
|
({'score': ''}, errors.ValidationError),
|
||||||
|
({'score': -2}, scores.InvalidScoreError),
|
||||||
|
({'score': 2}, scores.InvalidScoreError),
|
||||||
|
({'score': [1]}, errors.ValidationError),
|
||||||
|
])
|
||||||
|
def test_trying_to_pass_invalid_input(test_ctx, input, expected_exception):
|
||||||
|
user = test_ctx.user_factory()
|
||||||
|
comment = test_ctx.comment_factory(user=user)
|
||||||
|
db.session.add(comment)
|
||||||
|
db.session.commit()
|
||||||
|
with pytest.raises(expected_exception):
|
||||||
|
test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input=input, user=user),
|
||||||
|
comment.comment_id)
|
||||||
|
|
||||||
|
def test_trying_to_omit_mandatory_field(test_ctx):
|
||||||
|
user = test_ctx.user_factory()
|
||||||
|
comment = test_ctx.comment_factory(user=user)
|
||||||
|
db.session.add(comment)
|
||||||
|
db.session.commit()
|
||||||
|
with pytest.raises(errors.ValidationError):
|
||||||
|
test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={}, user=user),
|
||||||
|
comment.comment_id)
|
||||||
|
|
||||||
|
def test_trying_to_update_non_existing(test_ctx):
|
||||||
|
with pytest.raises(comments.CommentNotFoundError):
|
||||||
|
test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(
|
||||||
|
input={'score': 1},
|
||||||
|
user=test_ctx.user_factory(rank='regular_user')),
|
||||||
|
5)
|
||||||
|
|
||||||
|
def test_trying_to_rate_without_privileges(test_ctx):
|
||||||
|
comment = test_ctx.comment_factory()
|
||||||
|
db.session.add(comment)
|
||||||
|
db.session.commit()
|
||||||
|
with pytest.raises(errors.AuthError):
|
||||||
|
test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(
|
||||||
|
input={'score': 1},
|
||||||
|
user=test_ctx.user_factory(rank='anonymous')),
|
||||||
|
comment.comment_id)
|
|
@ -0,0 +1,148 @@
|
||||||
|
import datetime
|
||||||
|
import pytest
|
||||||
|
from szurubooru import api, db, errors
|
||||||
|
from szurubooru.func import util, posts, scores
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def test_ctx(config_injector, context_factory, user_factory, post_factory):
|
||||||
|
config_injector({
|
||||||
|
'ranks': ['anonymous', 'regular_user'],
|
||||||
|
'rank_names': {'anonymous': 'Peasant', 'regular_user': 'Lord'},
|
||||||
|
'privileges': {'posts:score': 'regular_user'},
|
||||||
|
'thumbnails': {'avatar_width': 200},
|
||||||
|
})
|
||||||
|
db.session.flush()
|
||||||
|
ret = util.dotdict()
|
||||||
|
ret.context_factory = context_factory
|
||||||
|
ret.user_factory = user_factory
|
||||||
|
ret.post_factory = post_factory
|
||||||
|
ret.api = api.PostScoreApi()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def test_simple_rating(test_ctx, fake_datetime):
|
||||||
|
post = test_ctx.post_factory()
|
||||||
|
db.session.add(post)
|
||||||
|
db.session.commit()
|
||||||
|
with fake_datetime('1997-12-01'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(
|
||||||
|
input={'score': 1}, user=test_ctx.user_factory()),
|
||||||
|
post.post_id)
|
||||||
|
assert 'post' in result
|
||||||
|
assert 'id' in result['post']
|
||||||
|
post = db.session.query(db.Post).one()
|
||||||
|
assert db.session.query(db.PostScore).count() == 1
|
||||||
|
assert post is not None
|
||||||
|
assert post.score == 1
|
||||||
|
|
||||||
|
def test_updating_rating(test_ctx, fake_datetime):
|
||||||
|
user = test_ctx.user_factory()
|
||||||
|
post = test_ctx.post_factory()
|
||||||
|
db.session.add(post)
|
||||||
|
db.session.commit()
|
||||||
|
with fake_datetime('1997-12-01'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': 1}, user=user),
|
||||||
|
post.post_id)
|
||||||
|
with fake_datetime('1997-12-02'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': -1}, user=user),
|
||||||
|
post.post_id)
|
||||||
|
post = db.session.query(db.Post).one()
|
||||||
|
assert db.session.query(db.PostScore).count() == 1
|
||||||
|
assert post.score == -1
|
||||||
|
|
||||||
|
def test_updating_rating_to_zero(test_ctx, fake_datetime):
|
||||||
|
user = test_ctx.user_factory()
|
||||||
|
post = test_ctx.post_factory()
|
||||||
|
db.session.add(post)
|
||||||
|
db.session.commit()
|
||||||
|
with fake_datetime('1997-12-01'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': 1}, user=user),
|
||||||
|
post.post_id)
|
||||||
|
with fake_datetime('1997-12-02'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': 0}, user=user),
|
||||||
|
post.post_id)
|
||||||
|
post = db.session.query(db.Post).one()
|
||||||
|
assert db.session.query(db.PostScore).count() == 0
|
||||||
|
assert post.score == 0
|
||||||
|
|
||||||
|
def test_deleting_rating(test_ctx, fake_datetime):
|
||||||
|
user = test_ctx.user_factory()
|
||||||
|
post = test_ctx.post_factory()
|
||||||
|
db.session.add(post)
|
||||||
|
db.session.commit()
|
||||||
|
with fake_datetime('1997-12-01'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': 1}, user=user),
|
||||||
|
post.post_id)
|
||||||
|
with fake_datetime('1997-12-02'):
|
||||||
|
result = test_ctx.api.delete(
|
||||||
|
test_ctx.context_factory(user=user), post.post_id)
|
||||||
|
post = db.session.query(db.Post).one()
|
||||||
|
assert db.session.query(db.PostScore).count() == 0
|
||||||
|
assert post.score == 0
|
||||||
|
|
||||||
|
def test_ratings_from_multiple_users(test_ctx, fake_datetime):
|
||||||
|
user1 = test_ctx.user_factory()
|
||||||
|
user2 = test_ctx.user_factory()
|
||||||
|
post = test_ctx.post_factory()
|
||||||
|
db.session.add_all([user1, user2, post])
|
||||||
|
db.session.commit()
|
||||||
|
with fake_datetime('1997-12-01'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': 1}, user=user1),
|
||||||
|
post.post_id)
|
||||||
|
with fake_datetime('1997-12-02'):
|
||||||
|
result = test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={'score': -1}, user=user2),
|
||||||
|
post.post_id)
|
||||||
|
post = db.session.query(db.Post).one()
|
||||||
|
assert db.session.query(db.PostScore).count() == 2
|
||||||
|
assert post.score == 0
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('input,expected_exception', [
|
||||||
|
({'score': None}, errors.ValidationError),
|
||||||
|
({'score': ''}, errors.ValidationError),
|
||||||
|
({'score': -2}, scores.InvalidScoreError),
|
||||||
|
({'score': 2}, scores.InvalidScoreError),
|
||||||
|
({'score': [1]}, errors.ValidationError),
|
||||||
|
])
|
||||||
|
def test_trying_to_pass_invalid_input(test_ctx, input, expected_exception):
|
||||||
|
post = test_ctx.post_factory()
|
||||||
|
db.session.add(post)
|
||||||
|
db.session.commit()
|
||||||
|
with pytest.raises(expected_exception):
|
||||||
|
test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input=input, user=test_ctx.user_factory()),
|
||||||
|
post.post_id)
|
||||||
|
|
||||||
|
def test_trying_to_omit_mandatory_field(test_ctx):
|
||||||
|
post = test_ctx.post_factory()
|
||||||
|
db.session.add(post)
|
||||||
|
db.session.commit()
|
||||||
|
with pytest.raises(errors.ValidationError):
|
||||||
|
test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(input={}, user=test_ctx.user_factory()),
|
||||||
|
post.post_id)
|
||||||
|
|
||||||
|
def test_trying_to_update_non_existing(test_ctx):
|
||||||
|
with pytest.raises(posts.PostNotFoundError):
|
||||||
|
test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(
|
||||||
|
input={'score': 1},
|
||||||
|
user=test_ctx.user_factory()),
|
||||||
|
5)
|
||||||
|
|
||||||
|
def test_trying_to_rate_without_privileges(test_ctx):
|
||||||
|
post = test_ctx.post_factory()
|
||||||
|
db.session.add(post)
|
||||||
|
db.session.commit()
|
||||||
|
with pytest.raises(errors.AuthError):
|
||||||
|
test_ctx.api.put(
|
||||||
|
test_ctx.context_factory(
|
||||||
|
input={'score': 1},
|
||||||
|
user=test_ctx.user_factory(rank='anonymous')),
|
||||||
|
post.post_id)
|
Loading…
Reference in New Issue