示例#1
0
    def next(self, xml, state, mongo, config, *, skip_reverse=False):
        xmliter = iter(xml)

        # consume up to this node
        ifnode = xmliter.find(lambda e: e.getAttribute('id') == self.id)

        if not get_values(state)[self.id]['condition']:
            xmliter.expand(ifnode)

        return make_node(xmliter.next_skipping_elifelse(), xmliter)
示例#2
0
    def work(self, config, state, channel, mongo):
        data_forms = self.make_request(get_values(state))

        return [
            Form.state_json(data_form['id'],
                            [{
                                'name': item['name'],
                                'state': 'valid',
                                'type': item['type'],
                                'value': item['value'],
                                'label': item['label'],
                                'value_caption': item['value_caption'],
                                'hidden': False,
                            } for item in data_form['items']])
            for data_form in data_forms
        ]
示例#3
0
    def work(self, config, state, channel, mongo):
        xml = Xml.load(config, self.procname)

        xmliter = iter(xml)
        node = make_node(next(xmliter), xmliter)
        context = get_values(state)

        data = {
            'form_array': [f.render(context) for f in self.forms],
        }

        collected_input = node.validate_input(data)

        xml.start(node, collected_input, mongo, channel, '__system__')

        return []
示例#4
0
def test_get_values():
    execution = {
        'values': {
            'form1': [
                {
                    'input1': 'A',
                },
                {
                    'input1': 'B',
                },
            ],
        },
    }

    context = get_values(execution)

    assert context['form1']['input1'] == 'B'
    assert list(context['form1'].all())[0]['input1'] == 'A'
示例#5
0
    def work(self, config, state, channel, mongo):
        tree = Condition().parse(self.condition)

        try:
            value = ConditionTransformer(get_values(state)).transform(tree)
        except ValueError as e:
            raise InconsistentState('Could not evaluate condition: {}'.format(
                str(e)))

        return [
            Form.state_json(self.id, [{
                'name': 'condition',
                'state': 'valid',
                'type': 'bool',
                'value': value,
                'value_caption': str(value),
            }])
        ]
示例#6
0
    def resolve_params(self, state=None):
        computed_params = {}

        for param in self.auth_params:
            if state is not None and param.type == 'ref':
                element_ref, req = param.value.split('#')

                if element_ref == 'user':
                    value = state['actors'][req]

                elif element_ref == 'form':
                    try:
                        _form, _input = req.split('.')

                        value = get_values(state)[_form][_input]
                    except ValueError:
                        value = None
            else:
                value = param.value

            computed_params[param.name] = value

        return computed_params
示例#7
0
    def next(self, xml, state, mongo, config, *, skip_reverse=False):
        context = get_values(state)

        if skip_reverse or context[self.id]['response'] == 'accept':
            return super().next(xml, state, mongo, config)

        state_updates = cascade_invalidate(xml, state,
                                           context[self.id]['inputs'],
                                           context[self.id]['comment'])

        # update state
        collection = mongo[config['EXECUTION_COLLECTION']]
        collection.update_one({
            'id': state['id'],
        }, {
            '$set': state_updates,
        })

        # reload state
        state = next(collection.find({'id': state['id']}))

        first_invalid_node = track_next_node(xml, state, mongo, config)

        return first_invalid_node
示例#8
0
def execution_template(id):
    # load values
    collection = mongo.db[app.config['EXECUTION_COLLECTION']]

    try:
        exc = next(collection.find({'id': id}))
    except StopIteration:
        raise ModelNotFoundError(
            'Specified execution never existed, and never will'
        )

    execution = json_prepare(exc)

    if 'process_name' not in exc:
        return 'Not supported for old processes', 409

    # prepare default template
    default = ['<div><b>Available keys</b></div>']
    context = get_values(execution)

    for key in context:
        token = '<div>{}</div>'
        default.append(token.format(key, key))

    template_string = ''.join(default)

    # load template
    template_dir = app.config['TEMPLATE_PATH']
    process_name = execution['process_name']
    name, version, _ = process_name.split('.')

    # file or folder
    ff_name = '.'.join([name, version])

    template_name = None
    # If template file exists...
    if os.path.isfile(
        os.path.join(template_dir, ff_name + '.html')
    ):
        template_name = ff_name + '.html'
    # Else check for any folder...
    elif os.path.isfile(
        os.path.join(template_dir, ff_name + '/', 'template.html')
    ):
        # set loader for "includes"
        custom_loader = jinja2.ChoiceLoader([
            jinja2.FileSystemLoader([
                app.config['TEMPLATE_PATH'] + '/' + ff_name,
            ]),
        ])
        bp.jinja_loader = custom_loader

        # ... and return the "main template"
        template_name = ff_name + '/template.html'

    if template_name:
        with open(os.path.join(template_dir, template_name), 'r') as contents:
            template_string = contents.read()

    # return template interpolation
    return make_response(
        render_template_string(template_string, **context),
        200,
    )
