aboutsummaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorrr-2016-04-24 09:50:11 +0200
committerrr-2016-04-24 10:31:49 +0200
commit612734e9ff7b6ca500bbf8247314804e1f806a09 (patch)
treea097000d617684633b15368f13610f81d3aafe80 /server
parent6e6c57d44a3255f277542d01a9de7c3decfe1c4c (diff)
server/comments: add comment creating
Diffstat (limited to 'server')
-rw-r--r--server/szurubooru/api/__init__.py3
-rw-r--r--server/szurubooru/api/comment_api.py29
-rw-r--r--server/szurubooru/api/context.py6
-rw-r--r--server/szurubooru/app.py4
-rw-r--r--server/szurubooru/func/comments.py29
-rw-r--r--server/szurubooru/tests/api/test_comment_creating.py89
-rw-r--r--server/szurubooru/tests/conftest.py18
7 files changed, 171 insertions, 7 deletions
diff --git a/server/szurubooru/api/__init__.py b/server/szurubooru/api/__init__.py
index 3548ecd..f95f776 100644
--- a/server/szurubooru/api/__init__.py
+++ b/server/szurubooru/api/__init__.py
@@ -10,6 +10,9 @@ from szurubooru.api.tag_api import (
from szurubooru.api.tag_category_api import (
TagCategoryListApi,
TagCategoryDetailApi)
+from szurubooru.api.comment_api import (
+ CommentListApi,
+ CommentDetailApi)
from szurubooru.api.post_api import PostFeatureApi
from szurubooru.api.snapshot_api import SnapshotListApi
from szurubooru.api.info_api import InfoApi
diff --git a/server/szurubooru/api/comment_api.py b/server/szurubooru/api/comment_api.py
new file mode 100644
index 0000000..2dba81f
--- /dev/null
+++ b/server/szurubooru/api/comment_api.py
@@ -0,0 +1,29 @@
+from szurubooru.api.base_api import BaseApi
+from szurubooru.func import auth, comments, posts
+
+class CommentListApi(BaseApi):
+ def get(self, ctx):
+ raise NotImplementedError()
+
+ def post(self, ctx):
+ auth.verify_privilege(ctx.user, 'comments:create')
+
+ text = ctx.get_param_as_string('text', required=True)
+ post_id = ctx.get_param_as_int('postId', required=True)
+ post = posts.get_post_by_id(post_id)
+ if not post:
+ raise posts.PostNotFoundError('Post %r not found.' % post_id)
+ comment = comments.create_comment(ctx.user, post, text)
+ ctx.session.add(comment)
+ ctx.session.commit()
+ return {'comment': comments.serialize_comment(comment, ctx.user)}
+
+class CommentDetailApi(BaseApi):
+ def get(self, ctx, comment_id):
+ raise NotImplementedError()
+
+ def put(self, ctx, comment_id):
+ raise NotImplementedError()
+
+ def delete(self, ctx, comment_id):
+ raise NotImplementedError()
diff --git a/server/szurubooru/api/context.py b/server/szurubooru/api/context.py
index 9c4fe68..3b725fc 100644
--- a/server/szurubooru/api/context.py
+++ b/server/szurubooru/api/context.py
@@ -29,7 +29,11 @@ class Context(object):
if name in self.input:
param = self.input[name]
if isinstance(param, list):
- param = ','.join(param)
+ try:
+ param = ','.join(param)
+ except:
+ raise errors.ValidationError(
+ 'Parameter %r is invalid - expected simple string.' % name)
return param
if not required:
return default
diff --git a/server/szurubooru/app.py b/server/szurubooru/app.py
index 729351e..bae728e 100644
--- a/server/szurubooru/app.py
+++ b/server/szurubooru/app.py
@@ -58,6 +58,8 @@ def create_app():
post_feature_api = api.PostFeatureApi()
password_reset_api = api.PasswordResetApi()
snapshot_list_api = api.SnapshotListApi()
+ comment_list_api = api.CommentListApi()
+ comment_detail_api = api.CommentDetailApi()
info_api = api.InfoApi()
app.add_error_handler(errors.AuthError, _on_auth_error)
@@ -79,5 +81,7 @@ def create_app():
app.add_route('/snapshots/', snapshot_list_api)
app.add_route('/info/', info_api)
app.add_route('/featured-post/', post_feature_api)
+ app.add_route('/comments/', comment_list_api)
+ app.add_route('/comment/{comment_id}', comment_detail_api)
return app
diff --git a/server/szurubooru/func/comments.py b/server/szurubooru/func/comments.py
new file mode 100644
index 0000000..2ee3439
--- /dev/null
+++ b/server/szurubooru/func/comments.py
@@ -0,0 +1,29 @@
+import datetime
+from szurubooru import db, errors
+from szurubooru.func import users, posts
+
+class CommentNotFoundError(errors.NotFoundError): pass
+class EmptyCommentTextError(errors.ValidationError): pass
+
+def serialize_comment(comment, authenticated_user):
+ return {
+ 'id': comment.comment_id,
+ 'user': users.serialize_user(comment.user, authenticated_user),
+ 'post': posts.serialize_post(comment.post, authenticated_user),
+ 'text': comment.text,
+ 'creationTime': comment.creation_time,
+ 'lastEditTime': comment.last_edit_time,
+ }
+
+def create_comment(user, post, text):
+ comment = db.Comment()
+ comment.user = user
+ comment.post = post
+ update_comment_text(comment, text)
+ comment.creation_time = datetime.datetime.now()
+ return comment
+
+def update_comment_text(comment, text):
+ if not text:
+ raise EmptyCommentTextError('Comment text cannot be empty.')
+ comment.text = text
diff --git a/server/szurubooru/tests/api/test_comment_creating.py b/server/szurubooru/tests/api/test_comment_creating.py
new file mode 100644
index 0000000..efa9130
--- /dev/null
+++ b/server/szurubooru/tests/api/test_comment_creating.py
@@ -0,0 +1,89 @@
+import datetime
+import pytest
+from szurubooru import api, db, errors
+from szurubooru.func import util, posts
+
+@pytest.fixture
+def test_ctx(config_injector, context_factory, post_factory, user_factory):
+ config_injector({
+ 'ranks': ['anonymous', 'regular_user'],
+ 'rank_names': {'anonymous': 'Peasant', 'regular_user': 'Lord'},
+ 'privileges': {'comments:create': 'regular_user'},
+ 'thumbnails': {'avatar_width': 200},
+ })
+ ret = util.dotdict()
+ ret.context_factory = context_factory
+ ret.post_factory = post_factory
+ ret.user_factory = user_factory
+ ret.api = api.CommentListApi()
+ return ret
+
+def test_creating_comment(test_ctx, fake_datetime):
+ post = test_ctx.post_factory()
+ user = test_ctx.user_factory(rank='regular_user')
+ db.session.add_all([post, user])
+ db.session.flush()
+ with fake_datetime('1997-01-01'):
+ result = test_ctx.api.post(
+ test_ctx.context_factory(
+ input={'text': 'input', 'postId': post.post_id},
+ user=user))
+ assert result['comment']['text'] == 'input'
+ assert 'id' in result['comment']
+ assert 'user' in result['comment']
+ assert 'post' in result['comment']
+ assert 'name' in result['comment']['user']
+ assert 'id' in result['comment']['post']
+ comment = db.session.query(db.Comment).one()
+ assert comment.text == 'input'
+ assert comment.creation_time == datetime.datetime(1997, 1, 1)
+ assert comment.last_edit_time is None
+ assert comment.user and comment.user.user_id == user.user_id
+ assert comment.post and comment.post.post_id == post.post_id
+
+@pytest.mark.parametrize('input', [
+ {'text': None},
+ {'text': ''},
+ {'text': [None]},
+ {'text': ['']},
+])
+def test_trying_to_pass_invalid_input(test_ctx, input):
+ post = test_ctx.post_factory()
+ user = test_ctx.user_factory(rank='regular_user')
+ db.session.add_all([post, user])
+ db.session.flush()
+ real_input = {'text': 'input', 'postId': post.post_id}
+ for key, value in input.items():
+ real_input[key] = value
+ with pytest.raises(errors.ValidationError):
+ test_ctx.api.post(
+ test_ctx.context_factory(input=real_input, user=user))
+
+@pytest.mark.parametrize('field', ['text', 'postId'])
+def test_trying_to_omit_mandatory_field(test_ctx, field):
+ input = {
+ 'text': 'input',
+ 'postId': 1,
+ }
+ del input[field]
+ with pytest.raises(errors.ValidationError):
+ test_ctx.api.post(
+ test_ctx.context_factory(
+ input={},
+ user=test_ctx.user_factory(rank='regular_user')))
+
+def test_trying_to_comment_non_existing(test_ctx):
+ user = test_ctx.user_factory(rank='regular_user')
+ db.session.add_all([user])
+ db.session.flush()
+ with pytest.raises(posts.PostNotFoundError):
+ test_ctx.api.post(
+ test_ctx.context_factory(
+ input={'text': 'bad', 'postId': 5}, user=user))
+
+def test_trying_to_create_without_privileges(test_ctx):
+ with pytest.raises(errors.AuthError):
+ test_ctx.api.post(
+ test_ctx.context_factory(
+ input={},
+ user=test_ctx.user_factory(rank='anonymous')))
diff --git a/server/szurubooru/tests/conftest.py b/server/szurubooru/tests/conftest.py
index f99934d..be4162d 100644
--- a/server/szurubooru/tests/conftest.py
+++ b/server/szurubooru/tests/conftest.py
@@ -101,7 +101,7 @@ def user_factory():
return factory
@pytest.fixture
-def tag_category_factory(session):
+def tag_category_factory():
def factory(name='dummy', color='dummy'):
category = db.TagCategory()
category.name = name
@@ -110,11 +110,11 @@ def tag_category_factory(session):
return factory
@pytest.fixture
-def tag_factory(session):
+def tag_factory():
def factory(names=None, category=None, category_name='dummy'):
if not category:
category = db.TagCategory(category_name)
- session.add(category)
+ db.session.add(category)
tag = db.Tag()
tag.names = [db.TagName(name) for name in (names or [get_unique_name()])]
tag.category = category
@@ -140,11 +140,17 @@ def post_factory():
return factory
@pytest.fixture
-def comment_factory():
+def comment_factory(user_factory, post_factory):
def factory(user=None, post=None, text='dummy'):
+ if not user:
+ user = user_factory()
+ db.session.add(user)
+ if not post:
+ post = post_factory()
+ db.session.add(post)
comment = db.Comment()
- comment.user = user or user_factory()
- comment.post = post or post_factory()
+ comment.user = user
+ comment.post = post
comment.text = text
comment.creation_time = datetime.datetime(1996, 1, 1)
return comment

© 2015 - 2026 Jakob L. Kreuze