class PystacheMessageBuilder: """A component that uses Pystache to populate a Mustache template in order to build a message.""" def __init__(self, template_dir, template_file): """Create a new PystacheMessageBuilder that uses the specified template file. :param template_dir: The directory to load template files from :param template_file: The template file to populate with values. """ self._renderer = Renderer(search_dirs=template_dir) raw_template = self._renderer.load_template(template_file) self._parsed_template = pystache.parse(raw_template) def build_message(self, message_dictionary): """Build a message by populating a Mustache template with values from the provided dictionary. :param message_dictionary: The dictionary of values to use when populating the template. :return: A string containing a message suitable for sending to a remote MHS. """ return self._renderer.render(self._parsed_template, message_dictionary)
class PagePropertiesEditor: def __init__(self, pagePropertiesEditor, templates={}, confluence=None, pagePropertiesOrder=None, **kwargs): self.editor = pagePropertiesEditor self.templates = templates self.confluence = confluence self.order = None if 'order' in kwargs: self.order = kwargs['order'] if pagePropertiesOrder is not None: self.order = pagePropertiesOrder self.renderer = Renderer( search_dirs="{}/templates".format(dirname(__file__)), file_extension="mustache", ) for t in ['user', 'page', 'link', 'list', 'value']: self.renderer.load_template(t) self.userkeys = {} def userkey(self, name): "resolve username to userkey" if name not in self.userkeys: self.userkeys[name] = self.confluence.getUser(name)['userKey'] return self.userkeys[name] ELEM = re.compile( r'''(?: \[ ( ~(?P<user>[^\]]*?) | (?P<spacekey>\w+):(?P<title>[^\]]*?) | (?P<link>[^\]]*?) ) \] | (?P<datetime>\d\d\d\d-\d\d-\d\d(?:\s\d\d:\d\d(?::\d\d)?)?) ) ''', re.VERBOSE) def get_storage(self, key, value, templates=None): "get storage representation for value using templates" def render(name, **context): # try first, if there is a name-specific template for _name in ["{}-{}".format(key, name), name]: # first try local templates if _name in templates: return self.renderer.render(templates[_name], context) # try editor templates elif _name in self.templates: return self.renderer.render(self.templates[_name], context) # finally return the default template return self.renderer.render_name(name, context) logger.debug("value (%s): %s", value.__class__.__name__, value) if isinstance(value, list): values = [{ 'value': self.get_storage(key, v, templates).strip() } for v in value] return render('list', list=values) if isinstance(value, date): value = value.isoformat() if isinstance(value, datetime): value = value.strftime('%Y-%m-%d') def replacer(m): d = m.groupdict() if d['user']: return render('user', userkey=self.userkey(d['user'])) if d['spacekey']: return render('page', **d) if d['link']: if '|' in d['link']: caption, href = d['link'].split('|') else: caption, href = (d['link'], ) * 2 return render('link', caption=caption, href=href) if d['datetime']: return render('datetime', datetime=d['datetime']) if not isinstance(value, basestring): value = str(value) value = self.ELEM.sub(replacer, value) return render('value', value=value.strip()) def edit_prop(self, key, data, action): if not isinstance(action, dict): return self.get_storage(key, action, {}) if 'replace' in action: data = action['replace'] if 'remove' in action: values = action['remove'] if not isinstance(values, list): values = [values] if not isinstance(data, list): if values[0] == data: data = [] else: logger.debug("replace(%s): value %s not present", key, values[0]) else: for val in values: if val in data: data.remove(val) if 'add' in action: values = action['add'] if not isinstance(values, list): values = [values] if not isinstance(data, list): if not data: data = [] else: data = [data] data += values return self.get_storage(key, data, action.get('templates', {})) def edit(self, page=None): updated_keys = [] if page is not None: content = page['body']['storage']['value'] pageProperties = page['pageProperties'] else: with open(dirname(__file__) + '/templates/page-props.html', 'r') as f: content = f.read() pageProperties = {} editor = edit(content) s = "ac|structured-macro[ac|name=details] > ac|rich-text-body > table > tbody > tr" for row in editor(s): key = editor(row).find('th').text().strip() if key not in self.editor: continue updated_keys.append(key) action = self.editor[key] if action == 'delete': editor(row).remove() continue data = pageProperties.get(key, '') html_data = self.edit_prop(key, data, action) x = editor(row).find('td') #import rpdb2 ; rpdb2.start_embedded_debugger('foo') x.html(html_data) selector = "ac|structured-macro[ac|name=details] table tbody" order = self.order if order is None: order = self.editor.keys() for key in order: action = self.editor[key] if action == 'delete': continue if key not in updated_keys: html_data = self.edit_prop(key, '', action) tr = "<tr><th>{}</th><td>{}</td></tr>".format(key, html_data) editor(selector).append(tr) return editor.end_edit()