Skip to content
This repository was archived by the owner on Sep 29, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bones/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
from server.bones.emailBone import emailBone
from server.bones.randomSliceBone import randomSliceBone
from server.bones.spatialBone import spatialBone
from server.bones.recordBone import recordBone
231 changes: 231 additions & 0 deletions bones/recordBone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
# -*- coding: utf-8 -*-
from server.bones.bone import baseBone, getSystemInitialized
from server.errors import ReadFromClientError
import extjson


class recordBone(baseBone):
type = "record"

def __init__(self, using, format=None, indexed=False, multiple=True, *args, **kwargs):
super(recordBone, self).__init__(indexed=indexed, multiple=multiple, *args, **kwargs)

self.using = using
self.format = format
if not format or indexed or not multiple:
NotImplemented("A recordBone must not be indexed, must be multiple and must have a format set")

if getSystemInitialized():
self._usingSkelCache = using()
else:
self._usingSkelCache = None

def setSystemInitialized(self):
super(recordBone, self).setSystemInitialized()
self._usingSkelCache = self.using()


def _restoreValueFromDatastore(self, val):
"""
Restores one of our values from the serialized data read from the datastore

:param value: Json-Encoded datastore property

:return: Our Value (with restored usingSkel data)
"""
value = extjson.loads(val)
assert isinstance(value, dict), "Read something from the datastore thats not a dict: %s" % str(type(value))

usingSkel = self._usingSkelCache
usingSkel.setValuesCache({})
usingSkel.unserialize(value)

return usingSkel.getValuesCache()

def unserialize(self, valuesCache, name, expando):
if name not in expando:
valuesCache[name] = None
return True

val = expando[name]

if self.multiple:
valuesCache[name] = []

if not val:
return True

if isinstance(val, list):
for res in val:
try:
valuesCache[name].append(self._restoreValueFromDatastore(res))
except:
raise
else:
try:
valuesCache[name].append(self._restoreValueFromDatastore(val))
except:
raise


return True

def serialize(self, valuesCache, name, entity):
if not valuesCache[name]:
entity.set(name, None, False)

else:
usingSkel = self._usingSkelCache
res = []

for val in valuesCache[name]:
usingSkel.setValuesCache(val)
res.append(extjson.dumps(usingSkel.serialize()))

entity.set(name, res, False)

return entity

def fromClient(self, valuesCache, name, data):
valuesCache[name] = []
tmpRes = {}

clientPrefix = "%s." % name

for k, v in data.items():
#print(k, v)

if k.startswith(clientPrefix) or k == name:
if k == name:
k = k.replace(name, "", 1)

else:
k = k.replace(clientPrefix, "", 1)

if "." in k:
try:
idx, bname = k.split(".", 1)
idx = int(idx)
except ValueError:
idx = 0

try:
bname = k.split(".", 1)
except ValueError:
# We got some garbage as input; don't try to parse it
continue

else:
idx = 0
bname = k

if not bname:
continue

if not idx in tmpRes:
tmpRes[idx] = {}

if bname in tmpRes[idx]:
if isinstance(tmpRes[idx][bname], list):
tmpRes[idx][bname].append(v)
else:
tmpRes[idx][bname] = [tmpRes[idx][bname], v]
else:
tmpRes[idx][bname] = v

tmpList = [tmpRes[k] for k in sorted(tmpRes.keys())]

errorDict = {}
forceFail = False

for i, r in enumerate(tmpList[:]):
usingSkel = self._usingSkelCache
usingSkel.setValuesCache({})

if not usingSkel.fromClient(r):
for k, v in usingSkel.errors.items():
errorDict["%s.%d.%s" % (name, i, k)] = v
forceFail = True

tmpList[i] = usingSkel.getValuesCache()

cleanList = []

for item in tmpList:
err = self.isInvalid(item)
if err:
errorDict["%s.%s" % (name, tmpList.index(item))] = err
else:
cleanList.append(item)

valuesCache[name] = tmpList

if not cleanList:
if not (self.required or errorDict):
# Returning a error will only cause a warning if we are not required
return "No value selected!"
errorDict[name] = "No value selected"

if len(errorDict.keys()):
return ReadFromClientError(errorDict, forceFail)

return None

def getSearchTags(self, values, key):
def getValues(res, skel, valuesCache):
for k, bone in skel.items():
if bone.searchable:
for tag in bone.getSearchTags(valuesCache, k):
if tag not in res:
res.append(tag)
return res

value = values.get(key)
res = []

if not value:
return res

for val in value:
res = getValues(res, self._usingSkelCache, val)

return res

def getSearchDocumentFields(self, valuesCache, name, prefix=""):
def getValues(res, skel, valuesCache, searchPrefix):
for key, bone in skel.items():
if bone.searchable:
res.extend(bone.getSearchDocumentFields(valuesCache, key, prefix=searchPrefix))

value = valuesCache.get(name)
res = []

if not value:
return res

for idx, val in enumerate(value):
getValues(res, self._usingSkelCache, val, "%s%s_%s" % (prefix, name, str(idx)))

return res

def getReferencedBlobs(self, valuesCache, name):
def blobsFromSkel(skel, valuesCache):
blobList = set()
for key, _bone in skel.items():
blobList.update(_bone.getReferencedBlobs(valuesCache, key))
return blobList

res = set()
value = valuesCache.get(name)

if not value:
return res

if isinstance(value, list):
for val in value:
res.update(blobsFromSkel(self._usingSkelCache, val))

elif isinstance(value, dict):
res.update(blobsFromSkel(self._usingSkelCache, value))

return res
22 changes: 19 additions & 3 deletions render/html/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,8 @@ def renderBoneValue(self, bone, skel, key):
elif skelValue in bone.values:
return KeyValueWrapper(skelValue, bone.values[skelValue])
return skelValue
elif bone.type=="relational" or bone.type.startswith("relational."):

elif bone.type == "relational" or bone.type.startswith("relational."):
if isinstance(skel[key], list):
tmpList = []
for k in skel[key]:
Expand Down Expand Up @@ -350,8 +351,23 @@ def renderBoneValue(self, bone, skel, key):
"dest": self.collectSkelData(refSkel),
"rel": usingData
}
else:
return None

elif bone.type == "record" or bone.type.startswith("record."):
usingSkel = bone._usingSkelCache
value = skel[key]

if isinstance(value, list):
ret = []
for entry in value:
usingSkel.setValuesCache(entry)
ret.append(self.collectSkelData(usingSkel))

return ret

elif isinstance(value, dict):
usingSkel.setValuesCache(value)
return self.collectSkelData(usingSkel)

else:
return skel[key]

Expand Down
6 changes: 6 additions & 0 deletions render/json/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ def renderBoneStructure(self, bone):
"relskel": self.renderSkelStructure(RefSkel.fromSkel(skeletonByKind(bone.kind), *bone.refKeys))
})

elif bone.type == "record" or bone.type.startswith("record."):
ret.update({
"multiple": bone.multiple,
"format": bone.format,
"using": self.renderSkelStructure(bone.using())
})

elif bone.type == "select" or bone.type.startswith("select."):
ret.update({
Expand Down