wikidot.module.site のソースコード

import re
from dataclasses import dataclass
from typing import TYPE_CHECKING, Optional

import httpx

from ..common import exceptions
from ..common.decorators import login_required
from ..util.quick_module import QMCUser, QuickModule
from .forum_category import ForumCategoryCollection
from .forum_thread import ForumThread, ForumThreadCollection
from .page import Page, PageCollection, SearchPagesQuery
from .site_application import SiteApplication
from .site_member import SiteMember

if TYPE_CHECKING:
    from .client import Client
    from .user import User


[ドキュメント] class SitePagesMethods: """ サイト内のページコレクションに対する操作を提供するクラス ページの検索機能など、複数のページに対する操作を提供する。 Site.pagesプロパティを通じてアクセスする。 """ def __init__(self, site: "Site"): """ 初期化メソッド Parameters ---------- site : Site 親サイトインスタンス """ self.site = site
[ドキュメント] def search(self, **kwargs) -> "PageCollection": """ サイト内のページを検索する キーワード引数を受け取り、SearchPagesQueryオブジェクトに変換して検索を実行する。 Parameters ---------- **kwargs SearchPagesQueryに渡す検索条件。以下のパラメータが利用可能: ページ選択パラメータ: - pagetype: str - ページタイプ(例: "normal", "admin"等) - category: str - カテゴリ名 - tags: list[str] | str - タグリスト(リストまたは空白区切り文字列) - parent: str - 親ページ名 - link_to: str - リンク先ページ名 - created_at: str - 作成日時の条件(例: "> -86400 86400") - updated_at: str - 更新日時の条件 - created_by: User | str - 作成者(ユーザーオブジェクトまたはユーザー名) - rating: str - 評価値による絞り込み - votes: str - 投票数による絞り込み - name: str - ページ名による絞り込み - fullname: str - フルネームによる絞り込み(完全一致) - range: str - 範囲指定 ソートパラメータ: - order: str - ソート順(例: "created_at desc", "title asc") ページネーションパラメータ: - offset: int - 取得開始位置 - limit: int - 取得件数制限 - perPage: int - 1ページあたりの表示件数 レイアウトパラメータ: - separate: str - 個別表示するかどうか - wrapper: str - ラッパー要素を表示するかどうか Returns ------- PageCollection 検索結果のページコレクション """ query = SearchPagesQuery(**kwargs) return PageCollection.search_pages(self.site, query)
[ドキュメント] class SitePageMethods: """ サイト内の個別ページに対する操作を提供するクラス ページの取得や作成などの個別ページ操作を提供する。 Site.pageプロパティを通じてアクセスする。 """ def __init__(self, site: "Site"): """ 初期化メソッド Parameters ---------- site : Site 親サイトインスタンス """ self.site = site
[ドキュメント] def get(self, fullname: str, raise_when_not_found: bool = True) -> Optional["Page"]: """ フルネームからページを取得する Parameters ---------- fullname : str ページのフルネーム(例: "コンポーネント:scp-173") raise_when_not_found : bool, default True ページが見つからなかった場合に例外を発生させるかどうか Falseの場合、ページが見つからなければNoneを返す Returns ------- Page | None ページオブジェクト、または見つからない場合はNone Raises ------ NotFoundException raise_when_not_foundがTrueでページが見つからない場合 """ res = PageCollection.search_pages(self.site, SearchPagesQuery(fullname=fullname)) if len(res) == 0: if raise_when_not_found: raise exceptions.NotFoundException(f"Page is not found: {fullname}") return None return res[0]
[ドキュメント] def create( self, fullname: str, title: str = "", source: str = "", comment: str = "", force_edit: bool = False, ) -> "Page": """ ページを新規作成する Parameters ---------- fullname : str ページのフルネーム(例: "scp-173") title : str, default "" ページのタイトル source : str, default "" ページのソースコード(Wikidot記法) comment : str, default "" 編集コメント force_edit : bool, default False ページが既に存在する場合に上書きするかどうか Returns ------- Page 作成されたページオブジェクト Raises ------ TargetErrorException ページが既に存在し、force_editがFalseの場合 """ return Page.create_or_edit( site=self.site, fullname=fullname, title=title, source=source, comment=comment, force_edit=force_edit, raise_on_exists=True, )
[ドキュメント] class SiteForumMethods: """ サイト内のフォーラム機能に対する操作を提供するクラス フォーラムカテゴリの取得などのフォーラム関連機能を提供する。 Site.forumプロパティを通じてアクセスする。 """ def __init__(self, site: "Site"): """ 初期化メソッド Parameters ---------- site : Site 親サイトインスタンス """ self.site = site @property def categories(self) -> "ForumCategoryCollection": """ サイト内のフォーラムカテゴリ一覧を取得する Returns ------- ForumCategoryCollection フォーラムカテゴリのコレクション """ return ForumCategoryCollection.acquire_all(self.site)
[ドキュメント] @dataclass class Site: """ Wikidotサイトを表すクラス サイトの基本情報とサイトに対する様々な操作機能を提供する。 ページ、フォーラム、メンバー管理などの機能にアクセスするための起点となる。 Attributes ---------- client : Client クライアントインスタンス id : int サイトID title : str サイトのタイトル unix_name : str サイトのUNIX名(URLの一部として使用される) domain : str サイトのドメイン(完全修飾ドメイン名) ssl_supported : bool サイトがSSL/HTTPS対応しているかどうか """ client: "Client" id: int title: str unix_name: str domain: str ssl_supported: bool _members = None _moderators = None _admins = None def __post_init__(self): """ 初期化後の処理 サイト関連の機能を提供する各サブクラスのインスタンスを初期化する。 """ self.pages = SitePagesMethods(self) self.page = SitePageMethods(self) self.forum = SiteForumMethods(self) def __str__(self): """ オブジェクトの文字列表現 Returns ------- str サイトオブジェクトの文字列表現 """ return f"Site(id={self.id}, title={self.title}, unix_name={self.unix_name})"
[ドキュメント] @staticmethod def from_unix_name(client: "Client", unix_name: str) -> "Site": """ UNIX名からサイトオブジェクトを取得する 指定されたUNIX名のサイトにアクセスし、サイト情報を解析してSiteオブジェクトを生成する。 Parameters ---------- client : Client クライアントインスタンス unix_name : str サイトのUNIX名(例: "fondation") Returns ------- Site サイトオブジェクト Raises ------ NotFoundException 指定されたUNIX名のサイトが存在しない場合 UnexpectedException サイト情報の解析中にエラーが発生した場合 """ # サイト情報を取得 # リダイレクトには従う response = httpx.get( f"http://{unix_name}.wikidot.com", follow_redirects=True, timeout=client.amc_client.config.request_timeout, ) # サイトが存在しない場合 if response.status_code == httpx.codes.NOT_FOUND: raise exceptions.NotFoundException(f"Site is not found: {unix_name}.wikidot.com") # サイトが存在する場合 source = response.text # id : WIKIREQUEST.info.siteId = xxxx; id_match = re.search(r"WIKIREQUEST\.info\.siteId = (\d+);", source) if id_match is None: raise exceptions.UnexpectedException(f"Cannot find site id: {unix_name}.wikidot.com") site_id = int(id_match.group(1)) # title : titleタグ title_match = re.search(r"<title>(.*?)</title>", source) if title_match is None: raise exceptions.UnexpectedException(f"Cannot find site title: {unix_name}.wikidot.com") title = title_match.group(1) # unix_name : WIKIREQUEST.info.siteUnixName = "xxxx"; unix_name_match = re.search(r'WIKIREQUEST\.info\.siteUnixName = "(.*?)";', source) if unix_name_match is None: raise exceptions.UnexpectedException(f"Cannot find site unix_name: {unix_name}.wikidot.com") unix_name = unix_name_match.group(1) # domain :WIKIREQUEST.info.domain = "xxxx"; domain_match = re.search(r'WIKIREQUEST\.info\.domain = "(.*?)";', source) if domain_match is None: raise exceptions.UnexpectedException(f"Cannot find site domain: {unix_name}.wikidot.com") domain = domain_match.group(1) # SSL対応チェック ssl_supported = str(response.url).startswith("https") return Site( client=client, id=site_id, title=title, unix_name=unix_name, domain=domain, ssl_supported=ssl_supported, )
[ドキュメント] def amc_request(self, bodies: list[dict], return_exceptions: bool = False): """ このサイトに対してAjax Module Connectorリクエストを実行する Parameters ---------- bodies : list[dict] リクエストボディのリスト return_exceptions : bool, default False 例外を返すか送出するか(True: 返す, False: 送出する) Returns ------- list | Exception レスポンスのリスト、またはreturn_exceptionsがTrueの場合は例外 """ return self.client.amc_client.request(bodies, return_exceptions, self.unix_name, self.ssl_supported)
@property def applications(self): """ サイトへの未処理の参加申請を取得する Returns ------- list[SiteApplication] 参加申請のリスト """ return SiteApplication.acquire_all(self)
[ドキュメント] @login_required def invite_user(self, user: "User", text: str): """ ユーザーをサイトに招待する Parameters ---------- user : User 招待するユーザー text : str 招待メッセージ Raises ------ TargetErrorException ユーザーが既に招待済み、または既にメンバーの場合 WikidotStatusCodeException その他のWikidot APIエラーが発生した場合 LoginRequiredException ログインしていない場合(@login_required装飾子による) """ try: self.amc_request( [ { "action": "ManageSiteMembershipAction", "event": "inviteMember", "user_id": user.id, "text": text, "moduleName": "Empty", } ] ) except exceptions.WikidotStatusCodeException as e: if e.status_code == "already_invited": raise exceptions.TargetErrorException( f"User is already invited to {self.unix_name}: {user.name}" ) from e elif e.status_code == "already_member": raise exceptions.TargetErrorException( f"User is already a member of {self.unix_name}: {user.name}" ) from e else: raise e
@property def url(self): """ サイトのURLを取得する Returns ------- str サイトの完全なURL """ return f"http{'s' if self.ssl_supported else ''}://{self.domain}" @property def members(self): """ サイトのメンバー一覧を取得する Returns ------- list[SiteMember] サイトメンバーのリスト """ if self._members is None: self._members = SiteMember.get(self) return self._members @property def moderators(self): """ サイトのモデレーター一覧を取得する Returns ------- list[SiteMember] サイトモデレーターのリスト """ if self._moderators is None: self._moderators = SiteMember.get(self, "moderators") return self._moderators @property def admins(self): """ サイトの管理者一覧を取得する Returns ------- list[SiteMember] サイト管理者のリスト """ if self._admins is None: self._admins = SiteMember.get(self, "admins") return self._admins
[ドキュメント] def member_lookup(self, user_name: str, user_id: int | None = None): """ 指定されたユーザーがサイトのメンバーかどうかを確認する Parameters ---------- user_name : str 確認するユーザー名 user_id : int | None, default None 確認するユーザーID(指定した場合はIDも一致する必要がある) Returns ------- bool ユーザーがサイトメンバーである場合はTrue、そうでない場合はFalse """ users: list["QMCUser"] = QuickModule.member_lookup(self.id, user_name) if len(users) == 0: return False for user in users: if user.name.strip() == user_name and (user_id is None or user.id == user_id): return True return False
[ドキュメント] def get_thread(self, thread_id: int): """ スレッドを取得する Parameters ---------- thread_id : int スレッドID Returns ------- ForumThread スレッドオブジェクト """ return ForumThread.get_from_id(self, thread_id)
[ドキュメント] def get_threads(self, thread_ids: list[int]): """ 複数のスレッドを取得する Parameters ---------- thread_ids : list[int] スレッドIDのリスト Returns ------- list[ForumThread] スレッドオブジェクトのリスト """ return ForumThreadCollection.acquire_from_thread_ids(self, thread_ids)