nc-py-api 0.11.0__tar.gz → 0.18.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.11.0 → nc_py_api-0.18.1}/AUTHORS +1 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/CHANGELOG.md +101 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/PKG-INFO +35 -23
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/README.md +15 -16
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/__init__.py +1 -1
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/_session.py +27 -14
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/_version.py +1 -1
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/apps.py +0 -13
- nc_py_api-0.18.1/nc_py_api/ex_app/__init__.py +25 -0
- nc_py_api-0.18.1/nc_py_api/ex_app/defs.py +37 -0
- nc_py_api-0.18.1/nc_py_api/ex_app/events_listener.py +137 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/ex_app/integration_fastapi.py +25 -14
- nc_py_api-0.18.1/nc_py_api/ex_app/logging.py +46 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/ex_app/misc.py +6 -1
- nc_py_api-0.18.1/nc_py_api/ex_app/occ_commands.py +153 -0
- nc_py_api-0.18.1/nc_py_api/ex_app/providers/providers.py +24 -0
- nc_py_api-0.18.1/nc_py_api/ex_app/providers/task_processing.py +261 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/ex_app/ui/files_actions.py +45 -61
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/files/__init__.py +76 -6
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/files/_files.py +12 -0
- nc_py_api-0.18.1/nc_py_api/files/files.py +520 -0
- nc_py_api-0.11.0/nc_py_api/files/files.py → nc_py_api-0.18.1/nc_py_api/files/files_async.py +23 -477
- nc_py_api-0.18.1/nc_py_api/loginflow_v2.py +161 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/nextcloud.py +77 -21
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/talk_bot.py +5 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/users.py +3 -3
- nc_py_api-0.18.1/nc_py_api/webhooks.py +224 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/pyproject.toml +123 -68
- nc_py_api-0.11.0/nc_py_api/ex_app/__init__.py +0 -15
- nc_py_api-0.11.0/nc_py_api/ex_app/defs.py +0 -49
- nc_py_api-0.11.0/nc_py_api/ex_app/providers/providers.py +0 -38
- nc_py_api-0.11.0/nc_py_api/ex_app/providers/speech_to_text.py +0 -128
- nc_py_api-0.11.0/nc_py_api/ex_app/providers/text_processing.py +0 -135
- nc_py_api-0.11.0/nc_py_api/ex_app/providers/translations.py +0 -165
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/.gitignore +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/LICENSE.txt +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/_deffered_error.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/_exceptions.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/_misc.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/_preferences.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/_preferences_ex.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/_talk_api.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/_theming.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/activity.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/calendar.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/ex_app/persist_transformers_cache.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/ex_app/providers/__init__.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/ex_app/ui/__init__.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/ex_app/ui/resources.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/ex_app/ui/settings.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/ex_app/ui/top_menu.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/ex_app/ui/ui.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/ex_app/uvicorn_fastapi.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/files/sharing.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/notes.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/notifications.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/options.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/talk.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/user_status.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/users_groups.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.18.1}/nc_py_api/weather_status.py +0 -0
|
@@ -6,6 +6,7 @@ answer newbie questions, and generally made NC-Py-API that much better:
|
|
|
6
6
|
Alexander Piskun <bigcat88@icloud.com>
|
|
7
7
|
CooperGerman <https://github.com/CooperGerman>
|
|
8
8
|
Tobias Tschech <Tobias@tschech-online.de>
|
|
9
|
+
Scott Williams <scottwilliams@ucsb.edu>
|
|
9
10
|
<Please alphabetize new entries>
|
|
10
11
|
|
|
11
12
|
A big THANK YOU goes to:
|
|
@@ -2,6 +2,107 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.18.1 - 2025-01-14]
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Chunked Upload V2 not working on Nextcloud 30 and later. #324 Thanks to @DrZoidberg09
|
|
10
|
+
|
|
11
|
+
## [0.18.0 - 2024-10-09]
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- New `webhooks.unregister_all` method. #309
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Files: `user` and `user_path` properties in `FSNode` when Nextcloud located in the sub-path. #297 Thanks to @vwbusguy
|
|
20
|
+
- `files.download_directory_as_zip` method now supports upcoming Nextcloud 31. #304
|
|
21
|
+
|
|
22
|
+
## [0.17.1 - 2024-09-06]
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- NextcloudApp: `setup_nextcloud_logging` function to support transparently sending logs to Nextcloud. #294
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- NextcloudApp: `nc.log` now suppresses all exceptions to safe call it anywhere(for example in exception handlers). #293
|
|
31
|
+
|
|
32
|
+
## [0.17.0 - 2024-09-05]
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- `message_type` property to TalkBotMessage. #292
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- NextcloudApp: `TextProcessing`, `Speech2Text` and `Translation` AI Providers API was removed. #289
|
|
41
|
+
|
|
42
|
+
## [0.16.0 - 2024-08-12]
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- NextcloudApp: rework of TaskProcessing provider API. #284
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- `nc.files.makedirs` not working properly on Windows. #280 Thanks to @Wuli6
|
|
51
|
+
|
|
52
|
+
## [0.15.1 - 2024-07-30]
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
|
|
56
|
+
- Corrected behaviour of `ocs` function for `Group Folders` app routes(they are not fully OCS API). #279
|
|
57
|
+
- NextcloudApp: `get_computation_device` function now correctly returns result in upper_case. #278
|
|
58
|
+
|
|
59
|
+
## [0.15.0 - 2024-07-19]
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
|
|
63
|
+
- Initial Webhooks API support for the upcoming Nextcloud 30. #272
|
|
64
|
+
|
|
65
|
+
### Changed
|
|
66
|
+
|
|
67
|
+
- NextcloudApp: `fetch_models_task` function now saves paths to downloaded models. #274 Thanks to @kyteinsky
|
|
68
|
+
|
|
69
|
+
## [0.14.0 - 2024-07-09]
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- `LoginFlowV2` implementation by @blvdek #255
|
|
74
|
+
- `files.get_tags` function to get all tags assigned to the file or directory. #260
|
|
75
|
+
- NextcloudApp: `nc.ui.files_dropdown_menu.register_ex` to register new version of FileActions(AppAPI 2.6.0+) #252
|
|
76
|
+
- NextcloudApp: `enabled_state` property to check if the current ExApp is disabled or enabled. #268
|
|
77
|
+
- NextcloudApp: support for the new AI API for the Nextcloud 30. #254
|
|
78
|
+
|
|
79
|
+
## [0.13.0 - 2024-04-28]
|
|
80
|
+
|
|
81
|
+
### Added
|
|
82
|
+
|
|
83
|
+
- NextcloudApp: `occ` commands registration API(AppAPI 2.5.0+). #247
|
|
84
|
+
- NextcloudApp: `Nodes` events listener registration API(AppAPI 2.5.0+). #249
|
|
85
|
+
|
|
86
|
+
## [0.12.1 - 2024-04-05]
|
|
87
|
+
|
|
88
|
+
### Fixed
|
|
89
|
+
|
|
90
|
+
- Incorrect `Display name` when creating user, which led to the parameter being ignored. #239 Thanks to @derekbuckley
|
|
91
|
+
|
|
92
|
+
## [0.12.0 - 2024-04-02]
|
|
93
|
+
|
|
94
|
+
Update with new features only for `NextcloudApp` class. #233
|
|
95
|
+
|
|
96
|
+
### Added
|
|
97
|
+
|
|
98
|
+
- `ex_app.get_computation_device` function for retrieving GPU type(only with AppAPI `2.5.0`+).
|
|
99
|
+
- `ex_app.integration_fastapi.fetch_models_task` are now public function, added `progress_init_start_value` param.
|
|
100
|
+
- Global authentication when used now sets `request.scope["username"]` for easy use.
|
|
101
|
+
|
|
102
|
+
### Changed
|
|
103
|
+
|
|
104
|
+
- `UiActionFileInfo` class marked as deprecated, instead `ActionFileInfo` class should be used.
|
|
105
|
+
|
|
5
106
|
## [0.11.0 - 2024-02-17]
|
|
6
107
|
|
|
7
108
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: nc-py-api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.18.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/
|
|
@@ -20,6 +20,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
24
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
24
25
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
25
26
|
Classifier: Topic :: Internet :: WWW/HTTP
|
|
@@ -38,13 +39,24 @@ Provides-Extra: app
|
|
|
38
39
|
Requires-Dist: uvicorn[standard]>=0.23.2; extra == 'app'
|
|
39
40
|
Provides-Extra: bench
|
|
40
41
|
Requires-Dist: matplotlib; extra == 'bench'
|
|
41
|
-
Requires-Dist: nc-py-api[app]; extra == 'bench'
|
|
42
42
|
Requires-Dist: numpy; extra == 'bench'
|
|
43
43
|
Requires-Dist: py-cpuinfo; extra == 'bench'
|
|
44
|
+
Requires-Dist: uvicorn[standard]>=0.23.2; extra == 'bench'
|
|
44
45
|
Provides-Extra: calendar
|
|
45
46
|
Requires-Dist: caldav==1.3.6; extra == 'calendar'
|
|
46
47
|
Provides-Extra: dev
|
|
47
|
-
Requires-Dist:
|
|
48
|
+
Requires-Dist: caldav==1.3.6; extra == 'dev'
|
|
49
|
+
Requires-Dist: coverage; extra == 'dev'
|
|
50
|
+
Requires-Dist: huggingface-hub; extra == 'dev'
|
|
51
|
+
Requires-Dist: matplotlib; extra == 'dev'
|
|
52
|
+
Requires-Dist: numpy; extra == 'dev'
|
|
53
|
+
Requires-Dist: pillow; extra == 'dev'
|
|
54
|
+
Requires-Dist: pre-commit; extra == 'dev'
|
|
55
|
+
Requires-Dist: py-cpuinfo; extra == 'dev'
|
|
56
|
+
Requires-Dist: pylint; extra == 'dev'
|
|
57
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
58
|
+
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
59
|
+
Requires-Dist: uvicorn[standard]>=0.23.2; extra == 'dev'
|
|
48
60
|
Provides-Extra: dev-min
|
|
49
61
|
Requires-Dist: coverage; extra == 'dev-min'
|
|
50
62
|
Requires-Dist: huggingface-hub; extra == 'dev-min'
|
|
@@ -55,12 +67,13 @@ Requires-Dist: pytest; extra == 'dev-min'
|
|
|
55
67
|
Requires-Dist: pytest-asyncio; extra == 'dev-min'
|
|
56
68
|
Provides-Extra: docs
|
|
57
69
|
Requires-Dist: autodoc-pydantic>=2.0.1; extra == 'docs'
|
|
58
|
-
Requires-Dist:
|
|
70
|
+
Requires-Dist: caldav==1.3.6; extra == 'docs'
|
|
59
71
|
Requires-Dist: sphinx-copybutton; extra == 'docs'
|
|
60
72
|
Requires-Dist: sphinx-inline-tabs; extra == 'docs'
|
|
61
73
|
Requires-Dist: sphinx-issues>=3.0.1; extra == 'docs'
|
|
62
|
-
Requires-Dist: sphinx-rtd-theme
|
|
63
|
-
Requires-Dist: sphinx
|
|
74
|
+
Requires-Dist: sphinx-rtd-theme<3; extra == 'docs'
|
|
75
|
+
Requires-Dist: sphinx<8; extra == 'docs'
|
|
76
|
+
Requires-Dist: uvicorn[standard]>=0.23.2; extra == 'docs'
|
|
64
77
|
Description-Content-Type: text/markdown
|
|
65
78
|
|
|
66
79
|
<p align="center">
|
|
@@ -73,7 +86,7 @@ Description-Content-Type: text/markdown
|
|
|
73
86
|
[](https://cloud-py-api.github.io/nc_py_api/)
|
|
74
87
|
[](https://codecov.io/github/cloud-py-api/nc_py_api)
|
|
75
88
|
|
|
76
|
-

|
|
77
90
|

|
|
78
91
|

|
|
79
92
|

|
|
@@ -89,23 +102,22 @@ Python library that provides a robust and well-documented API that allows develo
|
|
|
89
102
|
* **Sync + Async**: Provides both sync and async APIs.
|
|
90
103
|
|
|
91
104
|
### Capabilities
|
|
92
|
-
| **_Capability_**
|
|
93
|
-
|
|
94
|
-
| Calendar
|
|
95
|
-
| File System & Tags
|
|
96
|
-
| Nextcloud Talk
|
|
97
|
-
| Notifications
|
|
98
|
-
| Shares
|
|
99
|
-
| Users & Groups
|
|
100
|
-
| User & Weather status
|
|
101
|
-
| Other APIs
|
|
102
|
-
| Talk Bot API*
|
|
103
|
-
| Settings UI API*
|
|
104
|
-
|
|
|
105
|
+
| **_Capability_** | Nextcloud 27 | Nextcloud 28 | Nextcloud 29 | Nextcloud 30 |
|
|
106
|
+
|------------------------------|:------------:|:------------:|:------------:|:------------:|
|
|
107
|
+
| Calendar | ✅ | ✅ | ✅ | ✅ |
|
|
108
|
+
| File System & Tags | ✅ | ✅ | ✅ | ✅ |
|
|
109
|
+
| Nextcloud Talk | ✅ | ✅ | ✅ | ✅ |
|
|
110
|
+
| Notifications | ✅ | ✅ | ✅ | ✅ |
|
|
111
|
+
| Shares | ✅ | ✅ | ✅ | ✅ |
|
|
112
|
+
| Users & Groups | ✅ | ✅ | ✅ | ✅ |
|
|
113
|
+
| User & Weather status | ✅ | ✅ | ✅ | ✅ |
|
|
114
|
+
| Other APIs** | ✅ | ✅ | ✅ | ✅ |
|
|
115
|
+
| Talk Bot API* | ✅ | ✅ | ✅ | ✅ |
|
|
116
|
+
| Settings UI API* | N/A | N/A | ✅ | ✅ |
|
|
117
|
+
| TaskProcessing Provider API* | N/A | N/A | N/A | ✅ |
|
|
105
118
|
|
|
106
119
|
*_available only for **NextcloudApp**_<br>
|
|
107
|
-
**
|
|
108
|
-
***_Activity, Notes_
|
|
120
|
+
**_Activity, Notes_
|
|
109
121
|
|
|
110
122
|
### Differences between the Nextcloud and NextcloudApp classes
|
|
111
123
|
|
|
@@ -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,23 +24,22 @@ 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_**
|
|
28
|
-
|
|
29
|
-
| Calendar
|
|
30
|
-
| File System & Tags
|
|
31
|
-
| Nextcloud Talk
|
|
32
|
-
| Notifications
|
|
33
|
-
| Shares
|
|
34
|
-
| Users & Groups
|
|
35
|
-
| User & Weather status
|
|
36
|
-
| Other APIs
|
|
37
|
-
| Talk Bot API*
|
|
38
|
-
| Settings UI API*
|
|
39
|
-
|
|
|
27
|
+
| **_Capability_** | Nextcloud 27 | Nextcloud 28 | Nextcloud 29 | Nextcloud 30 |
|
|
28
|
+
|------------------------------|:------------:|:------------:|:------------:|:------------:|
|
|
29
|
+
| Calendar | ✅ | ✅ | ✅ | ✅ |
|
|
30
|
+
| File System & Tags | ✅ | ✅ | ✅ | ✅ |
|
|
31
|
+
| Nextcloud Talk | ✅ | ✅ | ✅ | ✅ |
|
|
32
|
+
| Notifications | ✅ | ✅ | ✅ | ✅ |
|
|
33
|
+
| Shares | ✅ | ✅ | ✅ | ✅ |
|
|
34
|
+
| Users & Groups | ✅ | ✅ | ✅ | ✅ |
|
|
35
|
+
| User & Weather status | ✅ | ✅ | ✅ | ✅ |
|
|
36
|
+
| Other APIs** | ✅ | ✅ | ✅ | ✅ |
|
|
37
|
+
| Talk Bot API* | ✅ | ✅ | ✅ | ✅ |
|
|
38
|
+
| Settings UI API* | N/A | N/A | ✅ | ✅ |
|
|
39
|
+
| TaskProcessing Provider API* | N/A | N/A | N/A | ✅ |
|
|
40
40
|
|
|
41
41
|
*_available only for **NextcloudApp**_<br>
|
|
42
|
-
**
|
|
43
|
-
***_Activity, Notes_
|
|
42
|
+
**_Activity, Notes_
|
|
44
43
|
|
|
45
44
|
### Differences between the Nextcloud and NextcloudApp classes
|
|
46
45
|
|
|
@@ -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
|
|
@@ -123,7 +126,7 @@ class AppConfig(BasicConfig):
|
|
|
123
126
|
super().__init__(**kwargs)
|
|
124
127
|
self.aa_version = self._get_config_value("aa_version", raise_not_found=False, **kwargs)
|
|
125
128
|
if not self.aa_version:
|
|
126
|
-
self.aa_version = "
|
|
129
|
+
self.aa_version = "2.2.0"
|
|
127
130
|
self.app_name = self._get_config_value("app_id", **kwargs)
|
|
128
131
|
self.app_version = self._get_config_value("app_version", **kwargs)
|
|
129
132
|
self.app_secret = self._get_config_value("app_secret", **kwargs)
|
|
@@ -147,7 +150,7 @@ class NcSessionBase(ABC):
|
|
|
147
150
|
self.init_adapter()
|
|
148
151
|
self.init_adapter_dav()
|
|
149
152
|
self.response_headers = Headers()
|
|
150
|
-
self._ocs_regexp = re.compile(r"/ocs/v[12]\.php/")
|
|
153
|
+
self._ocs_regexp = re.compile(r"/ocs/v[12]\.php/|/apps/groupfolders/")
|
|
151
154
|
|
|
152
155
|
def init_adapter(self, restart=False) -> None:
|
|
153
156
|
if getattr(self, "adapter", None) is None or restart:
|
|
@@ -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
|
|
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(
|
|
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
|
|
|
@@ -278,6 +289,7 @@ class NcSessionBasic(NcSessionBase, ABC):
|
|
|
278
289
|
str_url = str(request.url)
|
|
279
290
|
if re.search(self._ocs_regexp, str_url) is not None: # this is OCS call
|
|
280
291
|
request.url = request.url.copy_merge_params({"format": "json"})
|
|
292
|
+
request.headers["Accept"] = "application/json"
|
|
281
293
|
|
|
282
294
|
def _response_event(self, response: Response) -> None:
|
|
283
295
|
str_url = str(response.request.url)
|
|
@@ -289,7 +301,7 @@ class NcSessionBasic(NcSessionBase, ABC):
|
|
|
289
301
|
|
|
290
302
|
def download2fp(self, url_path: str, fp, dav: bool, params=None, **kwargs):
|
|
291
303
|
adapter = self.adapter_dav if dav else self.adapter
|
|
292
|
-
with adapter.stream("GET", url_path, params=params) as response:
|
|
304
|
+
with adapter.stream("GET", url_path, params=params, headers=kwargs.get("headers")) as response:
|
|
293
305
|
check_error(response)
|
|
294
306
|
for data_chunk in response.iter_raw(chunk_size=kwargs.get("chunk_size", 5 * 1024 * 1024)):
|
|
295
307
|
fp.write(data_chunk)
|
|
@@ -307,13 +319,16 @@ class AsyncNcSessionBasic(NcSessionBase, ABC):
|
|
|
307
319
|
content: bytes | str | typing.Iterable[bytes] | typing.AsyncIterable[bytes] | None = None,
|
|
308
320
|
json: dict | list | None = None,
|
|
309
321
|
params: dict | None = None,
|
|
322
|
+
files: dict | None = None,
|
|
310
323
|
**kwargs,
|
|
311
324
|
):
|
|
312
325
|
self.init_adapter()
|
|
313
326
|
info = f"request: {method} {path}"
|
|
314
327
|
nested_req = kwargs.pop("nested_req", False)
|
|
315
328
|
try:
|
|
316
|
-
response = await self.adapter.request(
|
|
329
|
+
response = await self.adapter.request(
|
|
330
|
+
method, path, content=content, json=json, params=params, files=files, **kwargs
|
|
331
|
+
)
|
|
317
332
|
except ReadTimeout:
|
|
318
333
|
raise NextcloudException(408, info=info) from None
|
|
319
334
|
|
|
@@ -398,6 +413,7 @@ class AsyncNcSessionBasic(NcSessionBase, ABC):
|
|
|
398
413
|
str_url = str(request.url)
|
|
399
414
|
if re.search(self._ocs_regexp, str_url) is not None: # this is OCS call
|
|
400
415
|
request.url = request.url.copy_merge_params({"format": "json"})
|
|
416
|
+
request.headers["Accept"] = "application/json"
|
|
401
417
|
|
|
402
418
|
async def _response_event(self, response: Response) -> None:
|
|
403
419
|
str_url = str(response.request.url)
|
|
@@ -409,7 +425,7 @@ class AsyncNcSessionBasic(NcSessionBase, ABC):
|
|
|
409
425
|
|
|
410
426
|
async def download2fp(self, url_path: str, fp, dav: bool, params=None, **kwargs):
|
|
411
427
|
adapter = self.adapter_dav if dav else self.adapter
|
|
412
|
-
async with adapter.stream("GET", url_path, params=params) as response:
|
|
428
|
+
async with adapter.stream("GET", url_path, params=params, headers=kwargs.get("headers")) as response:
|
|
413
429
|
check_error(response)
|
|
414
430
|
async for data_chunk in response.aiter_raw(chunk_size=kwargs.get("chunk_size", 5 * 1024 * 1024)):
|
|
415
431
|
fp.write(data_chunk)
|
|
@@ -459,7 +475,7 @@ class NcSessionAppBasic(ABC):
|
|
|
459
475
|
self.cfg = AppConfig(**kwargs)
|
|
460
476
|
super().__init__(**kwargs)
|
|
461
477
|
|
|
462
|
-
def sign_check(self, request: HTTPConnection) ->
|
|
478
|
+
def sign_check(self, request: HTTPConnection) -> str:
|
|
463
479
|
headers = {
|
|
464
480
|
"AA-VERSION": request.headers.get("AA-VERSION", ""),
|
|
465
481
|
"EX-APP-ID": request.headers.get("EX-APP-ID", ""),
|
|
@@ -474,13 +490,10 @@ class NcSessionAppBasic(ABC):
|
|
|
474
490
|
if headers["EX-APP-ID"] != self.cfg.app_name:
|
|
475
491
|
raise ValueError(f"Invalid EX-APP-ID:{headers['EX-APP-ID']} != {self.cfg.app_name}")
|
|
476
492
|
|
|
477
|
-
|
|
478
|
-
if headers["EX-APP-VERSION"] != our_version:
|
|
479
|
-
raise ValueError(f"Invalid EX-APP-VERSION:{headers['EX-APP-VERSION']} <=> {our_version}")
|
|
480
|
-
|
|
481
|
-
app_secret = get_username_secret_from_headers(headers)[1]
|
|
493
|
+
username, app_secret = get_username_secret_from_headers(headers)
|
|
482
494
|
if app_secret != self.cfg.app_secret:
|
|
483
495
|
raise ValueError(f"Invalid App secret:{app_secret} != {self.cfg.app_secret}")
|
|
496
|
+
return username
|
|
484
497
|
|
|
485
498
|
|
|
486
499
|
class NcSessionApp(NcSessionAppBasic, NcSessionBasic):
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Nextcloud API for working with applications."""
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
|
-
import datetime
|
|
5
4
|
|
|
6
5
|
from ._misc import require_capabilities
|
|
7
6
|
from ._session import AsyncNcSessionBasic, NcSessionBasic
|
|
@@ -34,18 +33,6 @@ class ExAppInfo:
|
|
|
34
33
|
"""Flag indicating if the application enabled."""
|
|
35
34
|
return bool(self._raw_data["enabled"])
|
|
36
35
|
|
|
37
|
-
@property
|
|
38
|
-
def last_check_time(self) -> datetime.datetime:
|
|
39
|
-
"""Time of the last successful application check."""
|
|
40
|
-
return datetime.datetime.utcfromtimestamp(int(self._raw_data["last_check_time"])).replace(
|
|
41
|
-
tzinfo=datetime.timezone.utc
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
@property
|
|
45
|
-
def system(self) -> bool:
|
|
46
|
-
"""Flag indicating if the application is a system application."""
|
|
47
|
-
return bool(self._raw_data["system"])
|
|
48
|
-
|
|
49
36
|
def __repr__(self):
|
|
50
37
|
return f"<{self.__class__.__name__} id={self.app_id}, ver={self.version}>"
|
|
51
38
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""All possible ExApp stuff for NextcloudApp that can be used."""
|
|
2
|
+
|
|
3
|
+
from ..files import ActionFileInfo
|
|
4
|
+
from .defs import FileSystemEventNotification, LogLvl
|
|
5
|
+
from .integration_fastapi import (
|
|
6
|
+
AppAPIAuthMiddleware,
|
|
7
|
+
anc_app,
|
|
8
|
+
atalk_bot_msg,
|
|
9
|
+
nc_app,
|
|
10
|
+
set_handlers,
|
|
11
|
+
talk_bot_msg,
|
|
12
|
+
)
|
|
13
|
+
from .logging import setup_nextcloud_logging
|
|
14
|
+
from .misc import (
|
|
15
|
+
get_computation_device,
|
|
16
|
+
get_model_path,
|
|
17
|
+
persistent_storage,
|
|
18
|
+
verify_version,
|
|
19
|
+
)
|
|
20
|
+
from .ui.settings import SettingsField, SettingsFieldType, SettingsForm
|
|
21
|
+
from .uvicorn_fastapi import run_app
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class UiActionFileInfo(ActionFileInfo):
|
|
25
|
+
"""``Deprecated``: use :py:class:`~nc_py_api.files.ActionFileInfo` instead."""
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Additional definitions for NextcloudApp."""
|
|
2
|
+
|
|
3
|
+
import enum
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
from ..files import ActionFileInfo
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LogLvl(enum.IntEnum):
|
|
11
|
+
"""Log levels."""
|
|
12
|
+
|
|
13
|
+
DEBUG = 0
|
|
14
|
+
"""Debug log level"""
|
|
15
|
+
INFO = 1
|
|
16
|
+
"""Informational log level"""
|
|
17
|
+
WARNING = 2
|
|
18
|
+
"""Warning log level. ``Default``"""
|
|
19
|
+
ERROR = 3
|
|
20
|
+
"""Error log level"""
|
|
21
|
+
FATAL = 4
|
|
22
|
+
"""Fatal log level"""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class FileSystemEventData(BaseModel):
|
|
26
|
+
"""FileSystem events format."""
|
|
27
|
+
|
|
28
|
+
target: ActionFileInfo
|
|
29
|
+
source: ActionFileInfo | None = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class FileSystemEventNotification(BaseModel):
|
|
33
|
+
"""AppAPI event notification common data."""
|
|
34
|
+
|
|
35
|
+
event_type: str
|
|
36
|
+
event_subtype: str
|
|
37
|
+
event_data: FileSystemEventData
|
|
@@ -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
|