nc-py-api 0.12.1__tar.gz → 0.14.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 (56) hide show
  1. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/CHANGELOG.md +17 -0
  2. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/PKG-INFO +16 -4
  3. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/__init__.py +1 -1
  4. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_session.py +17 -3
  5. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_version.py +1 -1
  6. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/__init__.py +1 -1
  7. nc_py_api-0.14.0/nc_py_api/ex_app/events_listener.py +137 -0
  8. nc_py_api-0.14.0/nc_py_api/ex_app/occ_commands.py +153 -0
  9. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/providers/providers.py +7 -0
  10. nc_py_api-0.14.0/nc_py_api/ex_app/providers/task_processing.py +189 -0
  11. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/ui/files_actions.py +45 -1
  12. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/files/__init__.py +9 -1
  13. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/files/_files.py +12 -0
  14. nc_py_api-0.14.0/nc_py_api/files/files.py +514 -0
  15. nc_py_api-0.12.1/nc_py_api/files/files.py → nc_py_api-0.14.0/nc_py_api/files/files_async.py +14 -473
  16. nc_py_api-0.14.0/nc_py_api/loginflow_v2.py +161 -0
  17. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/nextcloud.py +42 -5
  18. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/pyproject.toml +117 -57
  19. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/.gitignore +0 -0
  20. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/AUTHORS +0 -0
  21. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/LICENSE.txt +0 -0
  22. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/README.md +0 -0
  23. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_deffered_error.py +0 -0
  24. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_exceptions.py +0 -0
  25. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_misc.py +0 -0
  26. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_preferences.py +0 -0
  27. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_preferences_ex.py +0 -0
  28. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_talk_api.py +0 -0
  29. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_theming.py +0 -0
  30. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/activity.py +0 -0
  31. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/apps.py +0 -0
  32. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/calendar.py +0 -0
  33. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/defs.py +0 -0
  34. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/integration_fastapi.py +0 -0
  35. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/misc.py +0 -0
  36. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/persist_transformers_cache.py +0 -0
  37. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/providers/__init__.py +0 -0
  38. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/providers/speech_to_text.py +0 -0
  39. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/providers/text_processing.py +0 -0
  40. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/providers/translations.py +0 -0
  41. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/ui/__init__.py +0 -0
  42. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/ui/resources.py +0 -0
  43. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/ui/settings.py +0 -0
  44. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/ui/top_menu.py +0 -0
  45. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/ui/ui.py +0 -0
  46. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/uvicorn_fastapi.py +0 -0
  47. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/files/sharing.py +0 -0
  48. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/notes.py +0 -0
  49. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/notifications.py +0 -0
  50. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/options.py +0 -0
  51. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/talk.py +0 -0
  52. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/talk_bot.py +0 -0
  53. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/user_status.py +0 -0
  54. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/users.py +0 -0
  55. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/users_groups.py +0 -0
  56. {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/weather_status.py +0 -0
@@ -2,6 +2,23 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.14.0 - 2024-07-0X]
6
+
7
+ ### Added
8
+
9
+ - `LoginFlowV2` implementation by @blvdek #255
10
+ - `files.get_tags` function to get all tags assigned to the file or directory. #260
11
+ - NextcloudApp: `nc.ui.files_dropdown_menu.register_ex` to register new version of FileActions(AppAPI 2.6.0+) #252
12
+ - NextcloudApp: `enabled_state` property to check if the current ExApp is disabled or enabled. #268
13
+ - NextcloudApp: support for the new AI API for the Nextcloud 30. #254
14
+
15
+ ## [0.13.0 - 2024-04-28]
16
+
17
+ ### Added
18
+
19
+ - NextcloudApp: `occ` commands registration API(AppAPI 2.5.0+). #247
20
+ - NextcloudApp: `Nodes` events listener registration API(AppAPI 2.5.0+). #249
21
+
5
22
  ## [0.12.1 - 2024-04-05]
6
23
 
7
24
  ### 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.14.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">
