nc-py-api 0.11.0__py3-none-any.whl → 0.18.1__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.
@@ -0,0 +1,153 @@
1
+ """Nextcloud API for registering OCC commands for ExApps."""
2
+
3
+ import dataclasses
4
+
5
+ from .._exceptions import NextcloudExceptionNotFound
6
+ from .._misc import clear_from_params_empty, require_capabilities
7
+ from .._session import AsyncNcSessionApp, NcSessionApp
8
+
9
+ _EP_SUFFIX: str = "occ_command"
10
+
11
+
12
+ @dataclasses.dataclass
13
+ class OccCommand:
14
+ """OccCommand description."""
15
+
16
+ def __init__(self, raw_data: dict):
17
+ self._raw_data = raw_data
18
+
19
+ @property
20
+ def name(self) -> str:
21
+ """Unique ID for the command."""
22
+ return self._raw_data["name"]
23
+
24
+ @property
25
+ def description(self) -> str:
26
+ """Command description."""
27
+ return self._raw_data["description"]
28
+
29
+ @property
30
+ def hidden(self) -> bool:
31
+ """Flag determining ss command hidden or not."""
32
+ return bool(self._raw_data["hidden"])
33
+
34
+ @property
35
+ def arguments(self) -> dict:
36
+ """Look at PHP Symfony framework for details."""
37
+ return self._raw_data["arguments"]
38
+
39
+ @property
40
+ def options(self) -> str:
41
+ """Look at PHP Symfony framework for details."""
42
+ return self._raw_data["options"]
43
+
44
+ @property
45
+ def usages(self) -> str:
46
+ """Look at PHP Symfony framework for details."""
47
+ return self._raw_data["usages"]
48
+
49
+ @property
50
+ def action_handler(self) -> str:
51
+ """Relative ExApp url which will be called by Nextcloud."""
52
+ return self._raw_data["execute_handler"]
53
+
54
+ def __repr__(self):
55
+ return f"<{self.__class__.__name__} name={self.name}, handler={self.action_handler}>"
56
+
57
+
58
+ class OccCommandsAPI:
59
+ """API for registering OCC commands, avalaible as **nc.occ_command.<method>**."""
60
+
61
+ def __init__(self, session: NcSessionApp):
62
+ self._session = session
63
+
64
+ def register(
65
+ self,
66
+ name: str,
67
+ callback_url: str,
68
+ arguments: list | None = None,
69
+ options: list | None = None,
70
+ usages: list | None = None,
71
+ description: str = "",
72
+ hidden: bool = False,
73
+ ) -> None:
74
+ """Registers or edit the OCC command."""
75
+ require_capabilities("app_api", self._session.capabilities)
76
+ params = {
77
+ "name": name,
78
+ "description": description,
79
+ "arguments": arguments,
80
+ "hidden": int(hidden),
81
+ "options": options,
82
+ "usages": usages,
83
+ "execute_handler": callback_url,
84
+ }
85
+ clear_from_params_empty(["arguments", "options", "usages"], params)
86
+ self._session.ocs("POST", f"{self._session.ae_url}/{_EP_SUFFIX}", json=params)
87
+
88
+ def unregister(self, name: str, not_fail=True) -> None:
89
+ """Removes the OCC command."""
90
+ require_capabilities("app_api", self._session.capabilities)
91
+ try:
92
+ self._session.ocs("DELETE", f"{self._session.ae_url}/{_EP_SUFFIX}", params={"name": name})
93
+ except NextcloudExceptionNotFound as e:
94
+ if not not_fail:
95
+ raise e from None
96
+
97
+ def get_entry(self, name: str) -> OccCommand | None:
98
+ """Get information of the OCC command."""
99
+ require_capabilities("app_api", self._session.capabilities)
100
+ try:
101
+ return OccCommand(self._session.ocs("GET", f"{self._session.ae_url}/{_EP_SUFFIX}", params={"name": name}))
102
+ except NextcloudExceptionNotFound:
103
+ return None
104
+
105
+
106
+ class AsyncOccCommandsAPI:
107
+ """Async API for registering OCC commands, avalaible as **nc.occ_command.<method>**."""
108
+
109
+ def __init__(self, session: AsyncNcSessionApp):
110
+ self._session = session
111
+
112
+ async def register(
113
+ self,
114
+ name: str,
115
+ callback_url: str,
116
+ arguments: list | None = None,
117
+ options: list | None = None,
118
+ usages: list | None = None,
119
+ description: str = "",
120
+ hidden: bool = False,
121
+ ) -> None:
122
+ """Registers or edit the OCC command."""
123
+ require_capabilities("app_api", await self._session.capabilities)
124
+ params = {
125
+ "name": name,
126
+ "description": description,
127
+ "arguments": arguments,
128
+ "hidden": int(hidden),
129
+ "options": options,
130
+ "usages": usages,
131
+ "execute_handler": callback_url,
132
+ }
133
+ clear_from_params_empty(["arguments", "options", "usages"], params)
134
+ await self._session.ocs("POST", f"{self._session.ae_url}/{_EP_SUFFIX}", json=params)
135
+
136
+ async def unregister(self, name: str, not_fail=True) -> None:
137
+ """Removes the OCC command."""
138
+ require_capabilities("app_api", await self._session.capabilities)
139
+ try:
140
+ await self._session.ocs("DELETE", f"{self._session.ae_url}/{_EP_SUFFIX}", params={"name": name})
141
+ except NextcloudExceptionNotFound as e:
142
+ if not not_fail:
143
+ raise e from None
144
+
145
+ async def get_entry(self, name: str) -> OccCommand | None:
146
+ """Get information of the OCC command."""
147
+ require_capabilities("app_api", await self._session.capabilities)
148
+ try:
149
+ return OccCommand(
150
+ await self._session.ocs("GET", f"{self._session.ae_url}/{_EP_SUFFIX}", params={"name": name})
151
+ )
152
+ except NextcloudExceptionNotFound:
153
+ return None
@@ -1,38 +1,24 @@
1
1
  """Nextcloud API for AI Providers."""