示例#9
0
    def teardown(self, node, pointer, user, input):
        ''' finishes the node's lifecycle '''
        execution = pointer.proxy.execution.get()
        execution.proxy.actors.add(user)

        actor_json = {
            '_type': 'actor',
            'state': 'valid',
            'user': user.to_json(include=[
                '_type',
                'fullname',
                'identifier',
            ]),
            'forms': input,
        }

        # update pointer
        collection = self.get_mongo()[self.config['POINTER_COLLECTION']]
        collection.update_one({
            'id': pointer.id,
        }, {
            '$set': {
                'state':
                'finished',
                'finished_at':
                datetime.now(),
                'actors':
                Map([actor_json],
                    key=lambda a: a['user']['identifier']).to_json(),
            },
        })

        values = self.compact_values(input)

        # update state
        exe_collection = self.get_mongo()[self.config['EXECUTION_COLLECTION']]
        ptr_collection = self.get_mongo()[self.config['POINTER_COLLECTION']]

        mongo_exe = exe_collection.find_one_and_update(
            {'id': execution.id},
            {
                '$addToSet': {
                    'actor_list': {
                        'node': node.id,
                        'identifier': user.identifier,
                    },
                },
                '$set': {
                    **{
                        'state.items.{node}.state'.format(node=node.id):
                        'valid',
                        'state.items.{node}.actors.items.{identifier}'.format(
                            node=node.id,
                            identifier=user.identifier,
                        ):
                        actor_json,
                        'actors.{}'.format(node.id):
                        user.identifier,
                    },
                    **values
                },
            },
            return_document=pymongo.collection.ReturnDocument.AFTER,
        )

        context = get_values(mongo_exe)

        # update execution's name and description
        execution.name = render_or(
            execution.name_template,
            execution.name,
            context,
        )
        execution.description = render_or(execution.description_template,
                                          execution.description, context)
        execution.save()

        exe_collection.update_one(
            {'id': execution.id},
            {
                '$set': {
                    'name': execution.name,
                    'description': execution.description,
                    'values._execution.0.name': execution.name,
                    'values._execution.0.description': execution.description,
                }
            },
        )

        ptr_collection.update_many(
            {'execution.id': execution.id},
            {'$set': {
                'execution': execution.to_json(),
            }},
        )

        LOGGER.debug('Deleted pointer p:{} n:{} e:{}'.format(
            pointer.id,
            pointer.node_id,
            execution.id,
        ))

        pointer.delete()
示例#10
0
    def wakeup(self, node, execution, channel, state):
        ''' Waking up a node often means to notify someone or something about
        the execution, this is the first step in node's lifecycle '''

        # TODO remove this code from here since it doesn't belong to the limits
        # of the handler
        # BEGIN ------------
        exc_col = self.get_mongo()[self.config['EXECUTION_COLLECTION']]
        ptr_col = self.get_mongo()[self.config['POINTER_COLLECTION']]

        # get currect execution context
        exc_doc = next(exc_col.find({'id': execution.id}))
        context = get_values(exc_doc)

        # interpolate
        rendered_name = render_or(node.name, node.name, context)
        rendered_description = render_or(node.description, node.description,
                                         context)

        node.name = rendered_name
        node.description = rendered_description
        # END ------------
        # TODO read note above, this code does not belong here

        # create a pointer in this node
        pointer = self.create_pointer(node, execution)
        LOGGER.debug('Created pointer p:{} n:{} e:{}'.format(
            pointer.id,
            node.id,
            execution.id,
        ))

        # mark this node as ongoing
        exc_col.update_one({
            'id': execution.id,
        }, {
            '$set': {
                'state.items.{}.state'.format(node.id): 'ongoing',
            },
        })

        # update registry about this pointer
        ptr_col.insert_one(node.pointer_entry(execution, pointer))

        # notify someone (can raise an exception
        if isinstance(node, UserAttachedNode):
            notified_users = self.notify_users(node, pointer, channel, state)
        else:
            notified_users = []

        # do some work (can raise an exception
        if not node.is_async():
            input = node.work(self.config, state, channel, self.get_mongo())
        else:
            input = []

        # set actors to this pointer (means everything succeeded)
        ptr_col.update_one({
            'id': pointer.id,
        }, {
            '$set': {
                'notified_users': notified_users,
            },
        })

        # nodes with forms are not queued
        if not node.is_async():
            return pointer, input