@@ -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
@@ -176,6 +179,11 @@ class NcSessionBase(ABC):
176
179
  """Return base url for the App Ecosystem 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 App Ecosystem 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.14.0"
@@ -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
@@ -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)
@@ -0,0 +1,189 @@
1
+ """Nextcloud API for declaring TaskProcessing provider."""
2
+
3
+ import contextlib
4
+ import dataclasses
5
+ import typing
6
+
7
+ from ..._exceptions import NextcloudException, NextcloudExceptionNotFound
8
+ from ..._misc import require_capabilities
9
+ from ..._session import AsyncNcSessionApp, NcSessionApp
10
+
11
+ _EP_SUFFIX: str = "ai_provider/task_processing"
12
+
13
+
14
+ @dataclasses.dataclass
15
+ class TaskProcessingProvider:
16
+ """TaskProcessing provider description."""
17
+
18
+ def __init__(self, raw_data: dict):
19
+ self._raw_data = raw_data
20
+
21
+ @property
22
+ def name(self) -> str:
23
+ """Unique ID for the provider."""
24
+ return self._raw_data["name"]
25
+
26
+ @property
27
+ def display_name(self) -> str:
28
+ """Providers display name."""
29
+ return self._raw_data["display_name"]
30
+
31
+ @property
32
+ def task_type(self) -> str:
33
+ """The TaskType provided by this provider."""
34
+ return self._raw_data["task_type"]
35
+
36
+ def __repr__(self):
37
+ return f"<{self.__class__.__name__} name={self.name}, type={self.task_type}>"
38
+
39
+
40
+ class _TaskProcessingProviderAPI:
41
+ """API for TaskProcessing providers, available as **nc.providers.task_processing.<method>**."""
42
+
43
+ def __init__(self, session: NcSessionApp):
44
+ self._session = session
45
+
46
+ def register(self, name: str, display_name: str, task_type: str) -> None:
47
+ """Registers or edit the TaskProcessing provider."""
48
+ require_capabilities("app_api", self._session.capabilities)
49
+ params = {
50
+ "name": name,
51
+ "displayName": display_name,
52
+ "taskType": task_type,
53
+ }
54
+ self._session.ocs("POST", f"{self._session.ae_url}/{_EP_SUFFIX}", json=params)
55
+
56
+ def unregister(self, name: str, not_fail=True) -> None:
57
+ """Removes TaskProcessing provider."""
58
+ require_capabilities("app_api", self._session.capabilities)
59
+ try:
60
+ self._session.ocs("DELETE", f"{self._session.ae_url}/{_EP_SUFFIX}", params={"name": name})
61
+ except NextcloudExceptionNotFound as e:
62
+ if not not_fail:
63
+ raise e from None
64
+
65
+ def next_task(self, provider_ids: list[str], task_types: list[str]) -> dict[str, typing.Any]:
66
+ """Get the next task processing task from Nextcloud."""
67
+ with contextlib.suppress(NextcloudException):
68
+ if r := self._session.ocs(
69
+ "GET",
70
+ "/ocs/v2.php/taskprocessing/tasks_provider/next",
71
+ json={"providerIds": provider_ids, "taskTypeIds": task_types},
72
+ ):
73
+ return r
74
+ return {}
75
+
76
+ def set_progress(self, task_id: int, progress: float) -> dict[str, typing.Any]:
77
+ """Report new progress value of the task to Nextcloud. Progress should be in range from 0.0 to 100.0."""
78
+ with contextlib.suppress(NextcloudException):
79
+ if r := self._session.ocs(
80
+ "POST",
81
+ f"/ocs/v2.php/taskprocessing/tasks_provider/{task_id}/progress",
82
+ json={"taskId": task_id, "progress": progress / 100.0},
83
+ ):
84
+ return r
85
+ return {}
86
+
87
+ def upload_result_file(self, task_id: int, file: bytes | str | typing.Any) -> int:
88
+ """Uploads file and returns fileID that should be used in the ``report_result`` function.
89
+
90
+ .. note:: ``file`` can be any file-like object.
91
+ """
92
+ return self._session.ocs(
93
+ "POST",
94
+ f"/ocs/v2.php/taskprocessing/tasks_provider/{task_id}/file",
95
+ files={"file": file},
96
+ )["fileId"]
97
+
98
+ def report_result(
99
+ self,
100
+ task_id: int,
101
+ output: dict[str, typing.Any] | None = None,
102
+ error_message: str | None = None,
103
+ ) -> dict[str, typing.Any]:
104
+ """Report result of the task processing to Nextcloud."""
105
+ with contextlib.suppress(NextcloudException):
106
+ if r := self._session.ocs(
107
+ "POST",
108
+ f"/ocs/v2.php/taskprocessing/tasks_provider/{task_id}/result",
109
+ json={"taskId": task_id, "output": output, "errorMessage": error_message},
110
+ ):
111
+ return r
112
+ return {}
113
+
114
+
115
+ class _AsyncTaskProcessingProviderAPI:
116
+ """Async API for TaskProcessing providers."""
117
+
118
+ def __init__(self, session: AsyncNcSessionApp):
119
+ self._session = session
120
+
121
+ async def register(self, name: str, display_name: str, task_type: str) -> None:
122
+ """Registers or edit the TaskProcessing provider."""
123
+ require_capabilities("app_api", await self._session.capabilities)
124
+ params = {
125
+ "name": name,
126
+ "displayName": display_name,
127
+ "taskType": task_type,
128
+ }
129
+ await self._session.ocs("POST", f"{self._session.ae_url}/{_EP_SUFFIX}", json=params)
130
+
131
+ async def unregister(self, name: str, not_fail=True) -> None:
132
+ """Removes TaskProcessing provider."""
133
+ require_capabilities("app_api", await self._session.capabilities)
134
+ try:
135
+ await self._session.ocs("DELETE", f"{self._session.ae_url}/{_EP_SUFFIX}", params={"name": name})
136
+ except NextcloudExceptionNotFound as e:
137
+ if not not_fail:
138
+ raise e from None
139
+
140
+ async def next_task(self, provider_ids: list[str], task_types: list[str]) -> dict[str, typing.Any]:
141
+ """Get the next task processing task from Nextcloud."""
142
+ with contextlib.suppress(NextcloudException):
143
+ if r := await self._session.ocs(
144
+ "GET",
145
+ "/ocs/v2.php/taskprocessing/tasks_provider/next",
146
+ json={"providerIds": provider_ids, "taskTypeIds": task_types},
147
+ ):
148
+ return r
149
+ return {}
150
+
151
+ async def set_progress(self, task_id: int, progress: float) -> dict[str, typing.Any]:
152
+ """Report new progress value of the task to Nextcloud. Progress should be in range from 0.0 to 100.0."""
153
+ with contextlib.suppress(NextcloudException):
154
+ if r := await self._session.ocs(
155
+ "POST",
156
+ f"/ocs/v2.php/taskprocessing/tasks_provider/{task_id}/progress",
157
+ json={"taskId": task_id, "progress": progress / 100.0},
158
+ ):
159
+ return r
160
+ return {}
161
+
162
+ async def upload_result_file(self, task_id: int, file: bytes | str | typing.Any) -> int:
163
+ """Uploads file and returns fileID that should be used in the ``report_result`` function.
164
+
165
+ .. note:: ``file`` can be any file-like object.
166
+ """
167
+ return (
168
+ await self._session.ocs(
169
+ "POST",
170
+ f"/ocs/v2.php/taskprocessing/tasks_provider/{task_id}/file",
171
+ files={"file": file},
172
+ )
173
+ )["fileId"]
174
+
175
+ async def report_result(
176
+ self,
177
+ task_id: int,
178
+ output: dict[str, typing.Any] | None = None,
179
+ error_message: str | None = None,
180
+ ) -> dict[str, typing.Any]:
181
+ """Report result of the task processing to Nextcloud."""
182
+ with contextlib.suppress(NextcloudException):
183
+ if r := await self._session.ocs(
184
+ "POST",
185
+ f"/ocs/v2.php/taskprocessing/tasks_provider/{task_id}/result",
186
+ json={"taskId": task_id, "output": output, "errorMessage": error_message},
187
+ ):
188
+ return r
189
+ return {}