diff --git a/.env.example b/.env.example
index e251987..1bd5c31 100644
--- a/.env.example
+++ b/.env.example
@@ -129,7 +129,6 @@ COVER_PS_NAME = "pscover.jpg"
PODCAST = "podcast.mp3"
FILES_PATH = "files"
LOGS_PATH = "logs"
-WP_COOKIE_FILENAME = "cookie.pkl"
# KAFKA SETTINGS
KAFKA_SERVER = "kafka:9092"
diff --git a/app/bot/config.py b/app/bot/config.py
index 6e6957a..3177492 100644
--- a/app/bot/config.py
+++ b/app/bot/config.py
@@ -96,7 +96,6 @@ class Settings(BaseSettings):
COVER_RZ_NAME: str | None = None
COVER_PS_NAME: str | None = None
PODCAST: str | None = None
- WP_COOKIE_FILENAME: str | None = None
FILES_PATH: str = "files"
LOGS_PATH: str = "logs"
LOGS_ZIP_NAME: str = "logs.zip"
@@ -231,7 +230,6 @@ def parse_developer(cls, v: Any) -> int | None:
COVER_RZ_NAME = settings.COVER_RZ_NAME
COVER_PS_NAME = settings.COVER_PS_NAME
PODCAST = settings.PODCAST
-WP_COOKIE_FILENAME = settings.WP_COOKIE_FILENAME
LOGS_ZIP_NAME = settings.LOGS_ZIP_NAME
FILES_PATH: Path = PROJECT_PATH / settings.FILES_PATH
@@ -240,7 +238,6 @@ def parse_developer(cls, v: Any) -> int | None:
PODCAST_PATH = FILES_PATH / PODCAST if PODCAST else FILES_PATH / "podcast.mp3"
COVER_RZ_PATH = FILES_PATH / COVER_RZ_NAME if COVER_RZ_NAME else FILES_PATH / "cover.jpg"
COVER_PS_PATH = FILES_PATH / COVER_PS_NAME if COVER_PS_NAME else FILES_PATH / "pscover.jpg"
-WP_COOKIE_PATH = FILES_PATH / WP_COOKIE_FILENAME if WP_COOKIE_FILENAME else FILES_PATH / "cookie.pkl"
KEYBOARDS_PATH = SRC_PATH / KEYBOARDS_DIR if KEYBOARDS_DIR else SRC_PATH / "keyboards"
diff --git a/app/bot/utils/wordpress.py b/app/bot/utils/wordpress.py
deleted file mode 100644
index f2d8fd3..0000000
--- a/app/bot/utils/wordpress.py
+++ /dev/null
@@ -1,211 +0,0 @@
-import os
-import pickle
-import re
-import warnings
-from datetime import datetime
-
-import feedparser
-import requests
-from fake_useragent import UserAgent
-from loguru import logger
-from lxml import etree
-from requests import Response
-
-from config import TIMEZONE, WP_COOKIE_PATH, WP_LOGIN, WP_PASSWORD, WP_URL
-
-# TODO make this async
-# TODO: обернуть всё в определённый
-# TODO: Проблема с куками и сессией
-
-
-class WordPress:
- """
- A class for interacting with a WordPress site via the API.
-
- Attributes:
- _session (requests.Session): A session for sending HTTP requests.
- _filename (str): The path to the file for saving cookies.
- _userAgent (fake_useragent.UserAgent): A fake random user agent.
-
- Methods:
- __init__: Initialize the class and create a session.
- __enter__: Enter method for context management.
- __exit__: Exit method for context management.
- _dump_cookies: Save cookies to a file.
- _load_cookies: Load cookies from a file.
- _login: Authenticate on a WordPress site.
- _check_session: Check the session status.
- _make_session: Create a session with cookies in mind.
- close: Close the session.
- upload_post: Upload a new post to the site.
- get_last_post_id: Get the ID of the last uploaded post.
- """
-
- _instance = None
- _session: requests.Session = requests.Session()
- _filename: str = WP_COOKIE_PATH
- _userAgent: UserAgent = UserAgent().random
-
- def __new__(cls, *args, **kwargs):
- if not cls._instance:
- cls._instance = super().__new__(cls)
- return cls._instance
-
- def __init__(self):
- if not hasattr(self, "_initialized"):
- self._initialized = True # Флаг, чтобы инициализация выполнялась только раз
- self._session = None
- self._make_session()
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_value, traceback):
- self.close()
-
- def _dump_cookies(self) -> bool:
- if not self._filename:
- raise ValueError("Имя файла не может быть пустым")
-
- try:
- with open(self._filename, "wb") as f:
- pickle.dump(self._session.cookies, f)
- return True
- except Exception as e:
- print(f"Ошибка сохранения куков: {e}")
- return False
-
- def _load_cookies(self) -> bool:
- if os.path.exists(self._filename) and os.path.getsize(self._filename) > 0:
- with open(self._filename, "rb") as f:
- self._session.cookies.update(pickle.load(f))
- return True
- return False
-
- def _login(self) -> bool:
- url = f"{WP_URL}/wp-login.php"
- self._session.cookies["wordpress_test_cookie"] = "WP Cookie check"
- self._session.cookies["wp_lang"] = "ru_RU"
- form = {
- "log": WP_LOGIN,
- "pwd": WP_PASSWORD,
- "rememberme": "forever",
- "wp-submit": "Войти",
- "redirect_to": f"{WP_URL}/wp-admin/",
- "testcookie": 1,
- }
- s = self._session.post(url, data=form)
-
- if (
- s.status_code == 200
- and f'document.location.href="{WP_URL.replace("https", "http")}/wp-login.php' in s.text
- ):
- cookie_matches = re.findall(r'document\.cookie="(.*?)";', s.text)
- for match in cookie_matches:
- cookie_parts = match.split(";")
- for part in cookie_parts:
- if "=" in part:
- name, value = part.strip().split("=", 1)
- self._session.cookies[name.strip()] = value.strip()
-
- s = self._session.post(url, data=form)
- if s.status_code == 200 and f'document.location.href="{WP_URL.replace("https", "http")}/wp-admin' in s.text:
- return self._dump_cookies()
- return False
-
- def _check_session(self) -> bool:
- return (
- f'document.location.href="{WP_URL.replace("https", "http")}/wp-login.php?redirect_to='
- not in self._session.get(f"{WP_URL}/wp-admin/").text
- )
-
- def _make_session(self) -> requests.Session:
- self._session.headers = {"User-Agent": self._userAgent}
- if not (self._load_cookies() and self._check_session()):
- self._login()
-
- return self._session
-
- def close(self):
- self._session.close()
-
- def upload_post(self, info: dict) -> str:
- logger.debug("Starting post upload process")
- post = self._session.get(f"{WP_URL}/wp-admin/post-new.php?post_type=podcast").content
-
- logger.debug("Retrieved post content from WordPress")
-
- #! TODO check if exist
-
- html_dom = etree.HTML(post, etree.HTMLParser())
- podcastID = info["number"]
- name = info["title"]
- summary = info["comment"]
- chapters = ""
- for time, chapterName in info["chapters"]:
- chapters += f"[skipto time={time}]{time}[/skipto] — {chapterName}\n"
-
- time = datetime.now(TIMEZONE)
-
- timeStr = f"{time.day} {('января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря')[time.month - 1]} {time.year}" # TODO Locale settings!
-
- form = { # TODO refactor this (name.replace...)
- "post_title": f"Разговорный жанр — {podcastID}",
- "content": f"""{name.replace(podcastID + ". ", "")}
-
-Описание:
-{summary}
-
-Таймлайн:
-{chapters}
-
-Всё это вы услышите в {podcastID}-м эпизоде подкаста «Разговорный жанр».
-[podlove-template template="subscriptions"]
-Дата записи: {timeStr}""",
- "post_name": f"Разговорный жанр — {podcastID}",
- "post_category[]": "3",
- "newcategory": "Название новой рубрики",
- "newcategory_parent": "-1",
- "_podlove_meta[number]": podcastID,
- "_podlove_meta[title]": f"Разговорный жанр — {podcastID}",
- "_podlove_meta[summary]": summary,
- "_podlove_meta[type]": "full",
- "episode_contributor[0][1][id]": "1",
- "episode_contributor[0][1][comment]": "",
- "episode_contributor[0][3][id]": "3",
- "episode_contributor[0][3][comment]": "",
- "_podlove_meta[recording_date]": time.strftime("%Y-%m-%d"),
- "_podlove_meta[slug]": info["slug"],
- "_podlove_meta[chapters]": "\n".join(" ".join(x) for x in info["chapters"]),
- "_podlove_meta[duration]": info["duration"],
- "_podlove_meta[episode_assets][1]": "on",
- "trackback_url": "",
- "metakeyselect": "big_post",
- "metakeyinput": "",
- "metavalue": "1",
- "comment_status": "open",
- "ping_status": "open",
- "post_author_override": "361",
- "tax_input[shows]": "0",
- "referredby": f"{WP_URL}/wp-admin/profile.php",
- "_wp_original_http_referer": f"{WP_URL}/wp-admin/profile.php",
- "tax_input[post_tag]": ",".join(info["tags"]),
- "newtag[post_tag]": "",
- "_podlove_meta[subtitle]": "",
- "_thumbnail_id": "6038",
- }
- form_element = html_dom.find('.//form[@name="post"]')
- for field in form_element.xpath('.//input[@type="hidden"]'):
- field = field.attrib
- if field["name"] not in form:
- form[field["name"]] = field["value"]
-
- logger.debug("Submitting post data to WordPress")
- response: Response = self._session.post(f"{WP_URL}/wp-admin/post.php", data=form)
- logger.debug(f"Uploaded post with response code: {response.status_code}") # TODO
-
- @staticmethod
- def get_last_post_ID() -> str: # Deprecated
- warnings.warn("get_last_post_ID is deprecated", DeprecationWarning, stacklevel=2)
- feed = feedparser.parse(f"{WP_URL}/feed/podcast/")
- return feed["entries"][0]["itunes_episode"]
diff --git a/tests/unit/utils/wordpress/class_methods/test_enter.py b/tests/unit/utils/wordpress/class_methods/test_enter.py
deleted file mode 100644
index 96184a9..0000000
--- a/tests/unit/utils/wordpress/class_methods/test_enter.py
+++ /dev/null
@@ -1,3 +0,0 @@
-def test_enter_method(wordpress):
- with wordpress as entered_wp:
- assert entered_wp is wordpress
diff --git a/tests/unit/utils/wordpress/class_methods/test_exit.py b/tests/unit/utils/wordpress/class_methods/test_exit.py
deleted file mode 100644
index e002a41..0000000
--- a/tests/unit/utils/wordpress/class_methods/test_exit.py
+++ /dev/null
@@ -1,30 +0,0 @@
-from unittest.mock import patch
-
-import pytest
-
-from utils.wordpress import WordPress
-
-
-@patch.object(WordPress, "close")
-def test_exit_method_calls_close(mock_close, wordpress):
- with wordpress:
- pass
- # Проверяем, что метод close был вызван при выходе из контекста
- mock_close.assert_called_once()
-
-
-@patch.object(WordPress, "close")
-def test_exit_method_without_exception(mock_close, wordpress):
- with wordpress:
- pass
- # Проверяем, что close вызывается при отсутствии исключения
- mock_close.assert_called_once()
-
-
-@patch.object(WordPress, "close")
-def test_exit_method_with_exception(mock_close, wordpress):
- with pytest.raises(ValueError):
- with wordpress:
- raise ValueError("Test exception")
- # Проверяем, что close вызывается, даже если произошло исключение
- mock_close.assert_called_once()
diff --git a/tests/unit/utils/wordpress/conftest.py b/tests/unit/utils/wordpress/conftest.py
deleted file mode 100644
index f5b46cf..0000000
--- a/tests/unit/utils/wordpress/conftest.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from collections import UserDict
-from unittest.mock import MagicMock, patch
-
-import pytest
-
-from utils.wordpress import WordPress
-
-
-class TrackingDict(UserDict):
- def update(self, *args, **kwargs):
- super().update(*args, **kwargs)
-
-
-@pytest.fixture(autouse=True)
-def mock_session():
- with patch("utils.wordpress.requests.Session", new_callable=MagicMock) as MockSession:
- session_instance = MockSession.return_value
- session_instance.post = MagicMock()
- session_instance.get = MagicMock()
-
- cookies = TrackingDict()
- cookies.update = MagicMock(wraps=cookies.update)
- session_instance.cookies = cookies
- session_instance.headers = {}
- yield session_instance
-
-
-@pytest.fixture
-def wordpress(mock_session):
- with patch.object(WordPress, "__init__", lambda self: None):
- WordPress._instance = None
- wordpress_instance = WordPress()
- wordpress_instance._session = mock_session
- yield wordpress_instance
diff --git a/tests/unit/utils/wordpress/cookies/test_dump_cookies.py b/tests/unit/utils/wordpress/cookies/test_dump_cookies.py
deleted file mode 100644
index 5c10630..0000000
--- a/tests/unit/utils/wordpress/cookies/test_dump_cookies.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from unittest.mock import patch
-
-import pytest
-
-
-@patch("utils.wordpress.pickle.dump")
-@patch("utils.wordpress.open", create=True)
-def test_dump_cookies_success(mock_open, mock_pickle, wordpress, mock_session):
- """Тест на успешное сохранение куков"""
- wordpress._filename = "test_cookies.pkl"
- mock_session.cookies = {"test_cookie": "value"}
-
- mock_open.return_value.__enter__.return_value = mock_open
-
- result = wordpress._dump_cookies()
-
- assert result, "Метод _dump_cookies должен возвращать True при успешном сохранении"
- mock_pickle.assert_called_once_with(mock_session.cookies, mock_open)
-
-
-@patch("utils.wordpress.pickle.dump", side_effect=Exception("Ошибка сохранения"))
-@patch("utils.wordpress.open", create=True)
-def test_dump_cookies_fail(mock_open, mock_pickle, wordpress, mock_session):
- """Тест на ошибку при попытке сохранить куки"""
-
- wordpress._filename = "test_cookies.pkl"
-
- mock_session.cookies = {"test_cookie": "value"}
-
- mock_open.return_value.__enter__.return_value = mock_open
-
- # Проверка на случай возникновения ошибки
- result = wordpress._dump_cookies()
-
- assert not result, "Метод _dump_cookies должен возвращать False при ошибке сохранения"
- mock_pickle.assert_called_once()
-
-
-@patch("utils.wordpress.pickle.dump")
-@patch("utils.wordpress.open", create=True)
-def test_dump_cookies_no_cookies(mock_open, mock_pickle, wordpress, mock_session):
- """Тест на случай, когда в сессии нет куков для сохранения"""
-
- wordpress._filename = "test_cookies.pkl"
-
- mock_session.cookies = {}
-
- mock_open.return_value.__enter__.return_value = mock_open
-
- result = wordpress._dump_cookies()
-
- assert result, "Метод _dump_cookies должен возвращать True даже при отсутствии куков"
- mock_pickle.assert_called_once_with(mock_session.cookies, mock_open)
-
-
-@patch("utils.wordpress.pickle.dump")
-@patch("utils.wordpress.open", create=True)
-def test_dump_cookies_empty_filename(mock_open, mock_pickle, wordpress, mock_session):
- """Тест на случай отсутствия имени файла для сохранения"""
-
- wordpress._filename = "" # Пустое имя файла
-
- mock_session.cookies = {"test_cookie": "value"}
-
- mock_open.return_value.__enter__.return_value = mock_open
-
- # Проверка выполнения метода при пустом имени файла
- with pytest.raises(ValueError, match="Имя файла не может быть пустым"):
- wordpress._dump_cookies()
- mock_pickle.assert_not_called()
diff --git a/tests/unit/utils/wordpress/cookies/test_load_cookies.py b/tests/unit/utils/wordpress/cookies/test_load_cookies.py
deleted file mode 100644
index a40ad27..0000000
--- a/tests/unit/utils/wordpress/cookies/test_load_cookies.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from unittest.mock import mock_open, patch
-
-
-@patch("os.path.exists", return_value=True)
-@patch("os.path.getsize", return_value=10)
-@patch("builtins.open", new_callable=mock_open)
-@patch("pickle.load", return_value={"cookie_name": "cookie_value"})
-def test_load_cookies_file_exists_and_has_content(
- mock_pickle_load, mock_open, mock_getsize, mock_exists, wordpress, mock_session
-):
- # Выполняем метод _load_cookies
- result = wordpress._load_cookies()
-
- # Проверяем, что файл открылся и cookies обновлены
- mock_open.assert_called_once_with(wordpress._filename, "rb")
- mock_pickle_load.assert_called_once()
- mock_session.cookies.update.assert_called_once_with({"cookie_name": "cookie_value"})
- assert result is True # Метод должен вернуть True
-
-
-@patch("os.path.exists")
-@patch("os.path.getsize")
-def test_load_cookies_file_does_not_exist(mock_getsize, mock_exists, wordpress):
- mock_exists.return_value = False # Файл не существует
- mock_getsize.return_value = 0 # Размер не имеет значения, т.к. файл отсутствует
-
- result = wordpress._load_cookies()
-
- # Проверяем, что метод вернул False, так как файла нет
- assert result is False
-
-
-@patch("os.path.exists")
-@patch("os.path.getsize")
-def test_load_cookies_file_is_empty(mock_getsize, mock_exists, wordpress):
- mock_exists.return_value = True # Файл существует
- mock_getsize.return_value = 0 # Файл пустой
-
- result = wordpress._load_cookies()
-
- # Проверяем, что метод вернул False, так как файл пустой
- assert result is False
diff --git a/tests/unit/utils/wordpress/methods/test_get_last_post_id.py b/tests/unit/utils/wordpress/methods/test_get_last_post_id.py
deleted file mode 100644
index 518573a..0000000
--- a/tests/unit/utils/wordpress/methods/test_get_last_post_id.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from unittest.mock import patch
-
-import pytest
-
-
-@patch("utils.wordpress.feedparser.parse")
-def test_get_last_post_id(mock_feedparser, wordpress):
- mock_feedparser.return_value = {"entries": [{"itunes_episode": "123"}]}
-
- with pytest.warns(DeprecationWarning, match="get_last_post_ID is deprecated"):
- last_post_id = wordpress.get_last_post_ID()
-
- assert last_post_id == "123"
- mock_feedparser.assert_called_once()
diff --git a/tests/unit/utils/wordpress/methods/test_upload_post.py b/tests/unit/utils/wordpress/methods/test_upload_post.py
deleted file mode 100644
index 481dc94..0000000
--- a/tests/unit/utils/wordpress/methods/test_upload_post.py
+++ /dev/null
@@ -1,59 +0,0 @@
-def test_upload_post(mock_session, caplog, wordpress):
- info = {
- "number": "1",
- "title": "Test Title",
- "comment": "Test Comment",
- "chapters": [("00:00", "Intro")],
- "slug": "test-slug",
- "duration": "00:30",
- "tags": ["test", "post"],
- }
-
- # Настройка mock-ответов для запросов
- mock_session.get.return_value.content = b"