libapidokuwiki 1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- libapidokuwiki-1.0/PKG-INFO +25 -0
- libapidokuwiki-1.0/README.md +2 -0
- libapidokuwiki-1.0/pyproject.toml +41 -0
- libapidokuwiki-1.0/pyproject.toml.orig +33 -0
- libapidokuwiki-1.0/src/libapidokuwiki/__init__.py +6 -0
- libapidokuwiki-1.0/src/libapidokuwiki/client/__init__.py +6 -0
- libapidokuwiki-1.0/src/libapidokuwiki/client/base.py +489 -0
- libapidokuwiki-1.0/src/libapidokuwiki/enums/__init__.py +14 -0
- libapidokuwiki-1.0/src/libapidokuwiki/enums/acl.py +24 -0
- libapidokuwiki-1.0/src/libapidokuwiki/enums/change_type.py +24 -0
- libapidokuwiki-1.0/src/libapidokuwiki/enums/operations/__init__.py +6 -0
- libapidokuwiki-1.0/src/libapidokuwiki/enums/operations/core/__init__.py +12 -0
- libapidokuwiki-1.0/src/libapidokuwiki/enums/operations/core/info.py +9 -0
- libapidokuwiki-1.0/src/libapidokuwiki/enums/operations/core/media.py +13 -0
- libapidokuwiki-1.0/src/libapidokuwiki/enums/operations/core/pages.py +18 -0
- libapidokuwiki-1.0/src/libapidokuwiki/enums/operations/core/user.py +9 -0
- libapidokuwiki-1.0/src/libapidokuwiki/enums/page_link_type.py +9 -0
- libapidokuwiki-1.0/src/libapidokuwiki/errors.py +103 -0
- libapidokuwiki-1.0/src/libapidokuwiki/models/__init__.py +18 -0
- libapidokuwiki-1.0/src/libapidokuwiki/models/base.py +11 -0
- libapidokuwiki-1.0/src/libapidokuwiki/models/link.py +9 -0
- libapidokuwiki-1.0/src/libapidokuwiki/models/media.py +14 -0
- libapidokuwiki-1.0/src/libapidokuwiki/models/page.py +14 -0
- libapidokuwiki-1.0/src/libapidokuwiki/models/search.py +16 -0
- libapidokuwiki-1.0/src/libapidokuwiki/models/user.py +12 -0
- libapidokuwiki-1.0/src/libapidokuwiki/models/version.py +14 -0
- libapidokuwiki-1.0/src/libapidokuwiki/py.typed +0 -0
- libapidokuwiki-1.0/src/libapidokuwiki/types/__init__.py +41 -0
- libapidokuwiki-1.0/src/libapidokuwiki/types/base.py +20 -0
- libapidokuwiki-1.0/src/libapidokuwiki/types/base_results.py +51 -0
- libapidokuwiki-1.0/src/libapidokuwiki/types/payload.py +9 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: libapidokuwiki
|
|
3
|
+
Version: 1.0
|
|
4
|
+
Summary: Asynchronous client for your DokuWiki JSON API
|
|
5
|
+
Keywords: dokuwiki,api,async,client
|
|
6
|
+
Author: Ibryaev Timur
|
|
7
|
+
Author-email: Ibryaev Timur <nicecock@disroot.org>
|
|
8
|
+
License: GPL-3.0-or-later
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
11
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Classifier: Framework :: AsyncIO
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
Requires-Dist: aiohttp
|
|
17
|
+
Requires-Dist: pydantic
|
|
18
|
+
Requires-Python: >=3.14
|
|
19
|
+
Project-URL: Homepage, https://codeberg.org/ourempirecommunity/libapidokuwiki
|
|
20
|
+
Project-URL: Repository, https://codeberg.org/ourempirecommunity/libapidokuwiki
|
|
21
|
+
Project-URL: Issues, https://codeberg.org/ourempirecommunity/libapidokuwiki/issues
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# libapidokuwiki
|
|
25
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "libapidokuwiki"
|
|
3
|
+
version = "1.0"
|
|
4
|
+
description = "Asynchronous client for your DokuWiki JSON API"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.14"
|
|
7
|
+
classifiers = [
|
|
8
|
+
"Intended Audience :: Developers",
|
|
9
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
10
|
+
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
|
11
|
+
"Intended Audience :: Developers",
|
|
12
|
+
"Programming Language :: Python :: 3.14",
|
|
13
|
+
"Framework :: AsyncIO",
|
|
14
|
+
"Typing :: Typed",
|
|
15
|
+
]
|
|
16
|
+
keywords = [
|
|
17
|
+
"dokuwiki",
|
|
18
|
+
"api",
|
|
19
|
+
"async",
|
|
20
|
+
"client",
|
|
21
|
+
]
|
|
22
|
+
dependencies = [
|
|
23
|
+
"aiohttp",
|
|
24
|
+
"pydantic",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.license]
|
|
28
|
+
text = "GPL-3.0-or-later"
|
|
29
|
+
|
|
30
|
+
[[project.authors]]
|
|
31
|
+
name = "Ibryaev Timur"
|
|
32
|
+
email = "nicecock@disroot.org"
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://codeberg.org/ourempirecommunity/libapidokuwiki"
|
|
36
|
+
Repository = "https://codeberg.org/ourempirecommunity/libapidokuwiki"
|
|
37
|
+
Issues = "https://codeberg.org/ourempirecommunity/libapidokuwiki/issues"
|
|
38
|
+
|
|
39
|
+
[build-system]
|
|
40
|
+
requires = ["uv_build>=0.13.6,<0.14.0"]
|
|
41
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "libapidokuwiki"
|
|
3
|
+
version = "1.0"
|
|
4
|
+
description = "Asynchronous client for your DokuWiki JSON API"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = {text = "GPL-3.0-or-later"}
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Ibryaev Timur", email = "nicecock@disroot.org" }
|
|
9
|
+
]
|
|
10
|
+
requires-python = ">=3.14"
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
14
|
+
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"Programming Language :: Python :: 3.14",
|
|
17
|
+
"Framework :: AsyncIO",
|
|
18
|
+
"Typing :: Typed",
|
|
19
|
+
]
|
|
20
|
+
keywords = ["dokuwiki", "api", "async", "client"]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"aiohttp",
|
|
23
|
+
"pydantic"
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://codeberg.org/ourempirecommunity/libapidokuwiki"
|
|
28
|
+
Repository = "https://codeberg.org/ourempirecommunity/libapidokuwiki"
|
|
29
|
+
Issues = "https://codeberg.org/ourempirecommunity/libapidokuwiki/issues"
|
|
30
|
+
|
|
31
|
+
[build-system]
|
|
32
|
+
requires = ["uv_build>=0.13.6,<0.14.0"]
|
|
33
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
if TYPE_CHECKING:
|
|
5
|
+
from typing import Iterable
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from aiohttp import ClientResponse
|
|
8
|
+
from ..types import Payload
|
|
9
|
+
|
|
10
|
+
from aiohttp import ClientSession, ClientTimeout
|
|
11
|
+
from aiohttp.client_exceptions import ClientResponseError
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
from ..types import (
|
|
15
|
+
DokuWikiResult,
|
|
16
|
+
DokuWikiResultString,
|
|
17
|
+
DokuWikiResultInteger,
|
|
18
|
+
DokuWikiResultBoolean,
|
|
19
|
+
DokuWikiResultListString,
|
|
20
|
+
DokuWikiResultDatetime,
|
|
21
|
+
DokuWikiResultWhoAmI,
|
|
22
|
+
DokuWikiResultListPages,
|
|
23
|
+
DokuWikiResultSearchPages,
|
|
24
|
+
DokuWikiResultHistory,
|
|
25
|
+
DokuWikiResultGetPageInfo,
|
|
26
|
+
DokuWikiResultGetPageLinks,
|
|
27
|
+
DokuWikiResultListMedia,
|
|
28
|
+
DokuWikiResulGetMediaInfo,
|
|
29
|
+
)
|
|
30
|
+
from ..enums import core
|
|
31
|
+
from ..errors import (
|
|
32
|
+
DokuWikiHTTPError, DokuWikiHTMLError,
|
|
33
|
+
DokuWikiRPCError,
|
|
34
|
+
DokuWikiDataError,
|
|
35
|
+
DokuWikiBadRequestError, DokuWikiForbiddenError, DokuWikiNotFoundError, DokuWikiMethodNotAllowedError, DokuWikiInternalServerError, DokuWikiServiceUnaviableError
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class DokuWikiClient:
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
url: str,
|
|
43
|
+
token: str | None = None,
|
|
44
|
+
timeout: float = 10.0,
|
|
45
|
+
proxy_url: str | None = None
|
|
46
|
+
) -> None:
|
|
47
|
+
self._url: str = url.rstrip('/') + '/lib/exe/jsonrpc.php'
|
|
48
|
+
self.__token: str = token
|
|
49
|
+
self.__headers: dict[str, str] = {
|
|
50
|
+
'Content-Type': 'application/json',
|
|
51
|
+
'Accept': 'application/json'
|
|
52
|
+
}
|
|
53
|
+
if token:
|
|
54
|
+
self.__headers['Authorization'] = 'Bearer ' + token
|
|
55
|
+
|
|
56
|
+
self._session: ClientSession | None = None
|
|
57
|
+
self._timeout: ClientTimeout = ClientTimeout(total=timeout)
|
|
58
|
+
self._id: int = 0
|
|
59
|
+
self._proxy = proxy_url
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def token(self) -> str:
|
|
63
|
+
tkn = self.__token
|
|
64
|
+
if len(tkn) >= 12:
|
|
65
|
+
return tkn[:3] + '*' * (len(tkn) - 6) + tkn[-3:]
|
|
66
|
+
elif len(tkn) <= 3:
|
|
67
|
+
return '*' * len(tkn)
|
|
68
|
+
return tkn[:3] + '*' * (len(tkn) - 3)
|
|
69
|
+
|
|
70
|
+
async def __aenter__(self) -> DokuWikiClient:
|
|
71
|
+
if self._session is None or self._session.closed:
|
|
72
|
+
self._session = ClientSession(
|
|
73
|
+
headers=self.__headers,
|
|
74
|
+
proxy=self._proxy,
|
|
75
|
+
timeout=self._timeout
|
|
76
|
+
)
|
|
77
|
+
return self
|
|
78
|
+
|
|
79
|
+
async def __aexit__(self, exc_type, exc, tb) -> None:
|
|
80
|
+
if self._session and not self._session.closed:
|
|
81
|
+
await self._session.close()
|
|
82
|
+
|
|
83
|
+
def _get_payload(
|
|
84
|
+
self,
|
|
85
|
+
method: str,
|
|
86
|
+
params: Iterable | None
|
|
87
|
+
) -> Payload:
|
|
88
|
+
# Before calling this method, make sure to increment self._id by 1
|
|
89
|
+
return {
|
|
90
|
+
'jsonrpc': '2.0',
|
|
91
|
+
'method': method,
|
|
92
|
+
'params': params or (),
|
|
93
|
+
'id': self._id
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@staticmethod
|
|
98
|
+
def _catch_http_error(response_status: int, method: str) -> None:
|
|
99
|
+
if 200 <= response_status < 300:
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
match response_status:
|
|
103
|
+
case 400: raise DokuWikiBadRequestError(method)
|
|
104
|
+
case 403: raise DokuWikiForbiddenError(method)
|
|
105
|
+
case 404: raise DokuWikiNotFoundError(method)
|
|
106
|
+
case 405: raise DokuWikiMethodNotAllowedError(method)
|
|
107
|
+
case 500: raise DokuWikiInternalServerError(method)
|
|
108
|
+
case 503: raise DokuWikiServiceUnaviableError(method)
|
|
109
|
+
case _: raise DokuWikiHTTPError(response_status, None)
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
async def _catch_html_error(response: ClientResponse) -> None:
|
|
113
|
+
if response.content_type != 'application/json':
|
|
114
|
+
html_content = await response.text('utf-8')
|
|
115
|
+
raise DokuWikiHTMLError(response.status, html_content)
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
def _catch_data_error(data: dict[str]) -> None:
|
|
119
|
+
if 'error' in data:
|
|
120
|
+
error: dict[str] = data['error']
|
|
121
|
+
raise DokuWikiRPCError(
|
|
122
|
+
code=error.get('code'),
|
|
123
|
+
message=error.get('message')
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
if not 'result' in data:
|
|
127
|
+
raise DokuWikiDataError(
|
|
128
|
+
code=None,
|
|
129
|
+
message='JSON-RPC response has neither error nor result'
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@staticmethod
|
|
134
|
+
def _model_validate_string(data: dict[str]) -> DokuWikiResultString:
|
|
135
|
+
return DokuWikiResultString.model_validate(data)
|
|
136
|
+
|
|
137
|
+
@staticmethod
|
|
138
|
+
def _model_validate_integer(data: dict[str]) -> DokuWikiResultInteger:
|
|
139
|
+
return DokuWikiResultInteger.model_validate(data)
|
|
140
|
+
|
|
141
|
+
@staticmethod
|
|
142
|
+
def _model_validate_boolean(data: dict[str]) -> DokuWikiResultBoolean:
|
|
143
|
+
return DokuWikiResultBoolean.model_validate(data)
|
|
144
|
+
|
|
145
|
+
@staticmethod
|
|
146
|
+
def _model_validate_list_string(data: dict[str]) -> DokuWikiResultListString:
|
|
147
|
+
return DokuWikiResultListString.model_validate(data)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
async def _request(
|
|
151
|
+
self,
|
|
152
|
+
method: str,
|
|
153
|
+
*params
|
|
154
|
+
) -> DokuWikiResult:
|
|
155
|
+
if not self._session:
|
|
156
|
+
raise RuntimeError('Session isn\'t initialized')
|
|
157
|
+
|
|
158
|
+
self._id += 1
|
|
159
|
+
payload = self._get_payload(method, params)
|
|
160
|
+
|
|
161
|
+
try:
|
|
162
|
+
async with self._session.post(
|
|
163
|
+
url=self._url,
|
|
164
|
+
json=payload,
|
|
165
|
+
allow_redirects=False
|
|
166
|
+
) as response:
|
|
167
|
+
self._catch_http_error(response.status, method)
|
|
168
|
+
await self._catch_html_error(response)
|
|
169
|
+
|
|
170
|
+
data: dict[str] = await response.json()
|
|
171
|
+
self._catch_data_error(data)
|
|
172
|
+
|
|
173
|
+
return data
|
|
174
|
+
|
|
175
|
+
except ClientResponseError as e:
|
|
176
|
+
raise DokuWikiHTTPError(e.status, e.message) from e
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# Info
|
|
180
|
+
|
|
181
|
+
async def _get_api_version(self) -> DokuWikiResultInteger:
|
|
182
|
+
return self._model_validate_integer(await self._request(core.Info.GET_API_VERSION.value))
|
|
183
|
+
|
|
184
|
+
async def _get_wiki_version(self) -> DokuWikiResultString:
|
|
185
|
+
return self._model_validate_string(await self._request(core.Info.GET_WIKI_VERSION.value))
|
|
186
|
+
|
|
187
|
+
async def _get_wiki_title(self) -> DokuWikiResultString:
|
|
188
|
+
return self._model_validate_string(await self._request(core.Info.GET_WIKI_TITLE.value))
|
|
189
|
+
|
|
190
|
+
async def _get_wiki_time(self) -> DokuWikiResultDatetime:
|
|
191
|
+
return DokuWikiResultDatetime.model_validate(await self._request(core.Info.GET_WIKI_TIME.value))
|
|
192
|
+
|
|
193
|
+
# User
|
|
194
|
+
|
|
195
|
+
async def _login(self, user: str, passwd: str) -> DokuWikiResultInteger:
|
|
196
|
+
return self._model_validate_integer(await self._request(
|
|
197
|
+
core.User.LOGIN.value,
|
|
198
|
+
user, passwd
|
|
199
|
+
))
|
|
200
|
+
|
|
201
|
+
async def _logoff(self) -> DokuWikiResultInteger:
|
|
202
|
+
return self._model_validate_integer(await self._request(core.User.LOGOFF.value))
|
|
203
|
+
|
|
204
|
+
async def _whoami(self) -> DokuWikiResultWhoAmI:
|
|
205
|
+
return DokuWikiResultWhoAmI.model_validate(await self._request(core.User.WHO_AM_I.value))
|
|
206
|
+
|
|
207
|
+
async def _acl_check(self, page: str, user: str = '', groups: list[str] = []) -> DokuWikiResultInteger:
|
|
208
|
+
return self._model_validate_integer(await self._request(
|
|
209
|
+
core.User.ACL_CHECK.value,
|
|
210
|
+
page, user, groups
|
|
211
|
+
))
|
|
212
|
+
|
|
213
|
+
# Pages
|
|
214
|
+
|
|
215
|
+
async def _list_pages(self, namespace: str = '', depth: int = 1, hash: bool = False) -> DokuWikiResultListPages:
|
|
216
|
+
return DokuWikiResultListPages.model_validate(await self._request(
|
|
217
|
+
core.Pages.LIST_PAGES.value,
|
|
218
|
+
namespace, depth, hash
|
|
219
|
+
))
|
|
220
|
+
|
|
221
|
+
async def _search_pages(self, query: str) -> DokuWikiResultSearchPages:
|
|
222
|
+
return DokuWikiResultSearchPages.model_validate(await self._request(
|
|
223
|
+
core.Pages.SEARCH_PAGES.value,
|
|
224
|
+
query
|
|
225
|
+
))
|
|
226
|
+
|
|
227
|
+
async def _get_recent_page_changes(self, timestamp: int = 0) -> DokuWikiResultHistory:
|
|
228
|
+
return DokuWikiResultHistory.model_validate(await self._request(
|
|
229
|
+
core.Pages.GET_RECENT_PAGE_CHANGES.value,
|
|
230
|
+
timestamp
|
|
231
|
+
))
|
|
232
|
+
|
|
233
|
+
async def _get_page(self, page: str, rev: int = 0) -> DokuWikiResultString:
|
|
234
|
+
return self._model_validate_string(await self._request(
|
|
235
|
+
core.Pages.GET_PAGE.value,
|
|
236
|
+
page, rev
|
|
237
|
+
))
|
|
238
|
+
|
|
239
|
+
async def _get_page_html(self, page: str, rev: int = 0) -> DokuWikiResultString:
|
|
240
|
+
return self._model_validate_string(await self._request(
|
|
241
|
+
core.Pages.GET_PAGE_HTML.value,
|
|
242
|
+
page, rev
|
|
243
|
+
))
|
|
244
|
+
|
|
245
|
+
async def _get_page_info(self, page: str, rev: datetime = 0, author: bool = False, hash: bool = False) -> DokuWikiResultGetPageInfo:
|
|
246
|
+
return DokuWikiResultGetPageInfo.model_validate(await self._request(
|
|
247
|
+
core.Pages.GET_PAGE_INFO.value,
|
|
248
|
+
page, rev, author, hash
|
|
249
|
+
))
|
|
250
|
+
|
|
251
|
+
async def _get_page_history(self, page: str, first: int = 0) -> DokuWikiResultHistory:
|
|
252
|
+
return DokuWikiResultHistory.model_validate(await self._request(
|
|
253
|
+
core.Pages.GET_PAGE_HISTORY.value,
|
|
254
|
+
page, first
|
|
255
|
+
))
|
|
256
|
+
|
|
257
|
+
async def _get_page_links(self, page: str) -> DokuWikiResultGetPageLinks:
|
|
258
|
+
return DokuWikiResultGetPageLinks.model_validate(await self._request(
|
|
259
|
+
core.Pages.GET_PAGE_LINKS.value,
|
|
260
|
+
page
|
|
261
|
+
))
|
|
262
|
+
|
|
263
|
+
async def _get_page_back_links(self, page: str) -> DokuWikiResultListString:
|
|
264
|
+
return self._model_validate_list_string(await self._request(
|
|
265
|
+
core.Pages.GET_PAGE_BACK_LINKS.value,
|
|
266
|
+
page
|
|
267
|
+
))
|
|
268
|
+
|
|
269
|
+
async def _lock_pages(self, pages: list[str]) -> DokuWikiResultListString:
|
|
270
|
+
return self._model_validate_list_string(await self._request(
|
|
271
|
+
core.Pages.LOCK_PAGES.value,
|
|
272
|
+
pages
|
|
273
|
+
))
|
|
274
|
+
|
|
275
|
+
async def _unlock_pages(self, pages: list[str]) -> DokuWikiResultListString:
|
|
276
|
+
return self._model_validate_list_string(await self._request(
|
|
277
|
+
core.Pages.UNLOCK_PAGES.value,
|
|
278
|
+
pages
|
|
279
|
+
))
|
|
280
|
+
|
|
281
|
+
async def _save_page(self, page: str, text: str, summary: str = '', isminor: bool = False) -> DokuWikiResultBoolean:
|
|
282
|
+
return self._model_validate_boolean(await self._request(
|
|
283
|
+
core.Pages.SAVE_PAGE.value,
|
|
284
|
+
page, text, summary, isminor
|
|
285
|
+
))
|
|
286
|
+
|
|
287
|
+
async def _append_page(self, page: str, text: str, summary: str = '', isminor: bool = False) -> DokuWikiResultBoolean:
|
|
288
|
+
return self._model_validate_boolean(await self._request(
|
|
289
|
+
core.Pages.APPEND_PAGE.value,
|
|
290
|
+
page, text, summary, isminor
|
|
291
|
+
))
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
# Info
|
|
295
|
+
|
|
296
|
+
async def get_api_version(self):
|
|
297
|
+
result = await self._get_api_version()
|
|
298
|
+
return result.result
|
|
299
|
+
|
|
300
|
+
async def get_wiki_version(self):
|
|
301
|
+
result = await self._get_wiki_version()
|
|
302
|
+
return result.result
|
|
303
|
+
|
|
304
|
+
async def get_wiki_title(self):
|
|
305
|
+
result = await self._get_wiki_title()
|
|
306
|
+
return result.result
|
|
307
|
+
|
|
308
|
+
async def get_wiki_time(self):
|
|
309
|
+
result = await self._get_wiki_time()
|
|
310
|
+
return result.result
|
|
311
|
+
|
|
312
|
+
# User
|
|
313
|
+
|
|
314
|
+
async def login(
|
|
315
|
+
self,
|
|
316
|
+
login: str,
|
|
317
|
+
password: str
|
|
318
|
+
):
|
|
319
|
+
result = await self._login(
|
|
320
|
+
user=login,
|
|
321
|
+
passwd=password
|
|
322
|
+
)
|
|
323
|
+
return result.result
|
|
324
|
+
|
|
325
|
+
async def logoff(self):
|
|
326
|
+
result = await self._logoff()
|
|
327
|
+
return result.result
|
|
328
|
+
|
|
329
|
+
async def whoami(self):
|
|
330
|
+
result = await self._whoami()
|
|
331
|
+
return result.result
|
|
332
|
+
|
|
333
|
+
async def acl_check(
|
|
334
|
+
self,
|
|
335
|
+
id: str,
|
|
336
|
+
login: str | None = None,
|
|
337
|
+
groups: list[str] | None = None
|
|
338
|
+
):
|
|
339
|
+
result = await self._acl_check(
|
|
340
|
+
page=id,
|
|
341
|
+
user=login or '',
|
|
342
|
+
groups=groups or []
|
|
343
|
+
)
|
|
344
|
+
return result.result
|
|
345
|
+
|
|
346
|
+
# Pages
|
|
347
|
+
|
|
348
|
+
async def list_pages(
|
|
349
|
+
self,
|
|
350
|
+
namespace: str | None = None,
|
|
351
|
+
depth: int | None = None,
|
|
352
|
+
include_hash: bool | None = None
|
|
353
|
+
):
|
|
354
|
+
result = await self._list_pages(
|
|
355
|
+
namespace=namespace or '',
|
|
356
|
+
depth=depth or 1,
|
|
357
|
+
hash=include_hash or False
|
|
358
|
+
)
|
|
359
|
+
return result.result
|
|
360
|
+
|
|
361
|
+
async def search_pages(
|
|
362
|
+
self,
|
|
363
|
+
text_to_search: str
|
|
364
|
+
):
|
|
365
|
+
result = await self._search_pages(
|
|
366
|
+
query=text_to_search
|
|
367
|
+
)
|
|
368
|
+
return result.result
|
|
369
|
+
|
|
370
|
+
async def get_recent_page_changes(
|
|
371
|
+
self,
|
|
372
|
+
time: datetime | None = None
|
|
373
|
+
):
|
|
374
|
+
result = await self._get_recent_page_changes(
|
|
375
|
+
timestamp=int(time.time()) or 0
|
|
376
|
+
)
|
|
377
|
+
return result.result
|
|
378
|
+
|
|
379
|
+
async def get_page(
|
|
380
|
+
self,
|
|
381
|
+
page_id: str,
|
|
382
|
+
revision_time: datetime | None = None
|
|
383
|
+
):
|
|
384
|
+
result = await self._get_page(
|
|
385
|
+
page=page_id,
|
|
386
|
+
rev=int(revision_time.timestamp()) or 0
|
|
387
|
+
)
|
|
388
|
+
return result.result
|
|
389
|
+
|
|
390
|
+
async def get_page_html(
|
|
391
|
+
self,
|
|
392
|
+
page_id: str,
|
|
393
|
+
revision_time: datetime | None = None
|
|
394
|
+
):
|
|
395
|
+
result = await self._get_page_html(
|
|
396
|
+
page=page_id,
|
|
397
|
+
rev=int(revision_time.timestamp()) or 0
|
|
398
|
+
)
|
|
399
|
+
return result.result
|
|
400
|
+
|
|
401
|
+
async def get_page_info(
|
|
402
|
+
self,
|
|
403
|
+
page_id: str,
|
|
404
|
+
revision_time: datetime | None = None,
|
|
405
|
+
show_author: bool | None = None,
|
|
406
|
+
include_hash: bool | None = None
|
|
407
|
+
):
|
|
408
|
+
result = await self._get_page_info(
|
|
409
|
+
page=page_id,
|
|
410
|
+
rev=int(revision_time.timestamp()) or 0,
|
|
411
|
+
author=show_author or False,
|
|
412
|
+
hash=include_hash or False
|
|
413
|
+
)
|
|
414
|
+
return result.result
|
|
415
|
+
|
|
416
|
+
async def get_page_history(
|
|
417
|
+
self,
|
|
418
|
+
page_id: str,
|
|
419
|
+
skip_N_versions: int | None = None
|
|
420
|
+
):
|
|
421
|
+
result = await self._get_page_history(
|
|
422
|
+
page=page_id,
|
|
423
|
+
first=skip_N_versions
|
|
424
|
+
)
|
|
425
|
+
return result.result
|
|
426
|
+
|
|
427
|
+
async def get_page_links(
|
|
428
|
+
self,
|
|
429
|
+
page_id: str
|
|
430
|
+
):
|
|
431
|
+
result = await self._get_page_links(page_id)
|
|
432
|
+
return result.result
|
|
433
|
+
|
|
434
|
+
async def get_page_back_links(
|
|
435
|
+
self,
|
|
436
|
+
page_id: str
|
|
437
|
+
):
|
|
438
|
+
result = await self._get_page_back_links(
|
|
439
|
+
page=page_id
|
|
440
|
+
)
|
|
441
|
+
return result.result
|
|
442
|
+
|
|
443
|
+
async def lock_pages(
|
|
444
|
+
self,
|
|
445
|
+
pages_id: list[str]
|
|
446
|
+
):
|
|
447
|
+
result = await self._lock_pages(
|
|
448
|
+
pages=pages_id
|
|
449
|
+
)
|
|
450
|
+
return result.result
|
|
451
|
+
|
|
452
|
+
async def unlock_pages(
|
|
453
|
+
self,
|
|
454
|
+
pages_id: list[str]
|
|
455
|
+
):
|
|
456
|
+
result = await self._unlock_pages(
|
|
457
|
+
pages=pages_id
|
|
458
|
+
)
|
|
459
|
+
return result.result
|
|
460
|
+
|
|
461
|
+
async def save_page(
|
|
462
|
+
self,
|
|
463
|
+
page_id: str,
|
|
464
|
+
new_text: str,
|
|
465
|
+
comment: str | None = None,
|
|
466
|
+
is_minor: bool | None = None
|
|
467
|
+
):
|
|
468
|
+
result = await self._save_page(
|
|
469
|
+
page=page_id,
|
|
470
|
+
text=new_text,
|
|
471
|
+
summary=comment or '',
|
|
472
|
+
isminor=is_minor or False
|
|
473
|
+
)
|
|
474
|
+
return result.result
|
|
475
|
+
|
|
476
|
+
async def append_page(
|
|
477
|
+
self,
|
|
478
|
+
page_id: str,
|
|
479
|
+
text_to_append: str,
|
|
480
|
+
comment: str | None = None,
|
|
481
|
+
is_minor: bool | None = None
|
|
482
|
+
):
|
|
483
|
+
result = await self._append_page(
|
|
484
|
+
page=page_id,
|
|
485
|
+
text=text_to_append,
|
|
486
|
+
summary=comment or '',
|
|
487
|
+
isminor=is_minor or False
|
|
488
|
+
)
|
|
489
|
+
return result.result
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from enum import IntFlag
|
|
3
|
+
|
|
4
|
+
class Acl(IntFlag):
|
|
5
|
+
"""
|
|
6
|
+
Bitmask of the users' rights.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
NONE = 0
|
|
10
|
+
READ = 1
|
|
11
|
+
EDIT = 2
|
|
12
|
+
CREATE = 4
|
|
13
|
+
UPLOAD = 8
|
|
14
|
+
DELETE = 16
|
|
15
|
+
ADMIN = 255
|
|
16
|
+
|
|
17
|
+
# Backward compatibility aliases
|
|
18
|
+
AUTH_NONE = 0
|
|
19
|
+
AUTH_READ = 1
|
|
20
|
+
AUTH_EDIT = 2
|
|
21
|
+
AUTH_CREATE = 4
|
|
22
|
+
AUTH_UPLOAD = 8
|
|
23
|
+
AUTH_DELETE = 16
|
|
24
|
+
AUTH_ADMIN = 255
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ChangeType(str, Enum):
|
|
6
|
+
"""Type of change"""
|
|
7
|
+
|
|
8
|
+
E = 'E'
|
|
9
|
+
"""edit"""
|
|
10
|
+
C = 'C'
|
|
11
|
+
"""create"""
|
|
12
|
+
D = 'D'
|
|
13
|
+
"""delete"""
|
|
14
|
+
R = 'R'
|
|
15
|
+
"""revert"""
|
|
16
|
+
|
|
17
|
+
e = 'e'
|
|
18
|
+
"""edit"""
|
|
19
|
+
c = 'c'
|
|
20
|
+
"""create"""
|
|
21
|
+
d = 'd'
|
|
22
|
+
"""delete"""
|
|
23
|
+
r = 'r'
|
|
24
|
+
"""revert"""
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Media(str, Enum):
|
|
6
|
+
LIST_MEDIA = 'core.listMedia'
|
|
7
|
+
GET_RECENT_MEDIA_CHANGES = 'core.getRecentMediaChanges'
|
|
8
|
+
GET_MEDIA = 'core.getMedia'
|
|
9
|
+
GET_MEDIA_INFO = 'core.getMediaInfo'
|
|
10
|
+
GET_MEDIA_USAGE = 'core.getMediaUsage'
|
|
11
|
+
GET_MEDIA_HISTORY = 'core.getMediaHistory'
|
|
12
|
+
SAVE_MEDIA = 'core.saveMedia'
|
|
13
|
+
DELETE_MEDIA = 'core.deleteMedia'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Pages(str, Enum):
|
|
6
|
+
LIST_PAGES = 'core.listPages'
|
|
7
|
+
SEARCH_PAGES = 'core.searchPages'
|
|
8
|
+
GET_RECENT_PAGE_CHANGES = 'core.getRecentPageChanges'
|
|
9
|
+
GET_PAGE = 'core.getPage'
|
|
10
|
+
GET_PAGE_HTML = 'core.getPageHTML'
|
|
11
|
+
GET_PAGE_INFO = 'core.getPageInfo'
|
|
12
|
+
GET_PAGE_HISTORY = 'core.getPageHistory'
|
|
13
|
+
GET_PAGE_LINKS = 'core.getPageLinks'
|
|
14
|
+
GET_PAGE_BACK_LINKS = 'core.getPageBackLinks'
|
|
15
|
+
LOCK_PAGES = 'core.lockPages'
|
|
16
|
+
UNLOCK_PAGES = 'core.unlockPages'
|
|
17
|
+
SAVE_PAGE = 'core.savePage'
|
|
18
|
+
APPEND_PAGE = 'core.appendPage'
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from re import (
|
|
3
|
+
IGNORECASE, DOTALL,
|
|
4
|
+
search
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class _DokuWikiError(Exception):
|
|
9
|
+
def __init__(
|
|
10
|
+
self,
|
|
11
|
+
error_name: str | None = None,
|
|
12
|
+
code: int | None = None,
|
|
13
|
+
message: str | None = None
|
|
14
|
+
):
|
|
15
|
+
error_name: str = error_name or 'Unnamed Error'
|
|
16
|
+
code: int = -1 if code is None else code
|
|
17
|
+
message: str = message or 'Unknown ' + error_name
|
|
18
|
+
super().__init__(f'{error_name} {code}: {message}')
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DokuWikiHTMLError(_DokuWikiError):
|
|
22
|
+
def __init__(self, code: int | None, html_content: str | None):
|
|
23
|
+
message: str | None = None
|
|
24
|
+
if html_content:
|
|
25
|
+
title_match = search(r'<title[^>]*>(.*?)</title>', html_content, IGNORECASE | DOTALL)
|
|
26
|
+
message = title_match.group(1).strip() if title_match else None
|
|
27
|
+
|
|
28
|
+
super().__init__(
|
|
29
|
+
error_name='HTML Error',
|
|
30
|
+
code=code,
|
|
31
|
+
message=message
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
class DokuWikiHTTPError(_DokuWikiError):
|
|
35
|
+
def __init__(self, code: int | None, message: str | None):
|
|
36
|
+
super().__init__(
|
|
37
|
+
error_name='HTTP Error',
|
|
38
|
+
code=code,
|
|
39
|
+
message=message
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
class DokuWikiDataError(_DokuWikiError):
|
|
43
|
+
def __init__(self, code: int | None, message: str | None):
|
|
44
|
+
super().__init__(
|
|
45
|
+
error_name='JSON Data Error',
|
|
46
|
+
code=code,
|
|
47
|
+
message=message
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
class DokuWikiRPCError(DokuWikiDataError):
|
|
51
|
+
def __init__(self, code: int | None, message: str | None):
|
|
52
|
+
super().__init__(
|
|
53
|
+
error_name='JSON-RPC Error',
|
|
54
|
+
code=code,
|
|
55
|
+
message=message
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class _DokuWikiSpecifiedError(DokuWikiHTTPError):
|
|
60
|
+
def __init__(self, code: int, message: str):
|
|
61
|
+
super().__init__(code, message)
|
|
62
|
+
|
|
63
|
+
class DokuWikiBadRequestError(_DokuWikiSpecifiedError):
|
|
64
|
+
def __init__(self, method: str):
|
|
65
|
+
super().__init__(
|
|
66
|
+
code=400,
|
|
67
|
+
message=f'Bad request for method \'{method}\'. Is it exists? Does you have required plugins installed?'
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
class DokuWikiForbiddenError(_DokuWikiSpecifiedError):
|
|
71
|
+
def __init__(self, method: str):
|
|
72
|
+
super().__init__(
|
|
73
|
+
code=403,
|
|
74
|
+
message=f'Forbidden for method \'{method}\'. Does your token have required permissions?'
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
class DokuWikiNotFoundError(_DokuWikiSpecifiedError):
|
|
78
|
+
def __init__(self, method: str):
|
|
79
|
+
super().__init__(
|
|
80
|
+
code=404,
|
|
81
|
+
message=f'Not found for method \'{method}\'. Is it exists? Does you have required plugins installed?'
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
class DokuWikiMethodNotAllowedError(_DokuWikiSpecifiedError):
|
|
85
|
+
def __init__(self, method: str):
|
|
86
|
+
super().__init__(
|
|
87
|
+
code=405,
|
|
88
|
+
message=f'Method not allowed for method \'{method}\'. Is it exists? Does you have required plugins installed?'
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
class DokuWikiInternalServerError(_DokuWikiSpecifiedError):
|
|
92
|
+
def __init__(self, method: str):
|
|
93
|
+
super().__init__(
|
|
94
|
+
code=500,
|
|
95
|
+
message=f'Internal server error for method \'{method}\'. Try again later or contact your server administrator'
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
class DokuWikiServiceUnaviableError(_DokuWikiSpecifiedError):
|
|
99
|
+
def __init__(self, method: str):
|
|
100
|
+
super().__init__(
|
|
101
|
+
code=503,
|
|
102
|
+
message=f'Service unavailable for method \'{method}\'. Try again later or contact your server administrator'
|
|
103
|
+
)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from .base import DokuWikiObject
|
|
2
|
+
from .user import User
|
|
3
|
+
from .page import Page
|
|
4
|
+
from .link import Link
|
|
5
|
+
from .media import Media
|
|
6
|
+
from .version import Version
|
|
7
|
+
from .search import Search
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__all__: tuple[str] = (
|
|
11
|
+
'DokuWikiObject',
|
|
12
|
+
'User',
|
|
13
|
+
'Page',
|
|
14
|
+
'Link',
|
|
15
|
+
'Media',
|
|
16
|
+
'Version',
|
|
17
|
+
'Search',
|
|
18
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
|
|
4
|
+
from .base import DokuWikiObject
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Search(DokuWikiObject):
|
|
8
|
+
id: str
|
|
9
|
+
revision: datetime
|
|
10
|
+
size: int
|
|
11
|
+
title: str
|
|
12
|
+
permission: int
|
|
13
|
+
hash: str
|
|
14
|
+
author: str
|
|
15
|
+
score: int
|
|
16
|
+
snippet: str
|
|
File without changes
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from .payload import Payload
|
|
2
|
+
|
|
3
|
+
from .base import DokuWikiResult, DokuWikiError
|
|
4
|
+
from .base_results import (
|
|
5
|
+
DokuWikiResultString,
|
|
6
|
+
DokuWikiResultInteger,
|
|
7
|
+
DokuWikiResultBoolean,
|
|
8
|
+
DokuWikiResultListString,
|
|
9
|
+
DokuWikiResultDatetime,
|
|
10
|
+
DokuWikiResultWhoAmI,
|
|
11
|
+
DokuWikiResultListPages,
|
|
12
|
+
DokuWikiResultSearchPages,
|
|
13
|
+
DokuWikiResultHistory,
|
|
14
|
+
DokuWikiResultGetPageInfo,
|
|
15
|
+
DokuWikiResultGetPageLinks,
|
|
16
|
+
DokuWikiResultListMedia,
|
|
17
|
+
DokuWikiResulGetMediaInfo,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
__all__: tuple[str] = (
|
|
22
|
+
'Payload',
|
|
23
|
+
|
|
24
|
+
'DokuWikiResult',
|
|
25
|
+
'DokuWikiError',
|
|
26
|
+
|
|
27
|
+
'DokuWikiResultString',
|
|
28
|
+
'DokuWikiResultInteger',
|
|
29
|
+
'DokuWikiResultBoolean',
|
|
30
|
+
'DokuWikiResultListString',
|
|
31
|
+
'DokuWikiResultDatetime',
|
|
32
|
+
'DokuWikiResultAclCheck',
|
|
33
|
+
'DokuWikiResultWhoAmI',
|
|
34
|
+
'DokuWikiResultListPages',
|
|
35
|
+
'DokuWikiResultSearchPages',
|
|
36
|
+
'DokuWikiResultHistory',
|
|
37
|
+
'DokuWikiResultGetPageInfo',
|
|
38
|
+
'DokuWikiResultGetPageLinks',
|
|
39
|
+
'DokuWikiResultListMedia',
|
|
40
|
+
'DokuWikiResulGetMediaInfo',
|
|
41
|
+
)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DokuWikiReturnBase(BaseModel):
|
|
8
|
+
jsonrpc: str
|
|
9
|
+
id: int
|
|
10
|
+
|
|
11
|
+
class DokuWikiResult(DokuWikiReturnBase):
|
|
12
|
+
result: Any
|
|
13
|
+
|
|
14
|
+
class _DokuWikiErrorInner(BaseModel):
|
|
15
|
+
code: int
|
|
16
|
+
message: str
|
|
17
|
+
data: Any | None = None
|
|
18
|
+
|
|
19
|
+
class DokuWikiError(DokuWikiReturnBase):
|
|
20
|
+
error: _DokuWikiErrorInner
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
|
|
4
|
+
from .base import DokuWikiResult
|
|
5
|
+
from ..models import User
|
|
6
|
+
from ..models import Page
|
|
7
|
+
from ..models import Search
|
|
8
|
+
from ..models import Version
|
|
9
|
+
from ..models import Link
|
|
10
|
+
from ..models import Media
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DokuWikiResultString(DokuWikiResult):
|
|
14
|
+
result: str
|
|
15
|
+
|
|
16
|
+
class DokuWikiResultInteger(DokuWikiResult):
|
|
17
|
+
result: int
|
|
18
|
+
|
|
19
|
+
class DokuWikiResultBoolean(DokuWikiResult):
|
|
20
|
+
result: bool
|
|
21
|
+
|
|
22
|
+
class DokuWikiResultListString(DokuWikiResult):
|
|
23
|
+
result: list[str]
|
|
24
|
+
|
|
25
|
+
class DokuWikiResultDatetime(DokuWikiResult):
|
|
26
|
+
result: datetime
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class DokuWikiResultWhoAmI(DokuWikiResult):
|
|
30
|
+
result: User
|
|
31
|
+
|
|
32
|
+
class DokuWikiResultListPages(DokuWikiResult):
|
|
33
|
+
result: list[Page]
|
|
34
|
+
|
|
35
|
+
class DokuWikiResultSearchPages(DokuWikiResult):
|
|
36
|
+
result: list[Search]
|
|
37
|
+
|
|
38
|
+
class DokuWikiResultHistory(DokuWikiResult):
|
|
39
|
+
result: list[Version]
|
|
40
|
+
|
|
41
|
+
class DokuWikiResultGetPageInfo(DokuWikiResult):
|
|
42
|
+
result: Page
|
|
43
|
+
|
|
44
|
+
class DokuWikiResultGetPageLinks(DokuWikiResult):
|
|
45
|
+
result: list[Link]
|
|
46
|
+
|
|
47
|
+
class DokuWikiResultListMedia(DokuWikiResult):
|
|
48
|
+
result: list[Media]
|
|
49
|
+
|
|
50
|
+
class DokuWikiResulGetMediaInfo(DokuWikiResult):
|
|
51
|
+
result: Media
|