Esempio n. 1
0
 def buildDBFilter(self, name, skel, dbFilter, rawFilter, prefix=None):
     if not name in rawFilter and not any([(x.startswith(name + "$")
                                            or x.startswith(name + "."))
                                           for x in rawFilter.keys()]):
         return (super(stringBone,
                       self).buildDBFilter(name, skel, dbFilter, rawFilter,
                                           prefix))
     hasInequalityFilter = False
     if not self.languages:
         namefilter = name
     else:
         lang = None
         for key in rawFilter.keys():
             if key.startswith("%s." % name):
                 langStr = key.replace("%s." % name, "")
                 if langStr in self.languages:
                     lang = langStr
                     break
         if not lang:
             lang = currentLanguage.get()  # currentSession.getLanguage()
             if not lang or not lang in self.languages:
                 lang = self.languages[0]
         namefilter = "%s.%s" % (name, lang)
     if name + "$lk" in rawFilter:  # Do a prefix-match
         if not self.caseSensitive:
             dbFilter.filter((prefix or "") + namefilter + ".idx >=",
                             str(rawFilter[name + "$lk"]).lower())
             dbFilter.filter(
                 (prefix or "") + namefilter + ".idx <",
                 str(rawFilter[name + "$lk"] + u"\ufffd").lower())
         else:
             dbFilter.filter((prefix or "") + namefilter + " >=",
                             str(rawFilter[name + "$lk"]))
             dbFilter.filter((prefix or "") + namefilter + " <",
                             str(rawFilter[name + "$lk"] + u"\ufffd"))
         hasInequalityFilter = True
     if name + "$gt" in rawFilter:  # All entries after
         if not self.caseSensitive:
             dbFilter.filter((prefix or "") + namefilter + ".idx >",
                             str(rawFilter[name + "$gt"]).lower())
         else:
             dbFilter.filter((prefix or "") + namefilter + " >",
                             str(rawFilter[name + "$gt"]))
         hasInequalityFilter = True
     if name + "$lt" in rawFilter:  # All entries before
         if not self.caseSensitive:
             dbFilter.filter((prefix or "") + namefilter + ".idx <",
                             str(rawFilter[name + "$lt"]).lower())
         else:
             dbFilter.filter((prefix or "") + namefilter + " <",
                             str(rawFilter[name + "$lt"]))
         hasInequalityFilter = True
     if name in rawFilter:  # Normal, strict match
         if not self.caseSensitive:
             dbFilter.filter((prefix or "") + namefilter + ".idx",
                             str(rawFilter[name]).lower())
         else:
             dbFilter.filter((prefix or "") + namefilter,
                             str(rawFilter[name]))
     return (dbFilter)
Esempio n. 2
0
    def getTemplateFileName(self, template, ignoreStyle=False):
        """
			Returns the filename of the template.

			This function decides in which language and which style a given template is rendered.
			The style is provided as get-parameters for special-case templates that differ from
			their usual way.

			It is advised to override this function in case that
			:func:`server.render.jinja2.default.Render.getLoaders` is redefined.

			:param template: The basename of the template to use.
			:type template: str

			:param ignoreStyle: Ignore any maybe given style hints.
			:type ignoreStyle: bool

			:returns: Filename of the template
			:rtype: str
		"""
        validChars = "abcdefghijklmnopqrstuvwxyz1234567890-"
        if "htmlpath" in dir(self):
            htmlpath = self.htmlpath
        else:
            htmlpath = "html"
        currReq = currentRequest.get()
        if not ignoreStyle \
         and "style" in currReq.kwargs \
         and all([x in validChars for x in currReq.kwargs["style"].lower()]):
            stylePostfix = "_" + currReq.kwargs["style"]
        else:
            stylePostfix = ""
        lang = currentLanguage.get()  # session.current.getLanguage()
        fnames = [template + stylePostfix + ".html", template + ".html"]
        if lang:
            fnames = [
                os.path.join(lang, template + stylePostfix + ".html"),
                template + stylePostfix + ".html",
                os.path.join(lang, template + ".html"), template + ".html"
            ]
        for fn in fnames:  # check subfolders
            prefix = template.split("_")[0]
            if os.path.isfile(
                    os.path.join(utils.projectBasePath, htmlpath, prefix, fn)):
                return ("%s/%s" % (prefix, fn))
        for fn in fnames:  # Check the templatefolder of the application
            if os.path.isfile(os.path.join(utils.projectBasePath, htmlpath,
                                           fn)):
                return fn
        for fn in fnames:  # Check the fallback
            if os.path.isfile(
                    os.path.join(utils.projectBasePath, "viur", "core",
                                 "template", fn)):
                return fn
        raise errors.NotFound("Template %s not found." % template)
Esempio n. 3
0
def getLanguage(render, resolveAlias=False):
	"""
	Jinja2 global: Returns the language used for this request.

	:param resolveAlias: If True, the function tries to resolve the current language
	using conf["viur.languageAliasMap"].
	:type resolveAlias: bool
	"""
	lang = currentLanguage.get()
	if resolveAlias and lang in conf["viur.languageAliasMap"]:
		lang = conf["viur.languageAliasMap"][lang]
	return lang
Esempio n. 4
0
 def __str__(self):
     if self.translationCache is None:
         global systemTranslations
         self.translationCache = systemTranslations.get(self.key, {})
     try:
         lang = currentLanguage.get()
     except:
         return self.defaultText or self.key
     if lang in conf["viur.languageAliasMap"]:
         lang = conf["viur.languageAliasMap"][lang]
     if lang not in self.translationCache:
         return self.defaultText or self.key
     trStr = self.translationCache.get(lang, "")
     return trStr
Esempio n. 5
0
 def buildDBSort(self, name, skel, dbFilter, rawFilter):
     if "orderby" in rawFilter and (rawFilter["orderby"] == name or
                                    (isinstance(rawFilter["orderby"], str)
                                     and rawFilter["orderby"].startswith(
                                         "%s." % name) and self.languages)):
         if self.languages:
             lang = None
             if rawFilter["orderby"].startswith("%s." % name):
                 lng = rawFilter["orderby"].replace("%s." % name, "")
                 if lng in self.languages:
                     lang = lng
             if lang is None:
                 lang = currentLanguage.get(
                 )  # currentSession.getLanguage()
                 if not lang or not lang in self.languages:
                     lang = self.languages[0]
             if self.caseSensitive:
                 prop = "%s.%s" % (name, lang)
             else:
                 prop = "%s.%s.idx" % (name, lang)
         else:
             if self.caseSensitive:
                 prop = name
             else:
                 prop = name + ".idx"
         if "orderdir" in rawFilter and rawFilter["orderdir"] == "1":
             order = (prop, db.SortOrder.Descending)
         elif "orderdir" in rawFilter and rawFilter["orderdir"] == "2":
             order = (prop, db.SortOrder.InvertedAscending)
         elif "orderdir" in rawFilter and rawFilter["orderdir"] == "3":
             order = (prop, db.SortOrder.InvertedDescending)
         else:
             order = (prop, db.SortOrder.Ascending)
         inEqFilter = [
             x for x in dbFilter.queries.filters.keys()
             if  # FIXME: This will break on multi queries
             (">" in x[-3:] or "<" in x[-3:] or "!=" in x[-4:])
         ]
         if inEqFilter:
             inEqFilter = inEqFilter[0][:inEqFilter[0].find(" ")]
             if inEqFilter != order[0]:
                 logging.warning(
                     "I fixed you query! Impossible ordering changed to %s, %s"
                     % (inEqFilter, order[0]))
                 dbFilter.order(inEqFilter, order)
             else:
                 dbFilter.order(order)
         else:
             dbFilter.order(order)
     return (dbFilter)
