def preprocessJsonObject(o): """ Add support for Keys, Datetime, Bytes and db.Entities in deferred tasks. This is not a subclass of json.JSONEncoder anymore, as db.Entites are a subclass of dict, which is always handled from the json module itself. """ if isinstance(o, db.KeyClass): return {".__key__": db.encodeKey(o)} elif isinstance(o, datetime): return { ".__datetime__": o.astimezone(pytz.UTC).strftime("d.%m.%Y %H:%M:%S") } elif isinstance(o, bytes): return {".__bytes__": base64.b64encode(o).decode("ASCII")} elif isinstance(o, db.Entity): return { ".__entity__": preprocessJsonObject(dict(o)), ".__ekey__": db.encodeKey(o.key) if o.key else None } elif isinstance(o, dict): return { preprocessJsonObject(k): preprocessJsonObject(v) for k, v in o.items() } elif isinstance(o, (list, tuple, set)): return [preprocessJsonObject(x) for x in o] else: return o
def default(self, o: Any) -> Any: if isinstance(o, translate): return str(o) elif isinstance(o, datetime): return o.isoformat() elif isinstance(o, db.Key): return db.encodeKey(o) return json.JSONEncoder.default(self, o)
def default(self, o: Any) -> Any: if isinstance(o, db.KeyClass): return {".__key__": db.encodeKey(o)} elif isinstance(o, datetime): return { ".__datetime__": o.astimezone(pytz.UTC).strftime("d.%m.%Y %H:%M:%S") } elif isinstance(o, bytes): return {".__bytes__": base64.b64encode(o).decode("ASCII")} return json.JSONEncoder.default(self, o)
def renderSingleBoneValue(self, value, bone, skel, key): """ Renders the value of a bone. This function is used by :func:`collectSkelData`. It can be overridden and super-called from a custom renderer. :param bone: The bone which value should be rendered. :type bone: Any bone that inherits from :class:`server.bones.base.baseBone`. :return: A dict containing the rendered attributes. :rtype: dict """ if bone.type == "date" or bone.type.startswith("date."): if value: if bone.date and bone.time: return value.strftime("%d.%m.%Y %H:%M:%S") elif bone.date: return value.strftime("%d.%m.%Y") return value.strftime("%H:%M:%S") elif isinstance(bone, bones.relationalBone): if isinstance(value, dict): return { "dest": self.renderSkelValues(value["dest"], injectDownloadURL=isinstance( bone, bones.fileBone)), "rel": self.renderSkelValues(value["rel"], injectDownloadURL=isinstance( bone, bones.fileBone)) if value["rel"] else None, } elif isinstance(bone, bones.recordBone): return self.renderSkelValues(value) elif isinstance(bone, bones.keyBone): return db.encodeKey(value) if value else None else: return value return None
def initializeUpload(self, fileName: str, mimeType: str, node: Union[str, None], size: Union[int, None] = None) -> Tuple[str, str]: """ Internal helper that registers a new upload. Will create the pending fileSkel entry (needed to remove any started uploads from GCS if that file isn't used) and creates a resumable (and signed) uploadURL for that. :param fileName: Name of the file that will be uploaded :param mimeType: Mimetype of said file :param node: If set (to a string-key representation of a file-node) the upload will be written to this directory :param size: The *exact* filesize we're accepting in Bytes. Used to enforce a filesize limit by getUploadURL :return: Str-Key of the new file-leaf entry, the signed upload-url """ global bucket fileName = sanitizeFileName(fileName) targetKey = utils.generateRandomString() blob = bucket.blob("%s/source/%s" % (targetKey, fileName)) uploadUrl = blob.create_resumable_upload_session(content_type=mimeType, size=size, timeout=60) # Create a corresponding file-lock object early, otherwise we would have to ensure that the file-lock object # the user creates matches the file he had uploaded fileSkel = self.addSkel("leaf") fileSkel["name"] = "pending" fileSkel["size"] = 0 fileSkel["mimetype"] = "application/octetstream" fileSkel["dlkey"] = targetKey fileSkel["parentdir"] = None fileSkel["pendingparententry"] = db.keyHelper( node, self.addSkel("node").kindName) if node else None fileSkel["pending"] = True fileSkel["weak"] = True fileSkel["width"] = 0 fileSkel["height"] = 0 fileSkel.toDB() # Mark that entry dirty as we might never receive an add utils.markFileForDeletion(targetKey) return db.encodeKey(fileSkel["key"]), uploadUrl
def renderBoneValue(self, bone, skel, key, boneValue, isLanguageWrapped: bool = False): """ Renders the value of a bone. This function is used by :func:`collectSkelData`. It can be overridden and super-called from a custom renderer. :param bone: The bone which value should be rendered. :type bone: Any bone that inherits from :class:`server.bones.base.baseBone`. :return: A dict containing the rendered attributes. :rtype: dict """ if bone.languages and not isLanguageWrapped: res = LanguageWrapper(bone.languages) if isinstance(boneValue, dict): for language in bone.languages: if language in boneValue: res[language] = self.renderBoneValue( bone, skel, key, boneValue[language], True) return res elif bone.type == "select" or bone.type.startswith("select."): skelValue = boneValue if isinstance(skelValue, list): return {val: bone.values.get(val, val) for val in boneValue} elif skelValue in bone.values: return KeyValueWrapper(skelValue, bone.values[skelValue]) return KeyValueWrapper(skelValue, str(skelValue)) elif bone.type == "relational" or bone.type.startswith("relational."): if isinstance(boneValue, list): tmpList = [] for k in boneValue: if not k: continue if bone.using is not None and k["rel"]: k["rel"].renderPreparation = self.renderBoneValue usingData = k["rel"] else: usingData = None k["dest"].renderPreparation = self.renderBoneValue tmpList.append({"dest": k["dest"], "rel": usingData}) return tmpList elif isinstance(boneValue, dict): if bone.using is not None and boneValue["rel"]: boneValue["rel"].renderPreparation = self.renderBoneValue usingData = boneValue["rel"] else: usingData = None boneValue["dest"].renderPreparation = self.renderBoneValue return {"dest": boneValue["dest"], "rel": usingData} elif bone.type == "record" or bone.type.startswith("record."): value = boneValue if value: if bone.multiple: ret = [] for entry in value: entry.renderPreparation = self.renderBoneValue ret.append(entry) return ret value.renderPreparation = self.renderBoneValue return value elif bone.type == "password": return "" elif bone.type == "key": return db.encodeKey(boneValue) if boneValue else None else: return boneValue return None
def listRootNodes(self, rootNodes, tpl=None, params=None): for rn in rootNodes: rn["key"] = db.encodeKey(rn["key"]) return json.dumps(rootNodes)
def renderBoneValue(self, bone, skel, key, boneValue): """ Renders the value of a bone. This function is used by :func:`collectSkelData`. It can be overridden and super-called from a custom renderer. :param bone: The bone which value should be rendered. :type bone: Any bone that inherits from :class:`server.bones.base.baseBone`. :return: A dict containing the rendered attributes. :rtype: dict """ if bone.type == "select" or bone.type.startswith("select."): skelValue = boneValue if isinstance(skelValue, list): return {val: bone.values.get(val, val) for val in boneValue} elif skelValue in bone.values: return KeyValueWrapper(skelValue, bone.values[skelValue]) return KeyValueWrapper(skelValue, str(skelValue)) elif bone.type == "relational" or bone.type.startswith("relational."): if isinstance(boneValue, list): tmpList = [] for k in boneValue: if bone.using is None: tmpList.append(self.collectSkelData(k["dest"])) else: #usingSkel = bone._usingSkelCache if k["rel"]: usingData = self.collectSkelData(k["rel"]) else: usingData = None tmpList.append({ "dest": self.collectSkelData(k["dest"]), "rel": usingData }) return tmpList elif isinstance(boneValue, dict): if bone.using is None: return self.collectSkelData(boneValue["dest"]) else: #usingSkel = bone._usingSkelCache if boneValue["rel"]: usingData = self.collectSkelData(boneValue["rel"]) else: usingData = None return { "dest": self.collectSkelData(boneValue["dest"]), "rel": usingData } elif bone.type == "record" or bone.type.startswith("record."): value = boneValue if value: ret = [] for entry in value: ret.append(self.collectSkelData(entry)) return ret elif bone.type == "key": return db.encodeKey(boneValue) if boneValue else None else: return boneValue return None