nc-py-api 0.12.1__tar.gz → 0.15.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 (57) hide show
  1. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/CHANGELOG.md +27 -0
  2. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/PKG-INFO +21 -9
  3. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/README.md +5 -5
  4. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/__init__.py +1 -1
  5. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/_session.py +18 -4
  6. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/_version.py +1 -1
  7. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/apps.py +2 -2
  8. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/__init__.py +1 -1
  9. nc_py_api-0.15.0/nc_py_api/ex_app/events_listener.py +137 -0
  10. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/integration_fastapi.py +17 -7
  11. nc_py_api-0.15.0/nc_py_api/ex_app/occ_commands.py +153 -0
  12. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/providers/providers.py +7 -0
  13. nc_py_api-0.15.0/nc_py_api/ex_app/providers/task_processing.py +197 -0
  14. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/ui/files_actions.py +45 -1
  15. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/files/__init__.py +10 -4
  16. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/files/_files.py +12 -0
  17. nc_py_api-0.15.0/nc_py_api/files/files.py +514 -0
  18. nc_py_api-0.12.1/nc_py_api/files/files.py → nc_py_api-0.15.0/nc_py_api/files/files_async.py +14 -473
  19. nc_py_api-0.15.0/nc_py_api/loginflow_v2.py +161 -0
  20. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/nextcloud.py +53 -9
  21. nc_py_api-0.15.0/nc_py_api/webhooks.py +210 -0
  22. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/pyproject.toml +117 -57
  23. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/.gitignore +0 -0
  24. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/AUTHORS +0 -0
  25. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/LICENSE.txt +0 -0
  26. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/_deffered_error.py +0 -0
  27. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/_exceptions.py +0 -0
  28. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/_misc.py +0 -0
  29. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/_preferences.py +0 -0
  30. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/_preferences_ex.py +0 -0
  31. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/_talk_api.py +0 -0
  32. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/_theming.py +0 -0
  33. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/activity.py +0 -0
  34. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/calendar.py +0 -0
  35. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/defs.py +0 -0
  36. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/misc.py +0 -0
  37. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/persist_transformers_cache.py +0 -0
  38. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/providers/__init__.py +0 -0
  39. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/providers/speech_to_text.py +0 -0
  40. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/providers/text_processing.py +0 -0
  41. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/providers/translations.py +0 -0
  42. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/ui/__init__.py +0 -0
  43. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/ui/resources.py +0 -0
  44. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/ui/settings.py +0 -0
  45. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/ui/top_menu.py +0 -0
  46. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/ui/ui.py +0 -0
  47. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/ex_app/uvicorn_fastapi.py +0 -0
  48. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/files/sharing.py +0 -0
  49. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/notes.py +0 -0
  50. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/notifications.py +0 -0
  51. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/options.py +0 -0
  52. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/talk.py +0 -0
  53. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/talk_bot.py +0 -0
  54. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/user_status.py +0 -0
  55. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/users.py +0 -0
  56. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/users_groups.py +0 -0
  57. {nc_py_api-0.12.1 → nc_py_api-0.15.0}/nc_py_api/weather_status.py +0 -0
@@ -2,6 +2,33 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.15.0 - 2024-07-19]
6
+
7
+ ### Added
8
+
9
+ - Initial Webhooks API support for the upcoming Nextcloud 30. #272
10
+
11
+ ### Changed
12
+
13
+ - NextcloudApp: `fetch_models_task` function now saves paths to downloaded models. #274 Thanks to @kyteinsky
14
+
15
+ ## [0.14.0 - 2024-07-09]
16
+
17
+ ### Added
18
+
19
+ - `LoginFlowV2` implementation by @blvdek #255
20
+ - `files.get_tags` function to get all tags assigned to the file or directory. #260
21
+ - NextcloudApp: `nc.ui.files_dropdown_menu.register_ex` to register new version of FileActions(AppAPI 2.6.0+) #252
22
+ - NextcloudApp: `enabled_state` property to check if the current ExApp is disabled or enabled. #268
23
+ - NextcloudApp: support for the new AI API for the Nextcloud 30. #254
24
+
25
+ ## [0.13.0 - 2024-04-28]
26
+
27
+ ### Added
28
+
29
+ - NextcloudApp: `occ` commands registration API(AppAPI 2.5.0+). #247
30
+ - NextcloudApp: `Nodes` events listener registration API(AppAPI 2.5.0+). #249
31
+
5
32
  ## [0.12.1 - 2024-04-05]
