nc-py-api 0.14.0__tar.gz → 0.15.1__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.14.0 → nc_py_api-0.15.1}/CHANGELOG.md +18 -1
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/PKG-INFO +6 -6
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/README.md +5 -5
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/_session.py +5 -3
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/_version.py +1 -1
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/apps.py +2 -2
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/integration_fastapi.py +17 -7
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/misc.py +1 -1
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/providers/task_processing.py +11 -3
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/files/__init__.py +1 -3
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/nextcloud.py +11 -4
- nc_py_api-0.15.1/nc_py_api/webhooks.py +210 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/pyproject.toml +1 -1
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/.gitignore +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/AUTHORS +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/LICENSE.txt +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/__init__.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/_deffered_error.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/_exceptions.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/_misc.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/_preferences.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/_preferences_ex.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/_talk_api.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/_theming.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/activity.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/calendar.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/__init__.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/defs.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/events_listener.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/occ_commands.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/persist_transformers_cache.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/providers/__init__.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/providers/providers.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/providers/speech_to_text.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/providers/text_processing.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/providers/translations.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/ui/__init__.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/ui/files_actions.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/ui/resources.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/ui/settings.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/ui/top_menu.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/ui/ui.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/ex_app/uvicorn_fastapi.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/files/_files.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/files/files.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/files/files_async.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/files/sharing.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/loginflow_v2.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/notes.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/notifications.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/options.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/talk.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/talk_bot.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/user_status.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/users.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/users_groups.py +0 -0
- {nc_py_api-0.14.0 → nc_py_api-0.15.1}/nc_py_api/weather_status.py +0 -0
|
@@ -2,7 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## [0.
|
|
5
|
+
## [0.15.1 - 2024-07-30]
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Corrected behaviour of `ocs` function for `Group Folders` app routes(they are not fully OCS API). #279
|
|
10
|
+
- NextcloudApp: `get_computation_device` function now correctly returns result in upper_case. #278
|
|
11
|
+
|
|
12
|
+
## [0.15.0 - 2024-07-19]
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- Initial Webhooks API support for the upcoming Nextcloud 30. #272
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- NextcloudApp: `fetch_models_task` function now saves paths to downloaded models. #274 Thanks to @kyteinsky
|
|
21
|
+
|
|
22
|
+
## [0.14.0 - 2024-07-09]
|
|
6
23
|
|
|
7
24
|
### Added
|
|
8
25
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: nc-py-api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.1
|
|
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/
|
|
@@ -85,7 +85,7 @@ Description-Content-Type: text/markdown
|
|
|
85
85
|
[](https://cloud-py-api.github.io/nc_py_api/)
|
|
86
86
|
[](https://codecov.io/github/cloud-py-api/nc_py_api)
|
|
87
87
|
|
|
88
|
-

|
|
89
89
|

|
|
90
90
|

|
|
91
91
|

|
|
@@ -101,7 +101,7 @@ Python library that provides a robust and well-documented API that allows develo
|
|
|
101
101
|
* **Sync + Async**: Provides both sync and async APIs.
|
|
102
102
|
|
|
103
103
|
### Capabilities
|
|
104
|
-
| **_Capability_** | Nextcloud
|
|
104
|
+
| **_Capability_** | Nextcloud 27 | Nextcloud 28 | Nextcloud 29 | Nextcloud 30 |
|
|
105
105
|
|-----------------------|:------------:|:------------:|:------------:|:------------:|
|
|
106
106
|
| Calendar | ✅ | ✅ | ✅ | ✅ |
|
|
107
107
|
| File System & Tags | ✅ | ✅ | ✅ | ✅ |
|
|
@@ -111,9 +111,9 @@ Python library that provides a robust and well-documented API that allows develo
|
|
|
111
111
|
| Users & Groups | ✅ | ✅ | ✅ | ✅ |
|
|
112
112
|
| User & Weather status | ✅ | ✅ | ✅ | ✅ |
|
|
113
113
|
| Other APIs*** | ✅ | ✅ | ✅ | ✅ |
|
|
114
|
-
| Talk Bot API* |
|
|
115
|
-
| Settings UI API* | N/A | N/A |
|
|
116
|
-
| AI Providers API** | N/A | N/A |
|
|
114
|
+
| Talk Bot API* | ✅ | ✅ | ✅ | ✅ |
|
|
115
|
+
| Settings UI API* | N/A | N/A | ✅ | ✅ |
|
|
116
|
+
| AI Providers API** | N/A | N/A | ✅ | ✅ |
|
|
117
117
|
|
|
118
118
|
*_available only for **NextcloudApp**_<br>
|
|
119
119
|
**_available only for **NextcloudApp**: SpeechToText, TextProcessing, Translation_<br>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
[](https://cloud-py-api.github.io/nc_py_api/)
|
|
9
9
|
[](https://codecov.io/github/cloud-py-api/nc_py_api)
|
|
10
10
|
|
|
11
|
-

|
|
12
12
|

|
|
13
13
|

|
|
14
14
|

|
|
@@ -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
|
|
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* |
|
|
38
|
-
| Settings UI API* | N/A | N/A |
|
|
39
|
-
| AI Providers API** | 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
|
*_available only for **NextcloudApp**_<br>
|
|
42
42
|
**_available only for **NextcloudApp**: SpeechToText, TextProcessing, Translation_<br>
|
|
@@ -150,7 +150,7 @@ class NcSessionBase(ABC):
|
|
|
150
150
|
self.init_adapter()
|
|
151
151
|
self.init_adapter_dav()
|
|
152
152
|
self.response_headers = Headers()
|
|
153
|
-
self._ocs_regexp = re.compile(r"/ocs/v[12]\.php/")
|
|
153
|
+
self._ocs_regexp = re.compile(r"/ocs/v[12]\.php/|/apps/groupfolders/")
|
|
154
154
|
|
|
155
155
|
def init_adapter(self, restart=False) -> None:
|
|
156
156
|
if getattr(self, "adapter", None) is None or restart:
|
|
@@ -176,12 +176,12 @@ class NcSessionBase(ABC):
|
|
|
176
176
|
|
|
177
177
|
@property
|
|
178
178
|
def ae_url(self) -> str:
|
|
179
|
-
"""Return base url for the
|
|
179
|
+
"""Return base url for the AppAPI endpoints."""
|
|
180
180
|
return "/ocs/v1.php/apps/app_api/api/v1"
|
|
181
181
|
|
|
182
182
|
@property
|
|
183
183
|
def ae_url_v2(self) -> str:
|
|
184
|
-
"""Return base url for the
|
|
184
|
+
"""Return base url for the AppAPI endpoints(version 2)."""
|
|
185
185
|
return "/ocs/v1.php/apps/app_api/api/v2"
|
|
186
186
|
|
|
187
187
|
|
|
@@ -289,6 +289,7 @@ class NcSessionBasic(NcSessionBase, ABC):
|
|
|
289
289
|
str_url = str(request.url)
|
|
290
290
|
if re.search(self._ocs_regexp, str_url) is not None: # this is OCS call
|
|
291
291
|
request.url = request.url.copy_merge_params({"format": "json"})
|
|
292
|
+
request.headers["Accept"] = "application/json"
|
|
292
293
|
|
|
293
294
|
def _response_event(self, response: Response) -> None:
|
|
294
295
|
str_url = str(response.request.url)
|
|
@@ -412,6 +413,7 @@ class AsyncNcSessionBasic(NcSessionBase, ABC):
|
|
|
412
413
|
str_url = str(request.url)
|
|
413
414
|
if re.search(self._ocs_regexp, str_url) is not None: # this is OCS call
|
|
414
415
|
request.url = request.url.copy_merge_params({"format": "json"})
|
|
416
|
+
request.headers["Accept"] = "application/json"
|
|
415
417
|
|
|
416
418
|
async def _response_event(self, response: Response) -> None:
|
|
417
419
|
str_url = str(response.request.url)
|
|
@@ -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
|
|
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}>"
|
|
@@ -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
|
-
|
|
130
|
+
models[model]["path"] = __fetch_model_as_file(
|
|
131
|
+
current_progress, percent_for_each, nc, model, models[model]
|
|
132
|
+
)
|
|
131
133
|
else:
|
|
132
|
-
|
|
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
|
-
) ->
|
|
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(
|
|
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:
|
|
@@ -54,4 +54,4 @@ def get_model_path(model_name: str) -> str:
|
|
|
54
54
|
|
|
55
55
|
def get_computation_device() -> str:
|
|
56
56
|
"""Returns computation device(`ROCM` or `CUDA`) if it is defined in the environment variable."""
|
|
57
|
-
return os.environ.get("COMPUTE_DEVICE", "")
|
|
57
|
+
return str(os.environ.get("COMPUTE_DEVICE", "")).upper()
|
|
@@ -5,7 +5,7 @@ import dataclasses
|
|
|
5
5
|
import typing
|
|
6
6
|
|
|
7
7
|
from ..._exceptions import NextcloudException, NextcloudExceptionNotFound
|
|
8
|
-
from ..._misc import require_capabilities
|
|
8
|
+
from ..._misc import clear_from_params_empty, require_capabilities
|
|
9
9
|
from ..._session import AsyncNcSessionApp, NcSessionApp
|
|
10
10
|
|
|
11
11
|
_EP_SUFFIX: str = "ai_provider/task_processing"
|
|
@@ -43,14 +43,18 @@ class _TaskProcessingProviderAPI:
|
|
|
43
43
|
def __init__(self, session: NcSessionApp):
|
|
44
44
|
self._session = session
|
|
45
45
|
|
|
46
|
-
def register(
|
|
46
|
+
def register(
|
|
47
|
+
self, name: str, display_name: str, task_type: str, custom_task_type: dict[str, typing.Any] | None = None
|
|
48
|
+
) -> None:
|
|
47
49
|
"""Registers or edit the TaskProcessing provider."""
|
|
48
50
|
require_capabilities("app_api", self._session.capabilities)
|
|
49
51
|
params = {
|
|
50
52
|
"name": name,
|
|
51
53
|
"displayName": display_name,
|
|
52
54
|
"taskType": task_type,
|
|
55
|
+
"customTaskType": custom_task_type,
|
|
53
56
|
}
|
|
57
|
+
clear_from_params_empty(["customTaskType"], params)
|
|
54
58
|
self._session.ocs("POST", f"{self._session.ae_url}/{_EP_SUFFIX}", json=params)
|
|
55
59
|
|
|
56
60
|
def unregister(self, name: str, not_fail=True) -> None:
|
|
@@ -118,14 +122,18 @@ class _AsyncTaskProcessingProviderAPI:
|
|
|
118
122
|
def __init__(self, session: AsyncNcSessionApp):
|
|
119
123
|
self._session = session
|
|
120
124
|
|
|
121
|
-
async def register(
|
|
125
|
+
async def register(
|
|
126
|
+
self, name: str, display_name: str, task_type: str, custom_task_type: dict[str, typing.Any] | None = None
|
|
127
|
+
) -> None:
|
|
122
128
|
"""Registers or edit the TaskProcessing provider."""
|
|
123
129
|
require_capabilities("app_api", await self._session.capabilities)
|
|
124
130
|
params = {
|
|
125
131
|
"name": name,
|
|
126
132
|
"displayName": display_name,
|
|
127
133
|
"taskType": task_type,
|
|
134
|
+
"customTaskType": custom_task_type,
|
|
128
135
|
}
|
|
136
|
+
clear_from_params_empty(["customTaskType"], params)
|
|
129
137
|
await self._session.ocs("POST", f"{self._session.ae_url}/{_EP_SUFFIX}", json=params)
|
|
130
138
|
|
|
131
139
|
async def unregister(self, name: str, not_fail=True) -> None:
|
|
@@ -203,9 +203,7 @@ class FsNode:
|
|
|
203
203
|
)
|
|
204
204
|
|
|
205
205
|
def __eq__(self, other):
|
|
206
|
-
|
|
207
|
-
return True
|
|
208
|
-
return False
|
|
206
|
+
return bool(self.file_id and self.file_id == other.file_id)
|
|
209
207
|
|
|
210
208
|
@property
|
|
211
209
|
def has_extra(self) -> bool:
|
|
@@ -44,6 +44,7 @@ from .user_status import _AsyncUserStatusAPI, _UserStatusAPI
|
|
|
44
44
|
from .users import _AsyncUsersAPI, _UsersAPI
|
|
45
45
|
from .users_groups import _AsyncUsersGroupsAPI, _UsersGroupsAPI
|
|
46
46
|
from .weather_status import _AsyncWeatherStatusAPI, _WeatherStatusAPI
|
|
47
|
+
from .webhooks import _AsyncWebhooksAPI, _WebhooksAPI
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
class _NextcloudBasic(ABC): # pylint: disable=too-many-instance-attributes
|
|
@@ -71,6 +72,8 @@ class _NextcloudBasic(ABC): # pylint: disable=too-many-instance-attributes
|
|
|
71
72
|
"""Nextcloud API for managing users statuses"""
|
|
72
73
|
weather_status: _WeatherStatusAPI
|
|
73
74
|
"""Nextcloud API for managing user weather statuses"""
|
|
75
|
+
webhooks: _WebhooksAPI
|
|
76
|
+
"""Nextcloud API for managing webhooks"""
|
|
74
77
|
_session: NcSessionBasic
|
|
75
78
|
|
|
76
79
|
def __init__(self, session: NcSessionBasic):
|
|
@@ -86,6 +89,7 @@ class _NextcloudBasic(ABC): # pylint: disable=too-many-instance-attributes
|
|
|
86
89
|
self.users_groups = _UsersGroupsAPI(session)
|
|
87
90
|
self.user_status = _UserStatusAPI(session)
|
|
88
91
|
self.weather_status = _WeatherStatusAPI(session)
|
|
92
|
+
self.webhooks = _WebhooksAPI(session)
|
|
89
93
|
|
|
90
94
|
@property
|
|
91
95
|
def capabilities(self) -> dict:
|
|
@@ -169,6 +173,8 @@ class _AsyncNextcloudBasic(ABC): # pylint: disable=too-many-instance-attributes
|
|
|
169
173
|
"""Nextcloud API for managing users statuses"""
|
|
170
174
|
weather_status: _AsyncWeatherStatusAPI
|
|
171
175
|
"""Nextcloud API for managing user weather statuses"""
|
|
176
|
+
webhooks: _AsyncWebhooksAPI
|
|
177
|
+
"""Nextcloud API for managing webhooks"""
|
|
172
178
|
_session: AsyncNcSessionBasic
|
|
173
179
|
|
|
174
180
|
def __init__(self, session: AsyncNcSessionBasic):
|
|
@@ -184,6 +190,7 @@ class _AsyncNextcloudBasic(ABC): # pylint: disable=too-many-instance-attributes
|
|
|
184
190
|
self.users_groups = _AsyncUsersGroupsAPI(session)
|
|
185
191
|
self.user_status = _AsyncUserStatusAPI(session)
|
|
186
192
|
self.weather_status = _AsyncWeatherStatusAPI(session)
|
|
193
|
+
self.webhooks = _AsyncWebhooksAPI(session)
|
|
187
194
|
|
|
188
195
|
@property
|
|
189
196
|
async def capabilities(self) -> dict:
|
|
@@ -350,14 +357,14 @@ class NextcloudApp(_NextcloudBasic):
|
|
|
350
357
|
self._session.ocs("POST", f"{self._session.ae_url}/log", json={"level": int(log_lvl), "message": content})
|
|
351
358
|
|
|
352
359
|
def users_list(self) -> list[str]:
|
|
353
|
-
"""Returns list of users on the Nextcloud instance.
|
|
360
|
+
"""Returns list of users on the Nextcloud instance."""
|
|
354
361
|
return self._session.ocs("GET", f"{self._session.ae_url}/users")
|
|
355
362
|
|
|
356
363
|
@property
|
|
357
364
|
def user(self) -> str:
|
|
358
365
|
"""Property containing the current user ID.
|
|
359
366
|
|
|
360
|
-
**
|
|
367
|
+
**ExApps** can change user ID they impersonate with **set_user** method.
|
|
361
368
|
"""
|
|
362
369
|
return self._session.user
|
|
363
370
|
|
|
@@ -480,14 +487,14 @@ class AsyncNextcloudApp(_AsyncNextcloudBasic):
|
|
|
480
487
|
await self._session.ocs("POST", f"{self._session.ae_url}/log", json={"level": int(log_lvl), "message": content})
|
|
481
488
|
|
|
482
489
|
async def users_list(self) -> list[str]:
|
|
483
|
-
"""Returns list of users on the Nextcloud instance.
|
|
490
|
+
"""Returns list of users on the Nextcloud instance."""
|
|
484
491
|
return await self._session.ocs("GET", f"{self._session.ae_url}/users")
|
|
485
492
|
|
|
486
493
|
@property
|
|
487
494
|
async def user(self) -> str:
|
|
488
495
|
"""Property containing the current user ID.
|
|
489
496
|
|
|
490
|
-
**
|
|
497
|
+
**ExApps** can change user ID they impersonate with **set_user** method.
|
|
491
498
|
"""
|
|
492
499
|
return await self._session.user
|
|
493
500
|
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"""Nextcloud Webhooks API."""
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
|
|
5
|
+
from ._misc import clear_from_params_empty # , require_capabilities
|
|
6
|
+
from ._session import AsyncNcSessionBasic, NcSessionBasic
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclasses.dataclass
|
|
10
|
+
class WebhookInfo:
|
|
11
|
+
"""Information about the Webhook."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, raw_data: dict):
|
|
14
|
+
self._raw_data = raw_data
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def webhook_id(self) -> int:
|
|
18
|
+
"""`ID` of the webhook."""
|
|
19
|
+
return self._raw_data["id"]
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def app_id(self) -> str:
|
|
23
|
+
"""`ID` of the ExApp that registered webhook."""
|
|
24
|
+
return self._raw_data["appId"] if self._raw_data["appId"] else ""
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def user_id(self) -> str:
|
|
28
|
+
"""`UserID` if webhook was registered in user context."""
|
|
29
|
+
return self._raw_data["userId"] if self._raw_data["userId"] else ""
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def http_method(self) -> str:
|
|
33
|
+
"""HTTP method used to call webhook."""
|
|
34
|
+
return self._raw_data["httpMethod"]
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def uri(self) -> str:
|
|
38
|
+
"""URL address that will be called for this webhook."""
|
|
39
|
+
return self._raw_data["uri"]
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def event(self) -> str:
|
|
43
|
+
"""Nextcloud PHP event that triggers this webhook."""
|
|
44
|
+
return self._raw_data["event"]
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def event_filter(self):
|
|
48
|
+
"""Mongo filter to apply to the serialized data to decide if firing."""
|
|
49
|
+
return self._raw_data["eventFilter"]
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def user_id_filter(self) -> str:
|
|
53
|
+
"""Currently unknown."""
|
|
54
|
+
return self._raw_data["userIdFilter"]
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def headers(self) -> dict:
|
|
58
|
+
"""Headers that should be added to request when calling webhook."""
|
|
59
|
+
return self._raw_data["headers"] if self._raw_data["headers"] else {}
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def auth_method(self) -> str:
|
|
63
|
+
"""Currently unknown."""
|
|
64
|
+
return self._raw_data["authMethod"]
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def auth_data(self) -> dict:
|
|
68
|
+
"""Currently unknown."""
|
|
69
|
+
return self._raw_data["authData"] if self._raw_data["authData"] else {}
|
|
70
|
+
|
|
71
|
+
def __repr__(self):
|
|
72
|
+
return f"<{self.__class__.__name__} id={self.webhook_id}, event={self.event}>"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class _WebhooksAPI:
|
|
76
|
+
"""The class provides the application management API on the Nextcloud server."""
|
|
77
|
+
|
|
78
|
+
_ep_base: str = "/ocs/v1.php/apps/webhook_listeners/api/v1/webhooks"
|
|
79
|
+
|
|
80
|
+
def __init__(self, session: NcSessionBasic):
|
|
81
|
+
self._session = session
|
|
82
|
+
|
|
83
|
+
def get_list(self, uri_filter: str = "") -> list[WebhookInfo]:
|
|
84
|
+
params = {"uri": uri_filter} if uri_filter else {}
|
|
85
|
+
return [WebhookInfo(i) for i in self._session.ocs("GET", f"{self._ep_base}", params=params)]
|
|
86
|
+
|
|
87
|
+
def get_entry(self, webhook_id: int) -> WebhookInfo:
|
|
88
|
+
return WebhookInfo(self._session.ocs("GET", f"{self._ep_base}/{webhook_id}"))
|
|
89
|
+
|
|
90
|
+
def register(
|
|
91
|
+
self,
|
|
92
|
+
http_method: str,
|
|
93
|
+
uri: str,
|
|
94
|
+
event: str,
|
|
95
|
+
event_filter: dict | None = None,
|
|
96
|
+
user_id_filter: str = "",
|
|
97
|
+
headers: dict | None = None,
|
|
98
|
+
auth_method: str = "none",
|
|
99
|
+
auth_data: dict | None = None,
|
|
100
|
+
):
|
|
101
|
+
params = {
|
|
102
|
+
"httpMethod": http_method,
|
|
103
|
+
"uri": uri,
|
|
104
|
+
"event": event,
|
|
105
|
+
"eventFilter": event_filter,
|
|
106
|
+
"userIdFilter": user_id_filter,
|
|
107
|
+
"headers": headers,
|
|
108
|
+
"authMethod": auth_method,
|
|
109
|
+
"authData": auth_data,
|
|
110
|
+
}
|
|
111
|
+
clear_from_params_empty(["eventFilter", "userIdFilter", "headers", "authMethod", "authData"], params)
|
|
112
|
+
return WebhookInfo(self._session.ocs("POST", f"{self._ep_base}", json=params))
|
|
113
|
+
|
|
114
|
+
def update(
|
|
115
|
+
self,
|
|
116
|
+
webhook_id: int,
|
|
117
|
+
http_method: str,
|
|
118
|
+
uri: str,
|
|
119
|
+
event: str,
|
|
120
|
+
event_filter: dict | None = None,
|
|
121
|
+
user_id_filter: str = "",
|
|
122
|
+
headers: dict | None = None,
|
|
123
|
+
auth_method: str = "none",
|
|
124
|
+
auth_data: dict | None = None,
|
|
125
|
+
):
|
|
126
|
+
params = {
|
|
127
|
+
"id": webhook_id,
|
|
128
|
+
"httpMethod": http_method,
|
|
129
|
+
"uri": uri,
|
|
130
|
+
"event": event,
|
|
131
|
+
"eventFilter": event_filter,
|
|
132
|
+
"userIdFilter": user_id_filter,
|
|
133
|
+
"headers": headers,
|
|
134
|
+
"authMethod": auth_method,
|
|
135
|
+
"authData": auth_data,
|
|
136
|
+
}
|
|
137
|
+
clear_from_params_empty(["eventFilter", "userIdFilter", "headers", "authMethod", "authData"], params)
|
|
138
|
+
return WebhookInfo(self._session.ocs("POST", f"{self._ep_base}/{webhook_id}", json=params))
|
|
139
|
+
|
|
140
|
+
def unregister(self, webhook_id: int) -> bool:
|
|
141
|
+
return self._session.ocs("DELETE", f"{self._ep_base}/{webhook_id}")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class _AsyncWebhooksAPI:
|
|
145
|
+
"""The class provides the async application management API on the Nextcloud server."""
|
|
146
|
+
|
|
147
|
+
_ep_base: str = "/ocs/v1.php/webhooks"
|
|
148
|
+
|
|
149
|
+
def __init__(self, session: AsyncNcSessionBasic):
|
|
150
|
+
self._session = session
|
|
151
|
+
|
|
152
|
+
async def get_list(self, uri_filter: str = "") -> list[WebhookInfo]:
|
|
153
|
+
params = {"uri": uri_filter} if uri_filter else {}
|
|
154
|
+
return [WebhookInfo(i) for i in await self._session.ocs("GET", f"{self._ep_base}", params=params)]
|
|
155
|
+
|
|
156
|
+
async def get_entry(self, webhook_id: int) -> WebhookInfo:
|
|
157
|
+
return WebhookInfo(await self._session.ocs("GET", f"{self._ep_base}/{webhook_id}"))
|
|
158
|
+
|
|
159
|
+
async def register(
|
|
160
|
+
self,
|
|
161
|
+
http_method: str,
|
|
162
|
+
uri: str,
|
|
163
|
+
event: str,
|
|
164
|
+
event_filter: dict | None = None,
|
|
165
|
+
user_id_filter: str = "",
|
|
166
|
+
headers: dict | None = None,
|
|
167
|
+
auth_method: str = "none",
|
|
168
|
+
auth_data: dict | None = None,
|
|
169
|
+
):
|
|
170
|
+
params = {
|
|
171
|
+
"httpMethod": http_method,
|
|
172
|
+
"uri": uri,
|
|
173
|
+
"event": event,
|
|
174
|
+
"eventFilter": event_filter,
|
|
175
|
+
"userIdFilter": user_id_filter,
|
|
176
|
+
"headers": headers,
|
|
177
|
+
"authMethod": auth_method,
|
|
178
|
+
"authData": auth_data,
|
|
179
|
+
}
|
|
180
|
+
clear_from_params_empty(["eventFilter", "userIdFilter", "headers", "authMethod", "authData"], params)
|
|
181
|
+
return WebhookInfo(await self._session.ocs("POST", f"{self._ep_base}", json=params))
|
|
182
|
+
|
|
183
|
+
async def update(
|
|
184
|
+
self,
|
|
185
|
+
webhook_id: int,
|
|
186
|
+
http_method: str,
|
|
187
|
+
uri: str,
|
|
188
|
+
event: str,
|
|
189
|
+
event_filter: dict | None = None,
|
|
190
|
+
user_id_filter: str = "",
|
|
191
|
+
headers: dict | None = None,
|
|
192
|
+
auth_method: str = "none",
|
|
193
|
+
auth_data: dict | None = None,
|
|
194
|
+
):
|
|
195
|
+
params = {
|
|
196
|
+
"id": webhook_id,
|
|
197
|
+
"httpMethod": http_method,
|
|
198
|
+
"uri": uri,
|
|
199
|
+
"event": event,
|
|
200
|
+
"eventFilter": event_filter,
|
|
201
|
+
"userIdFilter": user_id_filter,
|
|
202
|
+
"headers": headers,
|
|
203
|
+
"authMethod": auth_method,
|
|
204
|
+
"authData": auth_data,
|
|
205
|
+
}
|
|
206
|
+
clear_from_params_empty(["eventFilter", "userIdFilter", "headers", "authMethod", "authData"], params)
|
|
207
|
+
return WebhookInfo(await self._session.ocs("POST", f"{self._ep_base}/{webhook_id}", json=params))
|
|
208
|
+
|
|
209
|
+
async def unregister(self, webhook_id: int) -> bool:
|
|
210
|
+
return await self._session.ocs("DELETE", f"{self._ep_base}/{webhook_id}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|