server/general: move extra details to resources
This commit is contained in:
parent
48bcbbff83
commit
d0314813cb
27 changed files with 213 additions and 236 deletions
67
API.md
67
API.md
|
@ -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.
|
||||||
|
|
|
@ -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)}
|
||||||
|
|
|
@ -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)}
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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)}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 \
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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'],
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue