From dca75915dd0238a1fb8780856493c7ddaec76144 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Sat, 1 Oct 2016 13:48:29 +0200 Subject: [PATCH] try parent path if theme retrieval fails for current path (fixes #13385) --- hobo/context_processors.py | 58 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/hobo/context_processors.py b/hobo/context_processors.py index 31bb8ba..3852f1a 100644 --- a/hobo/context_processors.py +++ b/hobo/context_processors.py @@ -30,43 +30,67 @@ def template_vars(request): template_vars.update({'statics_hash': statics_hash.hexdigest()}) return template_vars + class RemoteTemplate(object): def __init__(self, source): - self.source = source + self.source = urlparse.urlunparse(urlparse.urlparse(source)[:3] + ('', '', '')) + self.disable_recurse = False @property def cache_key(self): - return hashlib.md5(urlparse.urlunparse( - urlparse.urlparse(self.source)[:3] + ('', '', ''))).hexdigest() + return hashlib.md5(self.source).hexdigest() def get_template(self): + template_body = self.get_template_body() + if template_body is None: + logger.error('failed to retrieve theme') + raise Exception('failed to retrieve theme') + return Template(template_body) + + def get_template_body(self): item = cache.get(self.cache_key) if item is None: - template_body = self.update_content() - if template_body is None: - raise Exception('Failed to retrieve theme') + template_body = self.request_template_body() else: template_body, expiry_time = item if expiry_time < datetime.datetime.now(): # stale value, put it back into the cache for other consumers and # update the content in a different thread self.cache(template_body) - threading.Thread(target=self.update_content).start() - return Template(template_body) + # for background refresh we do not care about retrieval miss + self.disable_recurse = True + threading.Thread(target=self.request_template_body).start() + return template_body - def update_content(self): - r = requests.get(settings.THEME_SKELETON_URL, params={'source': self.source}) - if r.status_code != 200: - logger.error('failed to retrieve theme') + def get_template_body_recurse(self): + '''We were unable to retrieve a base template for this source URL, look for one level up.''' + if self.disable_recurse: + return None + parsed = urlparse.urlparse(self.source) + if not parsed.path or parsed.path == '/': return None - self.cache(r.text) + if parsed.path.endswith('/'): # cd .. + new_path = urlparse.urljoin(parsed.path, '..') + else: + new_path = urlparse.urljoin(parsed.path, '.') + self.source = urlparse.urlunparse(parsed[:2] + (new_path, '', '', '')) + return self.get_template() + + def request_template_body(self): + try: + r = requests.get(settings.THEME_SKELETON_URL, params={'source': self.source}) + except requests.RequestException: + return self.recurse() + if r.status_code != 200: + return self.recurse() + self.cache_template_body(r.text) return r.text - def cache(self, template_body): + def cache_template_body(self, template_body): expiry_time = datetime.datetime.now() + datetime.timedelta(seconds=CACHE_REFRESH_TIMEOUT) - cache.set(self.cache_key, - (template_body, expiry_time), - 2592000) # bypass cache level expiration time + cache.set(self.cache_key, (template_body, expiry_time), + 2592000) # bypass cache level expiration time + def theme_base(request): # this context processor adds two variables to context: -- 2.1.4