From d38c9fb1c6dc9364496613d40d7de11205f668fa 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 | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/hobo/context_processors.py b/hobo/context_processors.py index 31bb8ba..3459459 100644 --- a/hobo/context_processors.py +++ b/hobo/context_processors.py @@ -30,20 +30,22 @@ 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): item = cache.get(self.cache_key) if item is None: template_body = self.update_content() if template_body is None: + logger.error('failed to retrieve theme') raise Exception('Failed to retrieve theme') else: template_body, expiry_time = item @@ -51,22 +53,40 @@ class RemoteTemplate(object): # stale value, put it back into the cache for other consumers and # update the content in a different thread self.cache(template_body) + # for background refresh we do not care about retrieval miss + self.disable_recurse = True threading.Thread(target=self.update_content).start() return Template(template_body) + def 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 + 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 update_content(self): - r = requests.get(settings.THEME_SKELETON_URL, params={'source': self.source}) + try: + r = requests.get(settings.THEME_SKELETON_URL, params={'source': self.source}) + except requests.RequestException: + return self.recurse() if r.status_code != 200: - logger.error('failed to retrieve theme') - return None + return self.recurse() self.cache(r.text) return r.text def cache(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