Esempio n. 6
0
    def resolve(self):
        """
			Causes this wrapper to evaluate to the best language available for the current request.

			:returns: str|list of str
			:rtype: str|list of str
		"""
        lang = currentLanguage.get()
        if not lang:
            lang = self.languages[0]
        else:
            if lang in conf["viur.languageAliasMap"]:
                lang = conf["viur.languageAliasMap"][lang]
        if lang in self and self[lang] is not None and str(
                self[lang]).strip():  # The users language is available :)
            return self[lang]
        else:  # We need to select another lang for him
            for lang in self.languages:
                if lang in self and self[lang]:
                    return self[lang]
        return ""
Esempio n. 7
0
 def _translate(self, key, defaultText, hint, kwargs, trDict, caller):
     # Perform the actual translation during render
     lng = currentLanguage.get()
     if lng in trDict:
         return trDict[lng].format(kwargs)
     return str(defaultText).format(kwargs)
Esempio n. 8
0
    def mkDefered(func, self=__undefinedFlag_, *args, **kwargs):
        if not queueRegion:
            # Run tasks inline
            logging.info("Running inline: %s" % func)
            if "_countdown" in kwargs:
                del kwargs["_countdown"]
            if "_queue" in kwargs:
                del kwargs["_queue"]
            if self is __undefinedFlag_:
                task = lambda: func(*args, **kwargs)
            else:
                task = lambda: func(self, *args, **kwargs)
            req = currentRequest.get()
            if req:
                req.pendingTasks.append(
                    task
                )  # < This property will be only exist on development server!
            else:
                # Warmup request or something - we have to call it now as we can't defer it :/
                task()

            return  # Ensure no result gets passed back

        from viur.core.utils import getCurrentUser
        try:
            req = currentRequest.get()
        except:  # This will fail for warmup requests
            req = None
        if req is not None and req.request.headers.get("X-Appengine-Taskretrycount") \
         and "DEFERED_TASK_CALLED" not in dir(req):
            # This is the deferred call
            req.DEFERED_TASK_CALLED = True  # Defer recursive calls to an deferred function again.
            if self is __undefinedFlag_:
                return func(*args, **kwargs)
            else:
                return func(self, *args, **kwargs)
        else:
            try:
                if self.__class__.__name__ == "index":
                    funcPath = func.__name__
                else:
                    funcPath = "%s/%s" % (self.modulePath, func.__name__)
                command = "rel"
            except:
                funcPath = "%s.%s" % (func.__name__, func.__module__)
                if self != __undefinedFlag_:
                    args = (
                        self,
                    ) + args  # Reappend self to args, as this function is (hopefully) unbound
                command = "unb"
            taskargs = dict((x, kwargs.pop(("_%s" % x), None))
                            for x in ("countdown", "eta", "name", "target",
                                      "retry_options"))
            taskargs["url"] = "/_tasks/deferred"
            transactional = kwargs.pop("_transactional", False)
            taskargs["headers"] = {"Content-Type": "application/octet-stream"}
            queue = kwargs.pop("_queue", "default")
            # Try to preserve the important data from the current environment
            try:  # We might get called inside a warmup request without session
                usr = currentSession.get().get("user")
                if "password" in usr:
                    del usr["password"]
            except:
                usr = None
            env = {"user": usr}
            try:
                env["lang"] = currentLanguage.get()
            except AttributeError:  # This isn't originating from a normal request
                pass
            if db.IsInTransaction():
                # We have to ensure transaction guarantees for that task also
                env["transactionMarker"] = db.acquireTransactionSuccessMarker()
                # We move that task at least 90 seconds into the future so the transaction has time to settle
                taskargs["countdown"] = max(
                    90, (taskargs.get("countdown")
                         or 0))  # Countdown can be set to None
            if conf["viur.tasks.customEnvironmentHandler"]:
                # Check if this project relies on additional environmental variables and serialize them too
                assert isinstance(conf["viur.tasks.customEnvironmentHandler"], tuple) \
                    and len(conf["viur.tasks.customEnvironmentHandler"]) == 2 \
                    and callable(conf["viur.tasks.customEnvironmentHandler"][0]), \
                 "Your customEnvironmentHandler must be a tuple of two callable if set!"
                env["custom"] = conf["viur.tasks.customEnvironmentHandler"][0](
                )
            pickled = json.dumps(
                preprocessJsonObject(
                    (command, (funcPath, args, kwargs, env)))).encode("UTF-8")
            project = utils.projectID
            location = queueRegion
            parent = taskClient.queue_path(project, location, queue)
            task = {
                'app_engine_http_request': {  # Specify the type of request.
                    'http_method': tasks_v2.HttpMethod.POST,
                    'relative_uri': '/_tasks/deferred'
                }
            }
            if taskargs.get("countdown"):
                # We must send a Timestamp Protobuf instead of a date-string
                timestamp = timestamp_pb2.Timestamp()
                timestamp.FromDatetime(utils.utcNow() + timedelta(
                    seconds=taskargs["countdown"]))
                task['schedule_time'] = timestamp
            task['app_engine_http_request']['body'] = pickled

            # Use the client to build and send the task.
            response = taskClient.create_task(parent=parent, task=task)

            print('Created task {}'.format(response.name))
