示例#1
0
    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, useSessionKey=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)
示例#2
0
    def authenticateUser(self, userKey, **kwargs):
        """
			Performs Log-In for the current session and the given userKey.

			This resets the current session: All fields not explicitly marked as persistent
			by conf["viur.session.persistentFieldsOnLogin"] are gone afterwards.

			:param authProvider: Which authentication-provider issued the authenticateUser request
			:type authProvider: object
			:param userKey: The (DB-)Key of the user we shall authenticate
			:type userKey: db.Key
		"""
        currSess = currentSession.get()
        res = db.Get(userKey)
        assert res, "Unable to authenticate unknown user %s" % userKey
        oldSession = {k: v
                      for k, v in currSess.items()
                      }  # Store all items in the current session
        currSess.reset()
        # Copy the persistent fields over
        for k in conf["viur.session.persistentFieldsOnLogin"]:
            if k in oldSession:
                currSess[k] = oldSession[k]
        del oldSession
        currSess["user"] = res
        currSess.markChanged()
        currentRequest.get().response.headers[
            "Sec-X-ViUR-StaticSKey"] = currSess.staticSecurityKey
        self.onLogin()
        return self.render.loginSucceeded(**kwargs)
示例#3
0
def validate(key: str, useSessionKey: bool) -> Union[bool, db.Entity]:
    """
		Validates a security key. If useSessionKey is true, the key is expected to be the sessions current security key
		(or it's static security key). Otherwise it must be a key created with a duration (so it's not session
		dependent)

		:param key: The key to validate
		:param useSessionKey: If True, we validate against the session's skey, otherwise we'll lookup an unbound key
		:returns: False if the key was not valid for whatever reasons, the data (given during createSecurityKey) as
			dictionary or True if the dict is empty (or :param:useSessionKey was true).
	"""
    if useSessionKey:
        if key == "staticSessionKey":
            skeyHeaderValue = currentRequest.get().request.headers.get(
                "Sec-X-ViUR-StaticSKey")
            if skeyHeaderValue and currentSession.get(
            ).validateStaticSecurityKey(skeyHeaderValue):
                return True
        elif currentSession.get().validateSecurityKey(key):
            return True
        return False
    if not key:
        return False
    dbKey = db.Key(securityKeyKindName, key)
    dbObj = db.Get(dbKey)
    if dbObj:
        db.Delete(dbKey)
        until = dbObj["until"]
        if until < utcNow():  # This key has expired
            return False
        del dbObj["until"]
        if not dbObj:
            return True
        return dbObj
    return False
示例#4
0
    def getEntry(self, module, id, key=None):
        if not self._checkKey(key, export=True):
            raise errors.Forbidden()

        res = db.Get(id)

        return pickle.dumps(self.genDict(res))
示例#5
0
 def sofortStatus(self, *args, **kwargs):
     sortOrder = [
         "transaction", "user_id", "project_id", "sender_holder",
         "sender_account_number", "sender_bank_code", "sender_bank_name",
         "sender_bank_bic", "sender_iban", "sender_country_id",
         "recipient_holder", "recipient_account_number",
         "recipient_bank_code", "recipient_bank_name", "recipient_bank_bic",
         "recipient_iban", "recipient_country_id",
         "international_transaction", "amount", "currency_id", "reason_1",
         "reason_2", "security_criteria", "user_variable_0",
         "user_variable_1", "user_variable_2", "user_variable_3",
         "user_variable_4", "user_variable_5", "created"
     ]
     hashstr = "|".join([kwargs[key] for key in sortOrder] +
                        [conf["sofort"]["notificationpassword"]])
     if hashlib.sha512(
             hashstr.encode("utf-8")).hexdigest() != kwargs["hash"]:
         logging.error(
             "RECEIVED INVALID HASH FOR sofort (%s!=%s)" % (hashlib.sha512(
                 hashstr.encode("utf-8")).hexdigest(), kwargs["hash"]))
         return ("INVALID HASH")
     order = db.Get(db.Key(kwargs["user_variable_0"]))
     if not order:
         logging.error("RECEIVED UNKNOWN ORDER by sofort (%s)" %
                       (kwargs["user_variable_0"]))
         return ("UNKNOWN ORDER")
     if ("%.2f" % order["price"]) != kwargs["amount"]:
         logging.error("RECEIVED INVALID AMOUNT PAYED sofort (%s!=%s)" %
                       (order["price"], kwargs["amount"]))
         return ("INVALID AMOUNT")
     self.orderHandler.setPayed(kwargs["user_variable_0"])
     return ("OKAY")