6
33
 
7
34
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: nc-py-api
3
- Version: 0.12.1
3
+ Version: 0.15.0
4
4
  Summary: Nextcloud Python Framework
5
5
  Project-URL: Changelog, https://github.com/cloud-py-api/nc_py_api/blob/main/CHANGELOG.md
6
6
  Project-URL: Documentation, https://cloud-py-api.github.io/nc_py_api/
@@ -38,13 +38,24 @@ Provides-Extra: app
38
38
  Requires-Dist: uvicorn[standard]>=0.23.2; extra == 'app'
39
39
  Provides-Extra: bench
40
40
  Requires-Dist: matplotlib; extra == 'bench'
41
- Requires-Dist: nc-py-api[app]; extra == 'bench'
42
41
  Requires-Dist: numpy; extra == 'bench'
43
42
  Requires-Dist: py-cpuinfo; extra == 'bench'
43
+ Requires-Dist: uvicorn[standard]>=0.23.2; extra == 'bench'
44
44
  Provides-Extra: calendar
45
45
  Requires-Dist: caldav==1.3.6; extra == 'calendar'
46
46
  Provides-Extra: dev
47
- Requires-Dist: nc-py-api[bench,calendar,dev-min]; extra == 'dev'
47
+ Requires-Dist: caldav==1.3.6; extra == 'dev'
48
+ Requires-Dist: coverage; extra == 'dev'
49
+ Requires-Dist: huggingface-hub; extra == 'dev'
50
+ Requires-Dist: matplotlib; extra == 'dev'
51
+ Requires-Dist: numpy; extra == 'dev'
52
+ Requires-Dist: pillow; extra == 'dev'
53
+ Requires-Dist: pre-commit; extra == 'dev'
54
+ Requires-Dist: py-cpuinfo; extra == 'dev'
55
+ Requires-Dist: pylint; extra == 'dev'
56
+ Requires-Dist: pytest; extra == 'dev'
57
+ Requires-Dist: pytest-asyncio; extra == 'dev'
58
+ Requires-Dist: uvicorn[standard]>=0.23.2; extra == 'dev'
48
59
  Provides-Extra: dev-min
49
60
  Requires-Dist: coverage; extra == 'dev-min'
50
61
  Requires-Dist: huggingface-hub; extra == 'dev-min'
@@ -55,12 +66,13 @@ Requires-Dist: pytest; extra == 'dev-min'
55
66
  Requires-Dist: pytest-asyncio; extra == 'dev-min'
56
67
  Provides-Extra: docs
57
68
  Requires-Dist: autodoc-pydantic>=2.0.1; extra == 'docs'
58
- Requires-Dist: nc-py-api[app,calendar]; extra == 'docs'
69
+ Requires-Dist: caldav==1.3.6; extra == 'docs'
59
70
  Requires-Dist: sphinx-copybutton; extra == 'docs'
60
71
  Requires-Dist: sphinx-inline-tabs; extra == 'docs'
61
72
  Requires-Dist: sphinx-issues>=3.0.1; extra == 'docs'
62
73
  Requires-Dist: sphinx-rtd-theme>=1; extra == 'docs'
63
74
  Requires-Dist: sphinx>=6.2; extra == 'docs'
75
+ Requires-Dist: uvicorn[standard]>=0.23.2; extra == 'docs'
64
76
  Description-Content-Type: text/markdown
65
77
 
66
78
  <p align="center">
