from unittest.mock import patch import pytest from szurubooru import api, db, errors, model from szurubooru.func import net, posts, snapshots, tags @pytest.fixture(autouse=True) def inject_config(config_injector): config_injector( { "privileges": { "posts:create:anonymous": model.User.RANK_REGULAR, "posts:create:identified": model.User.RANK_REGULAR, "tags:create": model.User.RANK_REGULAR, "uploads:use_downloader": model.User.RANK_REGULAR, }, "allow_broken_uploads": False, } ) def test_creating_minimal_posts(context_factory, post_factory, user_factory): auth_user = user_factory(rank=model.User.RANK_REGULAR) post = post_factory() db.session.add(post) db.session.flush() with patch("szurubooru.func.posts.create_post"), patch( "szurubooru.func.posts.update_post_safety" ), patch("szurubooru.func.posts.update_post_source"), patch( "szurubooru.func.posts.update_post_relations" ), patch( "szurubooru.func.posts.update_post_notes" ), patch( "szurubooru.func.posts.update_post_flags" ), patch( "szurubooru.func.posts.update_post_thumbnail" ), patch( "szurubooru.func.posts.serialize_post" ), patch( "szurubooru.func.snapshots.create" ): posts.create_post.return_value = (post, []) posts.serialize_post.return_value = "serialized post" result = api.post_api.create_post( context_factory( params={ "safety": "safe", "tags": ["tag1", "tag2"], }, files={ "content": "post-content", "thumbnail": "post-thumbnail", }, user=auth_user, ) ) assert result == "serialized post" posts.create_post.assert_called_once_with( "post-content", ["tag1", "tag2"], auth_user ) posts.update_post_thumbnail.assert_called_once_with( post, "post-thumbnail" ) posts.update_post_safety.assert_called_once_with(post, "safe") posts.update_post_source.assert_called_once_with(post, "") posts.update_post_relations.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_thumbnail.assert_called_once_with( post, "post-thumbnail" ) posts.serialize_post.assert_called_once_with( post, auth_user, options=[] ) snapshots.create.assert_called_once_with(post, auth_user) def test_creating_full_posts(context_factory, post_factory, user_factory): auth_user = user_factory(rank=model.User.RANK_REGULAR) post = post_factory() db.session.add(post) db.session.flush() with patch("szurubooru.func.posts.create_post"), patch( "szurubooru.func.posts.update_post_safety" ), patch("szurubooru.func.posts.update_post_source"), patch( "szurubooru.func.posts.update_post_relations" ), patch( "szurubooru.func.posts.update_post_notes" ), patch( "szurubooru.func.posts.update_post_flags" ), patch( "szurubooru.func.posts.serialize_post" ), patch( "szurubooru.func.snapshots.create" ): posts.create_post.return_value = (post, []) posts.serialize_post.return_value = "serialized post" result = api.post_api.create_post( context_factory( params={ "safety": "safe", "tags": ["tag1", "tag2"], "relations": [1, 2], "source": "source", "notes": ["note1", "note2"], "flags": ["flag1", "flag2"], }, files={ "content": "post-content", }, user=auth_user, ) ) assert result == "serialized post" posts.create_post.assert_called_once_with( "post-content", ["tag1", "tag2"], auth_user ) posts.update_post_safety.assert_called_once_with(post, "safe") posts.update_post_source.assert_called_once_with(post, "source") 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_flags.assert_called_once_with( post, ["flag1", "flag2"] ) posts.serialize_post.assert_called_once_with( post, auth_user, options=[] ) snapshots.create.assert_called_once_with(post, auth_user) def test_anonymous_uploads( config_injector, context_factory, post_factory, user_factory ): auth_user = user_factory(rank=model.User.RANK_REGULAR) post = post_factory() db.session.add(post) db.session.flush() with patch("szurubooru.func.posts.serialize_post"), patch( "szurubooru.func.posts.create_post" ), patch("szurubooru.func.posts.update_post_source"), patch( "szurubooru.func.snapshots._post_to_webhooks" ): config_injector( { "privileges": { "posts:create:anonymous": model.User.RANK_REGULAR, "uploads:use_downloader": model.User.RANK_POWER, }, } ) posts.create_post.return_value = [post, []] api.post_api.create_post( context_factory( params={ "safety": "safe", "tags": ["tag1", "tag2"], "anonymous": "True", }, files={ "content": "post-content", }, user=auth_user, ) ) posts.create_post.assert_called_once_with( "post-content", ["tag1", "tag2"], None ) def test_creating_from_url_saves_source( config_injector, context_factory, post_factory, user_factory ): auth_user = user_factory(rank=model.User.RANK_REGULAR) post = post_factory() db.session.add(post) db.session.flush() with patch("szurubooru.func.net.download"), patch( "szurubooru.func.posts.serialize_post" ), patch("szurubooru.func.posts.create_post"), patch( "szurubooru.func.posts.update_post_source" ), patch( "szurubooru.func.snapshots._post_to_webhooks" ): config_injector( { "privileges": { "posts:create:identified": model.User.RANK_REGULAR, "uploads:use_downloader": model.User.RANK_POWER, }, } ) net.download.return_value = b"content" posts.create_post.return_value = [post, []] api.post_api.create_post( context_factory( params={ "safety": "safe", "tags": ["tag1", "tag2"], "contentUrl": "example.com", }, user=auth_user, ) ) net.download.assert_called_once_with( "example.com", use_video_downloader=False ) posts.create_post.assert_called_once_with( b"content", ["tag1", "tag2"], auth_user ) posts.update_post_source.assert_called_once_with(post, "example.com") def test_creating_from_url_with_source_specified( config_injector, context_factory, post_factory, user_factory ): auth_user = user_factory(rank=model.User.RANK_REGULAR) post = post_factory() db.session.add(post) db.session.flush() with patch("szurubooru.func.net.download"), patch( "szurubooru.func.posts.serialize_post" ), patch("szurubooru.func.posts.create_post"), patch( "szurubooru.func.posts.update_post_source" ), patch( "szurubooru.func.snapshots._post_to_webhooks" ): config_injector( { "privileges": { "posts:create:identified": model.User.RANK_REGULAR, "uploads:use_downloader": model.User.RANK_REGULAR, }, } ) net.download.return_value = b"content" posts.create_post.return_value = [post, []] api.post_api.create_post( context_factory( params={ "safety": "safe", "tags": ["tag1", "tag2"], "contentUrl": "example.com", "source": "example2.com", }, user=auth_user, ) ) net.download.assert_called_once_with( "example.com", use_video_downloader=True ) posts.create_post.assert_called_once_with( b"content", ["tag1", "tag2"], auth_user ) posts.update_post_source.assert_called_once_with(post, "example2.com") @pytest.mark.parametrize("field", ["safety"]) def test_trying_to_omit_mandatory_field(context_factory, user_factory, field): params = { "safety": "safe", } del params[field] with pytest.raises(errors.MissingRequiredParameterError): api.post_api.create_post( context_factory( params=params, files={"content": "..."}, user=user_factory(rank=model.User.RANK_REGULAR), ) ) @pytest.mark.parametrize( "field", ["tags", "relations", "source", "notes", "flags"] ) def test_omitting_optional_field( field, context_factory, post_factory, user_factory ): auth_user = user_factory(rank=model.User.RANK_REGULAR) post = post_factory() db.session.add(post) db.session.flush() params = { "safety": "safe", "tags": ["tag1", "tag2"], "relations": [1, 2], "source": "source", "notes": ["note1", "note2"], "flags": ["flag1", "flag2"], } del params[field] with patch("szurubooru.func.posts.create_post"), patch( "szurubooru.func.posts.update_post_safety" ), patch("szurubooru.func.posts.update_post_source"), patch( "szurubooru.func.posts.update_post_relations" ), patch( "szurubooru.func.posts.update_post_notes" ), patch( "szurubooru.func.posts.update_post_flags" ), patch( "szurubooru.func.posts.serialize_post" ), patch( "szurubooru.func.snapshots.create" ): posts.create_post.return_value = (post, []) posts.serialize_post.return_value = "serialized post" result = api.post_api.create_post( context_factory( params=params, files={"content": "post-content"}, user=auth_user, ) ) assert result == "serialized post" def test_errors_not_spending_ids( config_injector, tmpdir, context_factory, read_asset, user_factory ): config_injector( { "data_dir": str(tmpdir.mkdir("data")), "data_url": "example.com", "thumbnails": { "post_width": 300, "post_height": 300, }, "privileges": { "posts:create:identified": model.User.RANK_REGULAR, "uploads:use_downloader": model.User.RANK_POWER, }, "secret": "test", } ) auth_user = user_factory(rank=model.User.RANK_REGULAR) # successful request with patch("szurubooru.func.posts.serialize_post"), patch( "szurubooru.func.posts.update_post_tags" ), patch("szurubooru.func.snapshots._post_to_webhooks"): posts.serialize_post.side_effect = lambda post, *_, **__: post.post_id post1_id = api.post_api.create_post( context_factory( params={"safety": "safe", "tags": []}, files={"content": read_asset("png.png")}, user=auth_user, ) ) # erroreous request (duplicate post) with pytest.raises(posts.PostAlreadyUploadedError): api.post_api.create_post( context_factory( params={"safety": "safe", "tags": []}, files={"content": read_asset("png.png")}, user=auth_user, ) ) # successful request with patch("szurubooru.func.posts.serialize_post"), patch( "szurubooru.func.posts.update_post_tags" ), patch("szurubooru.func.snapshots._post_to_webhooks"): posts.serialize_post.side_effect = lambda post, *_, **__: post.post_id post2_id = api.post_api.create_post( context_factory( params={"safety": "safe", "tags": []}, files={"content": read_asset("jpeg.jpg")}, user=auth_user, ) ) assert post1_id > 0 assert post2_id > 0 assert post2_id == post1_id + 1 def test_trying_to_omit_content(context_factory, user_factory): with pytest.raises(errors.MissingRequiredFileError): api.post_api.create_post( context_factory( params={ "safety": "safe", "tags": ["tag1", "tag2"], }, user=user_factory(rank=model.User.RANK_REGULAR), ) ) def test_trying_to_create_post_without_privileges( context_factory, user_factory ): with pytest.raises(errors.AuthError): api.post_api.create_post( context_factory( params="whatever", user=user_factory(rank=model.User.RANK_ANONYMOUS), ) ) def test_trying_to_create_tags_without_privileges( config_injector, context_factory, user_factory ): config_injector( { "privileges": { "posts:create:anonymous": model.User.RANK_REGULAR, "posts:create:identified": model.User.RANK_REGULAR, "tags:create": model.User.RANK_ADMINISTRATOR, "uploads:use_downloader": model.User.RANK_POWER, }, } ) with pytest.raises(errors.AuthError), patch( "szurubooru.func.posts.update_post_content" ), patch("szurubooru.func.posts.update_post_tags"): posts.update_post_tags.return_value = ["new-tag"] api.post_api.create_post( context_factory( params={ "safety": "safe", "tags": ["tag1", "tag2"], }, files={ "content": posts.EMPTY_PIXEL, }, user=user_factory(rank=model.User.RANK_REGULAR), ) )