Island: Fix representations.py to encode lists and objects
Previously lists and objects didn't get encoded. This forced explicit encoding on the endpoints, which is not necessary
This commit is contained in:
parent
cd839884eb
commit
da9f3c97ed
|
@ -6,35 +6,39 @@ from bson.json_util import dumps
|
||||||
from flask import make_response
|
from flask import make_response
|
||||||
|
|
||||||
|
|
||||||
def normalize_obj(obj):
|
def _normalize_obj(obj):
|
||||||
if ("_id" in obj) and ("id" not in obj):
|
if ("_id" in obj) and ("id" not in obj):
|
||||||
obj["id"] = obj["_id"]
|
obj["id"] = obj["_id"]
|
||||||
del obj["_id"]
|
del obj["_id"]
|
||||||
|
|
||||||
for key, value in list(obj.items()):
|
for key, value in list(obj.items()):
|
||||||
if isinstance(value, list):
|
obj[key] = _normalize_value(value)
|
||||||
for i in range(0, len(value)):
|
|
||||||
obj[key][i] = _normalize_value(value[i])
|
|
||||||
else:
|
|
||||||
obj[key] = _normalize_value(value)
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
def _normalize_value(value):
|
def _normalize_value(value):
|
||||||
|
if isinstance(value, list):
|
||||||
|
for i in range(0, len(value)):
|
||||||
|
value[i] = _normalize_value(value[i])
|
||||||
if type(value) == dict:
|
if type(value) == dict:
|
||||||
return normalize_obj(value)
|
return _normalize_obj(value)
|
||||||
if isinstance(value, bson.objectid.ObjectId):
|
if isinstance(value, bson.objectid.ObjectId):
|
||||||
return str(value)
|
return str(value)
|
||||||
if isinstance(value, datetime):
|
if isinstance(value, datetime):
|
||||||
return str(value)
|
return str(value)
|
||||||
if issubclass(type(value), Enum):
|
if issubclass(type(value), Enum):
|
||||||
return value.name
|
return value.name
|
||||||
else:
|
|
||||||
return value
|
try:
|
||||||
|
return value.__dict__
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
def output_json(obj, code, headers=None):
|
def output_json(value, code, headers=None):
|
||||||
obj = normalize_obj(obj)
|
value = _normalize_value(value)
|
||||||
resp = make_response(dumps(obj), code)
|
resp = make_response(dumps(value), code)
|
||||||
resp.headers.extend(headers or {})
|
resp.headers.extend(headers or {})
|
||||||
return resp
|
return resp
|
||||||
|
|
|
@ -1,55 +1,62 @@
|
||||||
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
import bson
|
import bson
|
||||||
|
|
||||||
from monkey_island.cc.services.representations import normalize_obj
|
from monkey_island.cc.services.representations import _normalize_value
|
||||||
|
|
||||||
|
|
||||||
class TestRepresentations(TestCase):
|
@dataclass
|
||||||
def test_normalize_obj(self):
|
class MockClass:
|
||||||
# empty
|
a: int
|
||||||
self.assertEqual({}, normalize_obj({}))
|
|
||||||
|
|
||||||
# no special content
|
|
||||||
self.assertEqual({"a": "a"}, normalize_obj({"a": "a"}))
|
|
||||||
|
|
||||||
# _id field -> id field
|
obj_id_str = "123456789012345678901234"
|
||||||
self.assertEqual({"id": 12345}, normalize_obj({"_id": 12345}))
|
mock_object = MockClass(1)
|
||||||
|
|
||||||
# obj id field -> str
|
|
||||||
obj_id_str = "123456789012345678901234"
|
|
||||||
self.assertEqual(
|
|
||||||
{"id": obj_id_str}, normalize_obj({"_id": bson.objectid.ObjectId(obj_id_str)})
|
|
||||||
)
|
|
||||||
|
|
||||||
# datetime -> str
|
def test_normalize_dicts():
|
||||||
dt = datetime.now()
|
assert {} == _normalize_value({})
|
||||||
expected = {"a": str(dt)}
|
|
||||||
result = normalize_obj({"a": dt})
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
# dicts and lists
|
assert {"a": "a"} == _normalize_value({"a": "a"})
|
||||||
self.assertEqual(
|
|
||||||
{"a": [{"ba": obj_id_str, "bb": obj_id_str}], "b": {"id": obj_id_str}},
|
|
||||||
normalize_obj(
|
|
||||||
{
|
|
||||||
"a": [
|
|
||||||
{
|
|
||||||
"ba": bson.objectid.ObjectId(obj_id_str),
|
|
||||||
"bb": bson.objectid.ObjectId(obj_id_str),
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"b": {"_id": bson.objectid.ObjectId(obj_id_str)},
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_normalize__enum(self):
|
assert {"id": 12345} == _normalize_value({"_id": 12345})
|
||||||
class BogusEnum(Enum):
|
|
||||||
bogus_val = "Bogus"
|
|
||||||
|
|
||||||
my_obj = {"something": "something", "my_enum": BogusEnum.bogus_val}
|
assert {"id": obj_id_str} == _normalize_value({"_id": bson.objectid.ObjectId(obj_id_str)})
|
||||||
|
|
||||||
assert {"something": "something", "my_enum": "bogus_val"} == normalize_obj(my_obj)
|
dt = datetime.now()
|
||||||
|
expected = {"a": str(dt)}
|
||||||
|
result = _normalize_value({"a": dt})
|
||||||
|
assert expected == result
|
||||||
|
|
||||||
|
|
||||||
|
def test_normalize_complex():
|
||||||
|
mock_dict = {
|
||||||
|
"a": [
|
||||||
|
{
|
||||||
|
"ba": bson.objectid.ObjectId(obj_id_str),
|
||||||
|
"bb": bson.objectid.ObjectId(obj_id_str),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"b": {"_id": bson.objectid.ObjectId(obj_id_str)},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_dict = {"a": [{"ba": obj_id_str, "bb": obj_id_str}], "b": {"id": obj_id_str}}
|
||||||
|
assert expected_dict == _normalize_value(mock_dict)
|
||||||
|
|
||||||
|
|
||||||
|
def test_normalize_list():
|
||||||
|
mock_list = [bson.objectid.ObjectId(obj_id_str), {"a": "b"}, {"object": [mock_object]}]
|
||||||
|
|
||||||
|
expected_list = [obj_id_str, {"a": "b"}, {"object": [{"a": 1}]}]
|
||||||
|
assert expected_list == _normalize_value(mock_list)
|
||||||
|
|
||||||
|
|
||||||
|
def test_normalize__enum():
|
||||||
|
class BogusEnum(Enum):
|
||||||
|
bogus_val = "Bogus"
|
||||||
|
|
||||||
|
my_obj = {"something": "something", "my_enum": BogusEnum.bogus_val}
|
||||||
|
|
||||||
|
assert {"something": "something", "my_enum": "bogus_val"} == _normalize_value(my_obj)
|
||||||
|
|
Loading…
Reference in New Issue