Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
ciur committed Oct 8, 2024
1 parent eec533e commit 4ceab0c
Show file tree
Hide file tree
Showing 11 changed files with 367 additions and 66 deletions.
2 changes: 2 additions & 0 deletions papermerge/core/db/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
update_custom_field,
)
from .doc import (
add_document_custom_field_values,
get_doc,
get_document_custom_field_values,
update_document_custom_field_values,
Expand Down Expand Up @@ -77,5 +78,6 @@
"delete_document_type",
"update_document_type",
"update_document_custom_field_values",
"add_document_custom_field_values",
"get_document_custom_field_values",
]
136 changes: 105 additions & 31 deletions papermerge/core/db/doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,21 +82,100 @@ def update_document_custom_field_values(
id: UUID, # id of the document
custom_fields_update: schemas.DocumentCustomFieldsUpdate,
user_id: UUID,
):
) -> list[schemas.CustomFieldValue]:
"""
Updates already existing `CustomFieldValue` instances
Returns a list of updated `CustomFieldValue`
"""
# fetch doc
stmt_doc = select(Document).where(Document.id == id, Document.user_id == user_id)
db_doc = session.scalars(stmt_doc).one()
# set document type ID to the input value
db_doc.document_type_id = custom_fields_update.document_type_id
session.add(db_doc)
updated_db_items = []

field_value_ids = [cf.id for cf in custom_fields_update.custom_fields]
# fetch existing `CustomFieldValue` instances
stmt = select(CustomFieldValue).where(
CustomFieldValue.field_id.in_(field_value_ids),
CustomFieldValue.document_id == id,
)
db_field_values = session.execute(stmt).all()
for db_field_value in db_field_values:
incoming_cf = None
# for each DB item, find corresponding incoming values (i.e. newly provided by user)
for incoming in custom_fields_update.custom_fields:
if incoming.custom_field_value_id == db_field_value.id:
incoming_cf = incoming

if incoming_cf:
_dic = {
"value_text": None,
"value_bool": None,
"value_url": None,
"value_date": None,
"value_int": None,
"value_float": None,
"value_monetary": None,
"value_select": None,
}
attr_name = CUSTOM_FIELD_DATA_TYPE_MAP.get(
db_field_value.field.data_type, None
)
if attr_name:
if attr_name == "date":
_dic[f"value_{attr_name}"] = datetime.strptime(
incoming_cf.value, "%d.%m.%Y"
)
else:
_dic[f"value_{attr_name}"] = incoming_cf.value

db_field_value.value_text = _dic["value_text"]
db_field_value.value_bool = _dic["value_bool"]
db_field_value.value_url = _dic["value_url"]
db_field_value.value_date = _dic["value_date"]
db_field_value.value_int = _dic["value_int"]
db_field_value.value_float = _dic["value_float"]
db_field_value.value_monetary = _dic["value_monetary"]
db_field_value.value_select = _dic["value_select"]
updated_db_items.append(db_field_value)
session.add(db_field_value)

result = [
schemas.CustomFieldValue.model_validate(db_item) for db_item in updated_db_items
]

session.commit()
return result


def add_document_custom_field_values(
session: Session,
id: UUID, # id of the document
custom_fields_add: schemas.DocumentCustomFieldsAdd,
user_id: UUID,
) -> list[schemas.CustomFieldValue]:
"""
Adds new `CustomFieldValue` instances
Returns a list of newly added `CustomFieldValue`
"""
# fetch doc
stmt_doc = select(Document).where(Document.id == id, Document.user_id == user_id)
db_doc = session.scalars(stmt_doc).one()
# set document type ID to the input value
db_doc.document_type_id = custom_fields_add.document_type_id
session.add(db_doc)
# continue to update document fields
custom_field_ids = [cf.custom_field_id for cf in custom_fields_update.custom_fields]
custom_field_ids = [cf.custom_field_id for cf in custom_fields_add.custom_fields]
stmt = select(CustomField).where(CustomField.id.in_(custom_field_ids))
results = session.execute(stmt).all()
added_items = []

custom_fields = [schemas.CustomField.model_validate(cf[0]) for cf in results]

for incoming_cf in custom_fields_update.custom_fields:
for incoming_cf in custom_fields_add.custom_fields:
found = next(
(cf for cf in custom_fields if cf.id == incoming_cf.custom_field_id), None
)
Expand All @@ -112,40 +191,34 @@ def update_document_custom_field_values(
"value_select": None,
}
attr_name = CUSTOM_FIELD_DATA_TYPE_MAP.get(found.data_type.value, None)
value = ""
if attr_name:
if attr_name == "date":
_dic[f"value_{attr_name}"] = datetime.strptime(
incoming_cf.value, "%d.%m.%Y"
)
value = datetime.strptime(incoming_cf.value, "%d.%m.%Y")
else:
_dic[f"value_{attr_name}"] = incoming_cf.value
value = incoming_cf.value
_dic[f"value_{attr_name}"] = value