2
2
 
3
3
  from ..._session import AsyncNcSessionApp, NcSessionApp
4
- from .speech_to_text import _AsyncSpeechToTextProviderAPI, _SpeechToTextProviderAPI
5
- from .text_processing import _AsyncTextProcessingProviderAPI, _TextProcessingProviderAPI
6
- from .translations import _AsyncTranslationsProviderAPI, _TranslationsProviderAPI
4
+ from .task_processing import _AsyncTaskProcessingProviderAPI, _TaskProcessingProviderAPI
7
5
 
8
6
 
9
7
  class ProvidersApi:
10
8
  """Class that encapsulates all AI Providers functionality."""
11
9
 
12
- speech_to_text: _SpeechToTextProviderAPI
13
- """SpeechToText Provider API."""
14
- text_processing: _TextProcessingProviderAPI
15
- """TextProcessing Provider API."""
16
- translations: _TranslationsProviderAPI
17
- """Translations Provider API."""
10
+ task_processing: _TaskProcessingProviderAPI
11
+ """TaskProcessing Provider API."""
18
12
 
19
13
  def __init__(self, session: NcSessionApp):
20
- self.speech_to_text = _SpeechToTextProviderAPI(session)
21
- self.text_processing = _TextProcessingProviderAPI(session)
22
- self.translations = _TranslationsProviderAPI(session)
14
+ self.task_processing = _TaskProcessingProviderAPI(session)
23
15
 
24
16
 
25
17
  class AsyncProvidersApi:
26
18
  """Class that encapsulates all AI Providers functionality."""
27
19
 
28
- speech_to_text: _AsyncSpeechToTextProviderAPI
29
- """SpeechToText Provider API."""
30
- text_processing: _AsyncTextProcessingProviderAPI
31
- """TextProcessing Provider API."""
32
- translations: _AsyncTranslationsProviderAPI
33
- """Translations Provider API."""
20
+ task_processing: _AsyncTaskProcessingProviderAPI
21
+ """TaskProcessing Provider API."""
34
22
 
35
23
  def __init__(self, session: AsyncNcSessionApp):