示例#6
0
 def updateTransaction(userKey, idx):
     user = db.Get(userKey)
     if not "otptimedrift" in user or not isinstance(
             user["otptimedrift"], float):
         user["otptimedrift"] = 0.0
     user["otptimedrift"] += min(max(0.1 * idx, -0.3), 0.3)
     db.Put(user)
示例#7
0
    def assignBillSequence(self, orderKey):
        """
			Assigns an unique order-order to the given order.
		"""
        def getKeyTxn(kindName, orderKey):
            """Generates and returns a new, unique Key"""
            seqObj = db.GetOrInsert(kindName,
                                    "viur_bill_sequences",
                                    count=1000)
            idx = seqObj["count"]
            seqObj["count"] += 1
            db.Put(seqObj)
            return str(idx)

        def setKeyTxn(orderKey, idx):
            """Assigns the new order to the given order"""
            dbObj = db.Get(db.Key(orderKey))
            if not dbObj:
                return
            dbObj["idx"] = idx
            db.Put(dbObj)

        dbObj = db.Get(db.Key(orderKey))
        if not dbObj:
            return

        idx = db.RunInTransaction(getKeyTxn,
                                  self.viewSkel().kindName, orderKey)
        db.RunInTransaction(setKeyTxn, orderKey, idx)
        self.billSequenceAvailable(orderKey)
示例#8
0
 def setKeyTxn(orderKey, idx):
     """Assigns the new order to the given order"""
     dbObj = db.Get(db.Key(orderKey))
     if not dbObj:
         return
     dbObj["idx"] = idx
     db.Put(dbObj)
