30 |
30 |
template_vars.update({'statics_hash': statics_hash.hexdigest()})
|
31 |
31 |
return template_vars
|
32 |
32 |
|
|
33 |
|
33 |
34 |
class RemoteTemplate(object):
|
34 |
35 |
def __init__(self, source):
|
35 |
|
self.source = source
|
|
36 |
self.source = urlparse.urlunparse(urlparse.urlparse(source)[:3] + ('', '', ''))
|
|
37 |
self.disable_recurse = False
|
36 |
38 |
|
37 |
39 |
@property
|
38 |
40 |
def cache_key(self):
|
39 |
|
return hashlib.md5(urlparse.urlunparse(
|
40 |
|
urlparse.urlparse(self.source)[:3] + ('', '', ''))).hexdigest()
|
|
41 |
return hashlib.md5(self.source).hexdigest()
|
41 |
42 |
|
42 |
43 |
def get_template(self):
|
|
44 |
template_body = self.get_template_body()
|
|
45 |
if template_body is None:
|
|
46 |
logger.error('failed to retrieve theme')
|
|
47 |
raise Exception('failed to retrieve theme')
|
|
48 |
return Template(template_body)
|
|
49 |
|
|
50 |
def get_template_body(self):
|
43 |
51 |
item = cache.get(self.cache_key)
|
44 |
52 |
if item is None:
|
45 |
|
template_body = self.update_content()
|
46 |
|
if template_body is None:
|
47 |
|
raise Exception('Failed to retrieve theme')
|
|
53 |
template_body = self.request_template_body()
|
48 |
54 |
else:
|
49 |
55 |
template_body, expiry_time = item
|
50 |
56 |
if expiry_time < datetime.datetime.now():
|
51 |
57 |
# stale value, put it back into the cache for other consumers and
|
52 |
58 |
# update the content in a different thread
|
53 |
59 |
self.cache(template_body)
|
54 |
|
threading.Thread(target=self.update_content).start()
|
55 |
|
return Template(template_body)
|
|
60 |
# for background refresh we do not care about retrieval miss
|
|
61 |
self.disable_recurse = True
|
|
62 |
threading.Thread(target=self.request_template_body).start()
|
|
63 |
return template_body
|
56 |
64 |
|
57 |
|
def update_content(self):
|
58 |
|
r = requests.get(settings.THEME_SKELETON_URL, params={'source': self.source})
|
59 |
|
if r.status_code != 200:
|
60 |
|
logger.error('failed to retrieve theme')
|
|
65 |
def get_template_body_recurse(self):
|
|
66 |
'''We were unable to retrieve a base template for this source URL, look for one level up.'''
|
|
67 |
if self.disable_recurse:
|
61 |
68 |
return None
|
62 |
|
self.cache(r.text)
|
63 |
|
return r.text
|
|
69 |
parsed = urlparse.urlparse(self.source)
|
|
70 |
if not parsed.path or parsed.path == '/':
|
|
71 |
return None
|
|
72 |
if parsed.path.endswith('/'): # cd ..
|
|
73 |
new_path = urlparse.urljoin(parsed.path, '..')
|
|
74 |
else:
|
|
75 |
new_path = urlparse.urljoin(parsed.path, '.')
|
|
76 |
old_source = self.source
|
|
77 |
self.source = urlparse.urlunparse(parsed[:2] + (new_path, '', '', ''))
|
|
78 |
template_body = self.get_template_body()
|
|
79 |
self.source = old_source
|
|
80 |
return template_body
|
64 |
81 |
|
65 |
|
def cache(self, template_body):
|
|
82 |
def request_template_body(self):
|
|
83 |
try:
|
|
84 |
r = requests.get(settings.THEME_SKELETON_URL, params={'source': self.source})
|
|
85 |
except requests.RequestException:
|
|
86 |
template_body = self.get_template_body_recurse()
|
|
87 |
else:
|
|
88 |
if r.status_code != 200:
|
|
89 |
template_body = self.get_template_body_recurse()
|
|
90 |
else:
|
|
91 |
template_body = r.text
|
|
92 |
self.cache_template_body(template_body)
|
|
93 |
return template_body
|
|
94 |
|
|
95 |
def cache_template_body(self, template_body):
|
66 |
96 |
expiry_time = datetime.datetime.now() + datetime.timedelta(seconds=CACHE_REFRESH_TIMEOUT)
|
67 |
|
cache.set(self.cache_key,
|
68 |
|
(template_body, expiry_time),
|
69 |
|
2592000) # bypass cache level expiration time
|
|
97 |
cache.set(self.cache_key, (template_body, expiry_time),
|
|
98 |
2592000) # bypass cache level expiration time
|
|
99 |
|
70 |
100 |
|
71 |
101 |
def theme_base(request):
|
72 |
102 |
# this context processor adds two variables to context:
|