def view(self, *args, **kwargs): """ Prepares and renders a single entry for viewing. The entry is fetched by its entity key, which either is provided via *kwargs["key"]*, or as the first parameter in *args*. The function performs several access control checks on the requested entity before it is rendered. .. seealso:: :func:`viewSkel`, :func:`canView`, :func:`onItemViewed` :returns: The rendered representation of the requested entity. :raises: :exc:`server.errors.NotAcceptable`, when no *key* is provided. :raises: :exc:`server.errors.NotFound`, when no entry with the given *key* was found. :raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions. """ if "key" in kwargs: key = kwargs["key"] elif len(args) >= 1: key = args[0] else: raise errors.NotAcceptable() if not len(key): raise errors.NotAcceptable() skel = self.viewSkel() if not skel.fromDB(key): raise errors.NotFound() if not self.canView(skel): raise errors.Unauthorized() self.onItemViewed(skel) return self.render.view(skel)
def edit(self, *args, **kwargs): """ Modify an existing entry, and render the entry, eventually with error notes on incorrect data. Data is taken by any other arguments in *kwargs*. The entry is fetched by its entity key, which either is provided via *kwargs["key"]*, or as the first parameter in *args*. The function performs several access control checks on the requested entity before it is modified. .. seealso:: :func:`editSkel`, :func:`onItemEdited`, :func:`canEdit` :returns: The rendered, edited object of the entry, eventually with error hints. :raises: :exc:`server.errors.NotAcceptable`, when no *key* is provided. :raises: :exc:`server.errors.NotFound`, when no entry with the given *key* was found. :raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions. :raises: :exc:`server.errors.PreconditionFailed`, if the *skey* could not be verified. """ if "skey" in kwargs: skey = kwargs["skey"] else: skey = "" if "key" in kwargs: key = kwargs["key"] elif len(args) == 1: key = args[0] else: raise errors.NotAcceptable() skel = self.editSkel() if not skel.fromDB(key): raise errors.NotAcceptable() if not self.canEdit(skel): raise errors.Unauthorized() if (len(kwargs) == 0 # no data supplied or skey == "" # no security key or not request.current.get(). isPostRequest # failure if not using POST-method or not skel.fromClient( kwargs) # failure on reading into the bones or ("bounce" in list(kwargs.keys()) and kwargs["bounce"] == "1" ) # review before changing ): # render the skeleton in the version it could as far as it could be read. return self.render.edit(skel) if not securitykey.validate(skey, acceptSessionKey=True): raise errors.PreconditionFailed() skel.toDB() # write it! self.onItemEdited(skel) return self.render.editItemSuccess(skel)
def reparent(self, item, dest, skey, *args, **kwargs): """ Moves an entry *item* (and everything beneath it) to another parent-node *dest*. .. seealso:: :func:`canReparent` :param item: URL-safe key of the item which will be moved. :type item: str :param dest: URL-safe key of the new parent for this item. :type dest: str :returns: A rendered success result generated by the default renderer. :raises: :exc:`server.errors.NotFound`, when no entry with the given *id* was found. :raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions. :raises: :exc:`server.errors.PreconditionFailed`, if the *skey* could not be verified. """ if not securitykey.validate(skey, acceptSessionKey=True): raise errors.PreconditionFailed() if not self.canReparent(item, dest): raise errors.Unauthorized() if not self.isValidParent(dest) or item == dest: raise errors.NotAcceptable() ## Test for recursion isValid = False currLevel = db.Get(dest) for x in range(0, 99): if str(currLevel.key()) == item: break if currLevel.key().kind( ) == self.viewSkel().kindName + "_rootNode": # We reached a rootNode isValid = True break currLevel = db.Get(currLevel["parententry"]) if not isValid: raise errors.NotAcceptable() ## Update entry fromItem = db.Get(item) fromItem["parententry"] = dest fromItem["parentrepo"] = str(self.getRootNode(dest).key()) db.Put(fromItem) skel = self.editSkel() assert skel.fromDB(item) self.onItemReparent(skel) self.onItemChanged(skel) return self.render.reparentSuccess(obj=fromItem)
def view(self, *args, **kwargs): """ Prepares and renders a single entry for viewing. The entry is fetched by its entity key, which either is provided via *kwargs["key"]*, or as the first parameter in *args*. The function performs several access control checks on the requested entity before it is rendered. .. seealso:: :func:`viewSkel`, :func:`canView`, :func:`onItemViewed` :returns: The rendered representation of the requested entity. :raises: :exc:`server.errors.NotAcceptable`, when no *key* is provided. :raises: :exc:`server.errors.NotFound`, when no entry with the given *key* was found. :raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions. """ if "key" in kwargs: key = kwargs["key"] elif len(args) >= 1: key = args[0] else: raise errors.NotAcceptable() if not len(key): raise errors.NotAcceptable() skel = self.viewSkel() if key == u"structure": # We dump just the structure of that skeleton, including it's default values if "canView" in dir(self): if not self.canView(skel): raise errors.Unauthorized() else: if self.listFilter(self.viewSkel().all()) is None: raise errors.Unauthorized() else: # We return a single entry for viewing if "canView" in dir(self): if not skel.fromDB(key): raise errors.NotFound() if not self.canView(skel): raise errors.Unauthorized() else: queryObj = self.viewSkel().all().mergeExternalFilter( {"key": key}) queryObj = self.listFilter(queryObj) #Access control if queryObj is None: raise errors.Unauthorized() skel = queryObj.getSkel() if not skel: raise errors.NotFound() self.onItemViewed(skel) return self.render.view(skel)
def list(self, skelType, node, *args, **kwargs): """ List the entries and directories of the given *skelType* under the given *node*. Any other supplied parameters are interpreted as filters for the elements displayed. .. seealso:: :func:`canList`, :func:`server.db.mergeExternalFilter` :param skelType: May either be "node" or "leaf". :type skelType: str :param node: URL-safe key of the parent. :type node: str :returns: The rendered list objects for the matching entries. :raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions. :raises: :exc:`server.errors.NotFound`, if *node* could not be found. :raises: :exc:`server.errors.NotAcceptable`, if anything else than "node" or "leaf" is provided to *skelType*. """ if skelType == "node": skel = self.viewNodeSkel() elif skelType == "leaf": skel = self.viewLeafSkel() else: raise errors.NotAcceptable() if skel is None: raise errors.NotAcceptable() if not self.canList(skelType, node): raise errors.Unauthorized() nodeSkel = self.viewNodeSkel() if not nodeSkel.fromDB(node): raise errors.NotFound() query = skel.all() if "search" in kwargs and kwargs["search"]: query.filter("parentrepo =", str(nodeSkel["key"])) else: query.filter("parentdir =", str(nodeSkel["key"])) query.mergeExternalFilter(kwargs) res = query.fetch() return self.render.list(res, node=str(nodeSkel["key"]))
def view(self, skelType, key, *args, **kwargs): """ Prepares and renders a single entry for viewing. The entry is fetched by its *key* and its *skelType*. The function performs several access control checks on the requested entity before it is rendered. .. seealso:: :func:`canView`, :func:`onItemViewed` :returns: The rendered representation of the requested entity. :param skelType: May either be "node" or "leaf". :type skelType: str :param node: URL-safe key of the parent. :type node: str :raises: :exc:`server.errors.NotAcceptable`, when an incorrect *skelType* is provided. :raises: :exc:`server.errors.NotFound`, when no entry with the given *key* was found. :raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions. """ if skelType == "node": skel = self.viewNodeSkel() elif skelType == "leaf": skel = self.viewLeafSkel() else: raise errors.NotAcceptable() if skel is None: raise errors.NotAcceptable() if not len(key): raise errors.NotAcceptable() if key == u"structure": # We dump just the structure of that skeleton, including it's default values if not self.canView(skelType, None): raise errors.Unauthorized() else: # We return a single entry for viewing if not skel.fromDB(key): raise errors.NotFound() if not self.canView(skelType, skel): raise errors.Unauthorized() self.onItemViewed(skel) return self.render.view(skel)
def clone(self, fromRepo, toRepo, fromParent=None, toParent=None, *args, **kwargs): """ Clones a hierarchy recursively. This function only initiates the cloning process, which is performed in the background. It states only a successful result when the clone action has been correctly initiated. :param fromRepo: URL-safe key of the key to the repository (=root-node Key) to clone from. :type fromRepo: str :param toRepo: URL-safe key of the key to the repository (=root-node Key) to clone to. :type toRepo: str :param fromParent: URL-safe key of the parent to clone from; for root nodes, this is equal \ to fromRepo, and can be omitted. :type fromParent: str :param toParent: URL-safe key of the parent to clone to; for root nodes, this is equal to \ toRepo, and can be omitted. :type toParent: str :returns: A rendered success result generated by the default renderer. :raises: :exc:`server.errors.NotAcceptable`, when no valid *parent* was found. :raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions. :raises: :exc:`server.errors.PreconditionFailed`, if the *skey* could not be verified. """ if "skey" in kwargs: skey = kwargs["skey"] else: skey = "" if fromParent is None: fromParent = fromRepo if toParent is None: toParent = toRepo if not (self.isValidParent(fromParent) and self.isValidParent(toParent)): # Ensure the parents exists raise errors.NotAcceptable() if not self.canAdd(toParent): raise errors.Unauthorized() if not securitykey.validate(skey, acceptSessionKey=True): raise errors.PreconditionFailed() self._clone(fromRepo, toRepo, fromParent, toParent) return self.render.cloneSuccess()
def edit(self, skelType, key, skey="", *args, **kwargs): """ Modify an existing entry, and render the entry, eventually with error notes on incorrect data. Data is taken by any other arguments in *kwargs*. The function performs several access control checks on the requested entity before it is added. .. seealso:: :func:`onItemAdded`, :func:`canEdit` :param skelType: Defines the type of the entry that should be modified and may either be "node" or "leaf". :type skelType: str :param key: URL-safe key of the item to be edited. :type key: str :returns: The rendered, modified object of the entry, eventually with error hints. :raises: :exc:`server.errors.NotAcceptable`, when no valid *skelType* was provided. :raises: :exc:`server.errors.NotFound`, when no valid *node* was found. :raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions. :raises: :exc:`server.errors.PreconditionFailed`, if the *skey* could not be verified. """ if skelType == "node": skel = self.editNodeSkel() elif skelType == "leaf": skel = self.editLeafSkel() else: raise errors.NotAcceptable() if not skel.fromDB(key): raise errors.NotFound() if not self.canEdit(skelType, skel): raise errors.Unauthorized() if (len(kwargs) == 0 # no data supplied or skey == "" # no security key #or not request.current.get().isPostRequest fixme: POST-method check missing? # failure if not using POST-method or not skel.fromClient( kwargs) # failure on reading into the bones or ("bounce" in kwargs and kwargs["bounce"] == "1" ) # review before adding ): return self.render.edit(skel) if not securitykey.validate(skey, acceptSessionKey=True): raise errors.PreconditionFailed() skel.toDB() self.onItemEdited(skel) return self.render.editItemSuccess(skel)
def delete(self, skelType, key, *args, **kwargs): """ Deletes an entry or an directory (including its contents). The function runs several access control checks on the data before it is deleted. .. seealso:: :func:`canDelete`, :func:`onItemDeleted` :param skelType: Defines the type of the entry that should be deleted and may either be "node" or "leaf". :type skelType: str :param key: URL-safe key of the item to be deleted. :type key: str :returns: The rendered, deleted object of the entry. :raises: :exc:`server.errors.NotFound`, when no entry with the given *key* was found. :raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions. :raises: :exc:`server.errors.PreconditionFailed`, if the *skey* could not be verified. """ if skelType == "node": skel = self.viewNodeSkel() elif skelType == "leaf": skel = self.viewLeafSkel() else: raise errors.NotAcceptable() if "skey" in kwargs: skey = kwargs["skey"] else: skey = "" if not skel.fromDB(key): raise errors.NotFound() if not self.canDelete(skelType, skel): raise errors.Unauthorized() if not securitykey.validate(skey, acceptSessionKey=True): raise errors.PreconditionFailed() if type == "leaf": skel.delete() else: self.deleteRecursive(key) skel.delete() self.onItemDeleted(skel) return (self.render.deleteSuccess(skel, skelType=skelType))
def add(self, parent, *args, **kwargs): """ Add a new entry with the given parent, and render the entry, eventually with error notes on incorrect data. Data is taken by any other arguments in *kwargs*. The function performs several access control checks on the requested entity before it is added. .. seealso:: :func:`addSkel`, :func:`onItemAdded`, :func:`canAdd` :param parent: URL-safe key of the parent. :type parent: str :returns: The rendered, added object of the entry, eventually with error hints. :raises: :exc:`server.errors.NotAcceptable`, when no valid *parent* was found. :raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions. :raises: :exc:`server.errors.PreconditionFailed`, if the *skey* could not be verified. """ if "skey" in kwargs: skey = kwargs["skey"] else: skey = "" if not self.isValidParent(parent): # Ensure the parent exists raise errors.NotAcceptable() if not self.canAdd(parent): raise errors.Unauthorized() skel = self.addSkel() if (len(kwargs) == 0 or skey == "" or not request.current.get().isPostRequest or not skel.fromClient(kwargs) or ("bounce" in kwargs and kwargs["bounce"] == "1")): return self.render.add(skel) if not securitykey.validate(skey, acceptSessionKey=True): raise errors.PreconditionFailed() skel["parententry"] = str(parent) skel["parentrepo"] = str(self.getRootNode(parent).key()) key = skel.toDB() self.onItemAdded(skel) self.onItemChanged(skel) return self.render.addItemSuccess(skel)
def continueAuthenticationFlow(self, caller, userKey): session.current["_mayBeUserKey"] = str(userKey) session.current.markChanged() for authProvider, secondFactor in self.validAuthenticationMethods: if isinstance(caller, authProvider): if secondFactor is None: # We allow sign-in without a second factor return self.authenticateUser(userKey) # This Auth-Request was issued from this authenticationProvider secondFactorProvider = self.secondFactorProviderByClass(secondFactor) if secondFactorProvider.canHandle(userKey): # We choose the first second factor provider which claims it can verify that user return secondFactorProvider.startProcessing(userKey) # Whoops.. This user logged in successfully - but we have no second factor provider willing to confirm it raise errors.NotAcceptable("There are no more authentication methods to try") # Sorry...
def add(self, skelType, node, *args, **kwargs): # We can't add files directly (they need to be uploaded if skelType != "node": raise errors.NotAcceptable() return super(File, self).add(skelType, node, *args, **kwargs)
def checkout(self, step=None, key=None, skey=None, *args, **kwargs): """ Performs the checkout process trough the state machine provided by self.steps. :param step: The current step index, None for beginning a new checkout :param key: Key of the current checkout :param skey: Server security key :return: Returns the rendered template or throws redirection exceptions. """ myKindName = self.viewSkel().kindName if step is None: logging.info("Starting new checkout process") billObj = db.Entity(myKindName) billObj["idx"] = "0000000" for state in self.states: billObj["state_%s" % state] = "0" db.Put(billObj) key = str(billObj.key()) #Copy the Cart if "amountSkel" in dir(self): cart = session.current.get("cart_products") or {} s = self.amountSkel() products = [] for prod, atts in cart.items(): for i in range(0, atts["amount"]): products.append(str(prod)) s.fromClient({"product": products}) s.toDB() session.current["order_" + myKindName] = { "key": str(key), "completedSteps": [] } session.current.markChanged() raise errors.Redirect("?step=0&key=%s" % str(key)) elif key: try: orderKey = db.Key(key) step = int(step) assert (step >= 0) assert (step < len(self.steps)) except: raise errors.NotAcceptable() sessionInfo = session.current.get("order_" + myKindName) if not sessionInfo or not sessionInfo.get("key") == str(orderKey): raise errors.Unauthorized() if step in sessionInfo["completedSteps"]: session.current["order_" + myKindName]["completedSteps"] = [ x for x in sessionInfo["completedSteps"] if x < step ] session.current.markChanged() #Make sure that no steps can be skipped if step != 0 and not step - 1 in sessionInfo["completedSteps"]: raise errors.Redirect("?step=0&key=%s" % str(str(orderKey))) currentStep = self.steps[step] if "preHandler" in currentStep.keys(): try: if isinstance(currentStep["preHandler"], list): for handler in currentStep["preHandler"]: handler(self, step, str(orderKey), *args, **kwargs) else: currentStep["preHandler"](self, step, str(orderKey), refkwargs=kwargs, *args, **kwargs) except SkipStepException: session.current["order_" + myKindName]["completedSteps"].append(step) session.current.markChanged() raise errors.Redirect("?step=%s&key=%s" % (str(step + 1), str(orderKey))) except ReturnHtmlException as e: return (e.html) if "requiresSecurityKey" in currentStep and currentStep[ "requiresSecurityKey"]: if not securitykey.validate(skey): raise errors.PreconditionFailed() pass if "mainHandler" in currentStep: if currentStep["mainHandler"]["action"] == "edit": skel = self.getSkelByName( currentStep["mainHandler"]["skeleton"], str(orderKey)) skel.fromDB(str(orderKey)) if not len(kwargs.keys()) or not skel.fromClient(kwargs): return (self.render.edit( skel, tpl=currentStep["mainHandler"]["template"], step=step)) skel.toDB() if currentStep["mainHandler"]["action"] == "view": if not "complete" in kwargs or not kwargs[ "complete"] == u"1": skel = self.getSkelByName( currentStep["mainHandler"]["skeleton"], str(orderKey)) skel.fromDB(str(orderKey)) return (self.render.view( skel, tpl=currentStep["mainHandler"]["template"], step=step)) elif currentStep["mainHandler"]["action"] == "function": res = currentStep["mainHandler"]["function"](self, step, str(orderKey), *args, **kwargs) if res: return res if "postHandler" in currentStep: currentStep["postHandler"](self, step, str(orderKey), *args, **kwargs) session.current["order_" + myKindName]["completedSteps"].append(step) session.current.markChanged() logging.info("next ?step=%s&key=%s" % (str(step + 1), str(orderKey))) raise errors.Redirect("?step=%s&key=%s" % (str(step + 1), str(orderKey)))
def findAndCall(self, path, *args, **kwargs): #Do the actual work: process the request # Prevent Hash-collision attacks assert len(self.request.arguments()) < conf["viur.maxPostParamsCount"] # Fill the (surprisingly empty) kwargs dict with named request params tmpArgs = dict((k, self.request.get_all(k)) for k in self.request.arguments() if k is not None) for key in tmpArgs.keys()[:]: if len(tmpArgs[key]) == 0: continue if not key in kwargs.keys(): if len(tmpArgs[key]) == 1: kwargs[key] = tmpArgs[key][0] else: kwargs[key] = tmpArgs[key] else: if isinstance(kwargs[key], list): kwargs[key] = kwargs[key] + tmpArgs[key] else: kwargs[key] = [kwargs[key]] + tmpArgs[key] del tmpArgs if "self" in kwargs.keys(): #self is reserved for bound methods raise errors.BadRequest() #Parse the URL path = urlparse.urlparse(path).path self.pathlist = [ urlparse.unquote(x) for x in path.strip("/").split("/") ] caller = conf["viur.mainApp"] idx = 0 #Count how may items from *args we'd have consumed (so the rest can go into *args of the called func for currpath in self.pathlist: if "canAccess" in dir(caller) and not caller.canAccess(): # We have a canAccess function guarding that object, # and it returns False... raise (errors.Unauthorized()) idx += 1 currpath = currpath.replace("-", "_").replace(".", "_") if currpath in dir(caller): caller = getattr(caller, currpath) if (("exposed" in dir(caller) and caller.exposed) or ("internalExposed" in dir(caller) and caller.internalExposed and self.internalRequest)) and hasattr( caller, '__call__'): args = self.pathlist[idx:] + [ x for x in args ] #Prepend the rest of Path to args break elif "index" in dir(caller): caller = getattr(caller, "index") if (("exposed" in dir(caller) and caller.exposed) or ("internalExposed" in dir(caller) and caller.internalExposed and self.internalRequest)) and hasattr( caller, '__call__'): args = self.pathlist[idx - 1:] + [x for x in args] break else: raise (errors.NotFound( "The path %s could not be found" % "/".join([("".join([ y for y in x if y.lower() in "0123456789abcdefghijklmnopqrstuvwxyz" ])) for x in self.pathlist[:idx]]))) else: raise (errors.NotFound( "The path %s could not be found" % "/".join([("".join([ y for y in x if y.lower() in "0123456789abcdefghijklmnopqrstuvwxyz" ])) for x in self.pathlist[:idx]]))) if (not callable(caller) or ((not "exposed" in dir(caller) or not caller.exposed)) and (not "internalExposed" in dir(caller) or not caller.internalExposed or not self.internalRequest)): if "index" in dir( caller ) \ and (callable( caller.index ) \ and ( "exposed" in dir( caller.index ) and caller.index.exposed) \ or ("internalExposed" in dir( caller.index ) and caller.index.internalExposed and self.internalRequest)): caller = caller.index else: raise (errors.MethodNotAllowed()) # Check for forceSSL flag if not self.internalRequest \ and "forceSSL" in dir( caller ) \ and caller.forceSSL \ and not self.request.host_url.lower().startswith("https://") \ and not "Development" in os.environ['SERVER_SOFTWARE']: raise (errors.PreconditionFailed( "You must use SSL to access this ressource!")) # Check for forcePost flag if "forcePost" in dir( caller) and caller.forcePost and not self.isPostRequest: raise (errors.MethodNotAllowed( "You must use POST to access this ressource!")) self.args = [] for arg in args: if isinstance(x, unicode): self.args.append(arg) else: try: self.args.append(arg.decode("UTF-8")) except: pass self.kwargs = kwargs # Check if this request should bypass the caches if self.request.headers.get("X-Viur-Disable-Cache"): from server import utils #No cache requested, check if the current user is allowed to do so user = utils.getCurrentUser() if user and "root" in user["access"]: logging.debug( "Caching disabled by X-Viur-Disable-Cache header") self.disableCache = True try: if (conf["viur.debug.traceExternalCallRouting"] and not self.internalRequest ) or conf["viur.debug.traceInternalCallRouting"]: logging.debug("Calling %s with args=%s and kwargs=%s" % (str(caller), unicode(args), unicode(kwargs))) self.response.out.write(caller(*self.args, **self.kwargs)) except TypeError as e: if self.internalRequest: #We provide that "service" only for requests originating from outside raise #Check if the function got too few arguments and raise a NotAcceptable error tmpRes = {} argsOrder = list( caller.__code__.co_varnames)[1:caller.__code__.co_argcount] # Map default values in reversedArgsOrder = argsOrder[::-1] for defaultValue in list(caller.func_defaults or [])[::-1]: tmpRes[reversedArgsOrder.pop(0)] = defaultValue del reversedArgsOrder # Map args in setArgs = [] # Store a list of args already set by *args for idx in range(0, min(len(args), len(argsOrder))): setArgs.append(argsOrder[idx]) tmpRes[argsOrder[idx]] = args[idx] # Last, we map the kwargs in for k, v in kwargs.items(): if k in setArgs: #This key has already been set by *args raise ( errors.NotAcceptable() ) #We reraise that exception as we got duplicate arguments tmpRes[k] = v # Last check, that every parameter is satisfied: if not all([x in tmpRes.keys() for x in argsOrder]): raise (errors.NotAcceptable()) raise
def move(self, skelType, key, destNode, *args, **kwargs): """ Move a node (including its contents) or a leaf to another node. .. seealso:: :func:`canMove` :param skelType: Defines the type of the entry that should be moved and may either be "node" or "leaf". :type skelType: str :param key: URL-safe key of the item to be moved. :type key: str :param destNode: URL-safe key of the destination node, which must be a node. :type destNode: str :returns: The rendered, edited object of the entry. :raises: :exc:`server.errors.NotFound`, when no entry with the given *key* was found. :raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions. :raises: :exc:`server.errors.PreconditionFailed`, if the *skey* could not be verified. """ if skelType == "node": srcSkel = self.editNodeSkel() elif skelType == "leaf": srcSkel = self.editLeafSkel() else: raise errors.NotAcceptable() if "skey" in kwargs: skey = kwargs["skey"] else: skey = "" destSkel = self.editNodeSkel() if not self.canMove(skelType, key, destNode): raise errors.Unauthorized() if key == destNode: # Cannot move a node into itself raise errors.NotAcceptable() ## Test for recursion isValid = False currLevel = db.Get(destNode) for x in range(0, 99): if str(currLevel.key()) == key: break if "rootNode" in currLevel and currLevel["rootNode"] == 1: #We reached a rootNode isValid = True break currLevel = db.Get(currLevel["parentdir"]) if not isValid: raise errors.NotAcceptable() #Test if key points to a rootNone tmp = db.Get(key) if "rootNode" in tmp and tmp["rootNode"] == 1: #Cant move a rootNode away.. raise errors.NotAcceptable() if not srcSkel.fromDB(key) or not destSkel.fromDB(destNode): # Could not find one of the entities raise errors.NotFound() if not securitykey.validate(skey, acceptSessionKey=True): raise errors.PreconditionFailed() srcSkel["parentdir"] = str(destNode) srcSkel["parentrepo"] = destSkel[ "parentrepo"] #Fixme: Need to recursive fixing to parentrepo? srcSkel.toDB() self.updateParentRepo(key, destSkel["parentrepo"]) return self.render.editItemSuccess(srcSkel, skelType=skelType, action="move", destNode=destSkel)