nc-py-api 0.9.0__py3-none-any.whl → 0.11.0__py3-none-any.whl
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/__init__.py +1 -1
- nc_py_api/_preferences_ex.py +2 -2
- nc_py_api/_talk_api.py +1 -1
- nc_py_api/_version.py +1 -1
- nc_py_api/ex_app/__init__.py +1 -0
- nc_py_api/ex_app/defs.py +1 -1
- nc_py_api/ex_app/integration_fastapi.py +120 -89
- nc_py_api/ex_app/providers/speech_to_text.py +2 -2
- nc_py_api/ex_app/providers/text_processing.py +2 -2
- nc_py_api/ex_app/providers/translations.py +11 -2
- nc_py_api/ex_app/ui/files_actions.py +1 -1
- nc_py_api/ex_app/ui/resources.py +1 -1
- nc_py_api/ex_app/ui/settings.py +178 -0
- nc_py_api/ex_app/ui/top_menu.py +1 -1
- nc_py_api/ex_app/ui/ui.py +7 -0
- nc_py_api/files/__init__.py +61 -0
- nc_py_api/files/_files.py +32 -10
- nc_py_api/files/files.py +65 -8
- nc_py_api/files/sharing.py +1 -1
- nc_py_api/nextcloud.py +1 -48
- nc_py_api/user_status.py +1 -1
- {nc_py_api-0.9.0.dist-info → nc_py_api-0.11.0.dist-info}/METADATA +9 -7
- nc_py_api-0.11.0.dist-info/RECORD +49 -0
- nc_py_api-0.9.0.dist-info/RECORD +0 -48
- {nc_py_api-0.9.0.dist-info → nc_py_api-0.11.0.dist-info}/WHEEL +0 -0
- {nc_py_api-0.9.0.dist-info → nc_py_api-0.11.0.dist-info}/licenses/AUTHORS +0 -0
- {nc_py_api-0.9.0.dist-info → nc_py_api-0.11.0.dist-info}/licenses/LICENSE.txt +0 -0
nc_py_api/ex_app/ui/top_menu.py
CHANGED
nc_py_api/ex_app/ui/ui.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from ..._session import AsyncNcSessionApp, NcSessionApp
|
|
4
4
|
from .files_actions import _AsyncUiFilesActionsAPI, _UiFilesActionsAPI
|
|
5
5
|
from .resources import _AsyncUiResources, _UiResources
|
|
6
|
+
from .settings import _AsyncDeclarativeSettingsAPI, _DeclarativeSettingsAPI
|
|
6
7
|
from .top_menu import _AsyncUiTopMenuAPI, _UiTopMenuAPI
|
|
7
8
|
|
|
8
9
|
|
|
@@ -15,11 +16,14 @@ class UiApi:
|
|
|
15
16
|
"""Top App menu API."""
|
|
16
17
|
resources: _UiResources
|
|
17
18
|
"""Page(Template) resources API."""
|
|
19
|
+
settings: _DeclarativeSettingsAPI
|
|
20
|
+
"""API for ExApp settings UI"""
|
|
18
21
|
|
|
19
22
|
def __init__(self, session: NcSessionApp):
|
|
20
23
|
self.files_dropdown_menu = _UiFilesActionsAPI(session)
|
|
21
24
|
self.top_menu = _UiTopMenuAPI(session)
|
|
22
25
|
self.resources = _UiResources(session)
|
|
26
|
+
self.settings = _DeclarativeSettingsAPI(session)
|
|
23
27
|
|
|
24
28
|
|
|
25
29
|
class AsyncUiApi:
|
|
@@ -31,8 +35,11 @@ class AsyncUiApi:
|
|
|
31
35
|
"""Top App menu API."""
|
|
32
36
|
resources: _AsyncUiResources
|
|
33
37
|
"""Page(Template) resources API."""
|
|
38
|
+
settings: _AsyncDeclarativeSettingsAPI
|
|
39
|
+
"""API for ExApp settings UI"""
|
|
34
40
|
|
|
35
41
|
def __init__(self, session: AsyncNcSessionApp):
|
|
36
42
|
self.files_dropdown_menu = _AsyncUiFilesActionsAPI(session)
|
|
37
43
|
self.top_menu = _AsyncUiTopMenuAPI(session)
|
|
38
44
|
self.resources = _AsyncUiResources(session)
|
|
45
|
+
self.settings = _AsyncDeclarativeSettingsAPI(session)
|
nc_py_api/files/__init__.py
CHANGED
|
@@ -9,6 +9,63 @@ import warnings
|
|
|
9
9
|
from .. import _misc
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
class LockType(enum.IntEnum):
|
|
13
|
+
"""Nextcloud File Locks types."""
|
|
14
|
+
|
|
15
|
+
MANUAL_LOCK = 0
|
|
16
|
+
COLLABORATIVE_LOCK = 1
|
|
17
|
+
WEBDAV_TOKEN = 2
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclasses.dataclass
|
|
21
|
+
class FsNodeLockInfo:
|
|
22
|
+
"""File Lock information if Nextcloud `files_lock` is enabled."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, **kwargs):
|
|
25
|
+
self._is_locked = bool(int(kwargs.get("is_locked", False)))
|
|
26
|
+
self._lock_owner_type = LockType(int(kwargs.get("lock_owner_type", 0)))
|
|
27
|
+
self._lock_owner = kwargs.get("lock_owner", "")
|
|
28
|
+
self._owner_display_name = kwargs.get("owner_display_name", "")
|
|
29
|
+
self._owner_editor = kwargs.get("lock_owner_editor", "")
|
|
30
|
+
self._lock_time = int(kwargs.get("lock_time", 0))
|
|
31
|
+
self._lock_ttl = int(kwargs.get("_lock_ttl", 0))
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def is_locked(self) -> bool:
|
|
35
|
+
"""Returns ``True`` if the file is locked, ``False`` otherwise."""
|
|
36
|
+
return self._is_locked
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def type(self) -> LockType:
|
|
40
|
+
"""Type of the lock."""
|
|
41
|
+
return LockType(self._lock_owner_type)
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def owner(self) -> str:
|
|
45
|
+
"""User id of the lock owner."""
|
|
46
|
+
return self._lock_owner
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def owner_display_name(self) -> str:
|
|
50
|
+
"""Display name of the lock owner."""
|
|
51
|
+
return self._owner_display_name
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def owner_editor(self) -> str:
|
|
55
|
+
"""App id of an app owned lock to allow clients to suggest joining the collaborative editing session."""
|
|
56
|
+
return self._owner_editor
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def lock_creation_time(self) -> datetime.datetime:
|
|
60
|
+
"""Lock creation time."""
|
|
61
|
+
return datetime.datetime.utcfromtimestamp(self._lock_time).replace(tzinfo=datetime.timezone.utc)
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def lock_ttl(self) -> int:
|
|
65
|
+
"""TTL of the lock in seconds staring from the creation time. A value of 0 means the timeout is infinite."""
|
|
66
|
+
return self._lock_ttl
|
|
67
|
+
|
|
68
|
+
|
|
12
69
|
@dataclasses.dataclass
|
|
13
70
|
class FsNodeInfo:
|
|
14
71
|
"""Extra FS object attributes from Nextcloud."""
|
|
@@ -116,11 +173,15 @@ class FsNode:
|
|
|
116
173
|
info: FsNodeInfo
|
|
117
174
|
"""Additional extra information for the object"""
|
|
118
175
|
|
|
176
|
+
lock_info: FsNodeLockInfo
|
|
177
|
+
"""Class describing `lock` information if any."""
|
|
178
|
+
|
|
119
179
|
def __init__(self, full_path: str, **kwargs):
|
|
120
180
|
self.full_path = full_path
|
|
121
181
|
self.file_id = kwargs.get("file_id", "")
|
|
122
182
|
self.etag = kwargs.get("etag", "")
|
|
123
183
|
self.info = FsNodeInfo(**kwargs)
|
|
184
|
+
self.lock_info = FsNodeLockInfo(**kwargs)
|
|
124
185
|
|
|
125
186
|
@property
|
|
126
187
|
def is_dir(self) -> bool:
|
nc_py_api/files/_files.py
CHANGED
|
@@ -10,7 +10,7 @@ import xmltodict
|
|
|
10
10
|
from httpx import Response
|
|
11
11
|
|
|
12
12
|
from .._exceptions import NextcloudException, check_error
|
|
13
|
-
from .._misc import clear_from_params_empty
|
|
13
|
+
from .._misc import check_capabilities, clear_from_params_empty
|
|
14
14
|
from . import FsNode, SystemTag
|
|
15
15
|
|
|
16
16
|
PROPFIND_PROPERTIES = [
|
|
@@ -29,13 +29,16 @@ PROPFIND_PROPERTIES = [
|
|
|
29
29
|
"oc:share-types",
|
|
30
30
|
"oc:favorite",
|
|
31
31
|
"nc:is-encrypted",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
PROPFIND_LOCKING_PROPERTIES = [
|
|
32
35
|
"nc:lock",
|
|
33
36
|
"nc:lock-owner-displayname",
|
|
34
37
|
"nc:lock-owner",
|
|
35
38
|
"nc:lock-owner-type",
|
|
36
|
-
"nc:lock-owner-editor",
|
|
37
|
-
"nc:lock-time",
|
|
38
|
-
"nc:lock-timeout",
|
|
39
|
+
"nc:lock-owner-editor", # App id of an app owned lock
|
|
40
|
+
"nc:lock-time", # Timestamp of the log creation time
|
|
41
|
+
"nc:lock-timeout", # TTL of the lock in seconds staring from the creation time
|
|
39
42
|
]
|
|
40
43
|
|
|
41
44
|
SEARCH_PROPERTIES_MAP = {
|
|
@@ -57,7 +60,14 @@ class PropFindType(enum.IntEnum):
|
|
|
57
60
|
VERSIONS_FILE_ID = 3
|
|
58
61
|
|
|
59
62
|
|
|
60
|
-
def
|
|
63
|
+
def get_propfind_properties(capabilities: dict) -> list:
|
|
64
|
+
r = PROPFIND_PROPERTIES
|
|
65
|
+
if not check_capabilities("files.locking", capabilities):
|
|
66
|
+
r += PROPFIND_LOCKING_PROPERTIES
|
|
67
|
+
return r
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def build_find_request(req: list, path: str | FsNode, user: str, capabilities: dict) -> ElementTree.Element:
|
|
61
71
|
path = path.user_path if isinstance(path, FsNode) else path
|
|
62
72
|
root = ElementTree.Element(
|
|
63
73
|
"d:searchrequest",
|
|
@@ -65,7 +75,7 @@ def build_find_request(req: list, path: str | FsNode, user: str) -> ElementTree.
|
|
|
65
75
|
)
|
|
66
76
|
xml_search = ElementTree.SubElement(root, "d:basicsearch")
|
|
67
77
|
xml_select_prop = ElementTree.SubElement(ElementTree.SubElement(xml_search, "d:select"), "d:prop")
|
|
68
|
-
for i in
|
|
78
|
+
for i in get_propfind_properties(capabilities):
|
|
69
79
|
ElementTree.SubElement(xml_select_prop, i)
|
|
70
80
|
xml_from_scope = ElementTree.SubElement(ElementTree.SubElement(xml_search, "d:from"), "d:scope")
|
|
71
81
|
href = f"/files/{user}/{path.removeprefix('/')}"
|
|
@@ -76,7 +86,9 @@ def build_find_request(req: list, path: str | FsNode, user: str) -> ElementTree.
|
|
|
76
86
|
return root
|
|
77
87
|
|
|
78
88
|
|
|
79
|
-
def build_list_by_criteria_req(
|
|
89
|
+
def build_list_by_criteria_req(
|
|
90
|
+
properties: list[str] | None, tags: list[int | SystemTag] | None, capabilities: dict
|
|
91
|
+
) -> ElementTree.Element:
|
|
80
92
|
if not properties and not tags:
|
|
81
93
|
raise ValueError("Either specify 'properties' or 'tags' to filter results.")
|
|
82
94
|
root = ElementTree.Element(
|
|
@@ -84,7 +96,7 @@ def build_list_by_criteria_req(properties: list[str] | None, tags: list[int | Sy
|
|
|
84
96
|
attrib={"xmlns:d": "DAV:", "xmlns:oc": "http://owncloud.org/ns", "xmlns:nc": "http://nextcloud.org/ns"},
|
|
85
97
|
)
|
|
86
98
|
prop = ElementTree.SubElement(root, "d:prop")
|
|
87
|
-
for i in
|
|
99
|
+
for i in get_propfind_properties(capabilities):
|
|
88
100
|
ElementTree.SubElement(prop, i)
|
|
89
101
|
xml_filter_rules = ElementTree.SubElement(root, "oc:filter-rules")
|
|
90
102
|
if properties and "favorite" in properties:
|
|
@@ -243,7 +255,7 @@ def etag_fileid_from_response(response: Response) -> dict:
|
|
|
243
255
|
return {"etag": response.headers.get("OC-Etag", ""), "file_id": response.headers["OC-FileId"]}
|
|
244
256
|
|
|
245
257
|
|
|
246
|
-
def _parse_record(full_path: str, prop_stats: list[dict]) -> FsNode:
|
|
258
|
+
def _parse_record(full_path: str, prop_stats: list[dict]) -> FsNode: # noqa pylint: disable = too-many-branches
|
|
247
259
|
fs_node_args = {}
|
|
248
260
|
for prop_stat in prop_stats:
|
|
249
261
|
if str(prop_stat.get("d:status", "")).find("200 OK") == -1:
|
|
@@ -274,7 +286,17 @@ def _parse_record(full_path: str, prop_stats: list[dict]) -> FsNode:
|
|
|
274
286
|
fs_node_args["trashbin_original_location"] = prop["nc:trashbin-original-location"]
|
|
275
287
|
if "nc:trashbin-deletion-time" in prop_keys:
|
|
276
288
|
fs_node_args["trashbin_deletion_time"] = prop["nc:trashbin-deletion-time"]
|
|
277
|
-
|
|
289
|
+
for k, v in {
|
|
290
|
+
"nc:lock": "is_locked",
|
|
291
|
+
"nc:lock-owner-type": "lock_owner_type",
|
|
292
|
+
"nc:lock-owner": "lock_owner",
|
|
293
|
+
"nc:lock-owner-displayname": "lock_owner_displayname",
|
|
294
|
+
"nc:lock-owner-editor": "lock_owner_editor",
|
|
295
|
+
"nc:lock-time": "lock_time",
|
|
296
|
+
"nc:lock-timeout": "lock_ttl",
|
|
297
|
+
}.items():
|
|
298
|
+
if k in prop_keys and prop[k] is not None:
|
|
299
|
+
fs_node_args[v] = prop[k]
|
|
278
300
|
return FsNode(full_path, **fs_node_args)
|
|
279
301
|
|
|
280
302
|
|
nc_py_api/files/files.py
CHANGED
|
@@ -10,7 +10,7 @@ from httpx import Headers
|
|
|
10
10
|
from .._exceptions import NextcloudException, NextcloudExceptionNotFound, check_error
|
|
11
11
|
from .._misc import random_string, require_capabilities
|
|
12
12
|
from .._session import AsyncNcSessionBasic, NcSessionBasic
|
|
13
|
-
from . import FsNode, SystemTag
|
|
13
|
+
from . import FsNode, LockType, SystemTag
|
|
14
14
|
from ._files import (
|
|
15
15
|
PROPFIND_PROPERTIES,
|
|
16
16
|
PropFindType,
|
|
@@ -25,13 +25,14 @@ from ._files import (
|
|
|
25
25
|
dav_get_obj_path,
|
|
26
26
|
element_tree_as_str,
|
|
27
27
|
etag_fileid_from_response,
|
|
28
|
+
get_propfind_properties,
|
|
28
29
|
lf_parse_webdav_response,
|
|
29
30
|
)
|
|
30
31
|
from .sharing import _AsyncFilesSharingAPI, _FilesSharingAPI
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
class FilesAPI:
|
|
34
|
-
"""Class that encapsulates file system and file sharing API."""
|
|
35
|
+
"""Class that encapsulates file system and file sharing API, avalaible as **nc.files.<method>**."""
|
|
35
36
|
|
|
36
37
|
sharing: _FilesSharingAPI
|
|
37
38
|
"""API for managing Files Shares"""
|
|
@@ -50,7 +51,7 @@ class FilesAPI:
|
|
|
50
51
|
"""
|
|
51
52
|
if exclude_self and not depth:
|
|
52
53
|
raise ValueError("Wrong input parameters, query will return nothing.")
|
|
53
|
-
properties =
|
|
54
|
+
properties = get_propfind_properties(self._session.capabilities)
|
|
54
55
|
path = path.user_path if isinstance(path, FsNode) else path
|
|
55
56
|
return self._listdir(self._session.user, path, properties=properties, depth=depth, exclude_self=exclude_self)
|
|
56
57
|
|
|
@@ -76,7 +77,7 @@ class FilesAPI:
|
|
|
76
77
|
:param path: path where to search from. Default = **""**.
|
|
77
78
|
"""
|
|
78
79
|
# `req` possible keys: "name", "mime", "last_modified", "size", "favorite", "fileid"
|
|
79
|
-
root = build_find_request(req, path, self._session.user)
|
|
80
|
+
root = build_find_request(req, path, self._session.user, self._session.capabilities)
|
|
80
81
|
webdav_response = self._session.adapter_dav.request(
|
|
81
82
|
"SEARCH", "", content=element_tree_as_str(root), headers={"Content-Type": "text/xml"}
|
|
82
83
|
)
|
|
@@ -248,7 +249,7 @@ class FilesAPI:
|
|
|
248
249
|
Supported values: **favorite**
|
|
249
250
|
:param tags: List of ``tags ids`` or ``SystemTag`` that should have been set for the file.
|
|
250
251
|
"""
|
|
251
|
-
root = build_list_by_criteria_req(properties, tags)
|
|
252
|
+
root = build_list_by_criteria_req(properties, tags, self._session.capabilities)
|
|
252
253
|
webdav_response = self._session.adapter_dav.request(
|
|
253
254
|
"REPORT", dav_get_obj_path(self._session.user), content=element_tree_as_str(root)
|
|
254
255
|
)
|
|
@@ -396,6 +397,34 @@ class FilesAPI:
|
|
|
396
397
|
"""Removes Tag from a file/directory."""
|
|
397
398
|
self._file_change_tag_state(file_id, tag_id, False)
|
|
398
399
|
|
|
400
|
+
def lock(self, path: FsNode | str, lock_type: LockType = LockType.MANUAL_LOCK) -> None:
|
|
401
|
+
"""Locks the file.
|
|
402
|
+
|
|
403
|
+
.. note:: Exception codes: 423 - existing lock present.
|
|
404
|
+
"""
|
|
405
|
+
require_capabilities("files.locking", self._session.capabilities)
|
|
406
|
+
full_path = dav_get_obj_path(self._session.user, path.user_path if isinstance(path, FsNode) else path)
|
|
407
|
+
response = self._session.adapter_dav.request(
|
|
408
|
+
"LOCK",
|
|
409
|
+
quote(full_path),
|
|
410
|
+
headers={"X-User-Lock": "1", "X-User-Lock-Type": str(lock_type.value)},
|
|
411
|
+
)
|
|
412
|
+
check_error(response, f"lock: user={self._session.user}, path={full_path}")
|
|
413
|
+
|
|
414
|
+
def unlock(self, path: FsNode | str) -> None:
|
|
415
|
+
"""Unlocks the file.
|
|
416
|
+
|
|
417
|
+
.. note:: Exception codes: 412 - the file is not locked, 423 - the lock is owned by another user.
|
|
418
|
+
"""
|
|
419
|
+
require_capabilities("files.locking", self._session.capabilities)
|
|
420
|
+
full_path = dav_get_obj_path(self._session.user, path.user_path if isinstance(path, FsNode) else path)
|
|
421
|
+
response = self._session.adapter_dav.request(
|
|
422
|
+
"UNLOCK",
|
|
423
|
+
quote(full_path),
|
|
424
|
+
headers={"X-User-Lock": "1"},
|
|
425
|
+
)
|
|
426
|
+
check_error(response, f"unlock: user={self._session.user}, path={full_path}")
|
|
427
|
+
|
|
399
428
|
def _file_change_tag_state(self, file_id: FsNode | int, tag_id: SystemTag | int, tag_state: bool) -> None:
|
|
400
429
|
fs_object = file_id.info.fileid if isinstance(file_id, FsNode) else file_id
|
|
401
430
|
tag = tag_id.tag_id if isinstance(tag_id, SystemTag) else tag_id
|
|
@@ -493,7 +522,7 @@ class AsyncFilesAPI:
|
|
|
493
522
|
"""
|
|
494
523
|
if exclude_self and not depth:
|
|
495
524
|
raise ValueError("Wrong input parameters, query will return nothing.")
|
|
496
|
-
properties =
|
|
525
|
+
properties = get_propfind_properties(await self._session.capabilities)
|
|
497
526
|
path = path.user_path if isinstance(path, FsNode) else path
|
|
498
527
|
return await self._listdir(
|
|
499
528
|
await self._session.user, path, properties=properties, depth=depth, exclude_self=exclude_self
|
|
@@ -521,7 +550,7 @@ class AsyncFilesAPI:
|
|
|
521
550
|
:param path: path where to search from. Default = **""**.
|
|
522
551
|
"""
|
|
523
552
|
# `req` possible keys: "name", "mime", "last_modified", "size", "favorite", "fileid"
|
|
524
|
-
root = build_find_request(req, path, await self._session.user)
|
|
553
|
+
root = build_find_request(req, path, await self._session.user, await self._session.capabilities)
|
|
525
554
|
webdav_response = await self._session.adapter_dav.request(
|
|
526
555
|
"SEARCH", "", content=element_tree_as_str(root), headers={"Content-Type": "text/xml"}
|
|
527
556
|
)
|
|
@@ -695,7 +724,7 @@ class AsyncFilesAPI:
|
|
|
695
724
|
Supported values: **favorite**
|
|
696
725
|
:param tags: List of ``tags ids`` or ``SystemTag`` that should have been set for the file.
|
|
697
726
|
"""
|
|
698
|
-
root = build_list_by_criteria_req(properties, tags)
|
|
727
|
+
root = build_list_by_criteria_req(properties, tags, await self._session.capabilities)
|
|
699
728
|
webdav_response = await self._session.adapter_dav.request(
|
|
700
729
|
"REPORT", dav_get_obj_path(await self._session.user), content=element_tree_as_str(root)
|
|
701
730
|
)
|
|
@@ -848,6 +877,34 @@ class AsyncFilesAPI:
|
|
|
848
877
|
"""Removes Tag from a file/directory."""
|
|
849
878
|
await self._file_change_tag_state(file_id, tag_id, False)
|
|
850
879
|
|
|
880
|
+
async def lock(self, path: FsNode | str, lock_type: LockType = LockType.MANUAL_LOCK) -> None:
|
|
881
|
+
"""Locks the file.
|
|
882
|
+
|
|
883
|
+
.. note:: Exception codes: 423 - existing lock present.
|
|
884
|
+
"""
|
|
885
|
+
require_capabilities("files.locking", await self._session.capabilities)
|
|
886
|
+
full_path = dav_get_obj_path(await self._session.user, path.user_path if isinstance(path, FsNode) else path)
|
|
887
|
+
response = await self._session.adapter_dav.request(
|
|
888
|
+
"LOCK",
|
|
889
|
+
quote(full_path),
|
|
890
|
+
headers={"X-User-Lock": "1", "X-User-Lock-Type": str(lock_type.value)},
|
|
891
|
+
)
|
|
892
|
+
check_error(response, f"lock: user={self._session.user}, path={full_path}")
|
|
893
|
+
|
|
894
|
+
async def unlock(self, path: FsNode | str) -> None:
|
|
895
|
+
"""Unlocks the file.
|
|
896
|
+
|
|
897
|
+
.. note:: Exception codes: 412 - the file is not locked, 423 - the lock is owned by another user.
|
|
898
|
+
"""
|
|
899
|
+
require_capabilities("files.locking", await self._session.capabilities)
|
|
900
|
+
full_path = dav_get_obj_path(await self._session.user, path.user_path if isinstance(path, FsNode) else path)
|
|
901
|
+
response = await self._session.adapter_dav.request(
|
|
902
|
+
"UNLOCK",
|
|
903
|
+
quote(full_path),
|
|
904
|
+
headers={"X-User-Lock": "1"},
|
|
905
|
+
)
|
|
906
|
+
check_error(response, f"unlock: user={self._session.user}, path={full_path}")
|
|
907
|
+
|
|
851
908
|
async def _file_change_tag_state(self, file_id: FsNode | int, tag_id: SystemTag | int, tag_state: bool) -> None:
|
|
852
909
|
fs_object = file_id.info.fileid if isinstance(file_id, FsNode) else file_id
|
|
853
910
|
tag = tag_id.tag_id if isinstance(tag_id, SystemTag) else tag_id
|
nc_py_api/files/sharing.py
CHANGED
|
@@ -5,7 +5,7 @@ from . import FilePermissions, FsNode, Share, ShareType
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class _FilesSharingAPI:
|
|
8
|
-
"""Class provides all File Sharing functionality."""
|
|
8
|
+
"""Class provides all File Sharing functionality, avalaible as **nc.files.sharing.<method>**."""
|
|
9
9
|
|
|
10
10
|
_ep_base: str = "/ocs/v1.php/apps/files_sharing/api/v1"
|
|
11
11
|
|
nc_py_api/nextcloud.py
CHANGED
|
@@ -4,7 +4,6 @@ import typing
|
|
|
4
4
|
from abc import ABC
|
|
5
5
|
|
|
6
6
|
from httpx import Headers
|
|
7
|
-
from starlette.requests import HTTPConnection
|
|
8
7
|
|
|
9
8
|
from ._exceptions import NextcloudExceptionNotFound
|
|
10
9
|
from ._misc import check_capabilities, require_capabilities
|
|
@@ -30,7 +29,7 @@ from ._theming import ThemingInfo, get_parsed_theme
|
|
|
30
29
|
from .activity import _ActivityAPI, _AsyncActivityAPI
|
|
31
30
|
from .apps import _AppsAPI, _AsyncAppsAPI
|
|
32
31
|
from .calendar import _CalendarAPI
|
|
33
|
-
from .ex_app.defs import
|
|
32
|
+
from .ex_app.defs import LogLvl
|
|
34
33
|
from .ex_app.providers.providers import AsyncProvidersApi, ProvidersApi
|
|
35
34
|
from .ex_app.ui.ui import AsyncUiApi, UiApi
|
|
36
35
|
from .files.files import AsyncFilesAPI, FilesAPI
|
|
@@ -330,15 +329,6 @@ class NextcloudApp(_NextcloudBasic):
|
|
|
330
329
|
"""Returns list of users on the Nextcloud instance. **Available** only for ``System`` applications."""
|
|
331
330
|
return self._session.ocs("GET", f"{self._session.ae_url}/users")
|
|
332
331
|
|
|
333
|
-
def scope_allowed(self, scope: ApiScope) -> bool:
|
|
334
|
-
"""Check if API scope is avalaible for application.
|
|
335
|
-
|
|
336
|
-
Useful for applications that declare optional scopes to check if they are allowed.
|
|
337
|
-
"""
|
|
338
|
-
if self.check_capabilities("app_api"):
|
|
339
|
-
return False
|
|
340
|
-
return scope in self.capabilities["app_api"]["scopes"]
|
|
341
|
-
|
|
342
332
|
@property
|
|
343
333
|
def user(self) -> str:
|
|
344
334
|
"""Property containing the current user ID.
|
|
@@ -395,20 +385,6 @@ class NextcloudApp(_NextcloudBasic):
|
|
|
395
385
|
return False
|
|
396
386
|
return True
|
|
397
387
|
|
|
398
|
-
def request_sign_check(self, request: HTTPConnection) -> bool:
|
|
399
|
-
"""Verifies the signature and validity of an incoming request from the Nextcloud.
|
|
400
|
-
|
|
401
|
-
:param request: The `Starlette request <https://www.starlette.io/requests/>`_
|
|
402
|
-
|
|
403
|
-
.. note:: In most cases ``nc: Annotated[NextcloudApp, Depends(nc_app)]`` should be used.
|
|
404
|
-
"""
|
|
405
|
-
try:
|
|
406
|
-
self._session.sign_check(request)
|
|
407
|
-
except ValueError as e:
|
|
408
|
-
print(e)
|
|
409
|
-
return False
|
|
410
|
-
return True
|
|
411
|
-
|
|
412
388
|
def set_init_status(self, progress: int, error: str = "") -> None:
|
|
413
389
|
"""Sets state of the app initialization.
|
|
414
390
|
|
|
@@ -470,15 +446,6 @@ class AsyncNextcloudApp(_AsyncNextcloudBasic):
|
|
|
470
446
|
"""Returns list of users on the Nextcloud instance. **Available** only for ``System`` applications."""
|
|
471
447
|
return await self._session.ocs("GET", f"{self._session.ae_url}/users")
|
|
472
448
|
|
|
473
|
-
async def scope_allowed(self, scope: ApiScope) -> bool:
|
|
474
|
-
"""Check if API scope is avalaible for application.
|
|
475
|
-
|
|
476
|
-
Useful for applications that declare optional scopes to check if they are allowed.
|
|
477
|
-
"""
|
|
478
|
-
if await self.check_capabilities("app_api"):
|
|
479
|
-
return False
|
|
480
|
-
return scope in (await self.capabilities)["app_api"]["scopes"]
|
|
481
|
-
|
|
482
449
|
@property
|
|
483
450
|
async def user(self) -> str:
|
|
484
451
|
"""Property containing the current user ID.
|
|
@@ -535,20 +502,6 @@ class AsyncNextcloudApp(_AsyncNextcloudBasic):
|
|
|
535
502
|
return False
|
|
536
503
|
return True
|
|
537
504
|
|
|
538
|
-
def request_sign_check(self, request: HTTPConnection) -> bool:
|
|
539
|
-
"""Verifies the signature and validity of an incoming request from the Nextcloud.
|
|
540
|
-
|
|
541
|
-
:param request: The `Starlette request <https://www.starlette.io/requests/>`_
|
|
542
|
-
|
|
543
|
-
.. note:: In most cases ``nc: Annotated[NextcloudApp, Depends(nc_app)]`` should be used.
|
|
544
|
-
"""
|
|
545
|
-
try:
|
|
546
|
-
self._session.sign_check(request)
|
|
547
|
-
except ValueError as e:
|
|
548
|
-
print(e)
|
|
549
|
-
return False
|
|
550
|
-
return True
|
|
551
|
-
|
|
552
505
|
async def set_init_status(self, progress: int, error: str = "") -> None:
|
|
553
506
|
"""Sets state of the app initialization.
|
|
554
507
|
|
nc_py_api/user_status.py
CHANGED
|
@@ -39,7 +39,7 @@ class PredefinedStatus:
|
|
|
39
39
|
self.status_id = raw_status["id"]
|
|
40
40
|
self.icon = raw_status["icon"]
|
|
41
41
|
self.message = raw_status["message"]
|
|
42
|
-
clear_at_raw = raw_status.get("clearAt"
|
|
42
|
+
clear_at_raw = raw_status.get("clearAt")
|
|
43
43
|
if clear_at_raw:
|
|
44
44
|
self.clear_at = ClearAt(clear_at_raw)
|
|
45
45
|
else:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: nc-py-api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.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/
|
|
@@ -10,7 +10,7 @@ License-Expression: BSD-3-Clause
|
|
|
10
10
|
License-File: AUTHORS
|
|
11
11
|
License-File: LICENSE.txt
|
|
12
12
|
Keywords: api,client,framework,library,nextcloud
|
|
13
|
-
Classifier: Development Status ::
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
15
15
|
Classifier: License :: OSI Approved :: BSD License
|
|
16
16
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
@@ -29,8 +29,8 @@ Classifier: Topic :: Software Development :: Libraries
|
|
|
29
29
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
30
30
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
31
31
|
Requires-Python: >=3.10
|
|
32
|
-
Requires-Dist: fastapi>=0.
|
|
33
|
-
Requires-Dist: httpx>=0.
|
|
32
|
+
Requires-Dist: fastapi>=0.109.2
|
|
33
|
+
Requires-Dist: httpx>=0.25.2
|
|
34
34
|
Requires-Dist: pydantic>=2.1.1
|
|
35
35
|
Requires-Dist: python-dotenv>=1
|
|
36
36
|
Requires-Dist: xmltodict>=0.13
|
|
@@ -100,6 +100,7 @@ Python library that provides a robust and well-documented API that allows develo
|
|
|
100
100
|
| User & Weather status | ✅ | ✅ | ✅ | ✅ |
|
|
101
101
|
| Other APIs*** | ✅ | ✅ | ✅ | ✅ |
|
|
102
102
|
| Talk Bot API* | N/A | ✅ | ✅ | ✅ |
|
|
103
|
+
| Settings UI API* | N/A | N/A | N/A | ✅ |
|
|
103
104
|
| AI Providers API** | N/A | N/A | N/A | ✅ |
|
|
104
105
|
|
|
105
106
|
*_available only for **NextcloudApp**_<br>
|
|
@@ -132,16 +133,17 @@ from contextlib import asynccontextmanager
|
|
|
132
133
|
from fastapi import FastAPI
|
|
133
134
|
|
|
134
135
|
from nc_py_api import NextcloudApp
|
|
135
|
-
from nc_py_api.ex_app import LogLvl, run_app, set_handlers
|
|
136
|
+
from nc_py_api.ex_app import AppAPIAuthMiddleware, LogLvl, run_app, set_handlers
|
|
136
137
|
|
|
137
138
|
|
|
138
139
|
@asynccontextmanager
|
|
139
|
-
async def lifespan(
|
|
140
|
-
set_handlers(
|
|
140
|
+
async def lifespan(app: FastAPI):
|
|
141
|
+
set_handlers(app, enabled_handler)
|
|
141
142
|
yield
|
|
142
143
|
|
|
143
144
|
|
|
144
145
|
APP = FastAPI(lifespan=lifespan)
|
|
146
|
+
APP.add_middleware(AppAPIAuthMiddleware)
|
|
145
147
|
|
|
146
148
|
|
|
147
149
|
def enabled_handler(enabled: bool, nc: NextcloudApp) -> str:
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
nc_py_api/__init__.py,sha256=F-ZEHHtUIDe2Tb95wf9XE3KD0F76VxqtTgTBysV3SMc,428
|
|
2
|
+
nc_py_api/_deffered_error.py,sha256=BpEe_tBqflwfj2Zolb67nhW-K16XX-WbcY2IH_6u8fo,319
|
|
3
|
+
nc_py_api/_exceptions.py,sha256=7vbUECaLmD7RJBCU27t4fuP6NmQK6r4508u_gS4szhI,2298
|
|
4
|
+
nc_py_api/_misc.py,sha256=dUzCP9VmyhtICTsn1aexlFAYUioBm40k6Zh-YE5WwCY,3333
|
|
5
|
+
nc_py_api/_preferences.py,sha256=OtovFZuGHnHYKjdDjSnUappO795tW8Oxj7qVaejHWpQ,2479
|
|
6
|
+
nc_py_api/_preferences_ex.py,sha256=tThj6U0ZZMaBZ-jUkjrbaI0xDnafWsBowQKsC6gjOQs,7179
|
|
7
|
+
nc_py_api/_session.py,sha256=G8xFMMpiUlEShX5iWjUZvuU-TW-bQfxxycPkMbgXfCw,19761
|
|
8
|
+
nc_py_api/_talk_api.py,sha256=0Uo7OduYniuuX3UQPb468RyGJJ-PWBCgJ5HoPuz5Qa0,51068
|
|
9
|
+
nc_py_api/_theming.py,sha256=hTr3nuOemSuRFZaPy9iXNmBM7rDgQHECH43tHMWGqEY,1870
|
|
10
|
+
nc_py_api/_version.py,sha256=fYb2rgzhny-JgAlzv3sBUa6SNwUCpdYwegCFfTVj1hE,52
|
|
11
|
+
nc_py_api/activity.py,sha256=t9VDSnnaXRNOvALqOSGCeXSQZ-426pCOMSfQ96JHys4,9574
|
|
12
|
+
nc_py_api/apps.py,sha256=6vOFFs6vNHCCvZ_SwXxPq5-X1xfgyLjW8uZSfJKduC8,9774
|
|
13
|
+
nc_py_api/calendar.py,sha256=-T6CJ8cRbJZTLtxSEDWuuYpD29DMJGCTfLONmtxZV9w,1445
|
|
14
|
+
nc_py_api/nextcloud.py,sha256=8KeUDKeAsdLAU20T8O_SSjewPnI8MYLLnVUkA0QMttg,20520
|
|
15
|
+
nc_py_api/notes.py,sha256=ljO3TOe-Qg0bJ0mlFQwjg--Pxmj-XFknoLbcbJmII0A,15106
|
|
16
|
+
nc_py_api/notifications.py,sha256=WgzV21TuLOhLk-UEjhBSbMsIi2isa5MmAx6cbe0pc2Y,9187
|
|
17
|
+
nc_py_api/options.py,sha256=K5co-fIfFVbwF6r3sqWsJF3cKgAbS2CjLAXdyTOkP9s,1717
|
|
18
|
+
nc_py_api/talk.py,sha256=OZFemYkDOaM6o4xAK3EvQbjMFiK75E5qnsCDyihIElg,29368
|
|
19
|
+
nc_py_api/talk_bot.py,sha256=73V2UXQChqiEzC8JxhWgtKWVQ2YD9lxLRjQ5JJWQRRw,16562
|
|
20
|
+
nc_py_api/user_status.py,sha256=I101nwYS8X1WvC8AnLa2f3qJUCPDPHrbq-ke0h1VT4E,13282
|
|
21
|
+
nc_py_api/users.py,sha256=B6By-H9oUNvJj2omaRCMPIsQ17xeeDV_udn0VioRO7A,15488
|
|
22
|
+
nc_py_api/users_groups.py,sha256=IPxw-Ks5NjCm6r8_HC9xmf3IYptH00ulITbp5iazhAo,6289
|
|
23
|
+
nc_py_api/weather_status.py,sha256=wAkjuJPjxc0Rxe4za0BzfwB0XeUmkCXoisJtTH3-qdQ,7582
|
|
24
|
+
nc_py_api/ex_app/__init__.py,sha256=JNFZl1LRr8Qu7SqOK9W6CZw4Mf0ATFrRSo7HfVQBJQ0,470
|
|
25
|
+
nc_py_api/ex_app/defs.py,sha256=Suh_PpBlkQ8nbHne2-ypoEnl7Plsq39HPLI9Ns3NT2s,1267
|
|
26
|
+
nc_py_api/ex_app/integration_fastapi.py,sha256=lNxeMT6Jlhr8GEmP-4bu2tnjtyCD0J2MDYAcSER3tVM,10603
|
|
27
|
+
nc_py_api/ex_app/misc.py,sha256=6tPZuDVQa3lyXhK9M66M0dLNFQvrECRtXmULMjIa8-w,2098
|
|
28
|
+
nc_py_api/ex_app/persist_transformers_cache.py,sha256=ZoEBb1RnNaQrtxK_CjSZ8LZ36Oakz2Xciau_ZpNp8Ic,213
|
|
29
|
+
nc_py_api/ex_app/uvicorn_fastapi.py,sha256=WLtNmWXMBKN6CMip2uhKcgy4mC2Ch9AmNfwRScBUsP0,752
|
|
30
|
+
nc_py_api/ex_app/providers/__init__.py,sha256=jmUBdbAgzUCdYyHl8V5UCNYJI-FFpxPQQ4iEAoURKQs,43
|
|
31
|
+
nc_py_api/ex_app/providers/providers.py,sha256=jHDhxeQZdYh_ajN88rdNXYTMECCjx9YIt5I6_BlH9QQ,1548
|
|
32
|
+
nc_py_api/ex_app/providers/speech_to_text.py,sha256=JFD1ksdhXjpr5UFm5npqCxepqB5x-kdHG9CpPoGofx0,4959
|
|
33
|
+
nc_py_api/ex_app/providers/text_processing.py,sha256=VUZMZ2fof-c6JD7mTKHTZBWbDMOqxDllMCNQFOlHXXk,5265
|
|
34
|
+
nc_py_api/ex_app/providers/translations.py,sha256=io8UgVhdQXFmP7KnrJQx5Vtl8Dz0Z0EVZ0bt3hV7C7A,6112
|
|
35
|
+
nc_py_api/ex_app/ui/__init__.py,sha256=jUMU7_miFF-Q8BQNT90KZYQiLy_a3OvEyK6y8eRMKRk,38
|
|
36
|
+
nc_py_api/ex_app/ui/files_actions.py,sha256=bPohXjL-szrYQvI0JORLju3G6y8kTXZ0yzLD2g-dcyc,7465
|
|
37
|
+
nc_py_api/ex_app/ui/resources.py,sha256=Vwx69oZ93Ouh6HJtGUqaKFUr4Reo74H4vT1YCpb-7j0,12492
|
|
38
|
+
nc_py_api/ex_app/ui/settings.py,sha256=f0R17lGhBfo2JQULVw_hFxhpfoPw_CW7vBu0Rb1ABJw,6623
|
|
39
|
+
nc_py_api/ex_app/ui/top_menu.py,sha256=oCgGtIoMYbp-5iN5aXEbT7Q88HtccR7hg6IBFgbbyX4,5118
|
|
40
|
+
nc_py_api/ex_app/ui/ui.py,sha256=OqFHKn6oIZli8T1wnv6YtQ4glNfeNb90WwGCvtWI1Z4,1632
|
|
41
|
+
nc_py_api/files/__init__.py,sha256=jt29bbofuBN57_93se8OIitdP6S7L8SokYgqAbpzCt8,14583
|
|
42
|
+
nc_py_api/files/_files.py,sha256=XIAhjkDf92_FpPwsbA_X7_oh1_vZY2EZFefI5NjF-Wk,13180
|
|
43
|
+
nc_py_api/files/files.py,sha256=5UOo007q7MFt0unkifjEVn7JvLf8nBkT0eDvGU7ix7E,47805
|
|
44
|
+
nc_py_api/files/sharing.py,sha256=VRZCl-TYK6dbu9rUHPs3_jcVozu1EO8bLGZwoRpiLsU,14439
|
|
45
|
+
nc_py_api-0.11.0.dist-info/METADATA,sha256=24GFR6zNMKJUoe7qcJzrgglutujG5h2KXMrHGLr0E1I,8943
|
|
46
|
+
nc_py_api-0.11.0.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
|
|
47
|
+
nc_py_api-0.11.0.dist-info/licenses/AUTHORS,sha256=Y1omFHyI8ned9k4jJXs2ATgmgi1GmQ7EZ6S1gxqnX2k,572
|
|
48
|
+
nc_py_api-0.11.0.dist-info/licenses/LICENSE.txt,sha256=OLEMh401fAumGHfRSna365MLIfnjdTcdOHZ6QOzMjkg,1551
|
|
49
|
+
nc_py_api-0.11.0.dist-info/RECORD,,
|
nc_py_api-0.9.0.dist-info/RECORD
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
nc_py_api/__init__.py,sha256=IHPyeXjkOwX6cJlYGnyPpF9RR5E7E3LZ6lAuZ3J_L4M,418
|
|
2
|
-
nc_py_api/_deffered_error.py,sha256=BpEe_tBqflwfj2Zolb67nhW-K16XX-WbcY2IH_6u8fo,319
|
|
3
|
-
nc_py_api/_exceptions.py,sha256=7vbUECaLmD7RJBCU27t4fuP6NmQK6r4508u_gS4szhI,2298
|
|
4
|
-
nc_py_api/_misc.py,sha256=dUzCP9VmyhtICTsn1aexlFAYUioBm40k6Zh-YE5WwCY,3333
|
|
5
|
-
nc_py_api/_preferences.py,sha256=OtovFZuGHnHYKjdDjSnUappO795tW8Oxj7qVaejHWpQ,2479
|
|
6
|
-
nc_py_api/_preferences_ex.py,sha256=gW9bWVHayE6TifoA5hY_RWYUkdFgWrd0OabPvuNSAe0,7091
|
|
7
|
-
nc_py_api/_session.py,sha256=G8xFMMpiUlEShX5iWjUZvuU-TW-bQfxxycPkMbgXfCw,19761
|
|
8
|
-
nc_py_api/_talk_api.py,sha256=sIEBATbTVuLtLvcyOPwpUSURMyGl8ZpGB7hnEWKQbpM,51033
|
|
9
|
-
nc_py_api/_theming.py,sha256=hTr3nuOemSuRFZaPy9iXNmBM7rDgQHECH43tHMWGqEY,1870
|
|
10
|
-
nc_py_api/_version.py,sha256=E0M96T7WLWo45PguLM4xGRvb1eh6l3teRyjNgFMdKZw,51
|
|
11
|
-
nc_py_api/activity.py,sha256=t9VDSnnaXRNOvALqOSGCeXSQZ-426pCOMSfQ96JHys4,9574
|
|
12
|
-
nc_py_api/apps.py,sha256=6vOFFs6vNHCCvZ_SwXxPq5-X1xfgyLjW8uZSfJKduC8,9774
|
|
13
|
-
nc_py_api/calendar.py,sha256=-T6CJ8cRbJZTLtxSEDWuuYpD29DMJGCTfLONmtxZV9w,1445
|
|
14
|
-
nc_py_api/nextcloud.py,sha256=wW39a6GdfwlEJK2aM4vYLW6RdQgomz13HLBBMFu3GE8,22328
|
|
15
|
-
nc_py_api/notes.py,sha256=ljO3TOe-Qg0bJ0mlFQwjg--Pxmj-XFknoLbcbJmII0A,15106
|
|
16
|
-
nc_py_api/notifications.py,sha256=WgzV21TuLOhLk-UEjhBSbMsIi2isa5MmAx6cbe0pc2Y,9187
|
|
17
|
-
nc_py_api/options.py,sha256=K5co-fIfFVbwF6r3sqWsJF3cKgAbS2CjLAXdyTOkP9s,1717
|
|
18
|
-
nc_py_api/talk.py,sha256=OZFemYkDOaM6o4xAK3EvQbjMFiK75E5qnsCDyihIElg,29368
|
|
19
|
-
nc_py_api/talk_bot.py,sha256=73V2UXQChqiEzC8JxhWgtKWVQ2YD9lxLRjQ5JJWQRRw,16562
|
|
20
|
-
nc_py_api/user_status.py,sha256=AwixZTY_KBSbqTA-VLZs_auIs8hmi_wSrv-abf2lit8,13288
|
|
21
|
-
nc_py_api/users.py,sha256=B6By-H9oUNvJj2omaRCMPIsQ17xeeDV_udn0VioRO7A,15488
|
|
22
|
-
nc_py_api/users_groups.py,sha256=IPxw-Ks5NjCm6r8_HC9xmf3IYptH00ulITbp5iazhAo,6289
|
|
23
|
-
nc_py_api/weather_status.py,sha256=wAkjuJPjxc0Rxe4za0BzfwB0XeUmkCXoisJtTH3-qdQ,7582
|
|
24
|
-
nc_py_api/ex_app/__init__.py,sha256=yTUGL3SOAGlsE95P6IHuvt47s22Rh33Hnjk6gbX-HQ4,398
|
|
25
|
-
nc_py_api/ex_app/defs.py,sha256=CeUrY20Sf0zzhHrTVsfAvPn4N7PHwwPQh_4X49qAhHM,1352
|
|
26
|
-
nc_py_api/ex_app/integration_fastapi.py,sha256=u7j3cLKgMPvdDZnWertyvdFSAEL1lXRg_xSr5dj_Fag,8737
|
|
27
|
-
nc_py_api/ex_app/misc.py,sha256=6tPZuDVQa3lyXhK9M66M0dLNFQvrECRtXmULMjIa8-w,2098
|
|
28
|
-
nc_py_api/ex_app/persist_transformers_cache.py,sha256=ZoEBb1RnNaQrtxK_CjSZ8LZ36Oakz2Xciau_ZpNp8Ic,213
|
|
29
|
-
nc_py_api/ex_app/uvicorn_fastapi.py,sha256=WLtNmWXMBKN6CMip2uhKcgy4mC2Ch9AmNfwRScBUsP0,752
|
|
30
|
-
nc_py_api/ex_app/providers/__init__.py,sha256=jmUBdbAgzUCdYyHl8V5UCNYJI-FFpxPQQ4iEAoURKQs,43
|
|
31
|
-
nc_py_api/ex_app/providers/providers.py,sha256=jHDhxeQZdYh_ajN88rdNXYTMECCjx9YIt5I6_BlH9QQ,1548
|
|
32
|
-
nc_py_api/ex_app/providers/speech_to_text.py,sha256=J7aqYDwiEmGWiMM-LPwSI6N5KfcWeenyxmwMXiP_h4U,4897
|
|
33
|
-
nc_py_api/ex_app/providers/text_processing.py,sha256=nJQgdZ57461xkU5fzo4cYN1OXNDu0eH2iFjALx2wqbg,5204
|
|
34
|
-
nc_py_api/ex_app/providers/translations.py,sha256=0myOttPpMFH1LHTu2KJUOunRfA1JRIvpXxO0nPn8alw,5638
|
|
35
|
-
nc_py_api/ex_app/ui/__init__.py,sha256=jUMU7_miFF-Q8BQNT90KZYQiLy_a3OvEyK6y8eRMKRk,38
|
|
36
|
-
nc_py_api/ex_app/ui/files_actions.py,sha256=j2e8PXFoEmpFKF2z4YLChj0GN3S94lmwiddii1VmQKs,7412
|
|
37
|
-
nc_py_api/ex_app/ui/resources.py,sha256=Qgy3KB9n68EGGz8jRlHa2Y72WxXOdaqDy2iFbQ4pvhA,12457
|
|
38
|
-
nc_py_api/ex_app/ui/top_menu.py,sha256=6BvNtm03rF-fqmOiGM2mVrn0sJRLOWLfhrvzXj7ND7U,5076
|
|
39
|
-
nc_py_api/ex_app/ui/ui.py,sha256=dplr1ZIqjtHvOH3lIHBLWmP9vr-m7EIk_oJU5K62low,1284
|
|
40
|
-
nc_py_api/files/__init__.py,sha256=rtQTrWIMPjxMk8l7mrvyoBsg9ZHs_2S2woUwdfkJ-CY,12564
|
|
41
|
-
nc_py_api/files/_files.py,sha256=IJibj0_y3UQyyVhVI2RgQapPFPsOAV6tyH2sFlLy09I,12226
|
|
42
|
-
nc_py_api/files/files.py,sha256=298GqszMB1ya2CYPld9q6O2QhNGEIFAZShjQ_O84XZs,44904
|
|
43
|
-
nc_py_api/files/sharing.py,sha256=bZRSsFdlaXJKheXtyTjPJwpQSpYDnRcyDosMwrvRlRc,14395
|
|
44
|
-
nc_py_api-0.9.0.dist-info/METADATA,sha256=lYm6F-kvO11g_-fcE7iR--1dJiq-cVbXa97KA5RojrY,8791
|
|
45
|
-
nc_py_api-0.9.0.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
|
|
46
|
-
nc_py_api-0.9.0.dist-info/licenses/AUTHORS,sha256=Y1omFHyI8ned9k4jJXs2ATgmgi1GmQ7EZ6S1gxqnX2k,572
|
|
47
|
-
nc_py_api-0.9.0.dist-info/licenses/LICENSE.txt,sha256=OLEMh401fAumGHfRSna365MLIfnjdTcdOHZ6QOzMjkg,1551
|
|
48
|
-
nc_py_api-0.9.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|