pypaperless 2.2.0__tar.gz → 2.3.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.
- {pypaperless-2.2.0/pypaperless.egg-info → pypaperless-2.3.0}/PKG-INFO +9 -5
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/__init__.py +132 -34
- pypaperless-2.3.0/pypaperless/const.py +65 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/controllers/__init__.py +6 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/controllers/default.py +36 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/controllers/documents.py +6 -22
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/controllers/tasks.py +5 -3
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/errors.py +4 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/models/__init__.py +15 -7
- pypaperless-2.3.0/pypaperless/models/base.py +9 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/models/custom_fields.py +20 -1
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/models/documents.py +2 -1
- pypaperless-2.2.0/pypaperless/models/mail_rules.py → pypaperless-2.3.0/pypaperless/models/mails.py +18 -1
- pypaperless-2.3.0/pypaperless/models/matching.py +137 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/models/share_links.py +16 -3
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/models/tasks.py +15 -1
- pypaperless-2.3.0/pypaperless/models/workflows.py +130 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/util.py +21 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0/pypaperless.egg-info}/PKG-INFO +9 -5
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless.egg-info/SOURCES.txt +11 -9
- pypaperless-2.3.0/pypaperless.egg-info/requires.txt +17 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pyproject.toml +9 -5
- pypaperless-2.3.0/tests/test_paperless_0_0_0.py +754 -0
- pypaperless-2.3.0/tests/test_paperless_1_17_0.py +88 -0
- pypaperless-2.3.0/tests/test_paperless_1_8_0.py +124 -0
- pypaperless-2.3.0/tests/test_paperless_2_0_0.py +268 -0
- pypaperless-2.3.0/tests/test_paperless_2_3_0.py +206 -0
- pypaperless-2.3.0/tests/test_paperless_common.py +209 -0
- pypaperless-2.2.0/pypaperless/models/base.py +0 -34
- pypaperless-2.2.0/pypaperless/models/consumption_templates.py +0 -30
- pypaperless-2.2.0/pypaperless/models/correspondents.py +0 -27
- pypaperless-2.2.0/pypaperless/models/document_types.py +0 -25
- pypaperless-2.2.0/pypaperless/models/mail_accounts.py +0 -22
- pypaperless-2.2.0/pypaperless/models/shared.py +0 -106
- pypaperless-2.2.0/pypaperless/models/storage_paths.py +0 -27
- pypaperless-2.2.0/pypaperless/models/tags.py +0 -33
- pypaperless-2.2.0/pypaperless.egg-info/requires.txt +0 -13
- {pypaperless-2.2.0 → pypaperless-2.3.0}/LICENSE +0 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/MANIFEST.in +0 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/README.md +0 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/controllers/base.py +0 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/models/groups.py +0 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/models/saved_views.py +0 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless/models/users.py +0 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless.egg-info/dependency_links.txt +0 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless.egg-info/not-zip-safe +0 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/pypaperless.egg-info/top_level.txt +0 -0
- {pypaperless-2.2.0 → pypaperless-2.3.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pypaperless
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Little api wrapper for the paperless(-ngx) dms.
|
|
5
5
|
Author-email: Tobias Schulz <public.dev@tbsch.de>
|
|
6
6
|
License: MIT License
|
|
@@ -19,18 +19,22 @@ Classifier: Programming Language :: Python :: 3
|
|
|
19
19
|
Requires-Python: >=3.11
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: aiohttp
|
|
22
|
+
Requires-Dist: aiohttp==3.9.1
|
|
23
|
+
Requires-Dist: awesomeversion==23.11.0
|
|
24
|
+
Requires-Dist: yarl==1.9.4
|
|
23
25
|
Provides-Extra: test
|
|
24
26
|
Requires-Dist: black==23.12.1; extra == "test"
|
|
25
27
|
Requires-Dist: codespell==2.2.6; extra == "test"
|
|
26
28
|
Requires-Dist: mypy==1.8.0; extra == "test"
|
|
27
|
-
Requires-Dist: ruff==0.1.
|
|
28
|
-
Requires-Dist: pytest==7.4.
|
|
29
|
-
Requires-Dist: pytest-asyncio==0.23.
|
|
29
|
+
Requires-Dist: ruff==0.1.11; extra == "test"
|
|
30
|
+
Requires-Dist: pytest==7.4.4; extra == "test"
|
|
31
|
+
Requires-Dist: pytest-asyncio==0.23.3; extra == "test"
|
|
30
32
|
Requires-Dist: pytest-aiohttp==1.0.5; extra == "test"
|
|
31
33
|
Requires-Dist: pytest-cov==4.1.0; extra == "test"
|
|
32
34
|
Requires-Dist: pre-commit==3.6.0; extra == "test"
|
|
33
35
|
Requires-Dist: pylint==3.0.3; extra == "test"
|
|
36
|
+
Requires-Dist: fastapi==0.108.0; extra == "test"
|
|
37
|
+
Requires-Dist: httpx==0.26.0; extra == "test"
|
|
34
38
|
|
|
35
39
|
# PyPaperless
|
|
36
40
|
|
|
@@ -6,7 +6,17 @@ from contextlib import asynccontextmanager
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
import aiohttp
|
|
9
|
-
|
|
9
|
+
from awesomeversion import AwesomeVersion
|
|
10
|
+
from yarl import URL
|
|
11
|
+
|
|
12
|
+
from .const import (
|
|
13
|
+
PAPERLESS_V1_8_0,
|
|
14
|
+
PAPERLESS_V1_17_0,
|
|
15
|
+
PAPERLESS_V2_0_0,
|
|
16
|
+
PAPERLESS_V2_3_0,
|
|
17
|
+
ControllerPath,
|
|
18
|
+
PaperlessFeature,
|
|
19
|
+
)
|
|
10
20
|
from .controllers import (
|
|
11
21
|
ConsumptionTemplatesController,
|
|
12
22
|
CorrespondentsController,
|
|
@@ -22,17 +32,20 @@ from .controllers import (
|
|
|
22
32
|
TagsController,
|
|
23
33
|
TasksController,
|
|
24
34
|
UsersController,
|
|
35
|
+
WorkflowActionsController,
|
|
36
|
+
WorkflowsController,
|
|
37
|
+
WorkflowTriggersController,
|
|
25
38
|
)
|
|
26
|
-
from .errors import BadRequestException, DataNotExpectedException
|
|
27
|
-
from .
|
|
39
|
+
from .errors import BadRequestException, ControllerConfusion, DataNotExpectedException
|
|
40
|
+
from .util import create_url_from_input
|
|
28
41
|
|
|
29
42
|
|
|
30
|
-
class Paperless: # pylint: disable=too-many-instance-attributes
|
|
43
|
+
class Paperless: # pylint: disable=too-many-instance-attributes,too-many-public-methods
|
|
31
44
|
"""Retrieves and manipulates data from and to paperless via REST."""
|
|
32
45
|
|
|
33
46
|
def __init__(
|
|
34
47
|
self,
|
|
35
|
-
|
|
48
|
+
url: str | URL,
|
|
36
49
|
token: str,
|
|
37
50
|
request_opts: dict[str, Any] | None = None,
|
|
38
51
|
session: aiohttp.ClientSession | None = None,
|
|
@@ -41,18 +54,19 @@ class Paperless: # pylint: disable=too-many-instance-attributes
|
|
|
41
54
|
Initialize the Paperless api instance.
|
|
42
55
|
|
|
43
56
|
Parameters:
|
|
44
|
-
* host: the hostname or IP-address of Paperless as string.
|
|
57
|
+
* host: the hostname or IP-address of Paperless as string, or yarl.URL object.
|
|
45
58
|
* token: provide an api token created in Paperless Django settings.
|
|
46
59
|
* session: provide an existing aiohttp ClientSession.
|
|
47
60
|
"""
|
|
48
|
-
self.
|
|
61
|
+
self._url = create_url_from_input(url)
|
|
49
62
|
self._token = token
|
|
50
63
|
self._request_opts = request_opts
|
|
51
64
|
self._session = session
|
|
52
65
|
self._initialized = False
|
|
53
|
-
self.logger = logging.getLogger(f"{__package__}[{host}]")
|
|
66
|
+
self.logger = logging.getLogger(f"{__package__}[{self._url.host}]")
|
|
54
67
|
|
|
55
|
-
|
|
68
|
+
self.features: PaperlessFeature = PaperlessFeature(0)
|
|
69
|
+
# api controllers
|
|
56
70
|
self._consumption_templates: ConsumptionTemplatesController | None = None
|
|
57
71
|
self._correspondents: CorrespondentsController | None = None
|
|
58
72
|
self._custom_fields: CustomFieldsController | None = None
|
|
@@ -67,11 +81,14 @@ class Paperless: # pylint: disable=too-many-instance-attributes
|
|
|
67
81
|
self._tags: TagsController | None = None
|
|
68
82
|
self._tasks: TasksController | None = None
|
|
69
83
|
self._users: UsersController | None = None
|
|
84
|
+
self._workflows: WorkflowsController | None = None
|
|
85
|
+
self._workflow_actions: WorkflowActionsController | None = None
|
|
86
|
+
self._workflow_triggers: WorkflowTriggersController | None = None
|
|
70
87
|
|
|
71
88
|
@property
|
|
72
|
-
def
|
|
73
|
-
"""Return the
|
|
74
|
-
return self.
|
|
89
|
+
def url(self) -> URL:
|
|
90
|
+
"""Return the url of Paperless."""
|
|
91
|
+
return self._url
|
|
75
92
|
|
|
76
93
|
@property
|
|
77
94
|
def is_initialized(self) -> bool:
|
|
@@ -148,33 +165,95 @@ class Paperless: # pylint: disable=too-many-instance-attributes
|
|
|
148
165
|
"""Gateway to users."""
|
|
149
166
|
return self._users
|
|
150
167
|
|
|
168
|
+
@property
|
|
169
|
+
def workflows(self) -> WorkflowsController | None:
|
|
170
|
+
"""Gateway to workflows."""
|
|
171
|
+
return self._workflows
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
def workflow_actions(self) -> WorkflowActionsController | None:
|
|
175
|
+
"""Gateway to workflow actions."""
|
|
176
|
+
return self._workflow_actions
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def workflow_triggers(self) -> WorkflowTriggersController | None:
|
|
180
|
+
"""Gateway to workflow triggers."""
|
|
181
|
+
return self._workflow_triggers
|
|
182
|
+
|
|
151
183
|
async def initialize(self) -> None:
|
|
152
184
|
"""Initialize the connection to the api and fetch the endpoints."""
|
|
153
185
|
self.logger.info("Fetching api endpoints.")
|
|
154
186
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
187
|
+
async with self.generate_request("get", f"{self._url}") as res:
|
|
188
|
+
version = AwesomeVersion(
|
|
189
|
+
res.headers.get("x-version") if "x-version" in res.headers else "0.0.0"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
if version >= PAPERLESS_V1_8_0:
|
|
193
|
+
self.features |= PaperlessFeature.CONTROLLER_STORAGE_PATHS
|
|
194
|
+
if version >= PAPERLESS_V1_17_0:
|
|
195
|
+
self.features |= PaperlessFeature.FEATURE_DOCUMENT_NOTES
|
|
196
|
+
if version >= PAPERLESS_V2_0_0:
|
|
197
|
+
self.features |= (
|
|
198
|
+
PaperlessFeature.CONTROLLER_SHARE_LINKS
|
|
199
|
+
| PaperlessFeature.CONTROLLER_CONSUMPTION_TEMPLATES
|
|
200
|
+
| PaperlessFeature.CONTROLLER_CUSTOM_FIELDS
|
|
201
|
+
)
|
|
202
|
+
if version >= PAPERLESS_V2_3_0:
|
|
203
|
+
self.features |= (
|
|
204
|
+
PaperlessFeature.CONTROLLER_CONFIGS | PaperlessFeature.CONTROLLER_WORKFLOWS
|
|
205
|
+
)
|
|
206
|
+
self.features ^= PaperlessFeature.CONTROLLER_CONSUMPTION_TEMPLATES
|
|
207
|
+
|
|
208
|
+
paths = await res.json()
|
|
209
|
+
|
|
210
|
+
self._correspondents = CorrespondentsController(
|
|
211
|
+
self, paths.pop(ControllerPath.CORRESPONDENTS)
|
|
212
|
+
)
|
|
213
|
+
self._documents = DocumentsController(self, paths.pop(ControllerPath.DOCUMENTS))
|
|
214
|
+
self._document_types = DocumentTypesController(
|
|
215
|
+
self, paths.pop(ControllerPath.DOCUMENT_TYPES)
|
|
159
216
|
)
|
|
160
|
-
self.
|
|
161
|
-
self.
|
|
162
|
-
self.
|
|
163
|
-
self.
|
|
164
|
-
self.
|
|
165
|
-
self.
|
|
166
|
-
self.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
217
|
+
self._groups = GroupsController(self, paths.pop(ControllerPath.GROUPS))
|
|
218
|
+
self._mail_accounts = MailAccountsController(self, paths.pop(ControllerPath.MAIL_ACCOUNTS))
|
|
219
|
+
self._mail_rules = MailRulesController(self, paths.pop(ControllerPath.MAIL_RULES))
|
|
220
|
+
self._saved_views = SavedViewsController(self, paths.pop(ControllerPath.SAVED_VIEWS))
|
|
221
|
+
self._tags = TagsController(self, paths.pop(ControllerPath.TAGS))
|
|
222
|
+
self._tasks = TasksController(self, paths.pop(ControllerPath.TASKS))
|
|
223
|
+
self._users = UsersController(self, paths.pop(ControllerPath.USERS))
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
if PaperlessFeature.CONTROLLER_STORAGE_PATHS in self.features:
|
|
227
|
+
self._storage_paths = StoragePathsController(
|
|
228
|
+
self, paths.pop(ControllerPath.STORAGE_PATHS)
|
|
229
|
+
)
|
|
230
|
+
if PaperlessFeature.CONTROLLER_CONSUMPTION_TEMPLATES in self.features:
|
|
231
|
+
self._consumption_templates = ConsumptionTemplatesController(
|
|
232
|
+
self, paths.pop(ControllerPath.CONSUMPTION_TEMPLATES)
|
|
233
|
+
)
|
|
234
|
+
if PaperlessFeature.CONTROLLER_CUSTOM_FIELDS in self.features:
|
|
235
|
+
self._custom_fields = CustomFieldsController(
|
|
236
|
+
self, paths.pop(ControllerPath.CUSTOM_FIELDS)
|
|
237
|
+
)
|
|
238
|
+
if PaperlessFeature.CONTROLLER_SHARE_LINKS in self.features:
|
|
239
|
+
self._share_links = ShareLinksController(
|
|
240
|
+
self, paths.pop(ControllerPath.SHARE_LINKS)
|
|
241
|
+
)
|
|
242
|
+
if PaperlessFeature.CONTROLLER_WORKFLOWS in self.features:
|
|
243
|
+
self._workflows = WorkflowsController(self, paths.pop(ControllerPath.WORKFLOWS))
|
|
244
|
+
self._workflow_actions = WorkflowActionsController(
|
|
245
|
+
self, paths.pop(ControllerPath.WORKFLOW_ACTIONS)
|
|
246
|
+
)
|
|
247
|
+
self._workflow_triggers = WorkflowTriggersController(
|
|
248
|
+
self, paths.pop(ControllerPath.WORKFLOW_TRIGGERS)
|
|
249
|
+
)
|
|
250
|
+
except KeyError as exc:
|
|
251
|
+
raise ControllerConfusion(exc) from exc
|
|
173
252
|
|
|
174
253
|
self._initialized = True
|
|
175
254
|
|
|
176
|
-
if len(
|
|
177
|
-
self.logger.debug("Unused
|
|
255
|
+
if len(paths) > 0:
|
|
256
|
+
self.logger.debug("Unused paths: %s", ", ".join(paths))
|
|
178
257
|
self.logger.info("Initialized.")
|
|
179
258
|
|
|
180
259
|
async def close(self) -> None:
|
|
@@ -194,8 +273,7 @@ class Paperless: # pylint: disable=too-many-instance-attributes
|
|
|
194
273
|
if not isinstance(self._session, aiohttp.ClientSession):
|
|
195
274
|
self._session = aiohttp.ClientSession()
|
|
196
275
|
|
|
197
|
-
|
|
198
|
-
url = url.rstrip("/") + "/" # check and add trailing slash
|
|
276
|
+
path = path.rstrip("/") + "/" # check and add trailing slash
|
|
199
277
|
|
|
200
278
|
if isinstance(self._request_opts, dict):
|
|
201
279
|
kwargs.update(self._request_opts)
|
|
@@ -208,7 +286,27 @@ class Paperless: # pylint: disable=too-many-instance-attributes
|
|
|
208
286
|
}
|
|
209
287
|
)
|
|
210
288
|
|
|
211
|
-
|
|
289
|
+
# convert form to FormData, if dict
|
|
290
|
+
if "form" in kwargs:
|
|
291
|
+
payload = kwargs.pop("form")
|
|
292
|
+
if not isinstance(payload, dict):
|
|
293
|
+
raise TypeError()
|
|
294
|
+
form = aiohttp.FormData()
|
|
295
|
+
|
|
296
|
+
# we just convert data, no nesting dicts
|
|
297
|
+
for key, value in payload.items():
|
|
298
|
+
if isinstance(value, str | bytes):
|
|
299
|
+
form.add_field(key, value)
|
|
300
|
+
elif isinstance(value, list):
|
|
301
|
+
for list_value in value:
|
|
302
|
+
form.add_field(key, f"{list_value}")
|
|
303
|
+
else:
|
|
304
|
+
form.add_field(key, f"{value}")
|
|
305
|
+
|
|
306
|
+
kwargs["data"] = form
|
|
307
|
+
|
|
308
|
+
# request data
|
|
309
|
+
async with self._session.request(method, path, **kwargs) as res:
|
|
212
310
|
yield res
|
|
213
311
|
|
|
214
312
|
async def request_json(
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""PyPaperless constants."""
|
|
2
|
+
|
|
3
|
+
from enum import IntFlag, StrEnum
|
|
4
|
+
|
|
5
|
+
from awesomeversion import AwesomeVersion
|
|
6
|
+
|
|
7
|
+
PAPERLESS_V1_8_0 = AwesomeVersion("1.8.0")
|
|
8
|
+
PAPERLESS_V1_17_0 = AwesomeVersion("1.17.0")
|
|
9
|
+
PAPERLESS_V2_0_0 = AwesomeVersion("2.0.0")
|
|
10
|
+
PAPERLESS_V2_3_0 = AwesomeVersion("2.3.0")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
CTRL_CONSUMPTION_TEMPLATES = "consumption_templates"
|
|
14
|
+
CTRL_CORRESPONDENTS = "correspondents"
|
|
15
|
+
CTRL_CUSTOM_FIELDS = "custom_fields"
|
|
16
|
+
CTRL_DOCUMENTS = "documents"
|
|
17
|
+
CTRL_DOCUMENT_TYPES = "document_types"
|
|
18
|
+
CTRL_GROUPS = "groups"
|
|
19
|
+
CTRL_MAIL_ACCOUNTS = "mail_accounts"
|
|
20
|
+
CTRL_MAIL_RULES = "mail_rules"
|
|
21
|
+
CTRL_SAVED_VIEWS = "saved_views"
|
|
22
|
+
CTRL_SHARE_LINKS = "share_links"
|
|
23
|
+
CTRL_STORAGE_PATHS = "storage_paths"
|
|
24
|
+
CTRL_TAGS = "tags"
|
|
25
|
+
CTRL_TASKS = "tasks"
|
|
26
|
+
CTRL_USERS = "users"
|
|
27
|
+
CTRL_WORKFLOW_ACTIONS = "workflow_actions"
|
|
28
|
+
CTRL_WORKFLOWS = "workflows"
|
|
29
|
+
CTRL_WORKFLOW_TRIGGERS = "workflow_triggers"
|
|
30
|
+
CTRL_UNKNOWN = "unknown"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class PaperlessFeature(IntFlag):
|
|
34
|
+
"""Supported features."""
|
|
35
|
+
|
|
36
|
+
CONTROLLER_STORAGE_PATHS = 1
|
|
37
|
+
FEATURE_DOCUMENT_NOTES = 2
|
|
38
|
+
CONTROLLER_SHARE_LINKS = 4
|
|
39
|
+
CONTROLLER_CUSTOM_FIELDS = 8
|
|
40
|
+
CONTROLLER_CONSUMPTION_TEMPLATES = 16
|
|
41
|
+
CONTROLLER_WORKFLOWS = 32
|
|
42
|
+
CONTROLLER_CONFIGS = 64
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ControllerPath(StrEnum):
|
|
46
|
+
"""Represent paths of api endpoints."""
|
|
47
|
+
|
|
48
|
+
CONSUMPTION_TEMPLATES = CTRL_CONSUMPTION_TEMPLATES
|
|
49
|
+
CORRESPONDENTS = CTRL_CORRESPONDENTS
|
|
50
|
+
CUSTOM_FIELDS = CTRL_CUSTOM_FIELDS
|
|
51
|
+
DOCUMENTS = CTRL_DOCUMENTS
|
|
52
|
+
DOCUMENT_TYPES = CTRL_DOCUMENT_TYPES
|
|
53
|
+
GROUPS = CTRL_GROUPS
|
|
54
|
+
MAIL_ACCOUNTS = CTRL_MAIL_ACCOUNTS
|
|
55
|
+
MAIL_RULES = CTRL_MAIL_RULES
|
|
56
|
+
SAVED_VIEWS = CTRL_SAVED_VIEWS
|
|
57
|
+
SHARE_LINKS = CTRL_SHARE_LINKS
|
|
58
|
+
STORAGE_PATHS = CTRL_STORAGE_PATHS
|
|
59
|
+
TAGS = CTRL_TAGS
|
|
60
|
+
TASKS = CTRL_TASKS
|
|
61
|
+
USERS = CTRL_USERS
|
|
62
|
+
WORKFLOWS = CTRL_WORKFLOWS
|
|
63
|
+
WORKFLOW_ACTIONS = CTRL_WORKFLOW_ACTIONS
|
|
64
|
+
WORKFLOW_TRIGGERS = CTRL_WORKFLOW_TRIGGERS
|
|
65
|
+
UNKNOWN = CTRL_UNKNOWN
|
|
@@ -13,6 +13,9 @@ from .default import (
|
|
|
13
13
|
StoragePathsController,
|
|
14
14
|
TagsController,
|
|
15
15
|
UsersController,
|
|
16
|
+
WorkflowActionsController,
|
|
17
|
+
WorkflowsController,
|
|
18
|
+
WorkflowTriggersController,
|
|
16
19
|
)
|
|
17
20
|
from .documents import DocumentsController
|
|
18
21
|
from .tasks import TasksController
|
|
@@ -32,4 +35,7 @@ __all__ = [
|
|
|
32
35
|
"TagsController",
|
|
33
36
|
"TasksController",
|
|
34
37
|
"UsersController",
|
|
38
|
+
"WorkflowActionsController",
|
|
39
|
+
"WorkflowsController",
|
|
40
|
+
"WorkflowTriggersController",
|
|
35
41
|
]
|
|
@@ -13,6 +13,9 @@ from pypaperless.models import (
|
|
|
13
13
|
StoragePath,
|
|
14
14
|
Tag,
|
|
15
15
|
User,
|
|
16
|
+
Workflow,
|
|
17
|
+
WorkflowAction,
|
|
18
|
+
WorkflowTrigger,
|
|
16
19
|
)
|
|
17
20
|
|
|
18
21
|
from .base import (
|
|
@@ -174,3 +177,36 @@ class UsersController(
|
|
|
174
177
|
"""Represent Paperless users resource."""
|
|
175
178
|
|
|
176
179
|
_resource = User
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class WorkflowsController(
|
|
183
|
+
BaseController[Workflow],
|
|
184
|
+
PaginationMixin[Workflow],
|
|
185
|
+
ListMixin[Workflow],
|
|
186
|
+
OneMixin[Workflow],
|
|
187
|
+
):
|
|
188
|
+
"""Represent Paperless workflows resource."""
|
|
189
|
+
|
|
190
|
+
_resource = Workflow
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class WorkflowActionsController(
|
|
194
|
+
BaseController[WorkflowAction],
|
|
195
|
+
PaginationMixin[WorkflowAction],
|
|
196
|
+
ListMixin[WorkflowAction],
|
|
197
|
+
OneMixin[WorkflowAction],
|
|
198
|
+
):
|
|
199
|
+
"""Represent Paperless workflow actions resource."""
|
|
200
|
+
|
|
201
|
+
_resource = WorkflowAction
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class WorkflowTriggersController(
|
|
205
|
+
BaseController[WorkflowTrigger],
|
|
206
|
+
PaginationMixin[WorkflowTrigger],
|
|
207
|
+
ListMixin[WorkflowTrigger],
|
|
208
|
+
OneMixin[WorkflowTrigger],
|
|
209
|
+
):
|
|
210
|
+
"""Represent Paperless workflow triggers resource."""
|
|
211
|
+
|
|
212
|
+
_resource = WorkflowTrigger
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
|
|
5
|
+
from pypaperless.const import PaperlessFeature
|
|
7
6
|
from pypaperless.models import (
|
|
8
7
|
Document,
|
|
9
8
|
DocumentMetaInformation,
|
|
@@ -114,32 +113,17 @@ class DocumentsController( # pylint: disable=too-many-ancestors
|
|
|
114
113
|
"""Override initialize controller. Also initialize service controllers."""
|
|
115
114
|
super().__init__(paperless, path)
|
|
116
115
|
|
|
117
|
-
self.notes = DocumentNotesService(self)
|
|
118
116
|
self.files = DocumentFilesService(self)
|
|
117
|
+
self.notes: DocumentNotesService | None = None
|
|
118
|
+
|
|
119
|
+
if PaperlessFeature.FEATURE_DOCUMENT_NOTES in self._paperless.features:
|
|
120
|
+
self.notes = DocumentNotesService(self)
|
|
119
121
|
|
|
120
122
|
async def create(self, obj: DocumentPost) -> str:
|
|
121
123
|
"""Create a new document. Raise on failure."""
|
|
122
|
-
form = aiohttp.FormData()
|
|
123
|
-
form.add_field("document", obj.document)
|
|
124
|
-
|
|
125
|
-
for field in (
|
|
126
|
-
"title",
|
|
127
|
-
"created",
|
|
128
|
-
"correspondent",
|
|
129
|
-
"document_type",
|
|
130
|
-
"archive_serial_number",
|
|
131
|
-
):
|
|
132
|
-
if getattr(obj, field):
|
|
133
|
-
form.add_field(field, getattr(obj, field))
|
|
134
|
-
|
|
135
|
-
if isinstance(obj.tags, list):
|
|
136
|
-
for tag in obj.tags:
|
|
137
|
-
form.add_field("tags", f"{tag}")
|
|
138
|
-
|
|
139
124
|
url = f"{self.path}/post_document/"
|
|
140
|
-
|
|
141
125
|
# result is a string in this case
|
|
142
|
-
res =
|
|
126
|
+
res: str = await self._paperless.request_json("post", url, form=dataclass_to_dict(obj))
|
|
143
127
|
return res
|
|
144
128
|
|
|
145
129
|
async def meta(self, obj: _DocumentOrIdType) -> DocumentMetaInformation:
|
|
@@ -29,11 +29,13 @@ class TasksController(BaseController[Task]):
|
|
|
29
29
|
for item in res:
|
|
30
30
|
yield item
|
|
31
31
|
|
|
32
|
-
async def one(self, idx: str) -> Task:
|
|
32
|
+
async def one(self, idx: str) -> Task | None:
|
|
33
33
|
"""Request exactly one task item by pk."""
|
|
34
34
|
params = {
|
|
35
35
|
"task_id": idx,
|
|
36
36
|
}
|
|
37
37
|
res = await self._paperless.request_json("get", self.path, params=params)
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
if len(res) > 0:
|
|
39
|
+
data: Task = dataclass_from_dict(self.resource, res.pop())
|
|
40
|
+
return data
|
|
41
|
+
return None
|
|
@@ -11,3 +11,7 @@ class BadRequestException(PaperlessException):
|
|
|
11
11
|
|
|
12
12
|
class DataNotExpectedException(PaperlessException):
|
|
13
13
|
"""Raise when expecting a type and receiving something else."""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ControllerConfusion(PaperlessException):
|
|
17
|
+
"""Raise when Paperless version does not match to controllers."""
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
"""Models for Paperless resources."""
|
|
2
2
|
|
|
3
|
-
from .consumption_templates import ConsumptionTemplate
|
|
4
|
-
from .correspondents import Correspondent, CorrespondentPost
|
|
5
3
|
from .custom_fields import CustomField, CustomFieldPost
|
|
6
|
-
from .document_types import DocumentType, DocumentTypePost
|
|
7
4
|
from .documents import (
|
|
8
5
|
Document,
|
|
9
6
|
DocumentMetadata,
|
|
@@ -13,14 +10,22 @@ from .documents import (
|
|
|
13
10
|
DocumentPost,
|
|
14
11
|
)
|
|
15
12
|
from .groups import Group
|
|
16
|
-
from .
|
|
17
|
-
from .
|
|
13
|
+
from .mails import MailAccount, MailRule
|
|
14
|
+
from .matching import (
|
|
15
|
+
Correspondent,
|
|
16
|
+
CorrespondentPost,
|
|
17
|
+
DocumentType,
|
|
18
|
+
DocumentTypePost,
|
|
19
|
+
StoragePath,
|
|
20
|
+
StoragePathPost,
|
|
21
|
+
Tag,
|
|
22
|
+
TagPost,
|
|
23
|
+
)
|
|
18
24
|
from .saved_views import SavedView, SavedViewFilterRule
|
|
19
25
|
from .share_links import ShareLink, ShareLinkPost
|
|
20
|
-
from .storage_paths import StoragePath, StoragePathPost
|
|
21
|
-
from .tags import Tag, TagPost
|
|
22
26
|
from .tasks import Task
|
|
23
27
|
from .users import User
|
|
28
|
+
from .workflows import ConsumptionTemplate, Workflow, WorkflowAction, WorkflowTrigger
|
|
24
29
|
|
|
25
30
|
__all__ = [
|
|
26
31
|
"ConsumptionTemplate",
|
|
@@ -49,4 +54,7 @@ __all__ = [
|
|
|
49
54
|
"TagPost",
|
|
50
55
|
"Task",
|
|
51
56
|
"User",
|
|
57
|
+
"Workflow",
|
|
58
|
+
"WorkflowAction",
|
|
59
|
+
"WorkflowTrigger",
|
|
52
60
|
]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Base models."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class PaperlessModel: # pylint: disable=too-few-public-methods
|
|
5
|
+
"""Base class that represents a Paperless model."""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PaperlessPost(PaperlessModel): # pylint: disable=too-few-public-methods
|
|
9
|
+
"""Base class that represents a Paperless POST model."""
|
|
@@ -1,10 +1,29 @@
|
|
|
1
1
|
"""Model for custom field resource."""
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
+
from enum import Enum
|
|
4
5
|
from typing import Any
|
|
5
6
|
|
|
6
7
|
from .base import PaperlessModel, PaperlessPost
|
|
7
|
-
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CustomFieldType(Enum):
|
|
11
|
+
"""Enum with custom field types."""
|
|
12
|
+
|
|
13
|
+
STRING = "string"
|
|
14
|
+
BOOLEAN = "boolean"
|
|
15
|
+
INTEGER = "integer"
|
|
16
|
+
FLOAT = "float"
|
|
17
|
+
MONETARY = "monetary"
|
|
18
|
+
DATE = "date"
|
|
19
|
+
URL = "url"
|
|
20
|
+
DOCUMENT_LINK = "documentlink"
|
|
21
|
+
UNKNOWN = "unknown"
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def _missing_(cls: type, value: object) -> "CustomFieldType": # noqa ARG003
|
|
25
|
+
"""Set default member on unknown value."""
|
|
26
|
+
return CustomFieldType.UNKNOWN
|
|
8
27
|
|
|
9
28
|
|
|
10
29
|
@dataclass(kw_only=True)
|
|
@@ -80,7 +80,7 @@ class Document(PaperlessModel): # pylint: disable=too-many-instance-attributes
|
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
@dataclass(kw_only=True)
|
|
83
|
-
class DocumentPost(PaperlessPost):
|
|
83
|
+
class DocumentPost(PaperlessPost): # pylint: disable=too-many-instance-attributes
|
|
84
84
|
"""Attributes to send when creating a document on the Paperless api."""
|
|
85
85
|
|
|
86
86
|
document: bytes
|
|
@@ -88,5 +88,6 @@ class DocumentPost(PaperlessPost):
|
|
|
88
88
|
created: datetime | None = None
|
|
89
89
|
correspondent: int | None = None
|
|
90
90
|
document_type: int | None = None
|
|
91
|
+
storage_path: int | None = None
|
|
91
92
|
tags: list[int] | None = None
|
|
92
93
|
archive_serial_number: int | None = None
|
pypaperless-2.2.0/pypaperless/models/mail_rules.py → pypaperless-2.3.0/pypaperless/models/mails.py
RENAMED
|
@@ -1,10 +1,27 @@
|
|
|
1
|
-
"""Model for mail
|
|
1
|
+
"""Model for mail resources."""
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
|
|
5
5
|
from .base import PaperlessModel
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
@dataclass(kw_only=True)
|
|
9
|
+
class MailAccount(PaperlessModel): # pylint: disable=too-many-instance-attributes
|
|
10
|
+
"""Represent a mail account resource on the Paperless api."""
|
|
11
|
+
|
|
12
|
+
id: int | None = None
|
|
13
|
+
name: str | None = None
|
|
14
|
+
imap_server: str | None = None
|
|
15
|
+
imap_port: int | None = None
|
|
16
|
+
imap_security: int | None = None
|
|
17
|
+
username: str | None = None
|
|
18
|
+
password: str | None = None
|
|
19
|
+
character_set: str | None = None
|
|
20
|
+
is_token: bool | None = None
|
|
21
|
+
owner: int | None = None
|
|
22
|
+
user_can_change: bool | None = None
|
|
23
|
+
|
|
24
|
+
|
|
8
25
|
@dataclass(kw_only=True)
|
|
9
26
|
class MailRule(PaperlessModel): # pylint: disable=too-many-instance-attributes
|
|
10
27
|
"""Represent a mail rule resource on the Paperless api."""
|