diff --git a/app/services/platforms/reddit_post.py b/app/services/platforms/reddit_post.py new file mode 100644 index 0000000..10393af --- /dev/null +++ b/app/services/platforms/reddit_post.py @@ -0,0 +1,25 @@ +from __future__ import annotations + +from app.core.config import get_settings +from app.services.platforms.base import PostingStrategy, PostResult +from app.services.reddit.client import RedditClient + + +class RedditPostStrategy(PostingStrategy): + """Submit a new Reddit text post via RedditClient (Playwright subprocess).""" + + campaign_type = "reddit_post" + + def execute( + self, + *, + target: str, + title: str, + body: str, + flair: str | None = None, + extra: dict | None = None, + ) -> PostResult: + settings = get_settings() + client = RedditClient(session_file=settings.reddit_session_file) + url = client.post(sub=target, title=title, body=body, flair=flair) + return PostResult(url=url) diff --git a/tests/services/platforms/test_reddit_post_strategy.py b/tests/services/platforms/test_reddit_post_strategy.py new file mode 100644 index 0000000..086edc9 --- /dev/null +++ b/tests/services/platforms/test_reddit_post_strategy.py @@ -0,0 +1,58 @@ +from unittest.mock import MagicMock, patch + +from app.services.platforms.reddit_post import RedditPostStrategy +from app.services.platforms.base import PostResult + + +def test_execute_delegates_to_reddit_client(tmp_path): + session_file = tmp_path / "session.json" + session_file.write_text('{"cookies": [], "origins": []}') + + mock_client = MagicMock() + mock_client.post.return_value = "https://reddit.com/r/test/comments/abc/title/" + + with patch("app.services.platforms.reddit_post.RedditClient", return_value=mock_client): + with patch("app.services.platforms.reddit_post.get_settings") as mock_settings: + mock_settings.return_value.reddit_session_file = str(session_file) + strategy = RedditPostStrategy() + result = strategy.execute( + target="selfhosted", + title="Test Title", + body="Test body", + flair="Showcase", + ) + + mock_client.post.assert_called_once_with( + sub="selfhosted", + title="Test Title", + body="Test body", + flair="Showcase", + ) + assert isinstance(result, PostResult) + assert result.url == "https://reddit.com/r/test/comments/abc/title/" + + +def test_execute_propagates_client_error(tmp_path): + session_file = tmp_path / "session.json" + session_file.write_text('{"cookies": [], "origins": []}') + + mock_client = MagicMock() + mock_client.post.side_effect = RuntimeError("Playwright timeout") + + with patch("app.services.platforms.reddit_post.RedditClient", return_value=mock_client): + with patch("app.services.platforms.reddit_post.get_settings") as mock_settings: + mock_settings.return_value.reddit_session_file = str(session_file) + strategy = RedditPostStrategy() + try: + strategy.execute(target="selfhosted", title="T", body="B") + assert False, "Expected RuntimeError" + except RuntimeError as e: + assert "Playwright timeout" in str(e) + + +def test_campaign_type(): + assert RedditPostStrategy.campaign_type == "reddit_post" + + +def test_supports_dupe_guard(): + assert RedditPostStrategy().supports_dupe_guard() is True