36
- self.speech_to_text = _AsyncSpeechToTextProviderAPI(session)
37
- self.text_processing = _AsyncTextProcessingProviderAPI(session)
38
- self.translations = _AsyncTranslationsProviderAPI(session)
24
+ self.task_processing = _AsyncTaskProcessingProviderAPI(session)
@@ -0,0 +1,261 @@
1
+ """Nextcloud API for declaring TaskProcessing provider."""
2
+
3
+ import contextlib
4
+ import dataclasses
5
+ import typing
6
+ from enum import IntEnum
7
+
8
+ from pydantic import RootModel
9
+ from pydantic.dataclasses import dataclass
10
+
11
+ from ..._exceptions import NextcloudException, NextcloudExceptionNotFound
12
+ from ..._misc import require_capabilities
13
+ from ..._session import AsyncNcSessionApp, NcSessionApp
14
+
15
+ _EP_SUFFIX: str = "ai_provider/task_processing"
16
+
17
+
18
+ class ShapeType(IntEnum):
19
+ """Enum for shape types."""
20
+
21
+ NUMBER = 0
22
+ TEXT = 1
23
+ IMAGE = 2
24
+ AUDIO = 3
25
+ VIDEO = 4
26
+ FILE = 5
27
+ ENUM = 6
28
+ LIST_OF_NUMBERS = 10
29
+ LIST_OF_TEXTS = 11
30
+ LIST_OF_IMAGES = 12
31
+ LIST_OF_AUDIOS = 13
32
+ LIST_OF_VIDEOS = 14
33
+ LIST_OF_FILES = 15
34
+
35
+
36
+ @dataclass
37
+ class ShapeEnumValue:
38
+ """Data object for input output shape enum slot value."""
39
+
40
+ name: str
41
+ """Name of the enum slot value which will be displayed in the UI"""
42
+ value: str
43
+ """Value of the enum slot value"""
44
+
45
+
46
+ @dataclass
47
+ class ShapeDescriptor:
48
+ """Data object for input output shape entries."""
49
+
50
+ name: str
51
+ """Name of the shape entry"""
52
+ description: str
53
+ """Description of the shape entry"""
54
+ shape_type: ShapeType
55
+ """Type of the shape entry"""
56
+
57
+
58
+ @dataclass
59
+ class TaskType:
60
+ """TaskType description for the provider."""
61
+
62
+ id: str
63
+ """The unique ID for the task type."""
64
+ name: str
65
+ """The localized name of the task type."""
66
+ description: str
67
+ """The localized description of the task type."""
68
+ input_shape: list[ShapeDescriptor]
69
+ """The input shape of the task."""
70
+ output_shape: list[ShapeDescriptor]
71
+ """The output shape of the task."""
72
+
73
+
74
+ @dataclass
75
+ class TaskProcessingProvider:
76
+
77
+ id: str
78
+ """Unique ID for the provider."""
79
+ name: str
80
+ """The localized name of this provider"""
81
+ task_type: str
82
+ """The TaskType provided by this provider."""
83
+ expected_runtime: int = dataclasses.field(default=0)
84
+ """Expected runtime of the task in seconds."""
85
+ optional_input_shape: list[ShapeDescriptor] = dataclasses.field(default_factory=list)
86
+ """Optional input shape of the task."""
87
+ optional_output_shape: list[ShapeDescriptor] = dataclasses.field(default_factory=list)
88
+ """Optional output shape of the task."""
89
+ input_shape_enum_values: dict[str, list[ShapeEnumValue]] = dataclasses.field(default_factory=dict)
90
+ """The option dict for each input shape ENUM slot."""
91
+ input_shape_defaults: dict[str, str | int | float] = dataclasses.field(default_factory=dict)
92
+ """The default values for input shape slots."""
93
+ optional_input_shape_enum_values: dict[str, list[ShapeEnumValue]] = dataclasses.field(default_factory=dict)
94
+ """The option list for each optional input shape ENUM slot."""
95
+ optional_input_shape_defaults: dict[str, str | int | float] = dataclasses.field(default_factory=dict)
96
+ """The default values for optional input shape slots."""
97
+ output_shape_enum_values: dict[str, list[ShapeEnumValue]] = dataclasses.field(default_factory=dict)
98
+ """The option list for each output shape ENUM slot."""
99
+ optional_output_shape_enum_values: dict[str, list[ShapeEnumValue]] = dataclasses.field(default_factory=dict)
100
+ """The option list for each optional output shape ENUM slot."""
101
+
102
+ def __repr__(self):
103
+ return f"<{self.__class__.__name__} name={self.name}, type={self.task_type}>"
104
+
105
+
106
+ class _TaskProcessingProviderAPI:
107
+ """API for TaskProcessing providers, available as **nc.providers.task_processing.<method>**."""
108
+
109
+ def __init__(self, session: NcSessionApp):
110
+ self._session = session
111
+
112
+ def register(
113
+ self,
114
+ provider: TaskProcessingProvider,
115
+ custom_task_type: TaskType | None = None,
116
+ ) -> None:
117
+ """Registers or edit the TaskProcessing provider."""
118
+ require_capabilities("app_api", self._session.capabilities)
119
+ params = {
120
+ "provider": RootModel(provider).model_dump(),
121
+ **({"customTaskType": RootModel(custom_task_type).model_dump()} if custom_task_type else {}),
122
+ }
123
+ self._session.ocs("POST", f"{self._session.ae_url}/{_EP_SUFFIX}", json=params)
124
+
125
+ def unregister(self, name: str, not_fail=True) -> None:
126
+ """Removes TaskProcessing provider."""
127
+ require_capabilities("app_api", self._session.capabilities)
128
+ try:
129
+ self._session.ocs("DELETE", f"{self._session.ae_url}/{_EP_SUFFIX}", params={"name": name})
130
+ except NextcloudExceptionNotFound as e:
131
+ if not not_fail:
132
+ raise e from None
133
+
134
+ def next_task(self, provider_ids: list[str], task_types: list[str]) -> dict[str, typing.Any]:
135
+ """Get the next task processing task from Nextcloud."""
136
+ with contextlib.suppress(NextcloudException):
137
+ if r := self._session.ocs(
138
+ "GET",
139
+ "/ocs/v2.php/taskprocessing/tasks_provider/next",
140
+ json={"providerIds": provider_ids, "taskTypeIds": task_types},
141
+ ):
142
+ return r
143
+ return {}
144
+
145
+ def set_progress(self, task_id: int, progress: float) -> dict[str, typing.Any]:
146
+ """Report new progress value of the task to Nextcloud. Progress should be in range from 0.0 to 100.0."""
147
+ with contextlib.suppress(NextcloudException):
148
+ if r := self._session.ocs(
149
+ "POST",
150
+ f"/ocs/v2.php/taskprocessing/tasks_provider/{task_id}/progress",
151
+ json={"taskId": task_id, "progress": progress / 100.0},
152
+ ):
153
+ return r
154
+ return {}
155
+
156
+ def upload_result_file(self, task_id: int, file: bytes | str | typing.Any) -> int:
157
+ """Uploads file and returns fileID that should be used in the ``report_result`` function.
158
+
159
+ .. note:: ``file`` can be any file-like object.
160
+ """
161
+ return self._session.ocs(
162
+ "POST",
163
+ f"/ocs/v2.php/taskprocessing/tasks_provider/{task_id}/file",
164
+ files={"file": file},
165
+ )["fileId"]
166
+
167
+ def report_result(
168
+ self,
169
+ task_id: int,
170
+ output: dict[str, typing.Any] | None = None,
171
+ error_message: str | None = None,
172
+ ) -> dict[str, typing.Any]:
173
+ """Report result of the task processing to Nextcloud."""
174
+ with contextlib.suppress(NextcloudException):
175
+ if r := self._session.ocs(
176
+ "POST",
177
+ f"/ocs/v2.php/taskprocessing/tasks_provider/{task_id}/result",
178
+ json={"taskId": task_id, "output": output, "errorMessage": error_message},
179
+ ):
180
+ return r
181
+ return {}
182
+
183
+
184
+ class _AsyncTaskProcessingProviderAPI:
185
+ """Async API for TaskProcessing providers."""
186
+
187
+ def __init__(self, session: AsyncNcSessionApp):
188
+ self._session = session
189
+
190
+ async def register(
191
+ self,
192
+ provider: TaskProcessingProvider,
193
+ custom_task_type: TaskType | None = None,
194
+ ) -> None:
195
+ """Registers or edit the TaskProcessing provider."""
196
+ require_capabilities("app_api", await self._session.capabilities)
197
+ params = {
198
+ "provider": RootModel(provider).model_dump(),
199
+ **({"customTaskType": RootModel(custom_task_type).model_dump()} if custom_task_type else {}),
200
+ }
201
+ await self._session.ocs("POST", f"{self._session.ae_url}/{_EP_SUFFIX}", json=params)
202
+
203
+ async def unregister(self, name: str, not_fail=True) -> None:
204
+ """Removes TaskProcessing provider."""
205
+ require_capabilities("app_api", await self._session.capabilities)
206
+ try:
207
+ await self._session.ocs("DELETE", f"{self._session.ae_url}/{_EP_SUFFIX}", params={"name": name})
208
+ except NextcloudExceptionNotFound as e:
209
+ if not not_fail:
210
+ raise e from None
211
+
212
+ async def next_task(self, provider_ids: list[str], task_types: list[str]) -> dict[str, typing.Any]:
213
+ """Get the next task processing task from Nextcloud."""
214
+ with contextlib.suppress(NextcloudException):
215
+ if r := await self._session.ocs(
216
+ "GET",
217
+ "/ocs/v2.php/taskprocessing/tasks_provider/next",
218
+ json={"providerIds": provider_ids, "taskTypeIds": task_types},
219
+ ):
220
+ return r
221
+ return {}
222
+
223
+ async def set_progress(self, task_id: int, progress: float) -> dict[str, typing.Any]:
224
+ """Report new progress value of the task to Nextcloud. Progress should be in range from 0.0 to 100.0."""
225
+ with contextlib.suppress(NextcloudException):
226
+ if r := await self._session.ocs(
227
+ "POST",
228
+ f"/ocs/v2.php/taskprocessing/tasks_provider/{task_id}/progress",
229
+ json={"taskId": task_id, "progress": progress / 100.0},
230
+ ):
231
+ return r
232
+ return {}
233
+
234
+ async def upload_result_file(self, task_id: int, file: bytes | str | typing.Any) -> int:
235
+ """Uploads file and returns fileID that should be used in the ``report_result`` function.
236
+
237
+ .. note:: ``file`` can be any file-like object.
238
+ """
239
+ return (
240
+ await self._session.ocs(
241
+ "POST",
242
+ f"/ocs/v2.php/taskprocessing/tasks_provider/{task_id}/file",
243
+ files={"file": file},
244
+ )
245
+ )["fileId"]
246
+
247
+ async def report_result(
248
+ self,
249
+ task_id: int,
250
+ output: dict[str, typing.Any] | None = None,
251
+ error_message: str | None = None,
252
+ ) -> dict[str, typing.Any]:
253
+ """Report result of the task processing to Nextcloud."""
254
+ with contextlib.suppress(NextcloudException):
255
+ if r := await self._session.ocs(
256
+ "POST",
257
+ f"/ocs/v2.php/taskprocessing/tasks_provider/{task_id}/result",
258
+ json={"taskId": task_id, "output": output, "errorMessage": error_message},
259
+ ):
260
+ return r
261
+ return {}
@@ -1,15 +1,11 @@
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
4
+ import warnings
8
5
 