示例#9
0
    def setIndex(self, item, index, skey, *args, **kwargs):
        """
		Changes the order of the elements in the current level by changing the index of *item*.

		.. seealso:: :func:`canSetIndex`

		:param item: URL-safe key of the item which index should be changed.
		:type item: str

		:param index: New index for this item. This value must be cast-able to float.
		:type index: str

		:returns: A rendered success result generated by the default renderer.

		: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 not securitykey.validate(skey, useSessionKey=True):
            raise errors.PreconditionFailed()

        if not self.canSetIndex(item, index):
            raise errors.Unauthorized()

        fromItem = db.Get(item)
        fromItem["sortindex"] = float(index)
        db.Put(fromItem)
        skel = self.editSkel()
        assert skel.fromDB(item)
        self.onItemSetIndex(skel)
        self.onItemChanged(skel)

        return self.render.setIndexSuccess(obj=fromItem)
示例#10
0
def validate(key: str, useSessionKey: bool) -> Union[bool, db.Entity]:
    """
		Validates a onetime securitykey

		:type key: str
		:param key: The key to validate
		:type useSessionKey: Bool
		:param useSessionKey: If True, we validate against the session's skey, otherwise we'll lookup an unbound key
		:returns: False if the key was not valid for whatever reasons, the data (given during createSecurityKey) as dictionary or True if the dict is empty.
	"""
    if useSessionKey:
        if key == "staticSessionKey":
            skeyHeaderValue = request.current.get().request.headers.get(
                "Sec-X-ViUR-StaticSKey")
            if skeyHeaderValue and currentSession.validateStaticSecurityKey(
                    skeyHeaderValue):
                return True
        elif currentSession.validateSecurityKey(key):
            return True
        return False
    if not key or "/" in key:
        return False
    dbObj = db.Get((securityKeyKindName, key))
    if dbObj:
        db.Delete((securityKeyKindName, key))
        if dbObj["until"] < datetime.now():  # This key has expired
            return False
        del dbObj["until"]
        if not dbObj:
            return True
        return dbObj
    return False
示例#11
0
	def load(self, req):
		"""
			Initializes the Session.

			If the client supplied a valid Cookie, the session is read
			from the memcache/datastore, otherwise a new, empty session
			will be initialized.
		"""
		self.changed = False
		self.isInitial = False
		self.cookieKey = None
		self.sslKey = None
		self.staticSecurityKey = None
		self.securityKey = None
		self.session = {}
		if self.cookieName in req.request.cookies:
			cookie = str(req.request.cookies[self.cookieName])
			data = db.Get(db.Key(self.kindName, cookie))
			if data:  # Loaded successfully from Memcache
				if data["lastseen"] < time() - conf["viur.session.lifeTime"]:
					# This session is too old
					self.reset()
					return False
				self.session = data["data"]
				self.staticSecurityKey = data["staticSecurityKey"]
				self.securityKey = data["securityKey"]
				self.cookieKey = cookie
				if data["lastseen"] < time() - 5 * 60:  # Refresh every 5 Minutes
					self.changed = True
			else:
				# We could not load from firebase; create a new one
				self.reset()
		else:
			self.reset()
示例#12
0
    def getRootNode(self, entryKey: db.Key) -> Skeleton:
        """
		Returns the root-node for a given child.

		:param entryKey: URL-Safe key of the child entry
		:type entryKey: str

		:returns: The entity of the root-node.
		:rtype: :class:`server.db.Entity`
		"""
        rootNodeSkel = self.nodeSkelCls()
        entryKey = db.keyHelper(entryKey, rootNodeSkel.kindName)
        repo = db.Get(entryKey)
        while repo and "parententry" in repo:
            repo = db.Get(repo["parententry"])
        rootNodeSkel.fromDB(repo.key)
        return rootNodeSkel
示例#13
0
        def txn(orderKey, state, removeState):
            dbObj = db.Get(db.Key(orderKey))
            if not dbObj:
                return

            dbObj["state_%s" % state] = "1" if not removeState else "0"
            dbObj["changedate"] = datetime.now()
            db.Put(dbObj)
示例#14
0
    def getRootNode(self, entryKey):
        """
		Returns the root-node for a given child.

		:param entryKey: URL-Safe key of the child entry
		:type entryKey: str

		:returns: The entity of the root-node.
		:rtype: :class:`server.db.Entity`
		"""
        repo = db.Get(entryKey)
        while repo and "parententry" in repo:
            repo = db.Get(repo["parententry"])

        assert repo and repo.key().kind(
        ) == self.viewSkel().kindName + "_rootNode"
        return repo
示例#15
0
			def exchangeSecurityKey():
				dbSession = db.Get(db.Key(self.kindName, self.cookieKey))
				if not dbSession:  # Should not happen (except if session.reset has been called in the same request)
					return False
				if dbSession["securityKey"] != key:  # Race-Condidtion: That skey has been used in another instance
					return False
				dbSession["securityKey"] = utils.generateRandomString(13)
				db.Put(dbSession)
				return dbSession["securityKey"]
示例#16
0
 def updateTxn(cacheKey):
     key = db.Key(self.rateLimitKind, cacheKey)
     obj = db.Get(key)
     if obj is None:
         obj = db.Entity(key)
         obj["value"] = 0
     obj["value"] += 1
     obj["expires"] = utils.utcNow() + timedelta(minutes=2 *
                                                 self.minutes)
     db.Put(obj)
示例#17
0
 def getOldBlobKeysTxn(dbKey):
     obj = db.Get(dbKey)
     res = obj["old_blob_references"] or []
     if obj["is_stale"]:
         db.Delete(dbKey)
     else:
         obj["has_old_blob_references"] = False
         obj["old_blob_references"] = []
         db.Put(obj)
     return res
示例#18
0
 def getSofortURL(self, orderID):
     order = db.Get(db.Key(orderID))
     hashstr = "%s|%s|||||%.2f|EUR|%s||%s||||||%s" % (
         conf["sofort"]["userid"], conf["sofort"]["projectid"],
         float(order["price"]), str(order.key()), str(
             order.key()), conf["sofort"]["projectpassword"])
     hash = hashlib.sha512(hashstr.encode("UTF-8")).hexdigest()
     returnURL = "https://www.sofortueberweisung.de/payment/start?user_id=%s&project_id=%s&amount=%.2f&currency_id=EUR&reason_1=%s&user_variable_0=%s&hash=%s" % (
         conf["sofort"]["userid"], conf["sofort"]["projectid"],
         float(order["price"]), str(order.key()), str(order.key()), hash)
     return (returnURL)
示例#19
0
	def updateTxn(key, resDict):
		obj = db.Get(key)
		if not obj:  # File-object got deleted during building of our derives
			return
		obj["derived"] = obj.get("derived") or {}
		obj["derived"]["deriveStatus"] = obj["derived"].get("deriveStatus") or {}
		obj["derived"]["files"] = obj["derived"].get("files") or {}
		for k, v in resDict.items():
			obj["derived"]["deriveStatus"][k] = v["version"]
			for fileName, fileDict in v["files"].items():
				obj["derived"]["files"][fileName] = fileDict
		db.Put(obj)
示例#20
0
def importBlobFromViur2(dlKey, fileName):
    if not conf.get("viur.viur2import.blobsource"):
        return False
    existingImport = db.Get(db.Key("viur-viur2-blobimport", dlKey))
    if existingImport:
        if existingImport["success"]:
            return existingImport["dlurl"]
        return False
    if conf["viur.viur2import.blobsource"]["infoURL"]:
        try:
            importDataReq = urlopen(
                conf["viur.viur2import.blobsource"]["infoURL"] + dlKey)
        except:
            marker = db.Entity(db.Key("viur-viur2-blobimport", dlKey))
            marker["success"] = False
            marker["error"] = "Failed URL-FETCH 1"
            db.Put(marker)
            return False
        if importDataReq.status != 200:
            marker = db.Entity(db.Key("viur-viur2-blobimport", dlKey))
            marker["success"] = False
            marker["error"] = "Failed URL-FETCH 2"
            db.Put(marker)
            return False
        importData = json.loads(importDataReq.read())
        oldBlobName = conf["viur.viur2import.blobsource"][
            "gsdir"] + "/" + importData["key"]
        srcBlob = storage.Blob(
            bucket=bucket,
            name=conf["viur.viur2import.blobsource"]["gsdir"] + "/" +
            importData["key"])
    else:
        oldBlobName = conf["viur.viur2import.blobsource"]["gsdir"] + "/" + dlKey
        srcBlob = storage.Blob(
            bucket=bucket,
            name=conf["viur.viur2import.blobsource"]["gsdir"] + "/" + dlKey)
    if not srcBlob.exists():
        marker = db.Entity(db.Key("viur-viur2-blobimport", dlKey))
        marker["success"] = False
        marker["error"] = "Local SRC-Blob missing"
        marker["oldBlobName"] = oldBlobName
        db.Put(marker)
        return False
    bucket.rename_blob(srcBlob, "%s/source/%s" % (dlKey, fileName))
    marker = db.Entity(db.Key("viur-viur2-blobimport", dlKey))
    marker["success"] = True
    marker["old_src_key"] = dlKey
    marker["old_src_name"] = fileName
    marker["dlurl"] = utils.downloadUrlFor(dlKey, fileName, False, None)
    db.Put(marker)
    return marker["dlurl"]
示例#21
0
	def startProcessing(self, userKey):
		user = db.Get(userKey)
		if all([(x in user and user[x]) for x in ["otpid", "otpkey"]]):
			logging.info("OTP wanted for user")
			currentSession.get()["_otp_user"] = {"uid": str(userKey),
											"otpid": user["otpid"],
											"otpkey": user["otpkey"],
											"otptimedrift": user["otptimedrift"],
											"timestamp": time(),
											"failures": 0}
			currentSession.get().markChanged()
			return self.userModule.render.loginSucceeded(msg="X-VIUR-2FACTOR-TimeBasedOTP")

		return None
示例#22
0
 def hasblob(self, blobkey, key):
     if not self._checkKey(key, export=False):
         raise errors.Forbidden()
     try:
         oldKeyHash = sha256(blobkey).hexdigest().encode("hex")
         res = db.Get(db.Key.from_path("viur-blobimportmap", oldKeyHash))
         if res:
             if "available" in res:
                 return json.dumps(res["available"])
             else:
                 return json.dumps(True)
     except:
         pass
     return json.dumps(False)
示例#23
0
		def updateInplace(relDict):
			"""
				Fetches the entity referenced by valDict["dest.key"] and updates all dest.* keys
				accordingly
			"""
			if not (isinstance(relDict, dict) and "dest" in relDict):
				logging.error("Invalid dictionary in updateInplace: %s" % relDict)
				return
			newValues = db.Get(db.keyHelper(relDict["dest"]["key"], self.kind))
			if newValues is None:
				logging.info("The key %s does not exist" % relDict["dest"]["key"])
				return
			for boneName in self.refKeys:
				if boneName != "key" and boneName in newValues:
					relDict["dest"].dbEntity[boneName] = newValues[boneName]
示例#24
0
    def load(self, req):
        """
			Initializes the Session.

			If the client supplied a valid Cookie, the session is read
			from the memcache/datastore, otherwise a new, empty session
			will be initialized.
		"""
        self.changed = False
        self.isInitial = False
        self.httpKey = None
        self.sslKey = None
        self.staticSecurityKey = None
        self.securityKey = None
        self.session = {}
        if self.plainCookieName in req.request.cookies:
            cookie = str(req.request.cookies[self.plainCookieName])
            try:
                data = db.Get(db.Key(self.kindName, cookie))
            except:
                raise  # FIXME
                return False
            if data:  # Loaded successfully from Memcache
                if data["lastseen"] < time() - conf["viur.session.lifeTime"]:
                    # This session is too old
                    self.reset()
                    return False

                self.session = pickle.loads(base64.b64decode(data["data"]))
                self.sslKey = data["sslkey"]
                self.staticSecurityKey = data["staticSecurityKey"]
                self.securityKey = data["securityKey"]
                self.httpKey = cookie
                if data["lastseen"] < time(
                ) - 5 * 60:  # Refresh every 5 Minutes
                    self.changed = True
            else:
                # We could not load from firebase; create a new one
                self.reset()
            if req.isSSLConnection and self.sslKey and not req.request.cookies.get(
                    self.sslCookieName) == self.sslKey:
                logging.critical(
                    "Possible session hijack attempt! Session dropped.")
                self.reset()
                return False
            return True
        else:
            self.reset()
示例#25
0
	def startProcessing(self, step, orderID):
		def setTokenTxn(key, token):
			order = db.Get(key)
			if not order:
				return
			order["paypal_token"] = urllib.unquote(token)
			db.Put(order)

		paypal = PayPal.PayPalHandler()
		key = db.Key(orderID)
		order = db.Get(key)
		if not order:
			return
		token = paypal.SetExpressCheckout("%.2f" % order["price"])
		db.RunInTransaction(setTokenTxn, key, token)
		raise (errors.Redirect(paypal.getPayURL(token)))
示例#26
0
    def calculateOrderSum(self, step, orderKey, *args, **kwargs):
        """
		Calculates the final price for this order.
		This function *must* be called before any attempt is made to start a payment process.


		:param step: Current step within the ordering process
		:type step: int

		:param orderKey: order to calculate the price for
		:type orderKey: str
		"""
        price = sum([x[3] for x in self.getBillItems(orderKey)])
        orderObj = db.Get(db.Key(str(orderKey)))
        orderObj["price"] = price
        db.Put(orderObj)
示例#27
0
	def delete(self, skel: 'viur.core.skeleton.SkeletonInstance', name: str):
		"""
			Ensure any outgoing relational lock is cleared
		:param skel:
		:param name:
		:return:
		"""
		if skel.dbEntity.get("%s_outgoingRelationalLocks" % name):
			for refKey in skel.dbEntity["%s_outgoingRelationalLocks" % name]:
				referencedEntry = db.Get(refKey)
				if not referencedEntry:
					logging.warning("Programming error detected: Entry %s is gone despite lock" % refKey)
					continue
				incommingLocks = referencedEntry.get("viur_incomming_relational_locks", [])
				# We remove any reference to ourself as multiple bones may hold Locks to the same entry
				referencedEntry["viur_incomming_relational_locks"] = [x for x in incommingLocks if x != skel["key"]]
				db.Put(referencedEntry)
示例#28
0
 def wrapF(self, *args, **kwargs) -> Union[str, bytes]:
     currReq = currentRequest.get()
     if conf["viur.disableCache"] or currReq.disableCache:
         # Caching disabled
         if conf["viur.disableCache"]:
             logging.debug("Caching is disabled by config")
         return f(self, *args, **kwargs)
     # How many arguments are part of the way to the function called (and how many are just *args)
     offset = -len(currReq.args) or len(currReq.pathlist)
     path = "/" + "/".join(currReq.pathlist[:offset])
     if not path in urls:
         # This path (possibly a sub-render) should not be cached
         logging.debug("Not caching for %s" % path)
         return f(self, *args, **kwargs)
     key = keyFromArgs(f, userSensitive, languageSensitive, evaluatedArgs,
                       path, args, kwargs)
     if not key:
         # Something is wrong (possibly the parameter-count)
         # Let's call f, but we knew already that this will clash
         return f(self, *args, **kwargs)
     dbRes = db.Get(db.Key(viurCacheName, key))
     if dbRes is not None:
         if not maxCacheTime \
          or dbRes["creationtime"] > utils.utcNow() - timedelta(seconds=maxCacheTime):
             # We store it unlimited or the cache is fresh enough
             logging.debug("This request was served from cache.")
             currReq.response.headers['Content-Type'] = dbRes[
                 "content-type"]
             return dbRes["data"]
     # If we made it this far, the request wasn't cached or too old; we need to rebuild it
     oldAccessLog = db.startDataAccessLog()
     try:
         res = f(self, *args, **kwargs)
     finally:
         accessedEntries = db.endDataAccessLog(oldAccessLog)
     dbEntity = db.Entity(db.Key(viurCacheName, key))
     dbEntity["data"] = res
     dbEntity["creationtime"] = utils.utcNow()
     dbEntity["path"] = path
     dbEntity["content-type"] = currReq.response.headers['Content-Type']
     dbEntity["accessedEntries"] = list(accessedEntries)
     dbEntity.exclude_from_indexes = ["data", "content-type"
                                      ]  # We can save 2 DB-Writs :)
     db.Put(dbEntity)
     logging.debug("This request was a cache-miss. Cache has been updated.")
     return res
示例#29
0
 def wrapF(self, *args, **kwargs):
     currentRequest = request.current.get()
     if conf["viur.disableCache"] or currentRequest.disableCache:
         # Caching disabled
         if conf["viur.disableCache"]:
             logging.debug("Caching is disabled by config")
         return (f(self, *args, **kwargs))
     # How many arguments are part of the way to the function called (and how many are just *args)
     offset = -len(currentRequest.args) or len(currentRequest.pathlist)
     path = "/" + "/".join(currentRequest.pathlist[:offset])
     if not path in urls:
         # This path (possibly a sub-render) should not be cached
         logging.debug("Not caching for %s" % path)
         return (f(self, *args, **kwargs))
     key = keyFromArgs(f, userSensitive, languageSensitive, evaluatedArgs,
                       path, args, kwargs)
     if not key:
         # Someting is wrong (possibly the parameter-count)
         # Letz call f, but we knew already that this will clash
         return (f(self, *args, **kwargs))
     try:
         dbRes = db.Get(db.Key.from_path(viurCacheName, key))
     except db.EntityNotFoundError:
         dbRes = None
     if dbRes:
         if not maxCacheTime or \
           dbRes["creationtime"] > datetime.now() - timedelta(seconds=maxCacheTime):
             # We store it unlimited or the cache is fresh enough
             logging.debug("This request was served from cache.")
             currentRequest.response.headers['Content-Type'] = dbRes[
                 "content-type"].encode("UTF-8")
             return (dbRes["data"])
     # If we made it this far, the request wasnt cached or too old; we need to rebuild it
     res = f(self, *args, **kwargs)
     dbEntity = db.Entity(viurCacheName, name=key)
     dbEntity["data"] = res
     dbEntity["creationtime"] = datetime.now()
     dbEntity["path"] = path
     dbEntity["content-type"] = request.current.get(
     ).response.headers['Content-Type']
     dbEntity.set_unindexed_properties(["data", "content-type"
                                        ])  # We can save 2 DB-Writs :)
     db.Put(dbEntity)
     logging.debug("This request was a cache-miss. Cache has been updated.")
     return (res)
示例#30
0
    def getOrBuildIndex(self, origQuery):
        """
			Builds a specific index based on origQuery AND local variables (self.indexPage and self.indexMaxPage)
			Returns a list of starting-cursors for each page.
			You probably shouldn't call this directly. Use cursorForQuery.

			:param origQuery: Query to build the index for
			:type origQuery: db.Query
			:returns: []
		"""
        key = self.keyFromQuery(origQuery)
        if key in self._cache:  # We have it cached
            return self._cache[key]
        # We don't have it cached - try to load it from DB
        try:
            index = db.Get(db.Key.from_path(self._dbType, key))
            res = json.loads(index["data"])
            self._cache[key] = res
            return res
        except db.EntityNotFoundError:  # Its not in the datastore, too
            pass
        # We don't have this index yet.. Build it
        # Clone the original Query
        queryRes = origQuery.clone(keysOnly=True).datastoreQuery.Run(
            limit=self.maxPages * self.pageSize)
        # Build-Up the index
        res = list()
        previousCursor = None  # The first page dosnt have any cursor

        # enumerate is slightly faster than a manual loop counter
        for counter, discardedKey in enumerate(queryRes):
            if counter % self.pageSize == 0:
                res.append(previousCursor)
            if counter % self.pageSize == (self.pageSize - 1):
                previousCursor = str(queryRes.cursor().urlsafe())

        if not len(res):  # Ensure that the first page exists
            res.append(None)

        entry = db.Entity(self._dbType, name=key)
        entry["data"] = json.dumps(res)
        entry["creationdate"] = datetime.now()
        db.Put(entry)
        return res