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.
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/CHANGELOG.md +17 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/PKG-INFO +16 -4
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/__init__.py +1 -1
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_session.py +17 -3
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_version.py +1 -1
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/__init__.py +1 -1
- nc_py_api-0.14.0/nc_py_api/ex_app/events_listener.py +137 -0
- nc_py_api-0.14.0/nc_py_api/ex_app/occ_commands.py +153 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/providers/providers.py +7 -0
- nc_py_api-0.14.0/nc_py_api/ex_app/providers/task_processing.py +189 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/ui/files_actions.py +45 -1
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/files/__init__.py +9 -1
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/files/_files.py +12 -0
- nc_py_api-0.14.0/nc_py_api/files/files.py +514 -0
- 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
- nc_py_api-0.14.0/nc_py_api/loginflow_v2.py +161 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/nextcloud.py +42 -5
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/pyproject.toml +117 -57
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/.gitignore +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/AUTHORS +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/LICENSE.txt +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/README.md +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_deffered_error.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_exceptions.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_misc.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_preferences.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_preferences_ex.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_talk_api.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/_theming.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/activity.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/apps.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/calendar.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/defs.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/integration_fastapi.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/misc.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/persist_transformers_cache.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/providers/__init__.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/providers/speech_to_text.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/providers/text_processing.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/providers/translations.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/ui/__init__.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/ui/resources.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/ui/settings.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/ui/top_menu.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/ui/ui.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/ex_app/uvicorn_fastapi.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/files/sharing.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/notes.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/notifications.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/options.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/talk.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/talk_bot.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/user_status.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/users.py +0 -0
- {nc_py_api-0.12.1 → nc_py_api-0.14.0}/nc_py_api/users_groups.py +0 -0
- {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.
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
|
|
@@ -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 {}
|