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)
Exemplo n.º 2
0
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()