9
6
  from ..._exceptions import NextcloudExceptionNotFound
10
7
  from ..._misc import require_capabilities
11
8
  from ..._session import AsyncNcSessionApp, NcSessionApp
12
- from ...files import FsNode, permissions_to_str
13
9
 
14
10
 
15
11
  @dataclasses.dataclass
@@ -59,65 +55,15 @@ class UiFileActionEntry:
59
55
  """Relative ExApp url which will be called if user click on the entry."""
60
56
  return self._raw_data["action_handler"]
61
57
 
58
+ @property
59
+ def version(self) -> str:
60
+ """AppAPI `2.6.0` supports new version of UiActions(https://github.com/cloud-py-api/app_api/pull/284)."""
61
+ return self._raw_data.get("version", "1.0")
62
+
62
63
  def __repr__(self):
63
64
  return f"<{self.__class__.__name__} name={self.name}, mime={self.mime}, handler={self.action_handler}>"
64
65
 
65
66
 
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
67
  class _UiFilesActionsAPI:
122
68
  """API for the drop-down menu in Nextcloud **Files app**, avalaible as **nc.ui.files_dropdown_menu.<method>**."""
123
69
 
@@ -127,7 +73,12 @@ class _UiFilesActionsAPI:
127
73
  self._session = session
128
74
 