Esempio n. 9
0
def keyFromArgs(f, userSensitive, languageSensitive, evaluatedArgs, path, args,
                kwargs):
    """
		Parses args and kwargs according to the information's given
		by evaluatedArgs and argsOrder. Returns an unique key for this
		combination of arguments. This key is guaranteed to be stable for
		subsequent calls with the same arguments and context( the current user)

		:param f: Callable which is inspected for its signature
			(we need to figure out what positional arguments map to which key argument)
		:type f: Callable
		:param userSensitive: Signals wherever the output of f depends on the current user.
			0 means independent of wherever the user is a guest or known, all will get the same content.
			1 means cache only for guests, no cache will be performed if the user is logged-in.
			2 means cache in two groups, one for guests and one for all users
			3 will cache the result of that function for each individual users separately.
		:type userSensitive: int
		:param evaluatedArgs: List of keyword-arguments having influence to the output generated by
			that function. This list *must* complete! Parameters not named here are ignored!
		:type evaluatedArgs: list
		:param path: Path to the function called but without parameters (ie. "/page/view")
		:type path: str
		:returns: The unique key derived
	"""
    res = {}
    argsOrder = list(f.__code__.co_varnames)[1:f.__code__.co_argcount]
    # Map default values in
    reversedArgsOrder = argsOrder[::-1]
    for defaultValue in list(f.__defaults__ or [])[::-1]:
        res[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))):
        if argsOrder[idx] in evaluatedArgs:
            setArgs.append(argsOrder[idx])
            res[argsOrder[idx]] = args[idx]
    # Last, we map the kwargs in
    for k, v in kwargs.items():
        if k in evaluatedArgs:
            if k in setArgs:
                raise AssertionError("Got dupplicate arguments for %s" % k)
            res[k] = v
    if userSensitive:
        user = utils.getCurrentUser()
        if userSensitive == 1 and user:  # We dont cache requests for each user separately
            return None
        elif userSensitive == 2:
            if user:
                res["__user"] = "******"
            else:
                res["__user"] = None
        elif userSensitive == 3:
            if user:
                res["__user"] = user["key"]
            else:
                res["__user"] = None
    if languageSensitive:
        res["__lang"] = currentLanguage.get()
    if conf["viur.cacheEnvironmentKey"]:
        try:
            res["_cacheEnvironment"] = conf["viur.cacheEnvironmentKey"]()
        except RuntimeError:
            return None
    res["__path"] = path  # Different path might have different output (html,xml,..)
    try:
        appVersion = currentRequest.get(
        ).request.environ["CURRENT_VERSION_ID"].split('.')[0]
    except:
        # FIXME
        logging.error(
            "Could not determine the current application version! Caching might produce unexpected results!"
        )
        appVersion = ""
    res["__appVersion"] = appVersion
    # Last check, that every parameter is satisfied:
    if not all([x in res.keys() for x in argsOrder]):
        # we have too few parameters for this function; that wont work
        return None
    res = list(res.items())  # flatten our dict to a list
    res.sort(key=lambda x: x[0])  # sort by keys
    mysha512 = sha512()
    mysha512.update(str(res).encode("UTF8"))
    return mysha512.hexdigest()
