nc-py-api 0.11.0__tar.gz → 0.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/CHANGELOG.md +14 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/PKG-INFO +2 -2
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/_session.py +4 -7
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/_version.py +1 -1
- nc_py_api-0.12.0/nc_py_api/ex_app/__init__.py +24 -0
- nc_py_api-0.12.0/nc_py_api/ex_app/defs.py +37 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/integration_fastapi.py +8 -7
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/misc.py +5 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/ui/files_actions.py +0 -60
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/files/__init__.py +58 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/files/files.py +2 -2
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/pyproject.toml +1 -1
- 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-0.12.0}/.gitignore +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/AUTHORS +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/LICENSE.txt +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/README.md +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/__init__.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/_deffered_error.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/_exceptions.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/_misc.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/_preferences.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/_preferences_ex.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/_talk_api.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/_theming.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/activity.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/apps.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/calendar.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/persist_transformers_cache.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/providers/__init__.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/providers/providers.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/providers/speech_to_text.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/providers/text_processing.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/providers/translations.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/ui/__init__.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/ui/resources.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/ui/settings.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/ui/top_menu.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/ui/ui.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/ex_app/uvicorn_fastapi.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/files/_files.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/files/sharing.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/nextcloud.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/notes.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/notifications.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/options.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/talk.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/talk_bot.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/user_status.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/users.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/users_groups.py +0 -0
- {nc_py_api-0.11.0 → nc_py_api-0.12.0}/nc_py_api/weather_status.py +0 -0
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.12.0 - 2024-04-02]
|
|
6
|
+
|
|
7
|
+
Update with new features only for `NextcloudApp` class. #233
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `ex_app.get_computation_device` function for retrieving GPU type(only with AppAPI `2.4.0`+).
|
|
12
|
+
- `ex_app.integration_fastapi.fetch_models_task` are now public function, added `progress_init_start_value` param.
|
|
13
|
+
- Global authentication when used now sets `request.scope["username"]` for easy use.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- `UiActionFileInfo` class marked as deprecated, instead `ActionFileInfo` class should be used.
|
|
18
|
+
|
|
5
19
|
## [0.11.0 - 2024-02-17]
|
|
6
20
|
|
|
7
21
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: nc-py-api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.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/
|
|
@@ -123,7 +123,7 @@ class AppConfig(BasicConfig):
|
|
|
123
123
|
super().__init__(**kwargs)
|
|
124
124
|
self.aa_version = self._get_config_value("aa_version", raise_not_found=False, **kwargs)
|
|
125
125
|
if not self.aa_version:
|
|
126
|
-
self.aa_version = "
|
|
126
|
+
self.aa_version = "2.2.0"
|
|
127
127
|
self.app_name = self._get_config_value("app_id", **kwargs)
|
|
128
128
|
self.app_version = self._get_config_value("app_version", **kwargs)
|
|
129
129
|
self.app_secret = self._get_config_value("app_secret", **kwargs)
|
|
@@ -459,7 +459,7 @@ class NcSessionAppBasic(ABC):
|
|
|
459
459
|
self.cfg = AppConfig(**kwargs)
|
|
460
460
|
super().__init__(**kwargs)
|
|
461
461
|
|
|
462
|
-
def sign_check(self, request: HTTPConnection) ->
|
|
462
|
+
def sign_check(self, request: HTTPConnection) -> str:
|
|
463
463
|
headers = {
|
|
464
464
|
"AA-VERSION": request.headers.get("AA-VERSION", ""),
|
|
465
465
|
"EX-APP-ID": request.headers.get("EX-APP-ID", ""),
|
|
@@ -474,13 +474,10 @@ class NcSessionAppBasic(ABC):
|
|
|
474
474
|
if headers["EX-APP-ID"] != self.cfg.app_name:
|
|
475
475
|
raise ValueError(f"Invalid EX-APP-ID:{headers['EX-APP-ID']} != {self.cfg.app_name}")
|
|
476
476
|
|
|
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]
|
|
477
|
+
username, app_secret = get_username_secret_from_headers(headers)
|
|
482
478
|
if app_secret != self.cfg.app_secret:
|
|
483
479
|
raise ValueError(f"Invalid App secret:{app_secret} != {self.cfg.app_secret}")
|
|
480
|
+
return username
|
|
484
481
|
|
|
485
482
|
|
|
486
483
|
class NcSessionApp(NcSessionAppBasic, NcSessionBasic):
|
|
@@ -0,0 +1,24 @@
|
|
|
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 .misc import (
|
|
14
|
+
get_computation_device,
|
|
15
|
+
get_model_path,
|
|
16
|
+
persistent_storage,
|
|
17
|
+
verify_version,
|
|
18
|
+
)
|
|
19
|
+
from .ui.settings import SettingsField, SettingsFieldType, SettingsForm
|
|
20
|
+
from .uvicorn_fastapi import run_app
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class UiActionFileInfo(ActionFileInfo):
|
|
24
|
+
"""``Deprecated``: use :py:class:`~nc_py_api.ex_app.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
|
|
@@ -103,7 +103,7 @@ def set_handlers(
|
|
|
103
103
|
|
|
104
104
|
@fast_api_app.post("/init")
|
|
105
105
|
async def init_callback(b_tasks: BackgroundTasks, nc: typing.Annotated[NextcloudApp, Depends(nc_app)]):
|
|
106
|
-
b_tasks.add_task(
|
|
106
|
+
b_tasks.add_task(fetch_models_task, nc, models_to_fetch if models_to_fetch else {}, 0)
|
|
107
107
|
return JSONResponse(content={})
|
|
108
108
|
|
|
109
109
|
if map_app_static:
|
|
@@ -120,10 +120,11 @@ def __map_app_static_folders(fast_api_app: FastAPI):
|
|
|
120
120
|
fast_api_app.mount(f"/{mnt_dir}", staticfiles.StaticFiles(directory=mnt_dir_path), name=mnt_dir)
|
|
121
121
|
|
|
122
122
|
|
|
123
|
-
def
|
|
123
|
+
def fetch_models_task(nc: NextcloudApp, models: dict[str, dict], progress_init_start_value: int) -> None:
|
|
124
|
+
"""Use for cases when you want to define custom `/init` but still need to easy download models."""
|
|
124
125
|
if models:
|
|
125
|
-
current_progress =
|
|
126
|
-
percent_for_each = min(int(100 / len(models)), 99)
|
|
126
|
+
current_progress = progress_init_start_value
|
|
127
|
+
percent_for_each = min(int((100 - progress_init_start_value) / len(models)), 99)
|
|
127
128
|
for model in models:
|
|
128
129
|
if model.startswith(("http://", "https://")):
|
|
129
130
|
__fetch_model_as_file(current_progress, percent_for_each, nc, model, models[model])
|
|
@@ -206,9 +207,9 @@ def __request_sign_check_if_needed(request: HTTPConnection, nextcloud_app: Nextc
|
|
|
206
207
|
_request_sign_check(request, nextcloud_app)
|
|
207
208
|
|
|
208
209
|
|
|
209
|
-
def _request_sign_check(request: HTTPConnection, nextcloud_app: NextcloudApp | AsyncNextcloudApp) ->
|
|
210
|
+
def _request_sign_check(request: HTTPConnection, nextcloud_app: NextcloudApp | AsyncNextcloudApp) -> str:
|
|
210
211
|
try:
|
|
211
|
-
nextcloud_app._session.sign_check(request) # noqa pylint: disable=protected-access
|
|
212
|
+
return nextcloud_app._session.sign_check(request) # noqa pylint: disable=protected-access
|
|
212
213
|
except ValueError as e:
|
|
213
214
|
print(e)
|
|
214
215
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED) from None
|
|
@@ -238,7 +239,7 @@ class AppAPIAuthMiddleware:
|
|
|
238
239
|
url_path = conn.url.path.lstrip("/")
|
|
239
240
|
if not fnmatch.filter(self._disable_for, url_path):
|
|
240
241
|
try:
|
|
241
|
-
_request_sign_check(conn, AsyncNextcloudApp())
|
|
242
|
+
scope["username"] = _request_sign_check(conn, AsyncNextcloudApp())
|
|
242
243
|
except HTTPException as exc:
|
|
243
244
|
response = self._on_error(exc.status_code, exc.detail)
|
|
244
245
|
await response(scope, receive, send)
|
|
@@ -50,3 +50,8 @@ def get_model_path(model_name: str) -> str:
|
|
|
50
50
|
from huggingface_hub import snapshot_download # noqa isort:skip pylint: disable=C0415 disable=E0401
|
|
51
51
|
|
|
52
52
|
return snapshot_download(model_name, local_files_only=True, cache_dir=persistent_storage())
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_computation_device() -> str:
|
|
56
|
+
"""Returns computation device(`ROCM` or `CUDA`) if it is defined in the environment variable."""
|
|
57
|
+
return os.environ.get("COMPUTE_DEVICE", "")
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
"""Nextcloud API for working with drop-down file's menu."""
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
|
-
import datetime
|
|
5
|
-
import os
|
|
6
|
-
|
|
7
|
-
from pydantic import BaseModel
|
|
8
4
|
|
|
9
5
|
from ..._exceptions import NextcloudExceptionNotFound
|
|
10
6
|
from ..._misc import require_capabilities
|
|
11
7
|
from ..._session import AsyncNcSessionApp, NcSessionApp
|
|
12
|
-
from ...files import FsNode, permissions_to_str
|
|
13
8
|
|
|
14
9
|
|
|
15
10
|
@dataclasses.dataclass
|
|
@@ -63,61 +58,6 @@ class UiFileActionEntry:
|
|
|
63
58
|
return f"<{self.__class__.__name__} name={self.name}, mime={self.mime}, handler={self.action_handler}>"
|
|
64
59
|
|
|
65
60
|
|
|
66
|
-
class UiActionFileInfo(BaseModel):
|
|
67
|
-
"""File Information Nextcloud sends to the External Application."""
|
|
68
|
-
|
|
69
|
-
fileId: int
|
|
70
|
-
"""FileID without Nextcloud instance ID"""
|
|
71
|
-
name: str
|
|
72
|
-
"""Name of the file/directory"""
|
|
73
|
-
directory: str
|
|
74
|
-
"""Directory relative to the user's home directory"""
|
|
75
|
-
etag: str
|
|
76
|
-
mime: str
|
|
77
|
-
fileType: str
|
|
78
|
-
"""**file** or **dir**"""
|
|
79
|
-
size: int
|
|
80
|
-
"""size of file/directory"""
|
|
81
|
-
favorite: str
|
|
82
|
-
"""**true** or **false**"""
|
|
83
|
-
permissions: int
|
|
84
|
-
"""Combination of :py:class:`~nc_py_api.files.FilePermissions` values"""
|
|
85
|
-
mtime: int
|
|
86
|
-
"""Last modified time"""
|
|
87
|
-
userId: str
|
|
88
|
-
"""The ID of the user performing the action."""
|
|
89
|
-
shareOwner: str | None
|
|
90
|
-
"""If the object is shared, this is a display name of the share owner."""
|
|
91
|
-
shareOwnerId: str | None
|
|
92
|
-
"""If the object is shared, this is the owner ID of the share."""
|
|
93
|
-
instanceId: str | None
|
|
94
|
-
"""Nextcloud instance ID."""
|
|
95
|
-
|
|
96
|
-
def to_fs_node(self) -> FsNode:
|
|
97
|
-
"""Returns usual :py:class:`~nc_py_api.files.FsNode` created from this class."""
|
|
98
|
-
user_path = os.path.join(self.directory, self.name).rstrip("/")
|
|
99
|
-
is_dir = bool(self.fileType.lower() == "dir")
|
|
100
|
-
if is_dir:
|
|
101
|
-
user_path += "/"
|
|
102
|
-
full_path = os.path.join(f"files/{self.userId}", user_path.lstrip("/"))
|
|
103
|
-
file_id = str(self.fileId).rjust(8, "0")
|
|
104
|
-
|
|
105
|
-
permissions = "S" if self.shareOwnerId else ""
|
|
106
|
-
permissions += permissions_to_str(self.permissions, is_dir)
|
|
107
|
-
return FsNode(
|
|
108
|
-
full_path,
|
|
109
|
-
etag=self.etag,
|
|
110
|
-
size=self.size,
|
|
111
|
-
content_length=0 if is_dir else self.size,
|
|
112
|
-
permissions=permissions,
|
|
113
|
-
favorite=bool(self.favorite.lower() == "true"),
|
|
114
|
-
file_id=file_id + self.instanceId if self.instanceId else file_id,
|
|
115
|
-
fileid=self.fileId,
|
|
116
|
-
last_modified=datetime.datetime.utcfromtimestamp(self.mtime).replace(tzinfo=datetime.timezone.utc),
|
|
117
|
-
mimetype=self.mime,
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
|
|
121
61
|
class _UiFilesActionsAPI:
|
|
122
62
|
"""API for the drop-down menu in Nextcloud **Files app**, avalaible as **nc.ui.files_dropdown_menu.<method>**."""
|
|
123
63
|
|
|
@@ -4,8 +4,11 @@ import dataclasses
|
|
|
4
4
|
import datetime
|
|
5
5
|
import email.utils
|
|
6
6
|
import enum
|
|
7
|
+
import os
|
|
7
8
|
import warnings
|
|
8
9
|
|
|
10
|
+
from pydantic import BaseModel
|
|
11
|
+
|
|
9
12
|
from .. import _misc
|
|
10
13
|
|
|
11
14
|
|
|
@@ -461,3 +464,58 @@ class Share:
|
|
|
461
464
|
f"{self.share_type.name}: `{self.path}` with id={self.share_id}"
|
|
462
465
|
f" from {self.share_owner} to {self.share_with}"
|
|
463
466
|
)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
class ActionFileInfo(BaseModel):
|
|
470
|
+
"""Information Nextcloud sends to the External Application about File Nodes affected in action."""
|
|
471
|
+
|
|
472
|
+
fileId: int
|
|
473
|
+
"""FileID without Nextcloud instance ID"""
|
|
474
|
+
name: str
|
|
475
|
+
"""Name of the file/directory"""
|
|
476
|
+
directory: str
|
|
477
|
+
"""Directory relative to the user's home directory"""
|
|
478
|
+
etag: str
|
|
479
|
+
mime: str
|
|
480
|
+
fileType: str
|
|
481
|
+
"""**file** or **dir**"""
|
|
482
|
+
size: int
|
|
483
|
+
"""size of file/directory"""
|
|
484
|
+
favorite: str
|
|
485
|
+
"""**true** or **false**"""
|
|
486
|
+
permissions: int
|
|
487
|
+
"""Combination of :py:class:`~nc_py_api.files.FilePermissions` values"""
|
|
488
|
+
mtime: int
|
|
489
|
+
"""Last modified time"""
|
|
490
|
+
userId: str
|
|
491
|
+
"""The ID of the user performing the action."""
|
|
492
|
+
shareOwner: str | None = None
|
|
493
|
+
"""If the object is shared, this is a display name of the share owner."""
|
|
494
|
+
shareOwnerId: str | None = None
|
|
495
|
+
"""If the object is shared, this is the owner ID of the share."""
|
|
496
|
+
instanceId: str | None = None
|
|
497
|
+
"""Nextcloud instance ID."""
|
|
498
|
+
|
|
499
|
+
def to_fs_node(self) -> FsNode:
|
|
500
|
+
"""Returns usual :py:class:`~nc_py_api.files.FsNode` created from this class."""
|
|
501
|
+
user_path = os.path.join(self.directory, self.name).rstrip("/")
|
|
502
|
+
is_dir = bool(self.fileType.lower() == "dir")
|
|
503
|
+
if is_dir:
|
|
504
|
+
user_path += "/"
|
|
505
|
+
full_path = os.path.join(f"files/{self.userId}", user_path.lstrip("/"))
|
|
506
|
+
file_id = str(self.fileId).rjust(8, "0")
|
|
507
|
+
|
|
508
|
+
permissions = "S" if self.shareOwnerId else ""
|
|
509
|
+
permissions += permissions_to_str(self.permissions, is_dir)
|
|
510
|
+
return FsNode(
|
|
511
|
+
full_path,
|
|
512
|
+
etag=self.etag,
|
|
513
|
+
size=self.size,
|
|
514
|
+
content_length=0 if is_dir else self.size,
|
|
515
|
+
permissions=permissions,
|
|
516
|
+
favorite=bool(self.favorite.lower() == "true"),
|
|
517
|
+
file_id=file_id + self.instanceId if self.instanceId else file_id,
|
|
518
|
+
fileid=self.fileId,
|
|
519
|
+
last_modified=datetime.datetime.utcfromtimestamp(self.mtime).replace(tzinfo=datetime.timezone.utc),
|
|
520
|
+
mimetype=self.mime,
|
|
521
|
+
)
|
|
@@ -333,7 +333,7 @@ class FilesAPI:
|
|
|
333
333
|
headers = Headers({"Destination": dest}, encoding="utf-8")
|
|
334
334
|
response = self._session.adapter_dav.request(
|
|
335
335
|
"MOVE",
|
|
336
|
-
f"/versions/{self._session.user}/{file_object.user_path}",
|
|
336
|
+
quote(f"/versions/{self._session.user}/{file_object.user_path}"),
|
|
337
337
|
headers=headers,
|
|
338
338
|
)
|
|
339
339
|
check_error(response, f"restore_version: user={self._session.user}, src={file_object.user_path}")
|
|
@@ -813,7 +813,7 @@ class AsyncFilesAPI:
|
|
|
813
813
|
headers = Headers({"Destination": dest}, encoding="utf-8")
|
|
814
814
|
response = await self._session.adapter_dav.request(
|
|
815
815
|
"MOVE",
|
|
816
|
-
f"/versions/{await self._session.user}/{file_object.user_path}",
|
|
816
|
+
quote(f"/versions/{await self._session.user}/{file_object.user_path}"),
|
|
817
817
|
headers=headers,
|
|
818
818
|
)
|
|
819
819
|
check_error(response, f"restore_version: user={await self._session.user}, src={file_object.user_path}")
|
|
@@ -118,7 +118,7 @@ lint.extend-ignore = ["D107", "D105", "D203", "D213", "D401", "I001", "RUF100"]
|
|
|
118
118
|
"nc_py_api/ex_app/__init__.py" = ["F401"]
|
|
119
119
|
|
|
120
120
|
[tool.ruff.lint.extend-per-file-ignores]
|
|
121
|
-
"benchmarks/**/*.py" = ["D", "SIM"]
|
|
121
|
+
"benchmarks/**/*.py" = ["D", "SIM", "S311"]
|
|
122
122
|
"docs/**/*.py" = ["D"]
|
|
123
123
|
"examples/**/*.py" = ["D", "S106", "S311"]
|
|
124
124
|
"tests/**/*.py" = ["D", "E402", "S", "UP"]
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"""All possible ExApp stuff for NextcloudApp that can be used."""
|
|
2
|
-
|
|
3
|
-
from .defs import ApiScope, LogLvl
|
|
4
|
-
from .integration_fastapi import (
|
|
5
|
-
AppAPIAuthMiddleware,
|
|
6
|
-
anc_app,
|
|
7
|
-
atalk_bot_msg,
|
|
8
|
-
nc_app,
|
|
9
|
-
set_handlers,
|
|
10
|
-
talk_bot_msg,
|
|
11
|
-
)
|
|
12
|
-
from .misc import get_model_path, persistent_storage, verify_version
|
|
13
|
-
from .ui.files_actions import UiActionFileInfo
|
|
14
|
-
from .ui.settings import SettingsField, SettingsFieldType, SettingsForm
|
|
15
|
-
from .uvicorn_fastapi import run_app
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
"""Additional definitions for NextcloudApp."""
|
|
2
|
-
|
|
3
|
-
import enum
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class LogLvl(enum.IntEnum):
|
|
7
|
-
"""Log levels."""
|
|
8
|
-
|
|
9
|
-
DEBUG = 0
|
|
10
|
-
"""Debug log level"""
|
|
11
|
-
INFO = 1
|
|
12
|
-
"""Informational log level"""
|
|
13
|
-
WARNING = 2
|
|
14
|
-
"""Warning log level. ``Default``"""
|
|
15
|
-
ERROR = 3
|
|
16
|
-
"""Error log level"""
|
|
17
|
-
FATAL = 4
|
|
18
|
-
"""Fatal log level"""
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class ApiScope(enum.IntEnum):
|
|
22
|
-
"""Defined API scopes."""
|
|
23
|
-
|
|
24
|
-
SYSTEM = 2
|
|
25
|
-
"""Allows access to the System APIs."""
|
|
26
|
-
FILES = 10
|
|
27
|
-
"""Allows access to the Nextcloud file base."""
|
|
28
|
-
FILES_SHARING = 11
|
|
29
|
-
"""Allows access to APIs that provide File Sharing."""
|
|
30
|
-
USER_INFO = 30
|
|
31
|
-
"""Allows access to APIs that work with users."""
|
|
32
|
-
USER_STATUS = 31
|
|
33
|
-
"""Allows access to APIs that work with users statuses."""
|
|
34
|
-
NOTIFICATIONS = 32
|
|
35
|
-
"""Allows access to APIs that provide Notifications."""
|
|
36
|
-
WEATHER_STATUS = 33
|
|
37
|
-
"""Allows access to APIs that provide Weather status."""
|
|
38
|
-
TALK = 50
|
|
39
|
-
"""Allows access to Talk API endpoints."""
|
|
40
|
-
TALK_BOT = 60
|
|
41
|
-
"""Allows to register Talk Bots."""
|
|
42
|
-
AI_PROVIDERS = 61
|
|
43
|
-
"""Allows to register AI providers."""
|
|
44
|
-
ACTIVITIES = 110
|
|
45
|
-
"""Activity App endpoints."""
|
|
46
|
-
NOTES = 120
|
|
47
|
-
"""Notes App endpoints."""
|
|
48
|
-
ALL = 9999
|
|
49
|
-
"""All endpoints allowed."""
|
|
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
|