@@ -73,7 +85,7 @@ Description-Content-Type: text/markdown
73
85
  [![Docs](https://github.com/cloud-py-api/nc_py_api/actions/workflows/docs.yml/badge.svg)](https://cloud-py-api.github.io/nc_py_api/)
74
86
  [![codecov](https://codecov.io/github/cloud-py-api/nc_py_api/branch/main/graph/badge.svg?token=C91PL3FYDQ)](https://codecov.io/github/cloud-py-api/nc_py_api)
75
87
 
76
- ![NextcloudVersion](https://img.shields.io/badge/Nextcloud-26%20%7C%2027%20%7C%2028-blue)
88
+ ![NextcloudVersion](https://img.shields.io/badge/Nextcloud-27%20%7C%2028%20%7C%2029%20%7C%2030-blue)
77
89
  ![PythonVersion](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue)
78
90
  ![impl](https://img.shields.io/pypi/implementation/nc_py_api)
79
91
  ![pypi](https://img.shields.io/pypi/v/nc_py_api.svg)
@@ -89,7 +101,7 @@ Python library that provides a robust and well-documented API that allows develo
89
101
  * **Sync + Async**: Provides both sync and async APIs.
90
102
 
91
103
  ### Capabilities
92
- | **_Capability_** | Nextcloud 26 | Nextcloud 27 | Nextcloud 28 | Nextcloud 29 |
104
+ | **_Capability_** | Nextcloud 27 | Nextcloud 28 | Nextcloud 29 | Nextcloud 30 |
93
105
  |-----------------------|:------------:|:------------:|:------------:|:------------:|
94
106
  | Calendar | ✅ | ✅ | ✅ | ✅ |
95
107
  | File System & Tags | ✅ | ✅ | ✅ | ✅ |
@@ -99,9 +111,9 @@ Python library that provides a robust and well-documented API that allows develo
99
111
  | Users & Groups | ✅ | ✅ | ✅ | ✅ |
100
112
  | User & Weather status | ✅ | ✅ | ✅ | ✅ |
101
113
  | Other APIs*** | ✅ | ✅ | ✅ | ✅ |
102
- | Talk Bot API* | N/A | ✅ | ✅ | ✅ |
103
- | Settings UI API* | N/A | N/A | N/A | ✅ |
104
- | AI Providers API** | N/A | N/A | N/A | ✅ |
114
+ | Talk Bot API* | | ✅ | ✅ | ✅ |
115
+ | Settings UI API* | N/A | N/A | | ✅ |
116
+ | AI Providers API** | N/A | N/A | | ✅ |
105
117
 
106
118
  &ast;_available only for **NextcloudApp**_<br>
107
119
  &ast;&ast;_available only for **NextcloudApp**: SpeechToText, TextProcessing, Translation_<br>
@@ -8,7 +8,7 @@
8
8
  [![Docs](https://github.com/cloud-py-api/nc_py_api/actions/workflows/docs.yml/badge.svg)](https://cloud-py-api.github.io/nc_py_api/)
9
9
  [![codecov](https://codecov.io/github/cloud-py-api/nc_py_api/branch/main/graph/badge.svg?token=C91PL3FYDQ)](https://codecov.io/github/cloud-py-api/nc_py_api)
10
10
 
11
- ![NextcloudVersion](https://img.shields.io/badge/Nextcloud-26%20%7C%2027%20%7C%2028-blue)
11
+ ![NextcloudVersion](https://img.shields.io/badge/Nextcloud-27%20%7C%2028%20%7C%2029%20%7C%2030-blue)
12
12
  ![PythonVersion](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue)
13
13
  ![impl](https://img.shields.io/pypi/implementation/nc_py_api)
14
14
  ![pypi](https://img.shields.io/pypi/v/nc_py_api.svg)
@@ -24,7 +24,7 @@ Python library that provides a robust and well-documented API that allows develo
24
24
  * **Sync + Async**: Provides both sync and async APIs.
25
25
 
26
26
  ### Capabilities
27
- | **_Capability_** | Nextcloud 26 | Nextcloud 27 | Nextcloud 28 | Nextcloud 29 |
27
+ | **_Capability_** | Nextcloud 27 | Nextcloud 28 | Nextcloud 29 | Nextcloud 30 |
28
28
  |-----------------------|:------------:|:------------:|:------------:|:------------:|
29
29
  | Calendar | ✅ | ✅ | ✅ | ✅ |
30
30
  | File System & Tags | ✅ | ✅ | ✅ | ✅ |
@@ -34,9 +34,9 @@ Python library that provides a robust and well-documented API that allows develo
34
34
  | Users & Groups | ✅ | ✅ | ✅ | ✅ |
35
35
  | User & Weather status | ✅ | ✅ | ✅ | ✅ |
36
36
  | Other APIs*** | ✅ | ✅ | ✅ | ✅ |
37
- | Talk Bot API* | N/A | ✅ | ✅ | ✅ |
38
- | Settings UI API* | N/A | N/A | N/A | ✅ |
39
- | AI Providers API** | N/A | N/A | N/A | ✅ |
37
+ | Talk Bot API* | | ✅ | ✅ | ✅ |
38
+ | Settings UI API* | N/A | N/A | | ✅ |
39
+ | AI Providers API** | N/A | N/A | | ✅ |
40
40
 
41
41
  &ast;_available only for **NextcloudApp**_<br>
42
42
  &ast;&ast;_available only for **NextcloudApp**: SpeechToText, TextProcessing, Translation_<br>
@@ -7,6 +7,6 @@ from ._exceptions import (
7
7
  NextcloudMissingCapabilities,
8
8
  )
9
9
  from ._version import __version__
10
- from .files import FilePermissions, FsNode, LockType
10
+ from .files import FilePermissions, FsNode, LockType, SystemTag
11
11
  from .files.sharing import ShareType
12
12
  from .nextcloud import AsyncNextcloud, AsyncNextcloudApp, Nextcloud, NextcloudApp
@@ -103,7 +103,10 @@ class Config(BasicConfig):
103
103
 
104
104
  def __init__(self, **kwargs):
105
105
  super().__init__(**kwargs)
106
- self.auth = (self._get_config_value("nc_auth_user", **kwargs), self._get_config_value("nc_auth_pass", **kwargs))
106
+ nc_auth_user = self._get_config_value("nc_auth_user", raise_not_found=False, **kwargs)
107
+ nc_auth_pass = self._get_config_value("nc_auth_pass", raise_not_found=False, **kwargs)
108
+ if nc_auth_user and nc_auth_pass:
109
+ self.auth = (nc_auth_user, nc_auth_pass)
107
110
 
108
111
 
109
112
  @dataclass
@@ -173,9 +176,14 @@ class NcSessionBase(ABC):
173
176
 
174
177
  @property
175
178
  def ae_url(self) -> str:
176
- """Return base url for the App Ecosystem endpoints."""
179
+ """Return base url for the AppAPI endpoints."""
177
180
  return "/ocs/v1.php/apps/app_api/api/v1"
178
181
 
182
+ @property
183
+ def ae_url_v2(self) -> str:
184
+ """Return base url for the AppAPI endpoints(version 2)."""
185
+ return "/ocs/v1.php/apps/app_api/api/v2"
186
+
179
187
 
180
188
  class NcSessionBasic(NcSessionBase, ABC):
181
189
  adapter: Client
@@ -189,13 +197,16 @@ class NcSessionBasic(NcSessionBase, ABC):
189
197
  content: bytes | str | typing.Iterable[bytes] | typing.AsyncIterable[bytes] | None = None,
190
198
  json: dict | list | None = None,
191
199
  params: dict | None = None,
200
+ files: dict | None = None,
192
201
  **kwargs,
193
202
  ):
194
203
  self.init_adapter()
195
204
  info = f"request: {method} {path}"
196
205
  nested_req = kwargs.pop("nested_req", False)
197
206
  try:
198
- response = self.adapter.request(method, path, content=content, json=json, params=params, **kwargs)
207
+ response = self.adapter.request(
208
+ method, path, content=content, json=json, params=params, files=files, **kwargs
209
+ )
199
210
  except ReadTimeout:
200
211
  raise NextcloudException(408, info=info) from None
201
212
 
@@ -307,13 +318,16 @@ class AsyncNcSessionBasic(NcSessionBase, ABC):
307
318
  content: bytes | str | typing.Iterable[bytes] | typing.AsyncIterable[bytes] | None = None,
308
319
  json: dict | list | None = None,
309
320
  params: dict | None = None,
321
+ files: dict | None = None,
310
322
  **kwargs,
311
323
  ):
312
324
  self.init_adapter()
313
325
  info = f"request: {method} {path}"
314
326
  nested_req = kwargs.pop("nested_req", False)
315
327
  try:
316
- response = await self.adapter.request(method, path, content=content, json=json, params=params, **kwargs)
328
+ response = await self.adapter.request(
329
+ method, path, content=content, json=json, params=params, files=files, **kwargs
330
+ )
317
331
  except ReadTimeout:
318
332
  raise NextcloudException(408, info=info) from None
319
333
 
@@ -1,3 +1,3 @@
1
1
  """Version of nc_py_api."""
2
2
 
3
- __version__ = "0.12.1"
3
+ __version__ = "0.15.0"
@@ -43,8 +43,8 @@ class ExAppInfo:
43
43
 
44
44
  @property
45
45
  def system(self) -> bool:
46
- """Flag indicating if the application is a system application."""
47
- return bool(self._raw_data["system"])
46
+ """**DEPRECATED** Flag indicating if the application is a system application."""
47
+ return True
48
48
 
49
49
  def __repr__(self):
50
50
  return f"<{self.__class__.__name__} id={self.app_id}, ver={self.version}>"
@@ -21,4 +21,4 @@ from .uvicorn_fastapi import run_app
21
21
 
22
22
 
23
23
  class UiActionFileInfo(ActionFileInfo):
24
- """``Deprecated``: use :py:class:`~nc_py_api.ex_app.ActionFileInfo` instead."""
24
+ """``Deprecated``: use :py:class:`~nc_py_api.files.ActionFileInfo` instead."""
@@ -0,0 +1,137 @@
1
+ """Nextcloud API for registering Events listeners for ExApps."""
2
+
3
+ import dataclasses
4
+
5
+ from .._exceptions import NextcloudExceptionNotFound
6
+ from .._misc import require_capabilities
7
+ from .._session import AsyncNcSessionApp, NcSessionApp
8
+
9
+ _EP_SUFFIX: str = "events_listener"
10
+
11
+
12
+ @dataclasses.dataclass
13
+ class EventsListener:
14
+ """EventsListener description."""
15
+
16
+ def __init__(self, raw_data: dict):
17
+ self._raw_data = raw_data
18
+
19
+ @property
20
+ def event_type(self) -> str:
21
+ """Main type of event, e.g. ``node_event``."""
22
+ return self._raw_data["event_type"]
23
+
24
+ @property
25
+ def event_subtypes(self) -> str:
26
+ """Subtypes for which fire event, e.g. ``NodeCreatedEvent``, ``NodeDeletedEvent``."""
27
+ return self._raw_data["event_subtypes"]
28
+
29
+ @property
30
+ def action_handler(self) -> str:
31
+ """Relative ExApp url which will be called by Nextcloud."""
32
+ return self._raw_data["action_handler"]
33
+
34
+ def __repr__(self):
35
+ return f"<{self.__class__.__name__} event_type={self.event_type}, handler={self.action_handler}>"
36
+
37
+
38
+ class EventsListenerAPI:
39
+ """API for registering Events listeners, avalaible as **nc.events_handler.<method>**."""
40
+
41
+ def __init__(self, session: NcSessionApp):
42
+ self._session = session
43
+
44
+ def register(
45
+ self,
46
+ event_type: str,
47
+ callback_url: str,
48
+ event_subtypes: list[str] | None = None,
49
+ ) -> None:
50
+ """Registers or edits the events listener."""
51
+ if event_subtypes is None:
52
+ event_subtypes = []
53
+ require_capabilities("app_api", self._session.capabilities)
54
+ params = {
55
+ "eventType": event_type,
56
+ "actionHandler": callback_url,
57
+ "eventSubtypes": event_subtypes,
58
+ }
59
+ self._session.ocs("POST", f"{self._session.ae_url}/{_EP_SUFFIX}", json=params)
60
+
61
+ def unregister(self, event_type: str, not_fail=True) -> None:
62
+ """Removes the events listener."""
63
+ require_capabilities("app_api", self._session.capabilities)
64
+ try:
65
+ self._session.ocs(
66
+ "DELETE",
67
+ f"{self._session.ae_url}/{_EP_SUFFIX}",
68
+ params={"eventType": event_type},
69
+ )
70
+ except NextcloudExceptionNotFound as e:
71
+ if not not_fail:
72
+ raise e from None
73
+
74
+ def get_entry(self, event_type: str) -> EventsListener | None:
75
+ """Get information about the event listener."""
76
+ require_capabilities("app_api", self._session.capabilities)
77
+ try:
78
+ return EventsListener(
79
+ self._session.ocs(
80
+ "GET",
81
+ f"{self._session.ae_url}/{_EP_SUFFIX}",
82
+ params={"eventType": event_type},
83
+ )
84
+ )
85
+ except NextcloudExceptionNotFound:
86
+ return None
87
+
88
+
89
+ class AsyncEventsListenerAPI:
90
+ """API for registering Events listeners, avalaible as **nc.events_handler.<method>**."""
91
+
92
+ def __init__(self, session: AsyncNcSessionApp):
93
+ self._session = session
94
+
95
+ async def register(
96
+ self,
97
+ event_type: str,
98
+ callback_url: str,
99
+ event_subtypes: list[str] | None = None,
100
+ ) -> None:
101
+ """Registers or edits the events listener."""
102
+ if event_subtypes is None:
103
+ event_subtypes = []
104
+ require_capabilities("app_api", await self._session.capabilities)
105
+ params = {
106
+ "eventType": event_type,
107
+ "actionHandler": callback_url,
108
+ "eventSubtypes": event_subtypes,
109
+ }
110
+ await self._session.ocs("POST", f"{self._session.ae_url}/{_EP_SUFFIX}", json=params)
111
+
112
+ async def unregister(self, event_type: str, not_fail=True) -> None:
113
+ """Removes the events listener."""
114
+ require_capabilities("app_api", await self._session.capabilities)
115
+ try:
116
+ await self._session.ocs(
117
+ "DELETE",
118
+ f"{self._session.ae_url}/{_EP_SUFFIX}",
119
+ params={"eventType": event_type},
120
+ )
121
+ except NextcloudExceptionNotFound as e:
122
+ if not not_fail:
123
+ raise e from None
124
+
125
+ async def get_entry(self, event_type: str) -> EventsListener | None:
126
+ """Get information about the event listener."""
127
+ require_capabilities("app_api", await self._session.capabilities)
128
+ try:
129
+ return EventsListener(
130
+ await self._session.ocs(
131
+ "GET",
132
+ f"{self._session.ae_url}/{_EP_SUFFIX}",
133
+ params={"eventType": event_type},
134
+ )
135
+ )
136
+ except NextcloudExceptionNotFound:
137
+ return None
@@ -127,22 +127,26 @@ def fetch_models_task(nc: NextcloudApp, models: dict[str, dict], progress_init_s
127
127
  percent_for_each = min(int((100 - progress_init_start_value) / len(models)), 99)
128
128
  for model in models:
129
129
  if model.startswith(("http://", "https://")):
130
- __fetch_model_as_file(current_progress, percent_for_each, nc, model, models[model])
130
+ models[model]["path"] = __fetch_model_as_file(
131
+ current_progress, percent_for_each, nc, model, models[model]
132
+ )
131
133
  else:
132
- __fetch_model_as_snapshot(current_progress, percent_for_each, nc, model, models[model])
134
+ models[model]["path"] = __fetch_model_as_snapshot(
135
+ current_progress, percent_for_each, nc, model, models[model]
136
+ )
133
137
  current_progress += percent_for_each
134
138
  nc.set_init_status(100)
135
139
 
136
140
 
137
141
  def __fetch_model_as_file(
138
142
  current_progress: int, progress_for_task: int, nc: NextcloudApp, model_path: str, download_options: dict
139
- ) -> None:
143
+ ) -> str | None:
140
144
  result_path = download_options.pop("save_path", urlparse(model_path).path.split("/")[-1])
141
145
  try:
142
146
  with httpx.stream("GET", model_path, follow_redirects=True) as response:
143
147
  if not response.is_success:
144
148
  nc.log(LogLvl.ERROR, f"Downloading of '{model_path}' returned {response.status_code} status.")
145
- return
149
+ return None
146
150
  downloaded_size = 0
147
151
  linked_etag = ""
148
152
  for each_history in response.history:
@@ -163,7 +167,7 @@ def __fetch_model_as_file(
163
167
  sha256_hash.update(byte_block)
164
168
  if f'"{sha256_hash.hexdigest()}"' == linked_etag:
165
169
  nc.set_init_status(min(current_progress + progress_for_task, 99))
166
- return
170
+ return None
167
171
 
168
172
  with builtins.open(result_path, "wb") as file:
169
173
  last_progress = current_progress
@@ -174,13 +178,17 @@ def __fetch_model_as_file(
174
178
  if new_progress != last_progress:
175
179
  nc.set_init_status(new_progress)
176
180
  last_progress = new_progress
181
+
182
+ return result_path
177
183
  except Exception as e: # noqa pylint: disable=broad-exception-caught
178
184
  nc.log(LogLvl.ERROR, f"Downloading of '{model_path}' raised an exception: {e}")
179
185
 
186
+ return None
187
+
180
188
 
181
189
  def __fetch_model_as_snapshot(
182
190
  current_progress: int, progress_for_task, nc: NextcloudApp, mode_name: str, download_options: dict
183
- ) -> None:
191
+ ) -> str:
184
192
  from huggingface_hub import snapshot_download # noqa isort:skip pylint: disable=C0415 disable=E0401
185
193
  from tqdm import tqdm # noqa isort:skip pylint: disable=C0415 disable=E0401
186
194
 
@@ -191,7 +199,9 @@ def __fetch_model_as_snapshot(
191
199
 
192
200
  workers = download_options.pop("max_workers", 2)
193
201
  cache = download_options.pop("cache_dir", persistent_storage())
194
- snapshot_download(mode_name, tqdm_class=TqdmProgress, **download_options, max_workers=workers, cache_dir=cache)
202
+ return snapshot_download(
203
+ mode_name, tqdm_class=TqdmProgress, **download_options, max_workers=workers, cache_dir=cache
204
+ )
195
205
 
196
206
 
197
207
  def __nc_app(request: HTTPConnection) -> dict:
@@ -0,0 +1,153 @@
1
+ """Nextcloud API for registering OCC commands for ExApps."""
2
+
3
+ import dataclasses
4
+
5
+ from .._exceptions import NextcloudExceptionNotFound
6
+ from .._misc import clear_from_params_empty, require_capabilities
7
+ from .._session import AsyncNcSessionApp, NcSessionApp
8
+
9
+ _EP_SUFFIX: str = "occ_command"
10
+
11
+
12
+ @dataclasses.dataclass
13
+ class OccCommand:
14
+ """OccCommand description."""
15
+
16
+ def __init__(self, raw_data: dict):
17
+ self._raw_data = raw_data
18
+
19
+ @property
20
+ def name(self) -> str:
21
+ """Unique ID for the command."""
22
+ return self._raw_data["name"]
23
+
24
+ @property
25
+ def description(self) -> str:
26
+ """Command description."""
27
+ return self._raw_data["description"]
28
+
29
+ @property
30
+ def hidden(self) -> bool:
31
+ """Flag determining ss command hidden or not."""
32
+ return bool(self._raw_data["hidden"])
33
+
34
+ @property
35
+ def arguments(self) -> dict:
36
+ """Look at PHP Symfony framework for details."""
37
+ return self._raw_data["arguments"]
38
+
39
+ @property
40
+ def options(self) -> str:
41
+ """Look at PHP Symfony framework for details."""
42
+ return self._raw_data["options"]
43
+
44
+ @property
45
+ def usages(self) -> str:
46
+ """Look at PHP Symfony framework for details."""
47
+ return self._raw_data["usages"]
48
+
49
+ @property
50
+ def action_handler(self) -> str:
51
+ """Relative ExApp url which will be called by Nextcloud."""
52
+ return self._raw_data["execute_handler"]
53
+
54
+ def __repr__(self):
55
+ return f"<{self.__class__.__name__} name={self.name}, handler={self.action_handler}>"
56
+
57
+
58
+ class OccCommandsAPI:
59
+ """API for registering OCC commands, avalaible as **nc.occ_command.<method>**."""
60
+
61
+ def __init__(self, session: NcSessionApp):
62
+ self._session = session
63
+
64
+ def register(
65
+ self,
66
+ name: str,
67
+ callback_url: str,
68
+ arguments: list | None = None,
69
+ options: list | None = None,
70
+ usages: list | None = None,
71
+ description: str = "",
72
+ hidden: bool = False,
73
+ ) -> None:
74
+ """Registers or edit the OCC command."""
75
+ require_capabilities("app_api", self._session.capabilities)
76
+ params = {
77
+ "name": name,
78
+ "description": description,
79
+ "arguments": arguments,
80
+ "hidden": int(hidden),
81
+ "options": options,
82
+ "usages": usages,
83
+ "execute_handler": callback_url,
84
+ }
85
+ clear_from_params_empty(["arguments", "options", "usages"], params)
86
+ self._session.ocs("POST", f"{self._session.ae_url}/{_EP_SUFFIX}", json=params)
87
+
88
+ def unregister(self, name: str, not_fail=True) -> None:
89
+ """Removes the OCC command."""
90
+ require_capabilities("app_api", self._session.capabilities)
91
+ try:
92
+ self._session.ocs("DELETE", f"{self._session.ae_url}/{_EP_SUFFIX}", params={"name": name})
93
+ except NextcloudExceptionNotFound as e:
94
+ if not not_fail:
95
+ raise e from None
96
+
97
+ def get_entry(self, name: str) -> OccCommand | None:
98
+ """Get information of the OCC command."""
99
+ require_capabilities("app_api", self._session.capabilities)
100
+ try:
101
+ return OccCommand(self._session.ocs("GET", f"{self._session.ae_url}/{_EP_SUFFIX}", params={"name": name}))
102
+ except NextcloudExceptionNotFound:
103
+ return None
104
+
105
+
106
+ class AsyncOccCommandsAPI:
107
+ """Async API for registering OCC commands, avalaible as **nc.occ_command.<method>**."""
108
+
109
+ def __init__(self, session: AsyncNcSessionApp):
110
+ self._session = session
111
+
112
+ async def register(
113
+ self,
114
+ name: str,
115
+ callback_url: str,
116
+ arguments: list | None = None,
117
+ options: list | None = None,
118
+ usages: list | None = None,
119
+ description: str = "",
120
+ hidden: bool = False,
121
+ ) -> None:
122
+ """Registers or edit the OCC command."""
123
+ require_capabilities("app_api", await self._session.capabilities)
124
+ params = {
125
+ "name": name,
126
+ "description": description,
127
+ "arguments": arguments,
128
+ "hidden": int(hidden),
129
+ "options": options,
130
+ "usages": usages,
131
+ "execute_handler": callback_url,
132
+ }
133
+ clear_from_params_empty(["arguments", "options", "usages"], params)
134
+ await self._session.ocs("POST", f"{self._session.ae_url}/{_EP_SUFFIX}", json=params)
135
+
136
+ async def unregister(self, name: str, not_fail=True) -> None:
137
+ """Removes the OCC command."""
138
+ require_capabilities("app_api", await self._session.capabilities)
139
+ try:
140
+ await self._session.ocs("DELETE", f"{self._session.ae_url}/{_EP_SUFFIX}", params={"name": name})
141
+ except NextcloudExceptionNotFound as e:
142
+ if not not_fail:
143
+ raise e from None
144
+
145
+ async def get_entry(self, name: str) -> OccCommand | None:
146
+ """Get information of the OCC command."""
147
+ require_capabilities("app_api", await self._session.capabilities)
148
+ try:
149
+ return OccCommand(
150
+ await self._session.ocs("GET", f"{self._session.ae_url}/{_EP_SUFFIX}", params={"name": name})
151
+ )
152
+ except NextcloudExceptionNotFound:
153
+ return None
@@ -2,6 +2,7 @@
2
2
 
3
3
  from ..._session import AsyncNcSessionApp, NcSessionApp
4
4
  from .speech_to_text import _AsyncSpeechToTextProviderAPI, _SpeechToTextProviderAPI
5
+ from .task_processing import _AsyncTaskProcessingProviderAPI, _TaskProcessingProviderAPI
5
6
  from .text_processing import _AsyncTextProcessingProviderAPI, _TextProcessingProviderAPI
6
7
  from .translations import _AsyncTranslationsProviderAPI, _TranslationsProviderAPI
7
8
 
@@ -15,11 +16,14 @@ class ProvidersApi:
15
16
  """TextProcessing Provider API."""
16
17
  translations: _TranslationsProviderAPI
17
18
  """Translations Provider API."""
19
+ task_processing: _TaskProcessingProviderAPI
20
+ """TaskProcessing Provider API."""
18
21
 
19
22
  def __init__(self, session: NcSessionApp):
20
23
  self.speech_to_text = _SpeechToTextProviderAPI(session)
21
24
  self.text_processing = _TextProcessingProviderAPI(session)
22
25
  self.translations = _TranslationsProviderAPI(session)
26
+ self.task_processing = _TaskProcessingProviderAPI(session)
23
27
 
24
28
 
25
29
  class AsyncProvidersApi:
@@ -31,8 +35,11 @@ class AsyncProvidersApi:
31
35
  """TextProcessing Provider API."""
32
36
  translations: _AsyncTranslationsProviderAPI
33
37
  """Translations Provider API."""
38
+ task_processing: _AsyncTaskProcessingProviderAPI
39
+ """TaskProcessing Provider API."""
34
40
 
35
41
  def __init__(self, session: AsyncNcSessionApp):
36
42
  self.speech_to_text = _AsyncSpeechToTextProviderAPI(session)
37
43
  self.text_processing = _AsyncTextProcessingProviderAPI(session)
38
44
  self.translations = _AsyncTranslationsProviderAPI(session)
45
+ self.task_processing = _AsyncTaskProcessingProviderAPI(session)