in Allura/allura/lib/app_globals.py [0:0]
def cached_convert(self, artifact: MappedClass, field_name: str) -> Markup:
"""
Convert ``artifact.field_name`` markdown source to html, caching
the result if the render time is greater than the defined threshold.
:param artifact: often an artifact, but also can be Neighborhood, OAuthConsumerToken, etc
"""
source_text = getattr(artifact, field_name)
cache_field_name = field_name + '_cache'
cache = getattr(artifact, cache_field_name, None)
if not cache:
log.warning(
'Skipping Markdown caching - Missing cache field "%s" on class %s',
field_name, artifact.__class__.__name__)
return self.convert(source_text)
bugfix_rev = 4 # increment this if we need all caches to invalidated (e.g. xss in markdown rendering fixed)
md5 = None
# If a cached version exists and it is valid, return it.
if cache.md5 is not None:
md5 = hashlib.md5(source_text.encode('utf-8')).hexdigest()
if cache.md5 == md5 and getattr(cache, 'fix7528', False) == bugfix_rev:
return Markup(cache.html) # noqa: S704
# Convert the markdown and time the result.
start = time.time()
html = self.convert(source_text, render_limit=False)
render_time = time.time() - start
threshold = config.get('markdown_cache_threshold')
try:
threshold = float(threshold) if threshold else None
except ValueError:
threshold = None
log.warning('Skipping Markdown caching - The value for config param '
'"markdown_cache_threshold" must be a float.')
# Check if contains macro and never cache
if self.uncacheable_macro_regex.search(source_text):
if render_time > float(config.get('markdown_cache_threshold.nocache', 0.5)):
try:
details = artifact.index_id()
except Exception:
details = str(artifact._id)
try:
details += ' ' + artifact.url()
except Exception:
pass
log.info(f'Not saving markdown cache since it has a dynamic macro. Took {render_time:.03}s on {details}')
return html
if threshold is not None and render_time > threshold:
# Save the cache
if md5 is None:
md5 = hashlib.md5(source_text.encode('utf-8')).hexdigest()
cache.md5, cache.html, cache.render_time = md5, html, render_time
cache.fix7528 = bugfix_rev # flag to indicate good caches created after [#7528] and other critical bugs were fixed.
try:
sess = session(artifact)
except AttributeError:
# this can happen if a non-artifact object is used
log.exception('Could not get session for %s', artifact)
else:
with utils.skip_mod_date(artifact.__class__), \
utils.skip_last_updated(artifact.__class__):
sess.flush(artifact)
return html