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)
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)
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
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
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)
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 ""
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)
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))
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()
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()