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.
Files changed (31) hide show
  1. libapidokuwiki-1.0/PKG-INFO +25 -0
  2. libapidokuwiki-1.0/README.md +2 -0
  3. libapidokuwiki-1.0/pyproject.toml +41 -0
  4. libapidokuwiki-1.0/pyproject.toml.orig +33 -0
  5. libapidokuwiki-1.0/src/libapidokuwiki/__init__.py +6 -0
  6. libapidokuwiki-1.0/src/libapidokuwiki/client/__init__.py +6 -0
  7. libapidokuwiki-1.0/src/libapidokuwiki/client/base.py +489 -0
  8. libapidokuwiki-1.0/src/libapidokuwiki/enums/__init__.py +14 -0
  9. libapidokuwiki-1.0/src/libapidokuwiki/enums/acl.py +24 -0
  10. libapidokuwiki-1.0/src/libapidokuwiki/enums/change_type.py +24 -0
  11. libapidokuwiki-1.0/src/libapidokuwiki/enums/operations/__init__.py +6 -0
  12. libapidokuwiki-1.0/src/libapidokuwiki/enums/operations/core/__init__.py +12 -0
  13. libapidokuwiki-1.0/src/libapidokuwiki/enums/operations/core/info.py +9 -0
  14. libapidokuwiki-1.0/src/libapidokuwiki/enums/operations/core/media.py +13 -0
  15. libapidokuwiki-1.0/src/libapidokuwiki/enums/operations/core/pages.py +18 -0
  16. libapidokuwiki-1.0/src/libapidokuwiki/enums/operations/core/user.py +9 -0
  17. libapidokuwiki-1.0/src/libapidokuwiki/enums/page_link_type.py +9 -0
  18. libapidokuwiki-1.0/src/libapidokuwiki/errors.py +103 -0
  19. libapidokuwiki-1.0/src/libapidokuwiki/models/__init__.py +18 -0
  20. libapidokuwiki-1.0/src/libapidokuwiki/models/base.py +11 -0
  21. libapidokuwiki-1.0/src/libapidokuwiki/models/link.py +9 -0
  22. libapidokuwiki-1.0/src/libapidokuwiki/models/media.py +14 -0
  23. libapidokuwiki-1.0/src/libapidokuwiki/models/page.py +14 -0
  24. libapidokuwiki-1.0/src/libapidokuwiki/models/search.py +16 -0
  25. libapidokuwiki-1.0/src/libapidokuwiki/models/user.py +12 -0
  26. libapidokuwiki-1.0/src/libapidokuwiki/models/version.py +14 -0
  27. libapidokuwiki-1.0/src/libapidokuwiki/py.typed +0 -0
  28. libapidokuwiki-1.0/src/libapidokuwiki/types/__init__.py +41 -0
  29. libapidokuwiki-1.0/src/libapidokuwiki/types/base.py +20 -0
  30. libapidokuwiki-1.0/src/libapidokuwiki/types/base_results.py +51 -0
  31. 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,2 @@
1
+ # libapidokuwiki
2
+
@@ -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,6 @@
1
+ from .client import DokuWikiClient
2
+
3
+
4
+ __all__: tuple[str] = (
5
+ 'DokuWikiClient',
6
+ )
@@ -0,0 +1,6 @@
1
+ from .base import DokuWikiClient
2
+
3
+
4
+ __all__: tuple[str] = (
5
+ 'DokuWikiClient',
6
+ )
@@ -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,14 @@
1
+ from .change_type import ChangeType
2
+ from .page_link_type import PageLinkType
3
+ from .acl import Acl
4
+
5
+ from .operations import core
6
+
7
+
8
+ __all__: tuple[str] = (
9
+ 'ChangeType',
10
+ 'PageLinkType',
11
+ 'Acl',
12
+
13
+ 'core',
14
+ )
@@ -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,6 @@
1
+ from . import core
2
+
3
+
4
+ __all__: tuple[str] = (
5
+ 'core',
6
+ )
@@ -0,0 +1,12 @@
1
+ from .info import Info
2
+ from .user import User
3
+ from .pages import Pages
4
+ from .media import Media
5
+
6
+
7
+ __all__: tuple[str] = (
8
+ 'Info',
9
+ 'User',
10
+ 'Pages',
11
+ 'Media',
12
+ )
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+ from enum import Enum
3
+
4
+
5
+ class Info(str, Enum):
6
+ GET_API_VERSION = 'core.getAPIVersion'
7
+ GET_WIKI_VERSION = 'core.getWikiVersion'
8
+ GET_WIKI_TITLE = 'core.getWikiTitle'
9
+ GET_WIKI_TIME = 'core.getWikiTime'
@@ -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,9 @@
1
+ from __future__ import annotations
2
+ from enum import Enum
3
+
4
+
5
+ class User(str, Enum):
6
+ LOGIN = 'core.login'
7
+ LOGOFF = 'core.logoff'
8
+ WHO_AM_I = 'core.whoAmI'
9
+ ACL_CHECK = 'core.aclCheck'
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+ from enum import Enum
3
+
4
+
5
+ class PageLinkType(str, Enum):
6
+ """Type of page link"""
7
+
8
+ local = 'local'
9
+ extern = 'extern'
@@ -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,11 @@
1
+ from __future__ import annotations
2
+
3
+ from pydantic import BaseModel, ConfigDict
4
+
5
+
6
+ class DokuWikiObject(BaseModel):
7
+ """
8
+ Base DokuWiki object.
9
+ """
10
+
11
+ model_config = ConfigDict(frozen=True)
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+
3
+ from .base import DokuWikiObject
4
+
5
+
6
+ class Link(DokuWikiObject):
7
+ type: str
8
+ page: str
9
+ href: str
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+ from datetime import datetime
3
+
4
+ from .base import DokuWikiObject
5
+
6
+
7
+ class Media(DokuWikiObject):
8
+ id: str
9
+ revision: datetime
10
+ size: int
11
+ permission: int
12
+ isimage: bool
13
+ hash: str
14
+ author: str
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+ from datetime import datetime
3
+
4
+ from .base import DokuWikiObject
5
+
6
+
7
+ class Page(DokuWikiObject):
8
+ id: str
9
+ revision: datetime
10
+ size: int
11
+ title: str
12
+ permission: int
13
+ hash: str
14
+ author: str
@@ -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
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ from .base import DokuWikiObject
4
+
5
+
6
+ class User(DokuWikiObject):
7
+ login: str
8
+ name: str
9
+ mail: str
10
+ groups: list[str]
11
+ isadmin: bool
12
+ ismanager: bool
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+ from datetime import datetime
3
+
4
+ from .base import DokuWikiObject
5
+
6
+
7
+ class Version(DokuWikiObject):
8
+ id: str
9
+ revision: datetime
10
+ author: str
11
+ ip: str
12
+ summary: str
13
+ type: str
14
+ sizechange: int
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
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+ from typing import TypedDict
3
+
4
+
5
+ class Payload(TypedDict):
6
+ jsonrpc: str
7
+ method: str
8
+ params: list
9
+ id: int