diff --git a/server/szurubooru/api/post_api.py b/server/szurubooru/api/post_api.py index b048e9d..c98e205 100644 --- a/server/szurubooru/api/post_api.py +++ b/server/szurubooru/api/post_api.py @@ -37,8 +37,10 @@ class PostListApi(BaseApi): notes = ctx.get_param_as_list('notes', required=False) or [] flags = ctx.get_param_as_list('flags', required=False) or [] - post = posts.create_post( + post, new_tags = posts.create_post( content, tag_names, None if anonymous else ctx.user) + if len(new_tags): + auth.verify_privilege(ctx.user, 'tags:create') posts.update_post_safety(post, safety) posts.update_post_source(post, source) posts.update_post_relations(post, relations) @@ -65,7 +67,9 @@ class PostDetailApi(BaseApi): posts.update_post_content(post, ctx.get_file('content')) if ctx.has_param('tags'): auth.verify_privilege(ctx.user, 'posts:edit:tags') - posts.update_post_tags(post, ctx.get_param_as_list('tags')) + new_tags = posts.update_post_tags(post, ctx.get_param_as_list('tags')) + if len(new_tags): + auth.verify_privilege(ctx.user, 'tags:create') if ctx.has_param('safety'): auth.verify_privilege(ctx.user, 'posts:edit:safety') posts.update_post_safety(post, ctx.get_param_as_string('safety')) diff --git a/server/szurubooru/func/posts.py b/server/szurubooru/func/posts.py index f00eca5..4c7f5be 100644 --- a/server/szurubooru/func/posts.py +++ b/server/szurubooru/func/posts.py @@ -170,8 +170,8 @@ def create_post(content, tag_names, user): db.session.flush() update_post_content(post, content) - update_post_tags(post, tag_names) - return post + new_tags = update_post_tags(post, tag_names) + return (post, new_tags) def update_post_safety(post, safety): safety = util.flip(SAFETY_MAP).get(safety, None) @@ -251,6 +251,7 @@ def generate_post_thumbnail(post): def update_post_tags(post, tag_names): existing_tags, new_tags = tags.get_or_create_tags_by_names(tag_names) post.tags = existing_tags + new_tags + return new_tags def update_post_relations(post, new_post_ids): old_posts = post.relations diff --git a/server/szurubooru/tests/api/test_post_creating.py b/server/szurubooru/tests/api/test_post_creating.py index ae207d3..9b15379 100644 --- a/server/szurubooru/tests/api/test_post_creating.py +++ b/server/szurubooru/tests/api/test_post_creating.py @@ -11,6 +11,7 @@ def inject_config(config_injector): 'privileges': { 'posts:create:anonymous': db.User.RANK_REGULAR, 'posts:create:identified': db.User.RANK_REGULAR, + 'tags:create': db.User.RANK_REGULAR, }, }) @@ -31,7 +32,7 @@ def test_creating_minimal_posts( unittest.mock.patch('szurubooru.func.posts.serialize_post'), \ unittest.mock.patch('szurubooru.func.tags.export_to_json'), \ unittest.mock.patch('szurubooru.func.snapshots.save_entity_creation'): - posts.create_post.return_value = post + posts.create_post.return_value = (post, []) posts.serialize_post.return_value = 'serialized post' result = api.PostListApi().post( @@ -75,7 +76,7 @@ def test_creating_full_posts(context_factory, post_factory, user_factory): unittest.mock.patch('szurubooru.func.posts.serialize_post'), \ unittest.mock.patch('szurubooru.func.tags.export_to_json'), \ unittest.mock.patch('szurubooru.func.snapshots.save_entity_creation'): - posts.create_post.return_value = post + posts.create_post.return_value = (post, []) posts.serialize_post.return_value = 'serialized post' result = api.PostListApi().post( @@ -120,7 +121,7 @@ def test_anonymous_uploads( config_injector({ 'privileges': {'posts:create:anonymous': db.User.RANK_REGULAR}, }) - posts.create_post.return_value = post + posts.create_post.return_value = [post, []] api.PostListApi().post( context_factory( input={ @@ -152,7 +153,7 @@ def test_creating_from_url_saves_source( 'privileges': {'posts:create:identified': db.User.RANK_REGULAR}, }) net.download.return_value = b'content' - posts.create_post.return_value = post + posts.create_post.return_value = [post, []] api.PostListApi().post( context_factory( input={ @@ -183,7 +184,7 @@ def test_creating_from_url_with_source_specified( 'privileges': {'posts:create:identified': db.User.RANK_REGULAR}, }) net.download.return_value = b'content' - posts.create_post.return_value = post + posts.create_post.return_value = [post, []] api.PostListApi().post( context_factory( input={ @@ -222,9 +223,33 @@ def test_trying_to_omit_content(context_factory, user_factory): }, user=user_factory(rank=db.User.RANK_REGULAR))) -def test_trying_to_create_without_privileges(context_factory, user_factory): +def test_trying_to_create_post_without_privileges(context_factory, user_factory): with pytest.raises(errors.AuthError): api.PostListApi().post( context_factory( input='whatever', user=user_factory(rank=db.User.RANK_ANONYMOUS))) + +def test_trying_to_create_tags_without_privileges( + config_injector, context_factory, user_factory): + config_injector({ + 'privileges': { + 'posts:create:anonymous': db.User.RANK_REGULAR, + 'posts:create:identified': db.User.RANK_REGULAR, + 'tags:create': db.User.RANK_ADMINISTRATOR, + }, + }) + with pytest.raises(errors.AuthError), \ + unittest.mock.patch('szurubooru.func.posts.update_post_content'), \ + unittest.mock.patch('szurubooru.func.posts.update_post_tags'): + posts.update_post_tags.return_value = ['new-tag'] + api.PostListApi().post( + context_factory( + input={ + 'safety': 'safe', + 'tags': ['tag1', 'tag2'], + }, + files={ + 'content': posts.EMPTY_PIXEL, + }, + user=user_factory(rank=db.User.RANK_REGULAR))) diff --git a/server/szurubooru/tests/api/test_post_updating.py b/server/szurubooru/tests/api/test_post_updating.py index f285265..bfe05fc 100644 --- a/server/szurubooru/tests/api/test_post_updating.py +++ b/server/szurubooru/tests/api/test_post_updating.py @@ -141,7 +141,7 @@ def test_trying_to_update_non_existing(context_factory, user_factory): ('posts:edit:content', {'content': '...'}, {}), ('posts:edit:thumbnail', {'thumbnail': '...'}, {}), ]) -def test_trying_to_create_without_privileges( +def test_trying_to_update_field_without_privileges( config_injector, context_factory, post_factory, @@ -162,3 +162,23 @@ def test_trying_to_create_without_privileges( files=files, user=user_factory(rank=db.User.RANK_ANONYMOUS)), post.post_id) + +def test_trying_to_create_tags_without_privileges( + config_injector, context_factory, post_factory, user_factory): + config_injector({ + 'privileges': { + 'posts:edit:tags': db.User.RANK_REGULAR, + 'tags:create': db.User.RANK_ADMINISTRATOR, + }, + }) + post = post_factory() + db.session.add(post) + db.session.flush() + with pytest.raises(errors.AuthError), \ + unittest.mock.patch('szurubooru.func.posts.update_post_tags'): + posts.update_post_tags.return_value = ['new-tag'] + api.PostDetailApi().put( + context_factory( + input={'tags': ['tag1', 'tag2']}, + user=user_factory(rank=db.User.RANK_REGULAR)), + post.post_id) diff --git a/server/szurubooru/tests/func/test_posts.py b/server/szurubooru/tests/func/test_posts.py index e83934b..fa7be21 100644 --- a/server/szurubooru/tests/func/test_posts.py +++ b/server/szurubooru/tests/func/test_posts.py @@ -190,7 +190,7 @@ def test_create_post(user_factory, fake_datetime): unittest.mock.patch('szurubooru.func.posts.update_post_tags'), \ fake_datetime('1997-01-01'): auth_user = user_factory() - post = posts.create_post('content', ['tag'], auth_user) + post, new_tags = posts.create_post('content', ['tag'], auth_user) assert post.creation_time == datetime.datetime(1997, 1, 1) assert post.last_edit_time is None posts.update_post_tags.assert_called_once_with(post, ['tag'])