Esempio n. 10
0
def keyFromArgs(f: Callable, userSensitive: int, languageSensitive: bool,
                evaluatedArgs: List[str], path: str, args: Tuple,
                kwargs: Dict) -> str:
    """
		Utility function to derive a unique but stable string-key that can be used in a datastore-key
		for the given wrapped function f, the parameter *args and **kwargs it has been called with,
		the path-components from the url that point to the outer @exposed function which handles this request
		as well as the configuration (userSensitive, languageSensitive and evaluatedArgs) provided to the @enableCache
		decorator. To derive the key, we'll first map all positional arguments to their keyword equivalent, construct
		a dict with the parameters having an effect on the result, merge the context variables (language, session state)
		in, sort this dict by key, cast it to string and return it's sha512 hash.

		:param f: Callable which is inspected for its signature
			(we need to figure out what positional arguments map to which key argument)
		:param userSensitive: Signals wherever the output of f depends on the current user.
			0 means independent of wherever the user is a guest or known, all will get the same content.
			1 means cache only for guests, no cache will be performed if the user is logged-in.
			2 means cache in two groups, one for guests and one for all users
			3 will cache the result of that function for each individual users separately.
		:param evaluatedArgs: List of keyword-arguments having influence to the output generated by
			that function. This list *must* complete! Parameters not named here are ignored!
		:param path: Path to the function called but without parameters (ie. "/page/view")
		:returns: The unique key derived
	"""
    res = {}
    argsOrder = list(f.__code__.co_varnames)[1:f.__code__.co_argcount]
    # Map default values in
    reversedArgsOrder = argsOrder[::-1]
    for defaultValue in list(f.__defaults__ or [])[::-1]:
        res[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))):
        if argsOrder[idx] in evaluatedArgs:
            setArgs.append(argsOrder[idx])
            res[argsOrder[idx]] = args[idx]
    # Last, we map the kwargs in
    for k, v in kwargs.items():
        if k in evaluatedArgs:
            if k in setArgs:
                raise AssertionError("Got dupplicate arguments for %s" % k)
            res[k] = v
    if userSensitive:
        user = utils.getCurrentUser()
        if userSensitive == 1 and user:  # We dont cache requests for each user separately
            return None
        elif userSensitive == 2:
            if user:
                res["__user"] = "******"
            else:
                res["__user"] = None
        elif userSensitive == 3:
            if user:
                res["__user"] = user["key"]
            else:
                res["__user"] = None
    if languageSensitive:
        res["__lang"] = currentLanguage.get()
    if conf["viur.cacheEnvironmentKey"]:
        try:
            res["_cacheEnvironment"] = conf["viur.cacheEnvironmentKey"]()
        except RuntimeError:
            return None
    res["__path"] = path  # Different path might have different output (html,xml,..)
    try:
        appVersion = os.getenv("GAE_VERSION")
    except:
        logging.error(
            "Could not determine the current application version! Caching might produce unexpected results!"
        )
        appVersion = ""
    res["__appVersion"] = appVersion
    # Last check, that every parameter is satisfied:
    if not all([x in res.keys() for x in argsOrder]):
        # we have too few parameters for this function; that wont work
        return None
    res = list(res.items())  # flatten our dict to a list
    res.sort(key=lambda x: x[0])  # sort by keys
    mysha512 = sha512()
    mysha512.update(str(res).encode("UTF8"))
    return mysha512.hexdigest()