stmt = select(CustomFieldValue).where(
CustomFieldValue.field_id == incoming_cf.custom_field_id,
CustomFieldValue.document_id == id,
_id = uuid.uuid4()
cfv = CustomFieldValue(
id=uuid.uuid4(),
field_id=found.id,
document_id=id,
**_dic,
)
session.add(cfv)
validated_item = schemas.CustomFieldValue(
id=_id,
name=found.name,
data_type=found.data_type,
extra_data=found.extra_data,
value=str(value),
field_id=found.id,
)
db_found = session.scalar(stmt)
if db_found is None:
cfv = CustomFieldValue(
id=uuid.uuid4(),
field_id=incoming_cf.custom_field_id,
document_id=id,
**_dic,
)
session.add(cfv)
else:
# one of `_dic` values was changed
db_found.value_text = _dic["value_text"]
db_found.value_bool = _dic["value_bool"]
db_found.value_url = _dic["value_url"]
db_found.value_date = _dic["value_date"]
db_found.value_int = _dic["value_int"]
db_found.value_float = _dic["value_float"]
db_found.value_monetary = _dic["value_monetary"]
db_found.value_select = _dic["value_select"]
session.add(db_found)
added_items.append(validated_item)

session.commit()
return added_items


def get_document_custom_field_values(
Expand Down Expand Up @@ -189,6 +262,7 @@ def get_document_custom_field_values(
data_type=db_item.field.data_type,
extra_data=db_item.field.extra_data,
value=str(value),
field_id=db_item.field_id,
)
result.append(cfv)

Expand Down
42 changes: 37 additions & 5 deletions papermerge/core/routers/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,27 +39,59 @@ def get_document_details(
return doc


@router.post("/{document_id}/custom-fields")
@utils.docstring_parameter(scope=scopes.NODE_UPDATE)
def add_document_custom_field_values(
document_id: uuid.UUID,
custom_fields_add: schemas.DocumentCustomFieldsAdd,
user: Annotated[
schemas.User, Security(get_current_user, scopes=[scopes.NODE_UPDATE])
],
db_session: db.Session = Depends(db.get_session),
) -> list[schemas.CustomFieldValue]:
"""
Associates document type to specified `document_type_id` and set it custom field
value(s). This API will create a NEW custom field value
All custom fields must be part of `DocumentType` specified by `document_type_id`,
otherwise response will return error 400 - invalid request.
Required scope: `{scope}`
"""
try:
added_entries = db.add_document_custom_field_values(
db_session,
id=document_id,
custom_fields_add=custom_fields_add,
user_id=user.id,
)
except NoResultFound:
raise HTTPException(status_code=404, detail="Document not found")

return added_entries


@router.patch("/{document_id}/custom-fields")
@utils.docstring_parameter(scope=scopes.NODE_UPDATE)
def update_document_custom_fields(
def update_document_custom_field_values(
document_id: uuid.UUID,
custom_fields_update: schemas.DocumentCustomFieldsUpdate,
user: Annotated[
schemas.User, Security(get_current_user, scopes=[scopes.NODE_UPDATE])
],
db_session: db.Session = Depends(db.get_session),
):
) -> list[schemas.CustomFieldValue]:
"""
Update document type to specified `document_type_id` and set it custom field
value(s)
value(s). Will update existing custom field values.
All custom fields must be part of `DocumentType` specified by `document_type_id`,
otherwise response will return error 400 - invalid request.
Required scope: `{scope}`
"""
try:
doc = db.update_document_custom_field_values(
updated_entries = db.update_document_custom_field_values(
db_session,
id=document_id,
custom_fields_update=custom_fields_update,
Expand All @@ -68,7 +100,7 @@ def update_document_custom_fields(
except NoResultFound:
raise HTTPException(status_code=404, detail="Document not found")

return doc
return updated_entries


@router.get("/{document_id}/custom-fields")
Expand Down
4 changes: 4 additions & 0 deletions papermerge/core/schemas/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from .documents import (
CreateDocument,
Document,
DocumentCustomFieldsAdd,
DocumentCustomFieldsAddValue,
DocumentCustomFieldsUpdate,
DocumentCustomFieldsUpdateValue,
DocumentVersion,
Expand Down Expand Up @@ -59,6 +61,8 @@
"UpdateDocumentType",
"DocumentCustomFieldsUpdate",
"DocumentCustomFieldsUpdateValue",
"DocumentCustomFieldsAdd",
"DocumentCustomFieldsAddValue",
]


Expand Down
4 changes: 4 additions & 0 deletions papermerge/core/schemas/custom_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,8 @@ class UpdateCustomField(BaseModel):


class CustomFieldValue(CustomField):
# notice that attribue `id` indicates the ID of
# custom field value
value: str | None = None
# the ID of the custom field
field_id: UUID
12 changes: 11 additions & 1 deletion papermerge/core/schemas/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,18 @@ def _s3_docver_download_url(uid: UUID, file_name: str) -> str:
)


class DocumentCustomFieldsAddValue(BaseModel):
custom_field_id: UUID # custom field ID here, NOT custom field *value* ID!
value: str


class DocumentCustomFieldsAdd(BaseModel):
document_type_id: UUID
custom_fields: list[DocumentCustomFieldsAddValue]


class DocumentCustomFieldsUpdateValue(BaseModel):
custom_field_id: UUID
custom_field_value_id: UUID
value: str


Expand Down
14 changes: 14 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,17 @@ def document_type_with_one_date_cf( # cf = custom field
custom_field_ids=[cf1.id],
user_id=user.id,
)


@pytest.fixture
def document_type_with_one_string_cf( # cf = custom field
db_session: Session, user: User, make_custom_field
):
cf1 = make_custom_field(name="string-name1", data_type=CustomFieldType.string)

return db.create_document_type(
db_session,
name="document_type_with_one_string_cf",
custom_field_ids=[cf1.id],
user_id=user.id,
)
Loading

0 comments on commit 4ceab0c

Please sign in to comment.