lunduke-bot/po/lunduke_forum.py
2025-03-07 20:54:49 +00:00

120 lines
4.7 KiB
Python

from playwright.async_api import Page, Locator
class LundukeForum:
def __init__(self, page: Page, root_url: str = "https://forum.lunduke.com"):
# URL Configuration
self.page = page
self.root_url = root_url
self.latest_url = f"{self.root_url}/latest"
self.hot_url = f"{self.root_url}/hot"
self.categories_url = f"{self.root_url}/categories"
# Locators (encapsulated here for maintainability)
self.login_modal = self.page.locator('.login-left-side')
self.username_field = self.page.locator('#login-account-name')
self.password_field = self.page.locator('#login-account-password')
self.login_button = self.page.locator('#login-button')
self.create_topic_button = self.page.locator('#create-topic')
self.topic_drafts_button = self.page.locator('[data-identifier="topic-drafts-menu"]')
self.reply_control = self.page.locator('#reply-control')
self.category_dropdown = self.page.locator('.category-input')
self.submit_button = self.page.locator('.save-or-cancel')
# Asynchronous Navigation Methods
async def goto(self, endpoint: str):
"""Navigate to a specific endpoint on the site."""
target_url = f"{self.root_url}/{endpoint}"
await self.page.goto(target_url)
async def goto_latest(self):
"""Navigate to the 'Latest' discussions page."""
await self.goto("/latest")
async def goto_categories(self):
"""Navigate to the 'Categories' page."""
await self.goto("/categories")
# Login Action
async def login(self, username: str, password: str):
"""Perform a login on the forum."""
# Go to the login page
await self.page.goto(f"{self.root_url}/login")
# Wait for login modal to appear
await self.login_modal.wait_for(state="visible", timeout=30000)
# Type username and password
await self.username_field.type(username)
await self.password_field.type(password)
# Click the login button
await self.login_button.click()
await element_not_visible(self.login_modal)
# Confirm login
await self.wait_for_dom_load()
# Create a New Topic
async def create_new_topic(self, category: str, title: str, body: str, draft: bool = True):
"""Create a new topic in the forum.
:param category: the category to place the post under
:param title: the title of the topic.
:param body: the body of the topic.
:param draft: whether to store the post as a draft. (Default: True)
:return: None
"""
# Navigate to Categories
# await self.goto_categories()
# Click 'Create Topic' button and await visibility of reply control
await self.create_topic_button.click()
await self.reply_control.wait_for(state="visible", timeout=30000)
# Fill out the topic fields
title_field = self.page.locator('[placeholder="Type title, or paste a link here"]')
body_field = self.page.locator(
'[placeholder="Type here. Use Markdown, BBCode, or HTML to format. Drag or paste images."]')
await title_field.type(title)
await body_field.type(body)
# Select the desired category
await self.category_dropdown.click()
category_locator = self.page.locator(f'[data-name="{category}"]')
await category_locator.click()
if draft:
close_button = self.page.locator('.d-button-label', has_text='Close')
await close_button.click()
save_draft = self.page.locator('.d-button-label', has_text='Save draft for later')
await save_draft.click()
await self.wait_for_dom_load()
else:
await self.submit_button.click()
await self.wait_for_dom_load()
async def publish_draft_topic(self, title: str):
# Click 'Submit' to create the topic
await self.topic_drafts_button.click()
await self._select_draft(title)
await self.submit_button.click()
await self.wait_for_dom_load()
async def _select_draft(self, title: str):
draft_entry = self.page.locator('.d-button-label', has_text=title)
await draft_entry.wait_for(state="visible", timeout=5000)
await draft_entry.click()
async def wait_for_dom_load(self):
await self.page.wait_for_load_state("domcontentloaded", timeout=30000)
# Additional Utility Methods
async def element_visible(locator: Locator, timeout: int = 10000):
"""Wait for a specific element to confirm the page has loaded."""
await locator.wait_for(state="visible", timeout=timeout)
async def element_not_visible(locator: Locator, timeout: int = 10000):
await locator.wait_for(state="hidden", timeout=timeout)