Skip to content

Commit

Permalink
Optimize import text structure logic
Browse files Browse the repository at this point in the history
  • Loading branch information
bkis committed Oct 10, 2023
1 parent 2c96aa0 commit 61013bc
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 48 deletions.
78 changes: 78 additions & 0 deletions Tekst-API/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1546,6 +1546,69 @@
}
}
},
"/texts/{id}/structure": {
"post": {
"tags": [
"texts"
],
"summary": "Upload structure definition",
"description": "Upload the structure definition for a text to apply as a structure of nodes",
"operationId": "uploadStructureDefinition",
"security": [
{
"APIKeyCookie": []
},
{
"OAuth2PasswordBearer": []
}
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"example": "5eb7cf5a86d9755df3a6c593",
"title": "Id"
}
}
],
"requestBody": {
"required": true,
"content": {
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/Body_upload_structure_definition_texts__id__structure_post"
}
}
}
},
"responses": {
"201": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
},
"404": {
"description": "Not found"
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/texts/{id}/level/{index}": {
"post": {
"tags": [
Expand Down Expand Up @@ -3020,6 +3083,21 @@
],
"title": "Body_reset_reset_password_auth_reset_password_post"
},
"Body_upload_structure_definition_texts__id__structure_post": {
"properties": {
"file": {
"type": "string",
"format": "binary",
"title": "File",
"description": "JSON file containing the text's structure"
}
},
"type": "object",
"required": [
"file"
],
"title": "Body_upload_structure_definition_texts__id__structure_post"
},
"Body_verify_request_token_auth_request_verify_token_post": {
"properties": {
"email": {
Expand Down
9 changes: 4 additions & 5 deletions Tekst-API/tekst/routers/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,7 @@ async def delete_node(
# delete associated units
units_deleted += (
await UnitBaseDocument.find(
In(UnitBaseDocument.node_id, target_ids),
with_children=True
In(UnitBaseDocument.node_id, target_ids), with_children=True
).delete()
).deleted_count
# collect child nodes to delete
Expand All @@ -240,9 +239,9 @@ async def delete_node(
NodeDocument.position > target_nodes[0].position,
).inc({NodeDocument.position: len(target_nodes) * -1})
# delete current target nodes
nodes_deleted += (await NodeDocument.find(
In(NodeDocument.id, target_ids)
).delete()).deleted_count
nodes_deleted += (
await NodeDocument.find(In(NodeDocument.id, target_ids)).delete()
).deleted_count
to_delete.pop(0)
return DeleteNodeResult(units=units_deleted, nodes=nodes_deleted)

Expand Down
64 changes: 29 additions & 35 deletions Tekst-API/tekst/routers/texts.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

from copy import deepcopy
from pathlib import Path as SysPath
from typing import Annotated, List
Expand Down Expand Up @@ -188,42 +187,37 @@ async def upload_structure_definition(
detail="Invalid structure definition",
)
# import nodes depth-first
nodes = [
dict(
level=0,
position=i,
parent_id=None,
**structure_def.nodes[i].model_dump(by_alias=False),
)
for i in range(len(structure_def.nodes))
]
structure_def = None
positions = [0] * len(text.levels)
positions[0] += len(nodes) - 1
while nodes:
node = nodes.pop(0)
node["id"] = (
await NodeDocument(
nodes = structure_def.model_dump(exclude_none=True, by_alias=False)["nodes"]
structure_def = None # de-reference structure definition object
# apply parent IDs (None) to all 0-level nodes
for node in nodes:
node["parent_id"] = None
# process nodes level by level
for level in range(len(text.levels)):
if len(nodes) == 0:
break
# create NodeDocument instances for each node definition
node_docs = [
NodeDocument(
text_id=text_id,
label=node["label"],
level=node["level"],
position=node["position"],
parent_id=node["parent_id"],
).create()
).id
children_level = node["level"] + 1
if children_level >= len(text.levels):
continue
for child in node.get("nodes", []):
nodes.append(
dict(
level=children_level,
parent_id=node["id"],
position=positions[children_level],
**child,
)
parent_id=nodes[i]["parent_id"],
level=level,
position=i,
label=nodes[i]["label"],
)
positions[children_level] += 1
for i in range(len(nodes))
]
# bulk-insert documents
inserted_ids = (await NodeDocument.insert_many(node_docs)).inserted_ids
# collect children and their parents' IDs
children = []
for i in range(len(nodes)):
children_temp = nodes[i].get("nodes", [])
# apply parent ID
for c in children_temp:
c["parent_id"] = inserted_ids[i]
children += children_temp
nodes = children


@router.post(
Expand Down
17 changes: 9 additions & 8 deletions Tekst-Web/src/views/admin/AdminTextsNodesView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { useMessages } from '@/messages';
import { $t } from '@/i18n';
import { watch } from 'vue';
import type { Component } from 'vue';
import { positiveButtonProps, negativeButtonProps } from '@/components/dialogButtonProps';
import { positiveButtonProps } from '@/components/dialogButtonProps';
import RenameNodeModal from '@/components/admin/RenameNodeModal.vue';
import AddNodeModal from '@/components/admin/AddNodeModal.vue';
Expand Down Expand Up @@ -186,17 +186,18 @@ async function handleDeleteClick(node: NodeTreeOption) {
deleteNode(node);
return;
}
dialog.warning({
const d = dialog.create({
title: $t('general.warning'),
content: $t('admin.texts.nodes.warnDeleteNode', { nodeLabel: node.label }),
positiveText: $t('general.deleteAction'),
negativeText: $t('general.cancelAction'),
positiveButtonProps: positiveButtonProps,
negativeButtonProps: negativeButtonProps,
autoFocus: false,
closable: false,
loading: loading.value,
onPositiveClick: async () => await deleteNode(node),
autoFocus: true,
closable: true,
onPositiveClick: async () => {
d.loading = true;
await deleteNode(node);
d.loading = false;
},
});
}
Expand Down

0 comments on commit 61013bc

Please sign in to comment.