server/general: move extra details to resources

This commit is contained in:
rr- 2016-05-30 22:07:44 +02:00
parent 48bcbbff83
commit d0314813cb
27 changed files with 213 additions and 236 deletions

67
API.md
View file

@ -1391,7 +1391,8 @@ A single user.
- `<name>`: the user name. - `<name>`: the user name.
- `<email>`: the user email. It is available only if the request is - `<email>`: the user email. It is available only if the request is
authenticated by the same user, or the authenticated user can change the authenticated by the same user, or the authenticated user can change the
email. email. If it's unavailable, the server returns `false`. If the user hasn't
specified an email, the server returns `null`.
- `<rank>`: the user rank, which effectively affects their privileges. - `<rank>`: the user rank, which effectively affects their privileges.
Possible values: Possible values:
@ -1444,7 +1445,12 @@ experience.
"name": <name>, "name": <name>,
"color": <color>, "color": <color>,
"usages": <usages> "usages": <usages>
"default": <is-default> "default": <is-default>,
"snapshots": [
<snapshot>,
<snapshot>,
<snapshot>
]
} }
``` ```
@ -1454,6 +1460,8 @@ experience.
- `<color>`: the category color. - `<color>`: the category color.
- `<usages>`: how many tags is the given category used with. - `<usages>`: how many tags is the given category used with.
- `<is-default>`: whether the tag category is the default one. - `<is-default>`: whether the tag category is the default one.
- `<snapshot>`: a [snapshot resource](#snapshot) that contains the tag
category's earlier versions.
## Detailed tag category ## Detailed tag category
**Description** **Description**
@ -1465,19 +1473,12 @@ A tag category with extra information.
```json5 ```json5
{ {
"tagCategory": <tag-category>, "tagCategory": <tag-category>,
"snapshots": [
<snapshot>,
<snapshot>,
<snapshot>
]
} }
``` ```
**Field meaning** **Field meaning**
- `<tag-category>`: a [tag category resource](#tag-category) - `<tag-category>`: a [tag category resource](#tag-category)
- `<snapshot>`: a [snapshot resource](#snapshot) that contains the tag
category's earlier versions.
## Tag ## Tag
**Description** **Description**
@ -1494,7 +1495,12 @@ A single tag. Tags are used to let users search for posts.
"suggestions": <suggestions>, "suggestions": <suggestions>,
"creationTime": <creation-time>, "creationTime": <creation-time>,
"lastEditTime": <last-edit-time>, "lastEditTime": <last-edit-time>,
"usages": <usage-count> "usages": <usage-count>,
"snapshots": [
<snapshot>,
<snapshot>,
<snapshot>
]
} }
``` ```
@ -1510,6 +1516,8 @@ A single tag. Tags are used to let users search for posts.
- `<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.
- `<usage-count>`: the number of posts the tag was used in. - `<usage-count>`: the number of posts the tag was used in.
- `<snapshot>`: a [snapshot resource](#snapshot) that contains the tag's
earlier versions.
## Detailed tag ## Detailed tag
**Description** **Description**
@ -1521,18 +1529,11 @@ A tag with extra information.
```json5 ```json5
{ {
"tag": <tag>, "tag": <tag>,
"snapshots": [
<snapshot>,
<snapshot>,
<snapshot>
]
} }
``` ```
**Field meaning** **Field meaning**
- `<tag>`: a [tag resource](#tag) - `<tag>`: a [tag resource](#tag)
- `<snapshot>`: a [snapshot resource](#snapshot) that contains the tag's
earlier versions.
## Post ## Post
**Description** **Description**
@ -1566,6 +1567,16 @@ One file together with its metadata posted to the site.
"favoritedBy": <favorited-by>, "favoritedBy": <favorited-by>,
"hasCustomThumbnail": <has-custom-thumbnail>, "hasCustomThumbnail": <has-custom-thumbnail>,
"mimeType": <mime-type> "mimeType": <mime-type>
"snapshots": [
<snapshot>,
<snapshot>,
<snapshot>
],
"comments": {
<comment>,
<comment>,
<comment>
}
} }
``` ```
@ -1617,6 +1628,9 @@ One file together with its metadata posted to the site.
- `<has-custom-thumbnail>`: whether the post uses custom thumbnail. - `<has-custom-thumbnail>`: whether the post uses custom thumbnail.
- `<mime-type>`: subsidiary to `<type>`, used to tell exact content format; - `<mime-type>`: subsidiary to `<type>`, used to tell exact content format;
useful for `<video>` tags for instance. useful for `<video>` tags for instance.
- `<snapshot>`: a [snapshot resource](#snapshot) that contains the post's
earlier versions.
- `<comment>`: a [comment resource](#comment) for given post.
## Detailed post ## Detailed post
**Description** **Description**
@ -1628,24 +1642,11 @@ A post with extra information.
```json5 ```json5
{ {
"post": <post>, "post": <post>,
"snapshots": [
<snapshot>,
<snapshot>,
<snapshot>
],
"comments": {
<comment>,
<comment>,
<comment>
}
} }
``` ```
**Field meaning** **Field meaning**
- `<post>`: a [post resource](#post). - `<post>`: a [post resource](#post).
- `<snapshot>`: a [snapshot resource](#snapshot) that contains the post's
earlier versions.
- `<comment>`: a [comment resource](#comment) for given post.
## Note ## Note
**Description** **Description**
@ -1678,7 +1679,7 @@ A comment under a post.
```json5 ```json5
{ {
"id": <id>, "id": <id>,
"post": <post>, "postId": <post-id>,
"user": <author> "user": <author>
"text": <text>, "text": <text>,
"creationTime": <creation-time>, "creationTime": <creation-time>,
@ -1690,9 +1691,9 @@ A comment under a post.
**Field meaning** **Field meaning**
- `<id>`: the comment identifier. - `<id>`: the comment identifier.
- `<post>`: a post resource the post is linked with. - `<post-id>`: an id of the post the comment is for.
- `<text>`: the comment content. The client should render is as Markdown. - `<text>`: the comment content. The client should render is as Markdown.
- `<author>`: a user resource the post is created by. - `<author>`: a user resource the comment 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. - `<score>`: the collective score (+1/-1 rating) of the given comment.

View file

@ -23,13 +23,13 @@ class CommentListApi(BaseApi):
comment = comments.create_comment(ctx.user, post, text) comment = comments.create_comment(ctx.user, post, text)
ctx.session.add(comment) ctx.session.add(comment)
ctx.session.commit() ctx.session.commit()
return comments.serialize_comment_with_details(comment, ctx.user) return {'comment': comments.serialize_comment(comment, ctx.user)}
class CommentDetailApi(BaseApi): class CommentDetailApi(BaseApi):
def get(self, ctx, comment_id): def get(self, ctx, comment_id):
auth.verify_privilege(ctx.user, 'comments:view') auth.verify_privilege(ctx.user, 'comments:view')
comment = comments.get_comment_by_id(comment_id) comment = comments.get_comment_by_id(comment_id)
return comments.serialize_comment_with_details(comment, ctx.user) return {'comment': comments.serialize_comment(comment, ctx.user)}
def put(self, ctx, comment_id): def put(self, ctx, comment_id):
comment = comments.get_comment_by_id(comment_id) comment = comments.get_comment_by_id(comment_id)
@ -39,7 +39,7 @@ class CommentDetailApi(BaseApi):
comment.last_edit_time = datetime.datetime.now() comment.last_edit_time = datetime.datetime.now()
comments.update_comment_text(comment, text) comments.update_comment_text(comment, text)
ctx.session.commit() ctx.session.commit()
return comments.serialize_comment_with_details(comment, ctx.user) return {'comment': comments.serialize_comment(comment, ctx.user)}
def delete(self, ctx, comment_id): def delete(self, ctx, comment_id):
comment = comments.get_comment_by_id(comment_id) comment = comments.get_comment_by_id(comment_id)
@ -56,11 +56,11 @@ class CommentScoreApi(BaseApi):
comment = comments.get_comment_by_id(comment_id) comment = comments.get_comment_by_id(comment_id)
scores.set_score(comment, ctx.user, score) scores.set_score(comment, ctx.user, score)
ctx.session.commit() ctx.session.commit()
return comments.serialize_comment_with_details(comment, ctx.user) return {'comment': comments.serialize_comment(comment, ctx.user)}
def delete(self, ctx, comment_id): def delete(self, ctx, comment_id):
auth.verify_privilege(ctx.user, 'comments:score') auth.verify_privilege(ctx.user, 'comments:score')
comment = comments.get_comment_by_id(comment_id) comment = comments.get_comment_by_id(comment_id)
scores.delete_score(comment, ctx.user) scores.delete_score(comment, ctx.user)
ctx.session.commit() ctx.session.commit()
return comments.serialize_comment_with_details(comment, ctx.user) return {'comment': comments.serialize_comment(comment, ctx.user)}

View file

@ -38,13 +38,13 @@ class PostListApi(BaseApi):
snapshots.save_entity_creation(post, ctx.user) snapshots.save_entity_creation(post, ctx.user)
ctx.session.commit() ctx.session.commit()
tags.export_to_json() tags.export_to_json()
return posts.serialize_post_with_details(post, ctx.user) return {'post': posts.serialize_post(post, ctx.user)}
class PostDetailApi(BaseApi): class PostDetailApi(BaseApi):
def get(self, ctx, post_id): def get(self, ctx, post_id):
auth.verify_privilege(ctx.user, 'posts:view') auth.verify_privilege(ctx.user, 'posts:view')
post = posts.get_post_by_id(post_id) post = posts.get_post_by_id(post_id)
return posts.serialize_post_with_details(post, ctx.user) return {'post': posts.serialize_post(post, ctx.user)}
def put(self, ctx, post_id): def put(self, ctx, post_id):
post = posts.get_post_by_id(post_id) post = posts.get_post_by_id(post_id)
@ -79,7 +79,7 @@ class PostDetailApi(BaseApi):
snapshots.save_entity_modification(post, ctx.user) snapshots.save_entity_modification(post, ctx.user)
ctx.session.commit() ctx.session.commit()
tags.export_to_json() tags.export_to_json()
return posts.serialize_post_with_details(post, ctx.user) return {'post': posts.serialize_post(post, ctx.user)}
def delete(self, ctx, post_id): def delete(self, ctx, post_id):
auth.verify_privilege(ctx.user, 'posts:delete') auth.verify_privilege(ctx.user, 'posts:delete')
@ -104,11 +104,11 @@ class PostFeatureApi(BaseApi):
snapshots.save_entity_modification(featured_post, ctx.user) snapshots.save_entity_modification(featured_post, ctx.user)
snapshots.save_entity_modification(post, ctx.user) snapshots.save_entity_modification(post, ctx.user)
ctx.session.commit() ctx.session.commit()
return posts.serialize_post_with_details(post, ctx.user) return {'post': posts.serialize_post(post, ctx.user)}
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 {'post': posts.serialize_post(post, ctx.user)}
class PostScoreApi(BaseApi): class PostScoreApi(BaseApi):
def put(self, ctx, post_id): def put(self, ctx, post_id):
@ -117,14 +117,14 @@ class PostScoreApi(BaseApi):
score = ctx.get_param_as_int('score', required=True) score = ctx.get_param_as_int('score', required=True)
scores.set_score(post, ctx.user, score) scores.set_score(post, ctx.user, score)
ctx.session.commit() ctx.session.commit()
return posts.serialize_post_with_details(post, ctx.user) return {'post': posts.serialize_post(post, ctx.user)}
def delete(self, ctx, post_id): def delete(self, ctx, post_id):
auth.verify_privilege(ctx.user, 'posts:score') auth.verify_privilege(ctx.user, 'posts:score')
post = posts.get_post_by_id(post_id) post = posts.get_post_by_id(post_id)
scores.delete_score(post, ctx.user) scores.delete_score(post, ctx.user)
ctx.session.commit() ctx.session.commit()
return posts.serialize_post_with_details(post, ctx.user) return {'post': posts.serialize_post(post, ctx.user)}
class PostFavoriteApi(BaseApi): class PostFavoriteApi(BaseApi):
def post(self, ctx, post_id): def post(self, ctx, post_id):
@ -132,11 +132,11 @@ class PostFavoriteApi(BaseApi):
post = posts.get_post_by_id(post_id) post = posts.get_post_by_id(post_id)
favorites.set_favorite(post, ctx.user) favorites.set_favorite(post, ctx.user)
ctx.session.commit() ctx.session.commit()
return posts.serialize_post_with_details(post, ctx.user) return {'post': posts.serialize_post(post, ctx.user)}
def delete(self, ctx, post_id): def delete(self, ctx, post_id):
auth.verify_privilege(ctx.user, 'posts:favorite') auth.verify_privilege(ctx.user, 'posts:favorite')
post = posts.get_post_by_id(post_id) post = posts.get_post_by_id(post_id)
favorites.unset_favorite(post, ctx.user) favorites.unset_favorite(post, ctx.user)
ctx.session.commit() ctx.session.commit()
return posts.serialize_post_with_details(post, ctx.user) return {'post': posts.serialize_post(post, ctx.user)}

View file

@ -41,13 +41,13 @@ class TagListApi(BaseApi):
snapshots.save_entity_creation(tag, ctx.user) snapshots.save_entity_creation(tag, ctx.user)
ctx.session.commit() ctx.session.commit()
tags.export_to_json() tags.export_to_json()
return tags.serialize_tag_with_details(tag) return {'tag': tags.serialize_tag(tag)}
class TagDetailApi(BaseApi): class TagDetailApi(BaseApi):
def get(self, ctx, tag_name): def get(self, ctx, tag_name):
auth.verify_privilege(ctx.user, 'tags:view') auth.verify_privilege(ctx.user, 'tags:view')
tag = tags.get_tag_by_name(tag_name) tag = tags.get_tag_by_name(tag_name)
return tags.serialize_tag_with_details(tag) return {'tag': tags.serialize_tag(tag)}
def put(self, ctx, tag_name): def put(self, ctx, tag_name):
tag = tags.get_tag_by_name(tag_name) tag = tags.get_tag_by_name(tag_name)
@ -73,7 +73,7 @@ class TagDetailApi(BaseApi):
snapshots.save_entity_modification(tag, ctx.user) snapshots.save_entity_modification(tag, ctx.user)
ctx.session.commit() ctx.session.commit()
tags.export_to_json() tags.export_to_json()
return tags.serialize_tag_with_details(tag) return {'tag': tags.serialize_tag(tag)}
def delete(self, ctx, tag_name): def delete(self, ctx, tag_name):
tag = tags.get_tag_by_name(tag_name) tag = tags.get_tag_by_name(tag_name)
@ -101,7 +101,7 @@ class TagMergeApi(BaseApi):
tags.merge_tags(source_tag, target_tag) tags.merge_tags(source_tag, target_tag)
ctx.session.commit() ctx.session.commit()
tags.export_to_json() tags.export_to_json()
return tags.serialize_tag_with_details(target_tag) return {'tag': tags.serialize_tag(target_tag)}
class TagSiblingsApi(BaseApi): class TagSiblingsApi(BaseApi):
def get(self, ctx, tag_name): def get(self, ctx, tag_name):

View file

@ -21,13 +21,13 @@ class TagCategoryListApi(BaseApi):
snapshots.save_entity_creation(category, ctx.user) snapshots.save_entity_creation(category, ctx.user)
ctx.session.commit() ctx.session.commit()
tags.export_to_json() tags.export_to_json()
return tag_categories.serialize_category_with_details(category) return {'tagCategory': tag_categories.serialize_category(category)}
class TagCategoryDetailApi(BaseApi): class TagCategoryDetailApi(BaseApi):
def get(self, ctx, category_name): def get(self, ctx, category_name):
auth.verify_privilege(ctx.user, 'tag_categories:view') auth.verify_privilege(ctx.user, 'tag_categories:view')
category = tag_categories.get_category_by_name(category_name) category = tag_categories.get_category_by_name(category_name)
return tag_categories.serialize_category_with_details(category) return {'tagCategory': tag_categories.serialize_category(category)}
def put(self, ctx, category_name): def put(self, ctx, category_name):
category = tag_categories.get_category_by_name(category_name) category = tag_categories.get_category_by_name(category_name)
@ -43,7 +43,7 @@ class TagCategoryDetailApi(BaseApi):
snapshots.save_entity_modification(category, ctx.user) snapshots.save_entity_modification(category, ctx.user)
ctx.session.commit() ctx.session.commit()
tags.export_to_json() tags.export_to_json()
return tag_categories.serialize_category_with_details(category) return {'tagCategory': tag_categories.serialize_category(category)}
def delete(self, ctx, category_name): def delete(self, ctx, category_name):
category = tag_categories.get_category_by_name(category_name) category = tag_categories.get_category_by_name(category_name)
@ -69,4 +69,4 @@ class DefaultTagCategoryApi(BaseApi):
snapshots.save_entity_modification(category, ctx.user) snapshots.save_entity_modification(category, ctx.user)
ctx.session.commit() ctx.session.commit()
tags.export_to_json() tags.export_to_json()
return tag_categories.serialize_category_with_details(category) return {'tagCategory': tag_categories.serialize_category(category)}

View file

@ -28,14 +28,14 @@ class UserListApi(BaseApi):
ctx.get_file('avatar')) ctx.get_file('avatar'))
ctx.session.add(user) ctx.session.add(user)
ctx.session.commit() ctx.session.commit()
return users.serialize_user_with_details( return {'user': users.serialize_user(
user, ctx.user, force_show_email=True) user, ctx.user, force_show_email=True)}
class UserDetailApi(BaseApi): class UserDetailApi(BaseApi):
def get(self, ctx, user_name): def get(self, ctx, user_name):
auth.verify_privilege(ctx.user, 'users:view') auth.verify_privilege(ctx.user, 'users:view')
user = users.get_user_by_name(user_name) user = users.get_user_by_name(user_name)
return users.serialize_user_with_details(user, ctx.user) return {'user': users.serialize_user(user, ctx.user)}
def put(self, ctx, user_name): def put(self, ctx, user_name):
user = users.get_user_by_name(user_name) user = users.get_user_by_name(user_name)
@ -61,7 +61,7 @@ class UserDetailApi(BaseApi):
ctx.get_param_as_string('avatarStyle'), ctx.get_param_as_string('avatarStyle'),
ctx.get_file('avatar')) ctx.get_file('avatar'))
ctx.session.commit() ctx.session.commit()
return users.serialize_user_with_details(user, ctx.user) return {'user': users.serialize_user(user, ctx.user)}
def delete(self, ctx, user_name): def delete(self, ctx, user_name):
user = users.get_user_by_name(user_name) user = users.get_user_by_name(user_name)

View file

@ -1,25 +1,22 @@
import datetime import datetime
from szurubooru import db, errors from szurubooru import db, errors
from szurubooru.func import users, posts, scores from szurubooru.func import users, scores, util
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):
ret = { return util.serialize_entity(
'id': comment.comment_id, comment,
'user': users.serialize_user(comment.user, authenticated_user), {
'post': posts.serialize_post(comment.post, authenticated_user), 'id': lambda: comment.comment_id,
'text': comment.text, 'user': lambda: users.serialize_user(comment.user, authenticated_user),
'creationTime': comment.creation_time, 'postId': lambda: comment.post.post_id,
'lastEditTime': comment.last_edit_time, 'text': lambda: comment.text,
} 'creationTime': lambda: comment.creation_time,
if authenticated_user: 'lastEditTime': lambda: comment.last_edit_time,
ret['ownScore'] = scores.get_score(comment, authenticated_user) 'ownScore': lambda: scores.get_score(comment, authenticated_user),
return ret })
def serialize_comment_with_details(comment, authenticated_user):
return {'comment': serialize_comment(comment, authenticated_user)}
def try_get_comment_by_id(comment_id): def try_get_comment_by_id(comment_id):
return db.session \ return db.session \

View file

@ -62,54 +62,43 @@ def serialize_note(note):
} }
def serialize_post(post, authenticated_user): def serialize_post(post, authenticated_user):
if not post: return util.serialize_entity(
return None post,
{
ret = { 'id': lambda: post.post_id,
'id': post.post_id, 'creationTime': lambda: post.creation_time,
'creationTime': post.creation_time, 'lastEditTime': lambda: post.last_edit_time,
'lastEditTime': post.last_edit_time, 'safety': lambda: SAFETY_MAP[post.safety],
'safety': SAFETY_MAP[post.safety], 'source': lambda: post.source,
'source': post.source, 'type': lambda: TYPE_MAP[post.type],
'type': TYPE_MAP[post.type], 'mimeType': lambda: post.mime_type,
'checksum': post.checksum, 'checksum': lambda: post.checksum,
'fileSize': post.file_size, 'fileSize': lambda: post.file_size,
'canvasWidth': post.canvas_width, 'canvasWidth': lambda: post.canvas_width,
'canvasHeight': post.canvas_height, 'canvasHeight': lambda: post.canvas_height,
'contentUrl': get_post_content_url(post), 'contentUrl': lambda: get_post_content_url(post),
'thumbnailUrl': get_post_thumbnail_url(post), 'thumbnailUrl': lambda: get_post_thumbnail_url(post),
'flags': post.flags, 'flags': lambda: post.flags,
'tags': [tag.names[0].name for tag in post.tags], 'tags': lambda: [tag.names[0].name for tag in post.tags],
'relations': [rel.post_id for rel in post.relations], 'relations': lambda: [rel.post_id for rel in post.relations],
'notes': sorted( 'user': lambda: users.serialize_user(post.user, authenticated_user),
[ serialize_note(note) for note in post.notes], 'score': lambda: post.score,
key=lambda x: x['polygon']), 'ownScore': lambda: scores.get_score(post, authenticated_user),
'user': users.serialize_user(post.user, authenticated_user), 'featureCount': lambda: post.feature_count,
'score': post.score, 'lastFeatureTime': lambda: post.last_feature_time,
'featureCount': post.feature_count, 'favoritedBy': lambda: [
'lastFeatureTime': post.last_feature_time, users.serialize_user(rel.user, authenticated_user) \
'favoritedBy': [users.serialize_user(rel.user, authenticated_user) \
for rel in post.favorited_by], for rel in post.favorited_by],
'hasCustomThumbnail': files.has(get_post_thumbnail_backup_path(post)), 'hasCustomThumbnail':
'mimeType': post.mime_type, lambda: files.has(get_post_thumbnail_backup_path(post)),
} 'notes': lambda: sorted(
[serialize_note(note) for note in post.notes],
if authenticated_user: key=lambda x: x['polygon']),
ret['ownScore'] = scores.get_score(post, authenticated_user) 'comments': lambda: [
comments.serialize_comment(comment, authenticated_user) \
return ret for comment in post.comments],
'snapshots': lambda: snapshots.get_serialized_history(post),
def serialize_post_with_details(post, authenticated_user): })
comment_list = []
if post:
for comment in post.comments:
comment_list.append(
comments.serialize_comment(comment, authenticated_user))
return {
'post': serialize_post(post, authenticated_user),
'snapshots': snapshots.get_serialized_history(post),
'comments': comment_list,
}
def get_post_count(): def get_post_count():
return db.session.query(sqlalchemy.func.count(db.Post.post_id)).one()[0] return db.session.query(sqlalchemy.func.count(db.Post.post_id)).one()[0]

View file

@ -15,18 +15,15 @@ def _verify_name_validity(name):
'Name must satisfy regex %r.' % name_regex) 'Name must satisfy regex %r.' % name_regex)
def serialize_category(category): def serialize_category(category):
return { return util.serialize_entity(
'name': category.name, category,
'color': category.color, {
'usages': category.tag_count, 'name': lambda: category.name,
'default': category.default, 'color': lambda: category.color,
} 'usages': lambda: category.tag_count,
'default': lambda: category.default,
def serialize_category_with_details(category): 'snapshots': lambda: snapshots.get_serialized_history(category),
return { })
'tagCategory': serialize_category(category),
'snapshots': snapshots.get_serialized_history(category),
}
def create_category(name, color): def create_category(name, color):
category = db.TagCategory() category = db.TagCategory()

View file

@ -37,23 +37,20 @@ def _get_default_category_name():
return DEFAULT_CATEGORY_NAME return DEFAULT_CATEGORY_NAME
def serialize_tag(tag): def serialize_tag(tag):
return { return util.serialize_entity(
'names': [tag_name.name for tag_name in tag.names], tag,
'category': tag.category.name, {
'suggestions': [ 'names': lambda: [tag_name.name for tag_name in tag.names],
'category': lambda: tag.category.name,
'creationTime': lambda: tag.creation_time,
'lastEditTime': lambda: tag.last_edit_time,
'usages': lambda: tag.post_count,
'suggestions': lambda: [
relation.names[0].name for relation in tag.suggestions], relation.names[0].name for relation in tag.suggestions],
'implications': [ 'implications': lambda: [
relation.names[0].name for relation in tag.implications], relation.names[0].name for relation in tag.implications],
'creationTime': tag.creation_time, 'snapshots': lambda: snapshots.get_serialized_history(tag),
'lastEditTime': tag.last_edit_time, })
'usages': tag.post_count,
}
def serialize_tag_with_details(tag):
return {
'tag': serialize_tag(tag),
'snapshots': snapshots.get_serialized_history(tag),
}
def export_to_json(): def export_to_json():
output = { output = {

View file

@ -12,36 +12,34 @@ class InvalidPasswordError(errors.ValidationError): pass
class InvalidRankError(errors.ValidationError): pass class InvalidRankError(errors.ValidationError): pass
class InvalidAvatarError(errors.ValidationError): pass class InvalidAvatarError(errors.ValidationError): pass
def serialize_user(user, authenticated_user, force_show_email=False): def _get_avatar_url(user):
if not user:
return {}
ret = {
'name': user.name,
'rank': user.rank,
'creationTime': user.creation_time,
'lastLoginTime': user.last_login_time,
'avatarStyle': user.avatar_style,
'email': user.email,
}
if user.avatar_style == user.AVATAR_GRAVATAR: if user.avatar_style == user.AVATAR_GRAVATAR:
ret['avatarUrl'] = 'http://gravatar.com/avatar/%s?d=retro&s=%d' % ( return 'http://gravatar.com/avatar/%s?d=retro&s=%d' % (
util.get_md5((user.email or user.name).lower()), util.get_md5((user.email or user.name).lower()),
config.config['thumbnails']['avatar_width']) config.config['thumbnails']['avatar_width'])
else: else:
ret['avatarUrl'] = '%s/avatars/%s.png' % ( return '%s/avatars/%s.png' % (
config.config['data_url'].rstrip('/'), user.name.lower()) config.config['data_url'].rstrip('/'), user.name.lower())
if authenticated_user.user_id != user.user_id \ def _get_email(user, authenticated_user, force_show_email):
and not force_show_email \ if not force_show_email \
and authenticated_user.user_id != user.user_id \
and not auth.has_privilege(authenticated_user, 'users:edit:any:email'): and not auth.has_privilege(authenticated_user, 'users:edit:any:email'):
del ret['email'] return False
return user.email
return ret def serialize_user(user, authenticated_user, force_show_email=False):
return util.serialize_entity(
def serialize_user_with_details(user, authenticated_user, **kwargs): user,
return {'user': serialize_user(user, authenticated_user, **kwargs)} {
'name': lambda: user.name,
'rank': lambda: user.rank,
'creationTime': lambda: user.creation_time,
'lastLoginTime': lambda: user.last_login_time,
'avatarStyle': lambda: user.avatar_style,
'avatarUrl': lambda: _get_avatar_url(user),
'email': lambda: _get_email(user, authenticated_user, force_show_email),
})
def get_user_count(): def get_user_count():
return db.session.query(db.User).count() return db.session.query(db.User).count()

View file

@ -6,6 +6,14 @@ import tempfile
from contextlib import contextmanager from contextlib import contextmanager
from szurubooru.errors import ValidationError from szurubooru.errors import ValidationError
def serialize_entity(entity, field_factories):
if not entity:
return None
ret = {}
for key, factory in field_factories.items():
ret[key] = factory()
return ret
@contextmanager @contextmanager
def create_temp_file(**kwargs): def create_temp_file(**kwargs):
(handle, path) = tempfile.mkstemp(**kwargs) (handle, path) = tempfile.mkstemp(**kwargs)

View file

@ -32,9 +32,8 @@ def test_creating_comment(test_ctx, fake_datetime):
assert result['comment']['text'] == 'input' assert result['comment']['text'] == 'input'
assert 'id' in result['comment'] assert 'id' in result['comment']
assert 'user' in result['comment'] assert 'user' in result['comment']
assert 'post' in result['comment']
assert 'name' in result['comment']['user'] assert 'name' in result['comment']['user']
assert 'id' in result['comment']['post'] assert 'postId' in result['comment']
comment = db.session.query(db.Comment).one() comment = db.session.query(db.Comment).one()
assert comment.text == 'input' assert comment.text == 'input'
assert comment.creation_time == datetime.datetime(1997, 1, 1) assert comment.creation_time == datetime.datetime(1997, 1, 1)

View file

@ -60,8 +60,7 @@ def test_retrieving_single(test_ctx):
assert 'text' in result['comment'] assert 'text' in result['comment']
assert 'user' in result['comment'] assert 'user' in result['comment']
assert 'name' in result['comment']['user'] assert 'name' in result['comment']['user']
assert 'post' in result['comment'] assert 'postId' in result['comment']
assert 'id' in result['comment']['post']
def test_trying_to_retrieve_single_non_existing(test_ctx): def test_trying_to_retrieve_single_non_existing(test_ctx):
with pytest.raises(comments.CommentNotFoundError): with pytest.raises(comments.CommentNotFoundError):

View file

@ -25,12 +25,12 @@ def test_creating_minimal_posts(
unittest.mock.patch('szurubooru.func.posts.update_post_notes'), \ unittest.mock.patch('szurubooru.func.posts.update_post_notes'), \
unittest.mock.patch('szurubooru.func.posts.update_post_flags'), \ unittest.mock.patch('szurubooru.func.posts.update_post_flags'), \
unittest.mock.patch('szurubooru.func.posts.update_post_thumbnail'), \ unittest.mock.patch('szurubooru.func.posts.update_post_thumbnail'), \
unittest.mock.patch('szurubooru.func.posts.serialize_post_with_details'), \ unittest.mock.patch('szurubooru.func.posts.serialize_post'), \
unittest.mock.patch('szurubooru.func.tags.export_to_json'), \ unittest.mock.patch('szurubooru.func.tags.export_to_json'), \
unittest.mock.patch('szurubooru.func.snapshots.save_entity_creation'): unittest.mock.patch('szurubooru.func.snapshots.save_entity_creation'):
posts.create_post.return_value = post posts.create_post.return_value = post
posts.serialize_post_with_details.return_value = 'serialized post' posts.serialize_post.return_value = 'serialized post'
result = api.PostListApi().post( result = api.PostListApi().post(
context_factory( context_factory(
@ -44,7 +44,7 @@ def test_creating_minimal_posts(
}, },
user=auth_user)) user=auth_user))
assert result == 'serialized post' assert result == {'post': 'serialized post'}
posts.create_post.assert_called_once_with( posts.create_post.assert_called_once_with(
'post-content', ['tag1', 'tag2'], auth_user) 'post-content', ['tag1', 'tag2'], auth_user)
posts.update_post_thumbnail.assert_called_once_with(post, 'post-thumbnail') posts.update_post_thumbnail.assert_called_once_with(post, 'post-thumbnail')
@ -54,7 +54,7 @@ def test_creating_minimal_posts(
posts.update_post_notes.assert_called_once_with(post, []) posts.update_post_notes.assert_called_once_with(post, [])
posts.update_post_flags.assert_called_once_with(post, []) posts.update_post_flags.assert_called_once_with(post, [])
posts.update_post_thumbnail.assert_called_once_with(post, 'post-thumbnail') posts.update_post_thumbnail.assert_called_once_with(post, 'post-thumbnail')
posts.serialize_post_with_details.assert_called_once_with(post, auth_user) posts.serialize_post.assert_called_once_with(post, auth_user)
tags.export_to_json.assert_called_once_with() tags.export_to_json.assert_called_once_with()
snapshots.save_entity_creation.assert_called_once_with(post, auth_user) snapshots.save_entity_creation.assert_called_once_with(post, auth_user)
@ -70,12 +70,12 @@ def test_creating_full_posts(context_factory, post_factory, user_factory):
unittest.mock.patch('szurubooru.func.posts.update_post_relations'), \ unittest.mock.patch('szurubooru.func.posts.update_post_relations'), \
unittest.mock.patch('szurubooru.func.posts.update_post_notes'), \ unittest.mock.patch('szurubooru.func.posts.update_post_notes'), \
unittest.mock.patch('szurubooru.func.posts.update_post_flags'), \ unittest.mock.patch('szurubooru.func.posts.update_post_flags'), \
unittest.mock.patch('szurubooru.func.posts.serialize_post_with_details'), \ unittest.mock.patch('szurubooru.func.posts.serialize_post'), \
unittest.mock.patch('szurubooru.func.tags.export_to_json'), \ unittest.mock.patch('szurubooru.func.tags.export_to_json'), \
unittest.mock.patch('szurubooru.func.snapshots.save_entity_creation'): unittest.mock.patch('szurubooru.func.snapshots.save_entity_creation'):
posts.create_post.return_value = post posts.create_post.return_value = post
posts.serialize_post_with_details.return_value = 'serialized post' posts.serialize_post.return_value = 'serialized post'
result = api.PostListApi().post( result = api.PostListApi().post(
context_factory( context_factory(
@ -92,7 +92,7 @@ def test_creating_full_posts(context_factory, post_factory, user_factory):
}, },
user=auth_user)) user=auth_user))
assert result == 'serialized post' assert result == {'post': 'serialized post'}
posts.create_post.assert_called_once_with( posts.create_post.assert_called_once_with(
'post-content', ['tag1', 'tag2'], auth_user) 'post-content', ['tag1', 'tag2'], auth_user)
posts.update_post_safety.assert_called_once_with(post, 'safe') posts.update_post_safety.assert_called_once_with(post, 'safe')
@ -100,7 +100,7 @@ def test_creating_full_posts(context_factory, post_factory, user_factory):
posts.update_post_relations.assert_called_once_with(post, [1, 2]) posts.update_post_relations.assert_called_once_with(post, [1, 2])
posts.update_post_notes.assert_called_once_with(post, ['note1', 'note2']) posts.update_post_notes.assert_called_once_with(post, ['note1', 'note2'])
posts.update_post_flags.assert_called_once_with(post, ['flag1', 'flag2']) posts.update_post_flags.assert_called_once_with(post, ['flag1', 'flag2'])
posts.serialize_post_with_details.assert_called_once_with(post, auth_user) posts.serialize_post.assert_called_once_with(post, auth_user)
tags.export_to_json.assert_called_once_with() tags.export_to_json.assert_called_once_with()
snapshots.save_entity_creation.assert_called_once_with(post, auth_user) snapshots.save_entity_creation.assert_called_once_with(post, auth_user)
@ -114,7 +114,7 @@ def test_creating_from_url_saves_source(
with unittest.mock.patch('szurubooru.func.net.download'), \ with unittest.mock.patch('szurubooru.func.net.download'), \
unittest.mock.patch('szurubooru.func.tags.export_to_json'), \ unittest.mock.patch('szurubooru.func.tags.export_to_json'), \
unittest.mock.patch('szurubooru.func.snapshots.save_entity_creation'), \ unittest.mock.patch('szurubooru.func.snapshots.save_entity_creation'), \
unittest.mock.patch('szurubooru.func.posts.serialize_post_with_details'), \ unittest.mock.patch('szurubooru.func.posts.serialize_post'), \
unittest.mock.patch('szurubooru.func.posts.create_post'), \ unittest.mock.patch('szurubooru.func.posts.create_post'), \
unittest.mock.patch('szurubooru.func.posts.update_post_source'): unittest.mock.patch('szurubooru.func.posts.update_post_source'):
config_injector({ config_injector({
@ -145,7 +145,7 @@ def test_creating_from_url_with_source_specified(
with unittest.mock.patch('szurubooru.func.net.download'), \ with unittest.mock.patch('szurubooru.func.net.download'), \
unittest.mock.patch('szurubooru.func.tags.export_to_json'), \ unittest.mock.patch('szurubooru.func.tags.export_to_json'), \
unittest.mock.patch('szurubooru.func.snapshots.save_entity_creation'), \ unittest.mock.patch('szurubooru.func.snapshots.save_entity_creation'), \
unittest.mock.patch('szurubooru.func.posts.serialize_post_with_details'), \ unittest.mock.patch('szurubooru.func.posts.serialize_post'), \
unittest.mock.patch('szurubooru.func.posts.create_post'), \ unittest.mock.patch('szurubooru.func.posts.create_post'), \
unittest.mock.patch('szurubooru.func.posts.update_post_source'): unittest.mock.patch('szurubooru.func.posts.update_post_source'):
config_injector({ config_injector({

View file

@ -26,7 +26,7 @@ def test_no_featured_post(test_ctx):
result = test_ctx.api.get( result = test_ctx.api.get(
test_ctx.context_factory( test_ctx.context_factory(
user=test_ctx.user_factory(rank=db.User.RANK_REGULAR))) user=test_ctx.user_factory(rank=db.User.RANK_REGULAR)))
assert result == {'post': None, 'snapshots': [], 'comments': []} assert result == {'post': None}
def test_featuring(test_ctx): def test_featuring(test_ctx):
db.session.add(test_ctx.post_factory(id=1)) db.session.add(test_ctx.post_factory(id=1))
@ -41,15 +41,15 @@ def test_featuring(test_ctx):
assert posts.get_post_by_id(1).is_featured assert posts.get_post_by_id(1).is_featured
assert 'post' in result assert 'post' in result
assert 'id' in result['post'] assert 'id' in result['post']
assert 'snapshots' in result assert 'snapshots' in result['post']
assert 'comments' in result assert 'comments' in result['post']
result = test_ctx.api.get( result = test_ctx.api.get(
test_ctx.context_factory( test_ctx.context_factory(
user=test_ctx.user_factory(rank=db.User.RANK_REGULAR))) user=test_ctx.user_factory(rank=db.User.RANK_REGULAR)))
assert 'post' in result assert 'post' in result
assert 'id' in result['post'] assert 'id' in result['post']
assert 'snapshots' in result assert 'snapshots' in result['post']
assert 'comments' in result assert 'comments' in result['post']
def test_trying_to_feature_the_same_post_twice(test_ctx): def test_trying_to_feature_the_same_post_twice(test_ctx):
db.session.add(test_ctx.post_factory(id=1)) db.session.add(test_ctx.post_factory(id=1))

View file

@ -81,8 +81,8 @@ def test_retrieving_single(test_ctx):
user=test_ctx.user_factory(rank=db.User.RANK_REGULAR)), 1) user=test_ctx.user_factory(rank=db.User.RANK_REGULAR)), 1)
assert 'post' in result assert 'post' in result
assert 'id' in result['post'] assert 'id' in result['post']
assert 'snapshots' in result assert 'snapshots' in result['post']
assert 'comments' in result assert 'comments' in result['post']
def test_trying_to_retrieve_single_non_existing(test_ctx): def test_trying_to_retrieve_single_non_existing(test_ctx):
with pytest.raises(posts.PostNotFoundError): with pytest.raises(posts.PostNotFoundError):

View file

@ -33,11 +33,11 @@ def test_post_updating(
unittest.mock.patch('szurubooru.func.posts.update_post_relations'), \ unittest.mock.patch('szurubooru.func.posts.update_post_relations'), \
unittest.mock.patch('szurubooru.func.posts.update_post_notes'), \ unittest.mock.patch('szurubooru.func.posts.update_post_notes'), \
unittest.mock.patch('szurubooru.func.posts.update_post_flags'), \ unittest.mock.patch('szurubooru.func.posts.update_post_flags'), \
unittest.mock.patch('szurubooru.func.posts.serialize_post_with_details'), \ unittest.mock.patch('szurubooru.func.posts.serialize_post'), \
unittest.mock.patch('szurubooru.func.tags.export_to_json'), \ unittest.mock.patch('szurubooru.func.tags.export_to_json'), \
unittest.mock.patch('szurubooru.func.snapshots.save_entity_modification'): unittest.mock.patch('szurubooru.func.snapshots.save_entity_modification'):
posts.serialize_post_with_details.return_value = 'serialized post' posts.serialize_post.return_value = 'serialized post'
with fake_datetime('1997-01-01'): with fake_datetime('1997-01-01'):
result = api.PostDetailApi().put( result = api.PostDetailApi().put(
@ -57,7 +57,7 @@ def test_post_updating(
user=auth_user), user=auth_user),
post.post_id) post.post_id)
assert result == 'serialized post' assert result == {'post': 'serialized post'}
posts.create_post.assert_not_called() posts.create_post.assert_not_called()
posts.update_post_tags.assert_called_once_with(post, ['tag1', 'tag2']) posts.update_post_tags.assert_called_once_with(post, ['tag1', 'tag2'])
posts.update_post_content.assert_called_once_with(post, 'post-content') posts.update_post_content.assert_called_once_with(post, 'post-content')
@ -67,7 +67,7 @@ def test_post_updating(
posts.update_post_relations.assert_called_once_with(post, [1, 2]) posts.update_post_relations.assert_called_once_with(post, [1, 2])
posts.update_post_notes.assert_called_once_with(post, ['note1', 'note2']) posts.update_post_notes.assert_called_once_with(post, ['note1', 'note2'])
posts.update_post_flags.assert_called_once_with(post, ['flag1', 'flag2']) posts.update_post_flags.assert_called_once_with(post, ['flag1', 'flag2'])
posts.serialize_post_with_details.assert_called_once_with(post, auth_user) posts.serialize_post.assert_called_once_with(post, auth_user)
tags.export_to_json.assert_called_once_with() tags.export_to_json.assert_called_once_with()
snapshots.save_entity_modification.assert_called_once_with(post, auth_user) snapshots.save_entity_modification.assert_called_once_with(post, auth_user)
assert post.last_edit_time == datetime.datetime(1997, 1, 1) assert post.last_edit_time == datetime.datetime(1997, 1, 1)
@ -83,7 +83,7 @@ def test_uploading_from_url_saves_source(
with unittest.mock.patch('szurubooru.func.net.download'), \ with unittest.mock.patch('szurubooru.func.net.download'), \
unittest.mock.patch('szurubooru.func.tags.export_to_json'), \ unittest.mock.patch('szurubooru.func.tags.export_to_json'), \
unittest.mock.patch('szurubooru.func.snapshots.save_entity_modification'), \ unittest.mock.patch('szurubooru.func.snapshots.save_entity_modification'), \
unittest.mock.patch('szurubooru.func.posts.serialize_post_with_details'), \ unittest.mock.patch('szurubooru.func.posts.serialize_post'), \
unittest.mock.patch('szurubooru.func.posts.update_post_content'), \ unittest.mock.patch('szurubooru.func.posts.update_post_content'), \
unittest.mock.patch('szurubooru.func.posts.update_post_source'): unittest.mock.patch('szurubooru.func.posts.update_post_source'):
net.download.return_value = b'content' net.download.return_value = b'content'
@ -110,7 +110,7 @@ def test_uploading_from_url_with_source_specified(
with unittest.mock.patch('szurubooru.func.net.download'), \ with unittest.mock.patch('szurubooru.func.net.download'), \
unittest.mock.patch('szurubooru.func.tags.export_to_json'), \ unittest.mock.patch('szurubooru.func.tags.export_to_json'), \
unittest.mock.patch('szurubooru.func.snapshots.save_entity_modification'), \ unittest.mock.patch('szurubooru.func.snapshots.save_entity_modification'), \
unittest.mock.patch('szurubooru.func.posts.serialize_post_with_details'), \ unittest.mock.patch('szurubooru.func.posts.serialize_post'), \
unittest.mock.patch('szurubooru.func.posts.update_post_content'), \ unittest.mock.patch('szurubooru.func.posts.update_post_content'), \
unittest.mock.patch('szurubooru.func.posts.update_post_source'): unittest.mock.patch('szurubooru.func.posts.update_post_source'):
net.download.return_value = b'content' net.download.return_value = b'content'

View file

@ -21,13 +21,14 @@ def test_creating_category(test_ctx):
test_ctx.context_factory( test_ctx.context_factory(
input={'name': 'meta', 'color': 'black'}, input={'name': 'meta', 'color': 'black'},
user=test_ctx.user_factory(rank=db.User.RANK_REGULAR))) user=test_ctx.user_factory(rank=db.User.RANK_REGULAR)))
assert len(result['tagCategory']['snapshots']) == 1
del result['tagCategory']['snapshots']
assert result['tagCategory'] == { assert result['tagCategory'] == {
'name': 'meta', 'name': 'meta',
'color': 'black', 'color': 'black',
'usages': 0, 'usages': 0,
'default': True, 'default': True,
} }
assert len(result['snapshots']) == 1
category = db.session.query(db.TagCategory).one() category = db.session.query(db.TagCategory).one()
assert category.name == 'meta' assert category.name == 'meta'
assert category.color == 'black' assert category.color == 'black'

View file

@ -43,8 +43,8 @@ def test_retrieving_single(test_ctx):
'color': 'dummy', 'color': 'dummy',
'usages': 0, 'usages': 0,
'default': False, 'default': False,
},
'snapshots': [], 'snapshots': [],
},
} }
def test_trying_to_retrieve_single_non_existing(test_ctx): def test_trying_to_retrieve_single_non_existing(test_ctx):

View file

@ -37,13 +37,14 @@ def test_simple_updating(test_ctx):
}, },
user=test_ctx.user_factory(rank=db.User.RANK_REGULAR)), user=test_ctx.user_factory(rank=db.User.RANK_REGULAR)),
'name') 'name')
assert len(result['tagCategory']['snapshots']) == 1
del result['tagCategory']['snapshots']
assert result['tagCategory'] == { assert result['tagCategory'] == {
'name': 'changed', 'name': 'changed',
'color': 'white', 'color': 'white',
'usages': 0, 'usages': 0,
'default': False, 'default': False,
} }
assert len(result['snapshots']) == 1
assert tag_categories.try_get_category_by_name('name') is None assert tag_categories.try_get_category_by_name('name') is None
category = tag_categories.get_category_by_name('changed') category = tag_categories.get_category_by_name('changed')
assert category is not None assert category is not None

View file

@ -38,6 +38,8 @@ def test_creating_simple_tags(test_ctx, fake_datetime):
'implications': [], 'implications': [],
}, },
user=test_ctx.user_factory(rank=db.User.RANK_REGULAR))) user=test_ctx.user_factory(rank=db.User.RANK_REGULAR)))
assert len(result['tag']['snapshots']) == 1
del result['tag']['snapshots']
assert result['tag'] == { assert result['tag'] == {
'names': ['tag1', 'tag2'], 'names': ['tag1', 'tag2'],
'category': 'meta', 'category': 'meta',
@ -47,7 +49,6 @@ def test_creating_simple_tags(test_ctx, fake_datetime):
'lastEditTime': None, 'lastEditTime': None,
'usages': 0, 'usages': 0,
} }
assert len(result['snapshots']) == 1
tag = tags.get_tag_by_name('tag1') tag = tags.get_tag_by_name('tag1')
assert [tag_name.name for tag_name in tag.names] == ['tag1', 'tag2'] assert [tag_name.name for tag_name in tag.names] == ['tag1', 'tag2']
assert tag.category.name == 'meta' assert tag.category.name == 'meta'

View file

@ -33,6 +33,8 @@ def test_merging_without_usages(test_ctx, fake_datetime):
'mergeTo': 'target', 'mergeTo': 'target',
}, },
user=test_ctx.user_factory(rank=db.User.RANK_REGULAR))) user=test_ctx.user_factory(rank=db.User.RANK_REGULAR)))
assert 'snapshots' in result['tag']
del result['tag']['snapshots']
assert result['tag'] == { assert result['tag'] == {
'names': ['target'], 'names': ['target'],
'category': 'meta', 'category': 'meta',
@ -42,7 +44,6 @@ def test_merging_without_usages(test_ctx, fake_datetime):
'lastEditTime': None, 'lastEditTime': None,
'usages': 0, 'usages': 0,
} }
assert 'snapshots' in result
assert tags.try_get_tag_by_name('source') is None assert tags.try_get_tag_by_name('source') is None
tag = tags.get_tag_by_name('target') tag = tags.get_tag_by_name('target')
assert tag is not None assert tag is not None

View file

@ -56,8 +56,8 @@ def test_retrieving_single(test_ctx):
'suggestions': [], 'suggestions': [],
'implications': [], 'implications': [],
'usages': 0, 'usages': 0,
},
'snapshots': [], 'snapshots': [],
},
} }
def test_trying_to_retrieve_single_non_existing(test_ctx): def test_trying_to_retrieve_single_non_existing(test_ctx):

View file

@ -46,6 +46,8 @@ def test_simple_updating(test_ctx, fake_datetime):
}, },
user=test_ctx.user_factory(rank=db.User.RANK_REGULAR)), user=test_ctx.user_factory(rank=db.User.RANK_REGULAR)),
'tag1') 'tag1')
assert len(result['tag']['snapshots']) == 1
del result['tag']['snapshots']
assert result['tag'] == { assert result['tag'] == {
'names': ['tag3'], 'names': ['tag3'],
'category': 'character', 'category': 'character',
@ -55,7 +57,6 @@ def test_simple_updating(test_ctx, fake_datetime):
'lastEditTime': datetime.datetime(1997, 12, 1), 'lastEditTime': datetime.datetime(1997, 12, 1),
'usages': 0, 'usages': 0,
} }
assert len(result['snapshots']) == 1
assert tags.try_get_tag_by_name('tag1') is None assert tags.try_get_tag_by_name('tag1') is None
assert tags.try_get_tag_by_name('tag2') is None assert tags.try_get_tag_by_name('tag2') is None
tag = tags.get_tag_by_name('tag3') tag = tags.get_tag_by_name('tag3')

View file

@ -56,6 +56,7 @@ def test_retrieving_single(test_ctx):
'avatarStyle': 'gravatar', 'avatarStyle': 'gravatar',
'avatarUrl': 'http://gravatar.com/avatar/' + 'avatarUrl': 'http://gravatar.com/avatar/' +
'275876e34cf609db118f3d84b799a790?d=retro&s=200', '275876e34cf609db118f3d84b799a790?d=retro&s=200',
'email': False,
} }
} }

View file

@ -64,11 +64,17 @@ def test_serialize_note():
def test_serialize_empty_post(): def test_serialize_empty_post():
assert posts.serialize_post(None, None) is None assert posts.serialize_post(None, None) is None
def test_serialize_post(post_factory, user_factory, tag_factory, config_injector): def test_serialize_post(
post_factory, user_factory, comment_factory, tag_factory, config_injector):
config_injector({'data_url': 'http://example.com/'}) config_injector({'data_url': 'http://example.com/'})
with unittest.mock.patch('szurubooru.func.users.serialize_user'), \ with unittest.mock.patch('szurubooru.func.comments.serialize_comment'), \
unittest.mock.patch('szurubooru.func.posts.files.has', return_value=True): unittest.mock.patch('szurubooru.func.users.serialize_user'), \
unittest.mock.patch('szurubooru.func.posts.files.has', return_value=True), \
unittest.mock.patch('szurubooru.func.snapshots.get_serialized_history'):
users.serialize_user.side_effect = lambda user, auth_user: user.name users.serialize_user.side_effect = lambda user, auth_user: user.name
comments.serialize_comment.side_effect \
= lambda comment, auth_user: comment.user.name
snapshots.get_serialized_history.return_value = 'snapshot history'
auth_user = user_factory(name='auth user') auth_user = user_factory(name='auth user')
post = db.Post() post = db.Post()
@ -90,6 +96,11 @@ def test_serialize_post(post_factory, user_factory, tag_factory, config_injector
post.canvas_height = 300 post.canvas_height = 300
post.flags = ['loop'] post.flags = ['loop']
db.session.add(post) db.session.add(post)
post.comments = [
comment_factory(user=user_factory(name='commenter1')),
comment_factory(user=user_factory(name='commenter2')),
]
db.session.flush() db.session.flush()
db.session.add_all([ db.session.add_all([
db.PostFavorite( db.PostFavorite(
@ -144,31 +155,6 @@ def test_serialize_post(post_factory, user_factory, tag_factory, config_injector
'favoritedBy': ['fav1'], 'favoritedBy': ['fav1'],
'hasCustomThumbnail': True, 'hasCustomThumbnail': True,
'mimeType': 'image/jpeg', 'mimeType': 'image/jpeg',
}
def test_serialize_post_with_details(post_factory, comment_factory, user_factory):
with unittest.mock.patch('szurubooru.func.comments.serialize_comment'), \
unittest.mock.patch('szurubooru.func.snapshots.get_serialized_history'), \
unittest.mock.patch('szurubooru.func.posts.serialize_post'):
comments.serialize_comment.side_effect \
= lambda comment, auth_user: comment.user.name
posts.serialize_post.side_effect \
= lambda post, auth_user: post.post_id
snapshots.get_serialized_history.return_value = 'snapshot history'
auth_user = user_factory(name='auth user')
post = post_factory()
post.comments = [
comment_factory(user=user_factory(name='commenter1')),
comment_factory(user=user_factory(name='commenter2')),
]
db.session.add(post)
db.session.flush()
result = posts.serialize_post_with_details(post, auth_user)
assert result == {
'post': post.post_id,
'snapshots': 'snapshot history', 'snapshots': 'snapshot history',
'comments': ['commenter1', 'commenter2'], 'comments': ['commenter1', 'commenter2'],
} }