aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--backend/routes/forms/form.py22
-rw-r--r--poetry.lock48
-rw-r--r--pyproject.toml1
3 files changed, 46 insertions, 25 deletions
diff --git a/backend/routes/forms/form.py b/backend/routes/forms/form.py
index b87c7cf..8ecfdf6 100644
--- a/backend/routes/forms/form.py
+++ b/backend/routes/forms/form.py
@@ -1,15 +1,16 @@
"""
Returns, updates or deletes a single form given an ID.
"""
+import deepmerge
from pydantic import ValidationError
from spectree.response import Response
from starlette.authentication import requires
from starlette.requests import Request
from starlette.responses import JSONResponse
-from backend.route import Route
from backend.models import Form
-from backend.validation import OkayResponse, api, ErrorMessage
+from backend.route import Route
+from backend.validation import ErrorMessage, OkayResponse, api
class SingleForm(Route):
@@ -53,15 +54,22 @@ class SingleForm(Route):
"""Updates form by ID."""
data = await request.json()
- if raw_form := await request.state.db.forms.find_one(
- {"_id": request.path_params["form_id"]}
- ):
+ form_id = {"_id": request.path_params["form_id"]}
+ if raw_form := await request.state.db.forms.find_one(form_id):
if "_id" in data or "id" in data:
return JSONResponse({"error": "locked_field"}, status_code=400)
- raw_form.update(data)
+ # Build Data Merger
+ merge_strategy = [
+ (dict, ["merge"])
+ ]
+ merger = deepmerge.Merger(merge_strategy, ["override"], ["override"])
+
+ # Merge Form Data
+ updated_form = merger.merge(raw_form, data)
+
try:
- form = Form(**raw_form)
+ form = Form(**updated_form)
except ValidationError as e:
return JSONResponse(e.errors(), status_code=422)
diff --git a/poetry.lock b/poetry.lock
index 9a4c95d..785fec6 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -23,6 +23,14 @@ optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
+name = "deepmerge"
+version = "0.1.1"
+description = "a toolset to deeply merge python dictionaries."
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
name = "flake8"
version = "3.8.4"
description = "the modular source code checker: pep8 pyflakes and co"
@@ -55,10 +63,10 @@ optional = false
python-versions = ">=3.4"
[package.extras]
-tornado = ["tornado (>=0.2)"]
+eventlet = ["eventlet (>=0.9.7)"]
gevent = ["gevent (>=0.13)"]
setproctitle = ["setproctitle"]
-eventlet = ["eventlet (>=0.9.7)"]
+tornado = ["tornado (>=0.2)"]
[[package]]
name = "h11"
@@ -165,8 +173,8 @@ python-versions = ">=3.6"
[package.extras]
dotenv = ["python-dotenv (>=0.10.4)"]
-typing_extensions = ["typing-extensions (>=3.7.2)"]
email = ["email-validator (>=1.0.3)"]
+typing_extensions = ["typing-extensions (>=3.7.2)"]
[[package]]
name = "pyflakes"
@@ -185,9 +193,9 @@ optional = false
python-versions = "*"
[package.extras]
-test = ["pytest (>=4.0.1,<5.0.0)", "pytest-cov (>=2.6.0,<3.0.0)", "pytest-runner (>=4.2,<5.0.0)"]
crypto = ["cryptography (>=1.4)"]
flake8 = ["flake8", "flake8-import-order", "pep8-naming"]
+test = ["pytest (>=4.0.1,<5.0.0)", "pytest-cov (>=2.6.0,<3.0.0)", "pytest-runner (>=4.2,<5.0.0)"]
[[package]]
name = "pymongo"
@@ -198,14 +206,14 @@ optional = false
python-versions = "*"
[package.extras]
-tls = ["ipaddress"]
-encryption = ["pymongocrypt (<2.0.0)"]
aws = ["pymongo-auth-aws (<2.0.0)"]
+encryption = ["pymongocrypt (<2.0.0)"]
gssapi = ["pykerberos"]
+ocsp = ["pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"]
snappy = ["python-snappy"]
srv = ["dnspython (>=1.16.0,<1.17.0)"]
+tls = ["ipaddress"]
zstd = ["zstandard"]
-ocsp = ["pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"]
[[package]]
name = "python-dotenv"
@@ -260,9 +268,9 @@ python-versions = ">=3.6"
pydantic = ">=1.2"
[package.extras]
-flask = ["flask"]
-falcon = ["falcon"]
dev = ["pytest (>=6)", "flake8 (>=3.8)", "black (>=20.8b1)", "isort (>=5.6)", "autoflake (>=1.4)"]
+falcon = ["falcon"]
+flask = ["flask"]
starlette = ["starlette"]
[[package]]
@@ -278,21 +286,21 @@ full = ["aiofiles", "graphene", "itsdangerous", "jinja2", "python-multipart", "p
[[package]]
name = "uvicorn"
-version = "0.13.1"
+version = "0.13.2"
description = "The lightning-fast ASGI server."
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
-PyYAML = {version = ">=5.1", optional = true, markers = "extra == \"standard\""}
-uvloop = {version = ">=0.14.0", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""}
+click = ">=7.0.0,<8.0.0"
+colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""}
h11 = ">=0.8"
-watchgod = {version = ">=0.6,<0.7", optional = true, markers = "extra == \"standard\""}
httptools = {version = ">=0.1.0,<0.2.0", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""}
-colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""}
python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""}
-click = ">=7.0.0,<8.0.0"
+PyYAML = {version = ">=5.1", optional = true, markers = "extra == \"standard\""}
+uvloop = {version = ">=0.14.0", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""}
+watchgod = {version = ">=0.6,<0.7", optional = true, markers = "extra == \"standard\""}
websockets = {version = ">=8.0.0,<9.0.0", optional = true, markers = "extra == \"standard\""}
[package.extras]
@@ -325,7 +333,7 @@ python-versions = ">=3.6.1"
[metadata]
lock-version = "1.1"
python-versions = "^3.9"
-content-hash = "ba96cffc23bdf274acd85b4a4134fa76d7dfa06d135184282f28929957fea82e"
+content-hash = "7584e4eacc1b2615adce06899fe6e6b8d696955fea97533ccac2bd2c642e136f"
[metadata.files]
certifi = [
@@ -340,6 +348,10 @@ colorama = [
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
]
+deepmerge = [
+ {file = "deepmerge-0.1.1-py2.py3-none-any.whl", hash = "sha256:190e133a6657303db37f9bb302aa853d8d2b15a0e055d41b99a362598e79206a"},
+ {file = "deepmerge-0.1.1.tar.gz", hash = "sha256:fa1d44269786bcc12d30a7471b0b39478aa37a43703b134d7f12649792f92c1f"},
+]
flake8 = [
{file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"},
{file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"},
@@ -531,8 +543,8 @@ starlette = [
{file = "starlette-0.14.1.tar.gz", hash = "sha256:5268ef5d4904ec69582d5fd207b869a5aa0cd59529848ba4cf429b06e3ced99a"},
]
uvicorn = [
- {file = "uvicorn-0.13.1-py3-none-any.whl", hash = "sha256:6fcce74c00b77d4f4b3ed7ba1b2a370d27133bfdb46f835b7a76dfe0a8c110ae"},
- {file = "uvicorn-0.13.1.tar.gz", hash = "sha256:2a7b17f4d9848d6557ccc2274a5f7c97f1daf037d130a0c6918f67cd9bc8cdf5"},
+ {file = "uvicorn-0.13.2-py3-none-any.whl", hash = "sha256:6707fa7f4dbd86fd6982a2d4ecdaad2704e4514d23a1e4278104311288b04691"},
+ {file = "uvicorn-0.13.2.tar.gz", hash = "sha256:d19ca083bebd212843e01f689900e5c637a292c63bb336c7f0735a99300a5f38"},
]
uvloop = [
{file = "uvloop-0.14.0-cp35-cp35m-macosx_10_11_x86_64.whl", hash = "sha256:08b109f0213af392150e2fe6f81d33261bb5ce968a288eb698aad4f46eb711bd"},
diff --git a/pyproject.toml b/pyproject.toml
index 49e0f43..642fb6c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -17,6 +17,7 @@ httpx = "^0.16.1"
gunicorn = "^20.0.4"
pydantic = "^1.7.2"
spectree = "^0.3.16"
+deepmerge = "^0.1.1"
[tool.poetry.dev-dependencies]
flake8 = "^3.8.4"