129
75
  def register(self, name: str, display_name: str, callback_url: str, **kwargs) -> None:
130
- """Registers the files a dropdown menu element."""
76
+ """Registers the files dropdown menu element."""
77
+ warnings.warn(
78
+ "register() is deprecated and will be removed in a future version. Use register_ex() instead.",
79
+ DeprecationWarning,
80
+ stacklevel=2,
81
+ )
131
82
  require_capabilities("app_api", self._session.capabilities)
132
83
  params = {
133
84
  "name": name,
@@ -140,6 +91,20 @@ class _UiFilesActionsAPI:
140
91
  }
141
92
  self._session.ocs("POST", f"{self._session.ae_url}/{self._ep_suffix}", json=params)
142
93
 
94
+ def register_ex(self, name: str, display_name: str, callback_url: str, **kwargs) -> None:
95
+ """Registers the files dropdown menu element(extended version that receives ``ActionFileInfoEx``)."""
96
+ require_capabilities("app_api", self._session.capabilities)
97
+ params = {
98
+ "name": name,
99
+ "displayName": display_name,
100
+ "actionHandler": callback_url,
101
+ "icon": kwargs.get("icon", ""),
102
+ "mime": kwargs.get("mime", "file"),
103
+ "permissions": kwargs.get("permissions", 31),
104
+ "order": kwargs.get("order", 0),
105
+ }
106
+ self._session.ocs("POST", f"{self._session.ae_url_v2}/{self._ep_suffix}", json=params)
107
+
143
108
  def unregister(self, name: str, not_fail=True) -> None:
144
109
  """Removes files dropdown menu element."""
145
110
  require_capabilities("app_api", self._session.capabilities)
@@ -170,6 +135,11 @@ class _AsyncUiFilesActionsAPI:
170
135
 
171
136
  async def register(self, name: str, display_name: str, callback_url: str, **kwargs) -> None:
172
137
  """Registers the files a dropdown menu element."""
138
+ warnings.warn(
139
+ "register() is deprecated and will be removed in a future version. Use register_ex() instead.",
140
+ DeprecationWarning,
141
+ stacklevel=2,
142
+ )
173
143
  require_capabilities("app_api", await self._session.capabilities)
174
144
  params = {
175
145
  "name": name,
@@ -182,6 +152,20 @@ class _AsyncUiFilesActionsAPI:
182
152
  }
183
153
  await self._session.ocs("POST", f"{self._session.ae_url}/{self._ep_suffix}", json=params)
184
154
 
155
+ async def register_ex(self, name: str, display_name: str, callback_url: str, **kwargs) -> None:
156
+ """Registers the files dropdown menu element(extended version that receives ``ActionFileInfoEx``)."""
157
+ require_capabilities("app_api", await self._session.capabilities)
158
+ params = {
159
+ "name": name,
160
+ "displayName": display_name,
161
+ "actionHandler": callback_url,
162
+ "icon": kwargs.get("icon", ""),
163
+ "mime": kwargs.get("mime", "file"),
164
+ "permissions": kwargs.get("permissions", 31),
165
+ "order": kwargs.get("order", 0),
166
+ }
167
+ await self._session.ocs("POST", f"{self._session.ae_url_v2}/{self._ep_suffix}", json=params)
168
+
185
169
  async def unregister(self, name: str, not_fail=True) -> None:
186
170
  """Removes files dropdown menu element."""
187
171
  require_capabilities("app_api", await self._session.capabilities)