Skip to content

Commit eded5b5

Browse files
authored
feat: support for node custom IDs (issue#325) (#331)
1 parent bbb63cd commit eded5b5

File tree

6 files changed

+110
-4
lines changed

6 files changed

+110
-4
lines changed

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
### Adds
88

99
- Support for OpenLDAP (RFC 4510) authentication
10+
- Support for node's custom IDs [Issue#325](https://github.com/papermerge/papermerge-core/issues/325)
1011

1112
### Fixes
1213

papermerge/core/models/document.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,19 @@ def create_document(
103103
page_count=0,
104104
file_name=None,
105105
parent=None,
106+
id=None,
106107
**kwargs
107108
):
108-
doc = Document(
109+
attrs = dict(
109110
title=title,
110111
lang=lang,
111112
parent=parent,
112113
**kwargs
113114
)
115+
if id is not None:
116+
attrs['id'] = id
117+
118+
doc = Document(**attrs)
114119
doc.save()
115120

116121
document_version = DocumentVersion(

papermerge/core/routers/nodes.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,22 +79,35 @@ def create_node(
7979
pynode: PyCreateFolder | PyCreateDocument,
8080
user: schemas.User = Depends(get_current_user)
8181
) -> PyFolder | PyDocument:
82-
82+
"""Creates a node
83+
84+
Node's `ctype` may be either `folder` or `document`.
85+
Optionally you may pass ID attribute. If ID is present and has
86+
non-emtpy UUID value, then newly create node will be assigned this
87+
custom ID.
88+
If node has `parent_id` empty then node will not be accessible to user.
89+
The only nodes with `parent_id` set to empty value are "user custom folders"
90+
like Home and Inbox.
91+
"""
8392
try:
8493
if pynode.ctype == "folder":
85-
node = Folder.objects.create(
94+
attrs = dict(
8695
title=pynode.title,
8796
user_id=user.id,
8897
parent_id=pynode.parent_id
8998
)
99+
if pynode.id:
100+
attrs['id'] = pynode.id
101+
102+
node = Folder.objects.create(**attrs)
90103
klass = PyFolder
91104
else:
92105
# if user does not specify document's language, get that
93106
# value from user preferences
94107
if pynode.lang is None:
95108
pynode.lang = settings.OCR__DEFAULT_LANGUAGE
96109

97-
node = Document.objects.create_document(
110+
attrs = dict(
98111
title=pynode.title,
99112
lang=pynode.lang,
100113
user_id=user.id,
@@ -103,6 +116,10 @@ def create_node(
103116
page_count=0,
104117
file_name=pynode.title
105118
)
119+
if pynode.id:
120+
attrs['id'] = pynode.id
121+
122+
node = Document.objects.create_document(**attrs)
106123
klass = PyDocument
107124
except IntegrityError:
108125
raise HTTPException(

papermerge/core/schemas/documents.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,27 @@ def tags_validator(cls, value):
126126

127127

128128
class CreateDocument(BaseModel):
129+
# UUID may be present to allow custom IDs
130+
# See https://github.com/papermerge/papermerge-core/issues/325
131+
id: UUID | None = None
129132
title: str
130133
ctype: Literal["document"]
131134
parent_id: UUID | None
132135
lang: str | None = None
133136
file_name: str | None = None
134137

138+
model_config = {
139+
"json_schema_extra": {
140+
"examples": [
141+
{
142+
"title": "invoice.pdf",
143+
"ctype": "document",
144+
"parent_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
145+
}
146+
]
147+
}
148+
}
149+
135150

136151
class Thumbnail(BaseModel):
137152
url: str

papermerge/core/schemas/folders.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,21 @@ def tags_validator(cls, value):
3737

3838

3939
class CreateFolder(BaseModel):
40+
# UUID may be present to allow custom IDs
41+
# See https://github.com/papermerge/papermerge-core/issues/325
42+
id: UUID | None = None
4043
title: str
4144
ctype: Literal["folder"]
4245
parent_id: UUID | None
46+
47+
model_config = {
48+
"json_schema_extra": {
49+
"examples": [
50+
{
51+
"title": "My Documents",
52+
"ctype": "folder",
53+
"parent_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
54+
},
55+
]
56+
}
57+
}

tests/core/views/test_nodes.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
import uuid
23

34
import pytest
45
from django.urls import reverse
@@ -123,6 +124,58 @@ def test_nodes_move(self):
123124
assert response.status_code == 200, response.data
124125

125126

127+
@pytest.mark.django_db(transaction=True)
128+
def test_create_document_with_custom_id(auth_api_client: AuthTestClient):
129+
"""
130+
Allow custom ID attribute: if ID attribute is set, then node will set it
131+
as its ID.
132+
"""
133+
assert Document.objects.count() == 0
134+
135+
user = auth_api_client.user
136+
137+
custom_id = uuid.uuid4()
138+
139+
payload = dict(
140+
id=str(custom_id),
141+
ctype='document',
142+
# "lang" attribute is not set
143+
title='doc1.pdf',
144+
parent_id=str(user.home_folder.pk)
145+
)
146+
147+
response = auth_api_client.post('/nodes', json=payload)
148+
149+
assert response.status_code == 201, response.content
150+
assert Document.objects.count() == 1
151+
doc = Document.objects.first()
152+
assert doc.id == custom_id
153+
154+
155+
@pytest.mark.django_db(transaction=True)
156+
def test_create_folder_with_custom_id(auth_api_client: AuthTestClient):
157+
"""
158+
Allow custom ID attribute: if ID attribute is set, then node will set it
159+
as its ID.
160+
"""
161+
user = auth_api_client.user
162+
163+
custom_id = uuid.uuid4()
164+
165+
payload = dict(
166+
id=str(custom_id),
167+
ctype='folder',
168+
title='My Documents',
169+
parent_id=str(user.home_folder.pk)
170+
)
171+
172+
response = auth_api_client.post('/nodes', json=payload)
173+
folder = Folder.objects.get(title='My Documents')
174+
175+
assert response.status_code == 201, response.content
176+
assert folder.id == custom_id
177+
178+
126179
@pytest.mark.django_db(transaction=True)
127180
def test_create_document(auth_api_client: AuthTestClient):
128181
"""

0 commit comments

Comments
 (0)