예제 #1
0
파일: advanced.py 프로젝트: todun/ksweb
class PreconditionAdvancedController(RestController):
    def _before(self, *args, **kw):
        tmpl_context.sidebar_section = "preconditions"
        tmpl_context.sidebar_precondition_advanced = "preconditions-advanced"

    @expose()
    def get_all(self, workspace, **kw):
        tg.redirect('/precondition', params=dict(workspace=workspace))

    @expose('ksweb.templates.precondition.advanced.new')
    @validate({'workspace': WorkspaceExistValidator(required=True)})
    def new(self, workspace, **kw):
        return dict(precondition={}, workspace=workspace)

    @decode_params('json')
    @expose('json')
    @validate({
        'title': StringLengthValidator(min=2),
        'workspace': WorkspaceExistValidator(required=True),
        'conditions': LengthValidator(min=1, required=True),
    }, error_handler=validation_errors_response)
    def post(self, title, workspace, conditions, **kw):
        error, condition = self._marshall_complex_filter(conditions)
        if error:
            response.status_code = 412
            return dict(errors=error)

        user = request.identity['user']
        Precondition(
            _owner=user._id,
            _workspace=ObjectId(workspace),
            title=title,
            type='advanced',
            condition=condition
        )

        flash(_("Now you can create an output <a href='%s'>HERE</a>" % lurl('/output?workspace='+ str(workspace))))
        return dict(errors=None)

    @decode_params('json')
    @expose('json')
    @validate({
        '_id': PreconditionExistValidator(required=True),
        'title': StringLengthValidator(min=2),
        'workspace': WorkspaceExistValidator(required=True),
        'conditions': LengthValidator(min=1, required=True),
    }, error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this filter.'),
            field='_id',
            entity_model=Precondition))
    def put(self, _id, title, workspace, conditions, **kw):
        error, condition = self._marshall_complex_filter(conditions)
        if error:
            response.status_code = 412
            return dict(errors=error)

        check = self.get_related_entities(_id)

        if check.get("entities"):
            entity = dict(
                _id=_id,
                title=title,
                condition=list(map(str, condition)),
                _workspace=workspace,
                auto_generated=False,
                entity='precondition/advanced',
            )
            session['entity'] = entity  # overwrite always same key for avoiding conflicts
            session.save()
            return dict(redirect_url=tg.url('/resolve', params=dict(workspace=workspace)))

        precondition = Precondition.query.get(_id=ObjectId(_id))
        precondition.title = title
        precondition.condition = condition
        precondition.auto_generated = False
        precondition.status = Precondition.STATUS.UNREAD
        precondition._workspace = workspace

        return dict(errors=None, redirect_url=None)

    @expose('ksweb.templates.precondition.advanced.new')
    @validate({
        '_id': PreconditionExistValidator(),
        'workspace': WorkspaceExistValidator(),
    }, error_handler=validation_errors_response)
    @require(CanManageEntityOwner(msg=l_(u'You are not allowed to edit this filter.'), field='_id',
                                  entity_model=Precondition))
    def edit(self, _id, workspace=None, **kw):
        precondition = Precondition.query.get(ObjectId(_id))
        return dict(precondition=precondition, workspace=workspace, errors=None)

    @decode_params('json')
    @expose('json')
    def get_related_entities(self, _id):
        return get_related_entities_for_filters(_id)

    def _marshall_complex_filter(self, filters):
        boolean_str = ""
        marshalled_filter = []

        for _f in filters:
            if _f['type'] == 'precondition':
                p = Precondition.query.get(ObjectId(_f['content']))
                error = None if p else {'conditions': _('Filter not found.')}
                boolean_str += "True "
                marshalled_filter.append(ObjectId(_f['content']))
            elif _f['type'] == 'operator':
                o = _f['content'] in Precondition.PRECONDITION_OPERATOR
                error = None if o else {'conditions': _('Filter not found.')}
                boolean_str += _f['content'] + " "
                marshalled_filter.append(_f['content'])
            else:
                error = {'conditions': _('Invalid operator')}

        try:
            eval(boolean_str)
        except SyntaxError as e:
            error = {'conditions': _('Syntax error')}

        return error, marshalled_filter
예제 #2
0
파일: qa.py 프로젝트: fossabot/ksweb
class QaController(RestController):
    def _before(self, *args, **kw):
        tmpl_context.sidebar_section = "qas"

    allow_only = predicates.has_any_permission(
        'manage', 'lawyer', msg=l_('Only for admin or lawyer'))

    @expose('ksweb.templates.qa.index')
    @paginate('entities',
              items_per_page=int(tg.config.get('pagination.items_per_page')))
    @validate({
        'workspace': CategoryExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    def get_all(self, workspace=None, **kw):
        return dict(page='qa-index',
                    fields={
                        'columns_name':
                        [_('Label'), _('Question'),
                         _('Filter')],
                        'fields_name':
                        ['title', 'question', 'parent_precondition']
                    },
                    entities=model.Qa.qa_available_for_user(
                        request.identity['user']._id, workspace),
                    actions=False,
                    workspace=workspace)

    @expose('json')
    @validate({
        'id': QAExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    def get_one(self, id, **kw):
        qa = model.Qa.query.find({
            '_id': ObjectId(id),
            '_owner': request.identity['user']._id
        }).first()
        return dict(qa=qa)

    @expose('json')
    @validate({'workspace': CategoryExistValidator(required=True)})
    def get_single_or_multi_question(self, workspace):
        questions = model.Qa.query.find({
            'type': {
                '$in': ['single', 'multi']
            },
            '_owner': request.identity['user']._id,
            '_category': ObjectId(workspace)
        }).all()
        return dict(questions=[{
            '_id': qa._id,
            'title': qa.title
        } for qa in questions])

    @expose('json')
    @expose('ksweb.templates.qa.new')
    @validate({
        'workspace': CategoryExistValidator(required=True),
    })
    def new(self, workspace, **kw):
        return dict(errors=None,
                    workspace=workspace,
                    referrer=kw.get('referrer'),
                    qa={
                        'question': kw.get('question_content', None),
                        'title': kw.get('question_title', None),
                        '_parent_precondition': kw.get('precondition_id', None)
                    })

    @decode_params('json')
    @expose('json')
    @validate(
        {
            'title': StringLengthValidator(min=2),
            'category': CategoryExistValidator(required=True),
            'question': StringLengthValidator(min=2),
            'tooltip': StringLengthValidator(min=0, max=100),
            'link': StringLengthValidator(min=0, max=100),
            'answer_type': OneOfValidator(values=model.Qa.QA_TYPE,
                                          required=True),
            'precondition': PreconditionExistValidator(required=False),
        },
        error_handler=validation_errors_response)
    def post(self,
             title,
             category,
             question,
             tooltip,
             link,
             answer_type,
             precondition=None,
             answers=None,
             **kw):
        if not self._are_answers_valid(answer_type, answers):
            response.status_code = 412
            return dict(
                errors={'answers': _('Please add at least one more answer')})

        user = request.identity['user']

        qa = model.Qa(_owner=user._id,
                      _category=ObjectId(category),
                      _parent_precondition=ObjectId(precondition)
                      if precondition else None,
                      title=title,
                      question=question,
                      tooltip=tooltip,
                      link=link,
                      type=answer_type,
                      answers=answers,
                      public=True,
                      visible=True)

        self._autofill_qa_filters(qa)
        return dict(errors=None, _id=ObjectId(qa._id))

    @decode_params('json')
    @expose('json')
    @validate(
        {
            '_id': QAExistValidator(required=True),
            'title': StringLengthValidator(min=2),
            'category': CategoryExistValidator(required=True),
            'question': StringLengthValidator(min=2),
            'tooltip': StringLengthValidator(min=0, max=100),
            'link': StringLengthValidator(min=0, max=100),
            'answer_type': OneOfValidator(values=model.Qa.QA_TYPE,
                                          required=True),
            'precondition': PreconditionExistValidator(required=False),
        },
        error_handler=validation_errors_response)
    def put(self,
            _id,
            title,
            category,
            question,
            tooltip,
            link,
            answer_type,
            precondition=None,
            answers=None,
            **kw):
        if not self._are_answers_valid(answer_type, answers):
            response.status_code = 412
            return dict(
                errors={'answers': _('Please add at least one more answer')})

        check = self.get_related_entities(_id)

        if check.get("entities"):
            entity = dict(_id=_id,
                          _category=category,
                          title=title,
                          entity='qa',
                          question=question,
                          tooltip=tooltip,
                          link=link,
                          type=answer_type,
                          _parent_precondition=precondition,
                          answers=answers)

            session.data_serializer = 'pickle'
            session[
                'entity'] = entity  # overwrite always same key for avoiding conflicts
            session.save()

            return dict(redirect_url=tg.url('/resolve',
                                            params=dict(workspace=category)))

        qa = model.Qa.query.get(_id=ObjectId(_id))
        qa._category = ObjectId(category)
        qa._parent_precondition = to_object_id(precondition)
        qa.title = title
        qa.question = question
        qa.tooltip = tooltip
        qa.question = question
        qa.link = link
        qa.type = answer_type
        qa.answers = answers
        self._autofill_qa_filters(qa)

        return dict(errors=None)

    @expose('ksweb.templates.qa.new')
    @validate({'_id': QAExistValidator(model=True)},
              error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(msg=l_(u'You can not edit this Q/A'),
                             field='_id',
                             entity_model=model.Qa))
    def edit(self, _id, workspace=None, **kw):
        ws = model.Category.query.find({'_id': ObjectId(workspace)}).first()
        if not ws:
            return tg.abort(404)
        qa = model.Qa.query.find({'_id': ObjectId(_id)}).first()
        return dict(qa=qa, workspace=ws._id, errors=None)

    @expose('json')
    @decode_params('json')
    @validate({
        '_id': QAExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    def human_readable_details(self, _id, **kw):
        qa = model.Qa.query.find({'_id': ObjectId(_id)}).first()
        return dict(qa=qa)

    @decode_params('json')
    @expose('json')
    def get_related_entities(self, _id):
        """
        This method return ALL entities (Precondition simple) that have inside the given _id
        :param _id:
        :return:
        """

        preconditions_related = model.Precondition.query.find({
            'type':
            'simple',
            'condition':
            ObjectId(_id)
        })
        entities = list(preconditions_related)
        return {'entities': entities, 'len': len(entities)}

    def _autofill_qa_filters(self, qa):
        user = request.identity['user']
        if qa.type == 'text':  # model.Qa.QA_TYPE[0]
            model.Precondition(_owner=user._id,
                               _category=ObjectId(qa._category),
                               title=qa.title + _(' -> ANSWERED'),
                               type='simple',
                               condition=[qa._id, ''])
        else:
            base_precond = []
            for answer in qa.answers:
                prec = model.Precondition(
                    _owner=user._id,
                    _category=ObjectId(qa._category),
                    title=qa.title + ' -> %s' % answer,
                    type='simple',
                    condition=[qa._id, answer],
                )
                base_precond.append(prec)

            condition = []
            for prc in base_precond[:-1]:
                condition.append(prc._id)
                condition.append('or')

            condition.append(base_precond[-1]._id)

            created_precondition = model.Precondition(
                _owner=user._id,
                _category=ObjectId(qa._category),
                title=qa.title + _(' -> ANSWERED'),
                type='advanced',
                condition=condition)

    def _are_answers_valid(self, answer_type, answers):
        if (answer_type == "single" and len(answers) < 2) or\
           (answer_type == "multi" and len(answers) < 1):
            return False
        return True
예제 #3
0
class QuestionaryController(BaseController):
    def _before(self, *args, **kw):
        tmpl_context.sidebar_section = "questionaries"

    allow_only = predicates.has_any_permission(
        'manage', 'lawyer', msg=l_('Only for admin or lawyer'))

    @expose('ksweb.templates.questionary.index')
    @paginate('entities',
              items_per_page=int(tg.config.get('pagination.items_per_page')))
    @validate({'workspace': CategoryExistValidator(required=True)})
    def index(self, workspace, **kw):
        user = request.identity['user']
        documents_id = [
            ObjectId(documents._id)
            for documents in model.Document.document_available_for_user(
                user_id=user._id, workspace=workspace).all()
        ]
        entities = model.Questionary.query.find({
            '$or': [{
                '_user': ObjectId(user._id)
            }, {
                '_owner': ObjectId(user._id)
            }],
            '_document': {
                '$in': documents_id
            }
        }).sort('title')
        return dict(
            page='questionary-index',
            fields={
                'columns_name': [
                    _('Title'),
                    _('Owner'),
                    _('Shared with'),
                    _('Created on'),
                    _('Completion %')
                ],
                'fields_name':
                ['title', '_owner', '_user', 'creation_date', 'completion']
            },
            entities=entities,
            actions=False,
            actions_content=[_('Export')],
            workspace=workspace)

    @decode_params('json')
    @expose('json')
    @validate(
        {
            'questionary_title': StringLengthValidator(min=2),
            'document_id': DocumentExistValidator(required=True),
            'email_to_share': EmailValidator(),
        },
        error_handler=validation_errors_response)
    def create(self,
               questionary_title=None,
               document_id=None,
               email_to_share=None,
               **kw):
        #  create questionary for himself
        owner = request.identity['user']
        if email_to_share:
            user = model.User.by_email_address(email_to_share)

            if not user:
                user = model.User(
                    user_name=email_to_share,
                    email_address=email_to_share,
                    display_name=email_to_share,
                )
        else:
            user = owner

        questionary = model.Questionary(
            title=questionary_title,
            _user=user._id,
            _owner=owner._id,
            _document=ObjectId(document_id),
        )

        if email_to_share:
            from tgext.mailer import get_mailer
            from tgext.mailer import Message
            mailer = get_mailer(request)
            share_url = tg.url('/dashboard',
                               params={'share_id': user._id},
                               qualified=True)
            message = Message(
                subject=_("Invite to a KSWEB document"),
                sender="*****@*****.**",
                recipients=[user.email_address],
                body=_(
                    "Hi, you were invited to compile the following document %s "
                    "at the following url %s" %
                    (questionary_title, share_url)))
            mailer.send_immediately(message)
            flash(
                _("Questionary succesfully created and shared to %s" %
                  email_to_share))
        return dict(questionary=questionary)

    @expose('ksweb.templates.questionary.compile')
    @expose('json')
    @validate(
        {
            '_id': QuestionaryExistValidator(required=True),
            'workspace': CategoryExistValidator(required=True),
        },
        error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this questionary.'),
            field='_id',
            entity_model=model.Questionary))
    def compile(self, _id, workspace, **kwargs):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        return dict(questionary=questionary,
                    quest_compiled=questionary.evaluate_questionary,
                    html=self.get_questionary_html(_id),
                    workspace=workspace)

    @expose('odt:ksweb.templates.questionary.questionary',
            content_type='application/vnd.oasis.opendocument.text')
    @validate({
        '_id': QuestionaryExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this questionary.'),
            field='_id',
            entity_model=model.Questionary))
    def download(self, _id):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        response.headerlist.append(
            ('Content-Disposition',
             'attachment;filename=%s.odt' % questionary._id))
        return dict(content=self.get_questionary_html(_id).striptags())

    @staticmethod
    def get_questionary_html(quest_id):
        questionary = model.Questionary.query.get(_id=ObjectId(quest_id))
        questionary_compiled = Template(questionary.document.html)

        output_values, qa_values = dict(), dict()

        for output_dict in questionary.document.content:
            _id = ObjectId(output_dict['content'])
            if output_dict['content'] in questionary.output_values and \
                    questionary.output_values[output_dict['content']]['evaluation']:
                output = model.Output.query.get(_id=_id)
                output_values['output_' + str(_id)] = output.render(
                    questionary.output_values)
            else:
                # this clear useless output placeholder
                output_values['output_' + str(_id)] = ''
        questionary_compiled = questionary_compiled.safe_substitute(
            **output_values)
        questionary_compiled = Template(questionary_compiled)

        for qa_id, resp in questionary.qa_values.items():
            qa_values['qa_' + qa_id] = Markup.escape(resp['qa_response'])

        return Markup(questionary_compiled.safe_substitute(**qa_values))

    @expose('json')
    @decode_params('json')
    @validate(
        {
            '_id': QuestionaryExistValidator(required=True),
            'qa_id': QAExistValidator(required=True),
            'qa_response': StringLengthValidator(min=1, strip=False),
        },
        error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this questionary.'),
            field='_id',
            entity_model=model.Questionary))
    def responde(self, _id=None, qa_id=None, qa_response=None, **kwargs):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        #  Check if the qa response is valid
        qa = model.Qa.query.get(_id=ObjectId(qa_id))
        if qa.type == "single" and not qa_response in qa.answers:
            response.status_code = 412
            return dict(errors={'qa_response': _('Invalid answer')})

        if qa.type == "multi":
            #  check each qa_response if is in qa.answers
            if isinstance(qa_response, basestring):
                qa_response = [qa_response]

                # This comment is needed for to allow users to 'not response' a question
                # For disable this, just uncomment followings rows

                # for elem in qa_response:
                #     if not elem in qa.answers:
                #         response.status_code = 412
                #         return dict(errors={'qa_response': _('Invalid answer')})

        if not questionary.qa_values:
            order_number = 0
        else:
            order_number = max([
                questionary.qa_values[elem]['order_number']
                for elem in questionary.qa_values
            ]) + 1
        questionary.qa_values[qa_id] = {
            'qa_response': qa_response,
            'order_number': order_number
        }

        # Not sure about flush here
        DBSession.flush(questionary)
        quest_compiled = questionary.evaluate_questionary

        return dict(questionary=questionary,
                    quest_compiled=quest_compiled,
                    html=self.get_questionary_html(_id))

    @expose('ksweb.templates.questionary.completed')
    @validate(
        {
            '_id': QuestionaryExistValidator(required=True),
            'workspace': CategoryExistValidator(required=True),
        },
        error_handler=validation_errors_response)
    def completed(self, _id=None, workspace=None):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        completed = questionary.evaluate_questionary
        if not completed:
            return redirect('/questionary/compile',
                            params=dict(quest_complited=completed,
                                        workspace=workspace))

        questionary_compiled = Template(questionary.document.html)
        output_values, qa_values = dict(), dict()

        for output_dict in questionary.document.content:
            _id = ObjectId(output_dict['content'])
            if questionary.output_values.get(output_dict['content']):
                output = model.Output.query.get(_id=_id)
                output_values['output_' + str(_id)] = output.render(
                    questionary.output_values)
            else:
                # this clear useless output placeholder
                output_values['output_' + str(_id)] = ''

        questionary_compiled = questionary_compiled.safe_substitute(
            **output_values)
        questionary_compiled = Template(questionary_compiled)

        for qa_id, resp in questionary.qa_values.items():
            qa_values['qa_' + qa_id] = Markup.escape(resp['qa_response'])

        questionary_compiled = questionary_compiled.safe_substitute(
            **qa_values)

        return dict(questionary_compiled=Markup(questionary_compiled),
                    workspace=workspace)

    @expose('json')
    @decode_params('json')
    @validate({'_id': QuestionaryExistValidator(required=True)},
              error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this questionary.'),
            field='_id',
            entity_model=model.Questionary))
    def previous_question(self, _id=None, **kwargs):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        previous_response = {}

        if questionary.qa_values:
            last_order_number = max([
                questionary.qa_values[qa_val]['order_number']
                for qa_val in questionary.qa_values
            ])
            last_question_answered = [
                qa_val for qa_val in questionary.qa_values
                if questionary.qa_values[qa_val]['order_number'] ==
                last_order_number
            ][0]
            previous_response = questionary.qa_values[last_question_answered][
                'qa_response']
            questionary.qa_values.pop(last_question_answered, None)
            DBSession.flush_all()

        return dict(questionary=questionary,
                    quest_compiled=questionary.evaluate_questionary,
                    html=self.get_questionary_html(_id),
                    previous_response=previous_response)
예제 #4
0
class PreconditionSimpleController(RestController):
    def _before(self, *args, **kw):
        tmpl_context.sidebar_section = "preconditions"

    @expose('ksweb.templates.precondition.simple.new')
    @validate({'workspace': CategoryExistValidator(required=True)})
    def new(self, workspace, **kw):
        return dict(page='precondition-new',
                    workspace=workspace,
                    qa_value=kw.get('qa_value'),
                    precondition={
                        'question_content': kw.get('question_content', None),
                        'question_title': kw.get('question_title', None)
                    })

    @decode_params('json')
    @expose('json')
    @validate(
        {
            'title':
            StringLengthValidator(min=2),
            'category':
            CategoryExistValidator(required=True),
            'question':
            QAExistValidator(required=True),
            'answer_type':
            OneOfValidator(values=[u'have_response', u'what_response'],
                           required=True),
        },
        error_handler=validation_errors_response)
    def post(self, title, category, question, answer_type, interested_response,
             **kw):
        user = request.identity['user']

        qa = model.Qa.query.get(_id=ObjectId(question))

        #  CASO BASE in cui risco a creare un filtro semplice per definizione e' quella di che venga solamente selezionata una risposta
        if len(interested_response) == 1:
            #  La risposta e' solo una creo un filtro semplice
            created_precondition = model.Precondition(
                _owner=user._id,
                _category=ObjectId(category),
                title=title,
                type='simple',
                condition=[ObjectId(question), interested_response[0]])
        else:
            #  CASO AVANZATO sono state selezionate piu' risposte, devo prima creare tutte i filtri semplici e poi creare quella complessa
            if answer_type == "have_response":
                #  Create one precondition simple for all possibility answer to question
                #  After that create a complex precondition with previous simple precondition
                interested_response = qa.answers

            if answer_type == "what_response":
                #  Create one precondition simple for all selected answer to question
                #  After that create a complex precondition with previous simple precondition

                if len(interested_response) <= 1:
                    response.status_code = 412
                    return dict(
                        errors={
                            'interested_response':
                            _('Please select at least one answer')
                        })

            base_precond = []
            for resp in interested_response:
                prec = model.Precondition(_owner=user._id,
                                          _category=ObjectId(category),
                                          title="%s_%s" %
                                          (qa.title.upper(), resp.upper()),
                                          type='simple',
                                          condition=[ObjectId(question), resp],
                                          public=True,
                                          visible=False)
                base_precond.append(prec)

            condition = []
            for prc in base_precond[:-1]:
                condition.append(prc._id)
                condition.append('or')

            condition.append(base_precond[-1]._id)

            created_precondition = model.Precondition(
                _owner=user._id,
                _category=ObjectId(category),
                title=title,
                type='advanced',
                condition=condition)

        #flash(_("Now you can create an output <a href='%s'>HERE</a>" % lurl('/output?workspace='+ str(category))))

        return dict(precondition_id=str(created_precondition._id), errors=None)

    @decode_params('json')
    @expose('json')
    @validate(
        {
            '_id':
            PreconditionExistValidator(required=True),
            'title':
            StringLengthValidator(min=2),
            'category':
            CategoryExistValidator(required=True),
            'question':
            QAExistValidator(required=True),
            'answer_type':
            OneOfValidator(values=[u'what_response'], required=True),
        },
        error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this filter.'),
            field='_id',
            entity_model=model.Precondition))
    def put(self, _id, title, category, question, answer_type,
            interested_response, **kw):

        check = self.get_related_entities(_id)
        if check.get("entities"):
            entity = dict(_id=_id,
                          title=title,
                          condition=[question, interested_response],
                          _category=category,
                          entity='precondition/simple')
            session[
                'entity'] = entity  # overwrite always same key for avoiding conflicts
            session.save()
            return dict(redirect_url=tg.url('/resolve',
                                            params=dict(workspace=category)))

        precondition = model.Precondition.query.get(_id=ObjectId(_id))
        precondition.title = title
        precondition.condition = [ObjectId(question), interested_response]
        precondition._category = category

        return dict(errors=None, redirect_url=None)

    @decode_params('json')
    @expose('json')
    def get_related_entities(self, _id):
        return get_related_entities_for_filters(_id)

    @expose('ksweb.templates.precondition.simple.new')
    @validate(
        {
            '_id': PreconditionExistValidator(),
            'workspace': CategoryExistValidator()
        },
        error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this filter.'),
            field='_id',
            entity_model=model.Precondition))
    def edit(self, _id, workspace, **kw):
        precondition = model.Precondition.query.find({
            '_id':
            ObjectId(_id),
            '_category':
            ObjectId(workspace)
        }).first()
        return dict(precondition=precondition,
                    workspace=workspace,
                    errors=None)

    @expose('json')
    @decode_params('json')
    @validate({
        '_id': PreconditionExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    def human_readable_details(self, _id, **kw):
        precondition = model.Precondition.query.find({
            '_id': ObjectId(_id)
        }).first()
        return dict(precondition=precondition)
예제 #5
0
class DocumentController(RestController):
    def _before(self, *args, **kw):
        tmpl_context.sidebar_section = "documents"

    allow_only = predicates.has_any_permission(
        'manage', 'lawyer', msg=l_('Only for admin or lawyer'))

    @expose('ksweb.templates.document.index')
    @paginate('entities',
              items_per_page=int(tg.config.get('pagination.items_per_page')))
    @validate({'workspace': WorkspaceExistValidator(required=True)})
    def get_all(self, workspace, **kw):
        return dict(
            page='document-index',
            fields={
                'columns_name':
                [_('Title'),
                 _('Description'),
                 _('Version'),
                 _('License')],
                'fields_name': ['title', 'description', 'version', 'license']
            },
            entities=model.Document.document_available_for_user(
                request.identity['user']._id, workspace=workspace),
            actions_content=[_('Export'), _('Create Form')],
            workspace=workspace,
            download=True)

    @expose('ksweb.templates.document.new')
    @validate({'workspace': WorkspaceExistValidator(required=True)})
    def new(self, workspace, **kw):
        tmpl_context.sidebar_document = "document-new"
        return dict(document={}, workspace=workspace, errors=None)

    @decode_params('json')
    @expose('json')
    @validate(
        {
            'title': StringLengthValidator(min=2),
            'workspace': WorkspaceExistValidator(required=True),
            'html': DocumentContentValidator(strip=False),
            'description': StringLengthValidator(min=0),
            'license': StringLengthValidator(min=0, max=100),
            'version': StringLengthValidator(min=0, max=100),
            'tags': StringLengthValidator(min=0, max=100)
        },
        error_handler=validation_errors_response)
    def post(self, title, workspace, description, license, version, tags, html,
             **kw):
        user = request.identity['user']
        tags = {__.strip() for __ in tags.split(',')} if tags else []

        doc = model.Document(_owner=user._id,
                             _workspace=ObjectId(workspace),
                             title=title,
                             public=True,
                             visible=True,
                             html=html,
                             description=description,
                             license=license,
                             version=version,
                             tags=list(tags))
        return dict(errors=None)

    @decode_params('json')
    @expose('json')
    @validate(
        {
            '_id': DocumentExistValidator(required=True),
            'title': StringLengthValidator(min=2),
            'workspace': WorkspaceExistValidator(required=True),
            'html': DocumentContentValidator(strip=False),
            'description': StringLengthValidator(min=0),
            'license': StringLengthValidator(min=0, max=100),
            'version': StringLengthValidator(min=0, max=100),
            'tags': StringLengthValidator(min=0),
        },
        error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this document.'),
            field='_id',
            entity_model=model.Document))
    def put(self, _id, title, html, workspace, description, license, version,
            tags, **kw):
        tags = {__.strip() for __ in tags.split(',')} if tags else []
        document = model.Document.query.find({'_id': ObjectId(_id)}).first()
        document.title = title
        document._workspace = ObjectId(workspace)
        document.html = html
        document.tags = list(tags)
        document.description = description
        document.license = license
        document.version = version
        return dict(errors=None)

    @expose('ksweb.templates.document.new')
    @validate(
        {
            '_id': DocumentExistValidator(required=True),
            'workspace': WorkspaceExistValidator(required=True)
        },
        error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this document.'),
            field='_id',
            entity_model=model.Document))
    def edit(self, _id, workspace, **kw):
        tmpl_context.sidebar_document = "document-new"
        document = model.Document.by_id(_id)
        return dict(document=document, workspace=workspace, errors=None)

    @expose('json')
    @decode_params('json')
    @validate({
        '_id': DocumentExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    def human_readable_details(self, _id, **kw):
        # TODO: implement something meaningful
        document = model.Document.query.find({'_id': ObjectId(_id)}).first()
        return dict(document=document)

    @expose("json", content_type='application/json')
    @validate({
        '_id': DocumentExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    def export(self, _id):
        document = model.Document.query.get(_id=ObjectId(_id))
        filename = slugify(document, document.title)
        response.headerlist.append(
            ('Content-Disposition',
             str('attachment;filename=%s.json' % filename)))
        encoded = json_render.encode(document.export())
        return json.dumps(json.loads(encoded), sort_keys=True, indent=4)

    @expose()
    @validate({
        'workspace': WorkspaceExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    def import_document(self, workspace, file_import):
        owner = request.identity['user']._id
        file_content = file_import.file.read()
        importer = JsonImporter(file_content, ObjectId(workspace), owner)
        importer.run()
        tg.flash(_('Document successfully imported!'))
        return redirect(tg.url('/document', params=dict(workspace=workspace)))
예제 #6
0
class FormController(BaseController):
    def _before(self, *args, **kw):
        tmpl_context.sidebar_section = "questionaries"

    allow_only = predicates.not_anonymous(msg=l_('Only for admin or lawyer'))

    @expose('ksweb.templates.questionary.index')
    @paginate('entities',
              items_per_page=int(tg.config.get('pagination.items_per_page')))
    @validate({'workspace': WorkspaceExistValidator(required=True)})
    def index(self, workspace, **kw):
        user = request.identity['user']
        documents_id = [
            ObjectId(documents._id)
            for documents in model.Document.document_available_for_user(
                user_id=user._id, workspace=workspace).all()
        ]
        entities = model.Questionary.query.find({
            '$or': [{
                '_user': ObjectId(user._id)
            }, {
                '_owner': ObjectId(user._id)
            }],
            '_document': {
                '$in': documents_id
            }
        }).sort([('_id', pymongo.DESCENDING), ('completed', pymongo.ASCENDING),
                 ('title', pymongo.ASCENDING)])
        return dict(page='questionary-index',
                    fields={
                        'columns_name': [
                            _('Title'),
                            _('Owner'),
                            _('Shared with'),
                            _('Created on'),
                            _('Completion %')
                        ],
                        'fields_name':
                        'title _owner _user creation_date completion'.split()
                    },
                    entities=entities,
                    actions=False,
                    actions_content=[_('Export')],
                    workspace=workspace)

    @decode_params('json')
    @expose('json')
    @validate(
        {
            'questionary_title': StringLengthValidator(min=2),
            'document_id': DocumentExistValidator(required=True),
            'email_to_share': EmailValidator()
        },
        error_handler=validation_errors_response)
    def create(self,
               questionary_title=None,
               document_id=None,
               email_to_share=None,
               **kw):
        owner = request.identity['user']
        if email_to_share:
            user = model.User.by_email_address(email_to_share)

            if not user:
                user = model.User(
                    user_name=email_to_share,
                    email_address=email_to_share,
                    display_name=email_to_share,
                )
        else:
            user = owner

        questionary = model.Questionary(
            title=questionary_title,
            _user=user._id,
            _owner=owner._id,
            _document=ObjectId(document_id),
        )

        if email_to_share:
            from tgext.mailer import get_mailer
            from tgext.mailer import Message
            mailer = get_mailer(request)
            share_url = tg.url('/dashboard',
                               params={'share_id': user._id},
                               qualified=True)
            message = Message(
                subject=_("Invite to a KSWEB document"),
                sender="*****@*****.**",
                recipients=[user.email_address],
                body=_(
                    "Hi, you were invited to compile the following document %s "
                    "at the following url %s" %
                    (questionary_title, share_url)))
            mailer.send_immediately(message)
            flash(
                _("Questionary succesfully created and shared to %s" %
                  email_to_share))
        return dict(questionary=questionary)

    @expose('ksweb.templates.questionary.compile')
    @expose('json')
    @validate({
        '_id': QuestionaryExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this questionary.'),
            field='_id',
            entity_model=model.Questionary))
    def compile(self, _id, **kwargs):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        return dict(questionary=questionary,
                    quest_compiled=questionary.evaluate_questionary,
                    html=self.get_questionary_html(_id),
                    recap=questionary.answers)

    @expose(content_type='text/html')
    @validate({
        '_id': QuestionaryExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this questionary.'),
            field='_id',
            entity_model=model.Questionary))
    def download(self, _id):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        filename = slugify(questionary, questionary.title)
        response.headerlist.append(
            ('Content-Disposition', 'attachment;filename=%s.md' % filename))
        filled_md = self.get_questionary_html(_id)
        unanswered, __ = find_entities_from_html(filled_md)
        return TemplateOutput(filled_md).safe_substitute(
            {k: ''
             for k in unanswered})

    @staticmethod
    def get_questionary_html(quest_id):
        questionary = model.Questionary.query.get(ObjectId(quest_id))
        if not questionary.document.content:
            return

        output_values, qa_values = dict(), dict()

        for output_dict in questionary.document.content:
            _id = output_dict['content']
            if output_dict['content'] in questionary.output_values and \
                    questionary.output_values[output_dict['content']]['evaluation']:
                output = model.Output.query.get(ObjectId(_id))
                output_values[output.hash] = output.render(
                    questionary.output_values)
            else:
                # this clear useless output placeholder
                output_values[_id] = ''
        safe_template = questionary.document.html
        questionary_with_expanded_output = TemplateOutput(
            safe_template).safe_substitute(output_values)
        questionary_compiled = TemplateAnswer(questionary_with_expanded_output)

        for qa_id, resp in questionary.qa_values.items():
            qa_values[id_to_hash(qa_id,
                                 Qa)] = Markup.escape(resp['qa_response'])

        return Markup(questionary_compiled.safe_substitute(qa_values))

    @expose('json')
    @decode_params('json')
    @validate(
        {
            '_id': QuestionaryExistValidator(required=True),
            'qa_id': QAExistValidator(required=True),
            'qa_response': StringLengthValidator(min=1, strip=False),
        },
        error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this questionary.'),
            field='_id',
            entity_model=model.Questionary))
    def responde(self, _id=None, qa_id=None, qa_response=None, **kwargs):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        #  Check if the qa response is valid
        qa = model.Qa.query.get(_id=ObjectId(qa_id))

        if qa.type == "single" and not qa_response in qa.answers:
            response.status_code = 412
            return dict(errors={'qa_response': _('Invalid answer')})

        if qa.type == "multi":
            #  check each qa_response if is in qa.answers
            if isinstance(qa_response, str):
                qa_response = [qa_response]

        if not questionary.qa_values:
            order_number = 0
        else:
            order_number = max([
                questionary.qa_values[elem]['order_number']
                for elem in questionary.qa_values
            ]) + 1
        questionary.qa_values[qa_id] = {
            'qa_response': qa_response,
            'order_number': order_number
        }
        quest_compiled = questionary.evaluate_questionary

        return dict(questionary=questionary,
                    quest_compiled=quest_compiled,
                    html=self.get_questionary_html(_id),
                    recap=questionary.answers)

    @expose('ksweb.templates.questionary.completed')
    @validate({
        '_id': QuestionaryExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    def completed(self, _id=None, workspace=None):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        completed = questionary.evaluate_questionary
        if not completed:
            return redirect('/questionary/compile',
                            params=dict(quest_complited=completed))

        questionary_compiled = self.get_questionary_html(_id)
        return dict(questionary_compiled=questionary_compiled)

    @expose('json')
    @decode_params('json')
    @validate({'_id': QuestionaryExistValidator(required=True)},
              error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this questionary.'),
            field='_id',
            entity_model=model.Questionary))
    def previous_question(self, _id=None, **kwargs):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        previous_response = {}

        if questionary.qa_values:
            last_order_number = max([
                questionary.qa_values[qa_val]['order_number']
                for qa_val in questionary.qa_values
            ])
            last_question_answered = [
                qa_val for qa_val in questionary.qa_values
                if questionary.qa_values[qa_val]['order_number'] ==
                last_order_number
            ][0]
            previous_response = questionary.qa_values[last_question_answered][
                'qa_response']
            questionary.qa_values.pop(last_question_answered, None)
            DBSession.flush_all()

        return dict(questionary=questionary,
                    quest_compiled=questionary.evaluate_questionary,
                    html=self.get_questionary_html(_id),
                    previous_response=previous_response,
                    recap=questionary.answers)
예제 #7
0
파일: simple.py 프로젝트: todun/ksweb
class PreconditionSimpleController(RestController):
    def _before(self, *args, **kw):
        tmpl_context.sidebar_section = "preconditions"

    @expose()
    def get_all(self, workspace, **kw):
        tg.redirect('/precondition', params=dict(workspace=workspace))

    @expose('ksweb.templates.precondition.simple.new')
    @validate({'workspace': WorkspaceExistValidator(required=True)})
    def new(self, workspace, **kw):
        return dict(page='precondition-new',
                    workspace=workspace,
                    qa_value=kw.get('qa_value'),
                    precondition={
                        'question_content': kw.get('question_content', None),
                        'question_title': kw.get('question_title', None)
                    })

    @decode_params('json')
    @expose('json')
    @validate(
        {
            'title':
            StringLengthValidator(min=2),
            'workspace':
            WorkspaceExistValidator(required=True),
            'question':
            QAExistValidator(required=True),
            'answer_type':
            OneOfValidator(values=[u'have_response', u'what_response']),
        },
        error_handler=validation_errors_response)
    def post(self,
             title,
             workspace,
             question,
             answer_type,
             interested_response=[],
             **kw):
        user = request.identity['user']
        qa = Qa.query.get(_id=ObjectId(question))
        _type = Precondition.TYPES.SIMPLE

        if qa.is_text:
            _condition = [qa._id, '']
        else:
            if answer_type == 'have_response':
                interested_response = qa.answers
            answers_len = len(interested_response)
            if answers_len < 1:
                response.status_code = 412
                return dict(errors={
                    'interested_response':
                    _('Please select at least one answer')
                })

            if answers_len == 1:
                _condition = [qa._id, interested_response[0]]
            else:
                advanced_condition = []
                for answer in interested_response:
                    ___ = Precondition(_owner=user._id,
                                       _workspace=ObjectId(workspace),
                                       title="%s_%s" %
                                       (qa.title.upper(), answer.upper()),
                                       type=_type,
                                       condition=[qa._id, answer],
                                       public=True,
                                       visible=False)
                    advanced_condition.append(___._id)
                    advanced_condition.append('or')
                del advanced_condition[-1]

                _condition = advanced_condition
                _type = Precondition.TYPES.ADVANCED

        new_filter = Precondition(_owner=user._id,
                                  _workspace=ObjectId(workspace),
                                  title=title,
                                  type=_type,
                                  condition=_condition)

        return dict(precondition_id=str(new_filter._id), errors=None)

    @decode_params('json')
    @expose('json')
    @validate(
        {
            '_id': PreconditionExistValidator(required=True),
            'title': StringLengthValidator(min=2),
            'workspace': WorkspaceExistValidator(required=True),
            'question': QAExistValidator(required=True),
        },
        error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this filter.'),
            field='_id',
            entity_model=Precondition))
    def put(self, _id, title, workspace, question, interested_response, **kw):
        check = self.get_related_entities(_id)

        if check.get("entities"):
            entity = dict(_id=_id,
                          title=title,
                          condition=[question, interested_response],
                          _workspace=workspace,
                          auto_generated=False,
                          entity='precondition/simple')
            session[
                'entity'] = entity  # overwrite always same key for avoiding conflicts
            session.save()
            return dict(redirect_url=tg.url('/resolve',
                                            params=dict(workspace=workspace)))

        precondition = Precondition.query.get(_id=ObjectId(_id))
        precondition.title = title
        precondition.condition = [ObjectId(question), interested_response]
        precondition.auto_generated = False
        precondition.status = Precondition.STATUS.UNREAD
        precondition._workspace = workspace

        return dict(errors=None, redirect_url=None)

    @decode_params('json')
    @expose('json')
    def get_related_entities(self, _id):
        return get_related_entities_for_filters(_id)

    @expose('ksweb.templates.precondition.simple.new')
    @validate(
        {
            '_id': PreconditionExistValidator(),
            'workspace': WorkspaceExistValidator()
        },
        error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this filter.'),
            field='_id',
            entity_model=Precondition))
    def edit(self, _id, workspace):
        precondition = Precondition.query.find({
            '_id':
            ObjectId(_id),
            '_workspace':
            ObjectId(workspace)
        }).first()
        return dict(precondition=precondition,
                    workspace=workspace,
                    errors=None)

    @expose('json')
    @decode_params('json')
    @validate({
        '_id': PreconditionExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    def human_readable_details(self, _id):
        return dict(precondition=Precondition.query.get(ObjectId(_id)))
예제 #8
0
파일: qa.py 프로젝트: todun/ksweb
class QaController(RestController):
    def _before(self, *args, **kw):
        tmpl_context.sidebar_section = "qas"

    allow_only = predicates.not_anonymous(msg=l_('Only for admin or lawyer'))

    @expose('ksweb.templates.qa.index')
    @paginate('entities',
              items_per_page=int(tg.config.get('pagination.items_per_page')))
    @validate({
        'workspace': WorkspaceExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    def get_all(self, workspace, **kw):
        return dict(page='qa-index',
                    fields={
                        'columns_name':
                        [_('Label'),
                         _('Question'),
                         _('Filter'),
                         _('Id')],
                        'fields_name':
                        'title question parent_precondition hash'.split()
                    },
                    entities=Qa.available_for_user(
                        request.identity['user']._id, workspace),
                    actions=False,
                    workspace=workspace)

    @expose('json')
    @validate({
        'id': QAExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    def get_one(self, id, **kw):
        id = hash_to_id(id, Qa)
        return dict(qa=Qa.by_id(id))

    @expose('json')
    @validate({'workspace': WorkspaceExistValidator(required=True)})
    def valid_options(self, workspace):
        questions = Qa.available_for_user(request.identity['user']._id,
                                          workspace)
        return dict(questions=[{
            '_id': qa._id,
            'title': qa.title
        } for qa in questions])

    @expose('json')
    @expose('ksweb.templates.qa.new')
    @validate({
        'workspace': WorkspaceExistValidator(required=True),
    })
    def new(self, workspace, **kw):
        return dict(errors=None,
                    workspace=workspace,
                    referrer=kw.get('referrer'),
                    qa={
                        'question': kw.get('question_content', None),
                        'title': kw.get('question_title', None),
                        '_parent_precondition': kw.get('precondition_id', None)
                    })

    @decode_params('json')
    @expose('json')
    @validate(
        {
            'title': StringLengthValidator(min=2),
            'workspace': WorkspaceExistValidator(required=True),
            'question': StringLengthValidator(min=2),
            'tooltip': StringLengthValidator(min=0, max=100),
            'link': StringLengthValidator(min=0, max=100),
            'answer_type': OneOfValidator(values=Qa.QA_TYPE, required=True),
            'precondition': PreconditionExistValidator(required=False),
        },
        error_handler=validation_errors_response)
    def post(self,
             title,
             workspace,
             question,
             tooltip,
             link,
             answer_type,
             precondition=None,
             answers=None,
             **kw):
        if not self._are_answers_valid(answer_type, answers):
            response.status_code = 412
            return dict(
                errors={'answers': _('Please add at least one more answer')})

        user = request.identity['user']

        qa = Qa(_owner=user._id,
                _workspace=ObjectId(workspace),
                _parent_precondition=to_object_id(precondition),
                title=title,
                question=question,
                tooltip=tooltip,
                link=link,
                type=answer_type,
                answers=answers,
                auto_generated=False,
                public=True,
                visible=True)
        DBSession.flush(qa)
        qa.generate_output_from()

        return dict(errors=None, _id=ObjectId(qa._id))

    @decode_params('json')
    @expose('json')
    @validate(
        {
            '_id': QAExistValidator(required=True),
            'title': StringLengthValidator(min=2),
            'workspace': WorkspaceExistValidator(required=True),
            'question': StringLengthValidator(min=2),
            'tooltip': StringLengthValidator(min=0, max=100),
            'link': StringLengthValidator(min=0, max=100),
            'answer_type': OneOfValidator(values=Qa.QA_TYPE, required=True),
            'precondition': PreconditionExistValidator(required=False),
        },
        error_handler=validation_errors_response)
    def put(self,
            _id,
            title,
            workspace,
            question,
            tooltip,
            link,
            answer_type,
            precondition=None,
            answers=None,
            **kw):
        if not self._are_answers_valid(answer_type, answers):
            response.status_code = 412
            return dict(
                errors={'answers': _('Please add at least one more answer')})

        check = self.get_related_entities(_id)

        if check.get("entities"):
            entity = dict(_id=_id,
                          _workspace=workspace,
                          title=title,
                          entity='qa',
                          question=question,
                          tooltip=tooltip,
                          link=link,
                          auto_generated=False,
                          type=answer_type,
                          _parent_precondition=precondition,
                          answers=answers)

            session.data_serializer = 'pickle'
            session[
                'entity'] = entity  # overwrite always same key for avoiding conflicts
            session.save()

            return dict(redirect_url=tg.url('/resolve',
                                            params=dict(workspace=workspace)))

        qa = Qa.upsert({'_id': ObjectId(_id)},
                       dict(_workspace=ObjectId(workspace),
                            _parent_precondition=to_object_id(precondition),
                            title=title,
                            question=question,
                            auto_generated=False,
                            tooltip=tooltip,
                            link=link,
                            type=answer_type,
                            answers=answers))
        DBSession.flush(qa)
        qa.generate_output_from()
        return dict(errors=None)

    @expose('ksweb.templates.qa.new')
    @validate({'_id': QAExistValidator(model=True)},
              error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(msg=l_(u'You can not edit this Q/A'),
                             field='_id',
                             entity_model=Qa))
    def edit(self, _id, workspace=None, **kw):
        ws = Workspace.query.find({'_id': ObjectId(workspace)}).first()
        if not ws:
            return tg.abort(404)
        qa = Qa.query.find({'_id': ObjectId(_id)}).first()
        return dict(qa=qa, workspace=ws._id, errors=None)

    @expose('json')
    @decode_params('json')
    @validate({
        '_id': QAExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    def human_readable_details(self, _id, **kw):
        qa = Qa.query.find({'_id': ObjectId(_id)}).first()
        return dict(qa=qa)

    @decode_params('json')
    @expose('json')
    def get_related_entities(self, _id):
        """
        This method return ALL entities (Precondition simple) that have inside the given _id
        :param _id:
        :return:
        """
        entities = Precondition.query.find({
            'type': Precondition.TYPES.SIMPLE,
            'condition': ObjectId(_id)
        }).all()
        return {'entities': entities, 'len': len(entities)}

    def _are_answers_valid(self, answer_type, answers):
        if (answer_type == Qa.TYPES.SINGLE and len(answers) < 2) or\
           (answer_type == Qa.TYPES.MULTI and len(answers) < 1):
            return False
        return True

    @expose('json')
    @validate({'workspace': WorkspaceExistValidator(required=True)})
    def mark_as_read(self, workspace):
        Qa.mark_as_read(request.identity['user']._id, workspace)
예제 #9
0
class OutputController(RestController):
    def _validate_precondition_with_qa(self, precondition, content):
        if not precondition:
            return dict(errors={'content': _('Filter not found')})
        #  Check content precondition element
        precond = model.Precondition.query.find({
            '_id': ObjectId(precondition)
        }).first()
        related_qa = precond.response_interested
        #  Check elem['content'] contain the obj id of the related
        for elem in content:
            if elem['type'] == 'qa_response':
                if elem['content'] not in related_qa.keys():
                    response.status_code = 412
                    return dict(
                        errors={
                            'content':
                            _('The question %s is not related to the filter') %
                            elem['title']
                        })
        return dict()

    def _before(self, *args, **kw):
        tmpl_context.sidebar_section = "outputs"
        tmpl_context.id_obj = kw.get('_id')

    allow_only = predicates.has_any_permission(
        'manage', 'lawyer', msg=l_('Only for admin or lawyer'))

    @expose('ksweb.templates.output.index')
    @paginate('entities',
              items_per_page=int(tg.config.get('pagination.items_per_page')))
    @validate({'workspace': CategoryExistValidator(required=True)})
    def get_all(self, workspace, **kw):
        return dict(page='output-index',
                    fields={
                        'columns_name':
                        [_('Label'), _('Filter'),
                         _('Content')],
                        'fields_name': ['title', 'precondition', 'content']
                    },
                    entities=model.Output.output_available_for_user(
                        request.identity['user']._id, workspace),
                    actions=False,
                    workspace=workspace)

    @expose('json')
    @expose('ksweb.templates.output.new')
    @validate({'workspace': CategoryExistValidator(required=True)})
    def new(self, workspace, **kw):
        tmpl_context.sidebar_output = "output-new"
        return dict(output={'_precondition': kw.get('precondition_id', None)},
                    workspace=workspace,
                    errors=None)

    @decode_params('json')
    @expose('json')
    @validate(
        {
            'title': StringLengthValidator(min=2),
            'content': OutputContentValidator(),
            'ks_editor': StringLengthValidator(min=2),
            'category': CategoryExistValidator(required=True),
            'precondition': PreconditionExistValidator(),
        },
        error_handler=validation_errors_response)
    def post(self, title, content, category, precondition, **kw):
        content = content or []

        #  Check content precondition element
        error = self._validate_precondition_with_qa(precondition, content)
        if error:
            return error

        user = request.identity['user']
        model.Output(_owner=user._id,
                     _category=ObjectId(category),
                     _precondition=ObjectId(precondition),
                     title=title,
                     content=content,
                     public=True,
                     visible=True,
                     html=kw['ks_editor'])
        return dict(errors=None)

    @expose('json')
    @decode_params('json')
    @validate(
        {
            '_id': OutputExistValidator(required=True),
            'title': StringLengthValidator(min=2),
            'content': OutputContentValidator(),
            'category': CategoryExistValidator(required=True),
            'precondition': PreconditionExistValidator(),
        },
        error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this output.'),
            field='_id',
            entity_model=model.Output))
    def put(self, _id, title, content, category, precondition, **kw):
        content = content or []

        #  Check content precondition element
        error = self._validate_precondition_with_qa(precondition, content)
        if error:
            return error

        check = self.get_related_entities(_id)

        if check.get("entities"):
            entity = dict(_id=_id,
                          title=title,
                          content=content,
                          _category=category,
                          _precondition=precondition,
                          entity='output',
                          html=kw['ks_editor'])
            session[
                'entity'] = entity  # overwrite always same key for avoiding conflicts
            session.save()
            return dict(redirect_url=tg.url('/resolve',
                                            params=dict(workspace=category)))

        output = model.Output.query.find({'_id': ObjectId(_id)}).first()
        output.title = title
        output._category = ObjectId(category)
        output._precondition = ObjectId(precondition)
        output.content = content
        output.html = kw['ks_editor']

        return dict(errors=None, redirect_url=None)

    @expose('ksweb.templates.output.new')
    @validate(
        {
            '_id': OutputExistValidator(required=True),
            'workspace': CategoryExistValidator(required=True),
        },
        error_handler=validation_errors_response)
    @require(
        CanManageEntityOwner(
            msg=l_(u'You are not allowed to edit this output.'),
            field='_id',
            entity_model=model.Output))
    def edit(self, _id, workspace, **kw):
        output = model.Output.query.find({
            '_id': ObjectId(_id),
            '_category': ObjectId(workspace)
        }).first()
        tmpl_context.sidebar_output = "output-edit"
        return dict(output=output, workspace=workspace, errors=None)

    @expose('json')
    def sidebar_output(self, _id=None, workspace=None):  #pragma: no cover
        res = list(
            model.Output.query.aggregate([{
                '$match': {
                    '_owner': request.identity['user']._id,
                    '_id': {
                        '$ne': ObjectId(_id)
                    },
                    'visible': True,
                    '_category': ObjectId(workspace)
                }
            }, {
                '$group': {
                    '_id': '$_category',
                    'output': {
                        '$push': "$$ROOT",
                    }
                }
            }]))

        #  Insert category name into res
        for e in res:
            e['category_name'] = model.Category.query.get(
                _id=ObjectId(e['_id'])).name

        return dict(outputs=res)

    @expose('json')
    @decode_params('json')
    @validate({
        '_id': OutputExistValidator(required=True),
    },
              error_handler=validation_errors_response)
    def human_readable_details(self, _id, **kw):
        output = model.Output.query.get(_id=ObjectId(_id))

        return dict(
            output={
                '_id': output._id,
                'title': output.title,
                'content': output.human_readbale_content,
                'human_readbale_content': output.human_readbale_content,
                '_owner': output._owner,
                'owner': output.owner.display_name,
                '_precondition': output._precondition,
                'precondition': output.precondition.title,
                '_category': output._category,
                'category': output.category.name,
                'public': output.public,
                'visible': output.visible,
                'created_at': output.created_at
            })

    @decode_params('json')
    @expose('json')
    def get_related_entities(self, _id):
        """
        This method return ALL entities (Output, Document) that have inside a `content.content` the given _id
        :param _id:
        :return:
        """
        output_related = model.Output.query.find({
            "content.type": "output",
            "content.content": _id
        }).all()
        documents_related = model.Document.query.find({
            "content.type": "output",
            "content.content": _id
        }).all()
        entities = list(output_related + documents_related)
        return dict(entities=entities, len=len(entities))
예제 #10
0
파일: form.py 프로젝트: puria/ksweb
class FormController(BaseController):
    def _before(self, *args, **kw):
        tmpl_context.sidebar_section = "questionaries"

    allow_only = predicates.not_anonymous(msg=l_("Only for admin or lawyer"))

    @expose("ksweb.templates.questionary.index")
    @paginate("entities",
              items_per_page=int(tg.config.get("pagination.items_per_page")))
    @validate({"workspace": WorkspaceExistValidator(required=True)})
    def index(self, workspace, **kw):
        user = request.identity["user"]
        documents_id = [
            ObjectId(documents._id)
            for documents in model.Document.document_available_for_user(
                user_id=user._id, workspace=workspace).all()
        ]
        entities = model.Questionary.query.find({
            "$or": [{
                "_user": ObjectId(user._id)
            }, {
                "_owner": ObjectId(user._id)
            }],
            "_document": {
                "$in": documents_id
            },
        }).sort([
            ("_id", pymongo.DESCENDING),
            ("completed", pymongo.ASCENDING),
            ("title", pymongo.ASCENDING),
        ])
        return dict(
            page="questionary-index",
            fields={
                "columns_name": [
                    _("Title"),
                    _("Owner"),
                    _("Shared with"),
                    _("Created on"),
                    _("Completion %"),
                ],
                "fields_name":
                "title _owner _user creation_date completion".split(),
            },
            entities=entities,
            actions=False,
            actions_content=[_("Export")],
            workspace=workspace,
        )

    @decode_params("json")
    @expose("json")
    @validate(
        {
            "questionary_title": StringLengthValidator(min=2),
            "document_id": DocumentExistValidator(required=True),
            "email_to_share": EmailValidator(),
        },
        error_handler=validation_errors_response,
    )
    def create(self,
               questionary_title=None,
               document_id=None,
               email_to_share=None,
               **kw):
        owner = request.identity["user"]
        if email_to_share:
            user = model.User.by_email_address(email_to_share)

            if not user:
                user = model.User(
                    user_name=email_to_share,
                    email_address=email_to_share,
                    display_name=email_to_share,
                )
        else:
            user = owner

        questionary = model.Questionary(
            title=questionary_title,
            _user=user._id,
            _owner=owner._id,
            _document=ObjectId(document_id),
        )

        if email_to_share:
            from tgext.mailer import get_mailer
            from tgext.mailer import Message

            mailer = get_mailer(request)
            share_url = tg.url("/dashboard",
                               params={"share_id": user._id},
                               qualified=True)
            message = Message(
                subject=_("Invite to a KSWEB document"),
                sender="*****@*****.**",
                recipients=[user.email_address],
                body=_(
                    "Hi, you were invited to compile the following document %s "
                    "at the following url %s" %
                    (questionary_title, share_url)),
            )
            mailer.send_immediately(message)
            flash(
                _("Questionary succesfully created and shared to %s" %
                  email_to_share))
        return dict(questionary=questionary)

    @expose("ksweb.templates.questionary.compile")
    @expose("json")
    @validate(
        {"_id": QuestionaryExistValidator(required=True)},
        error_handler=validation_errors_response,
    )
    @require(
        CanManageEntityOwner(
            msg=l_("You are not allowed to edit this questionary."),
            field="_id",
            entity_model=model.Questionary,
        ))
    def compile(self, _id, **kwargs):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        return dict(
            questionary=questionary,
            quest_compiled=questionary.evaluate_questionary,
            html=self.get_questionary_html(_id),
            recap=questionary.answers,
        )

    @expose(content_type="application/application/octet-stream")
    @validate(
        {"_id": QuestionaryExistValidator(required=True)},
        error_handler=validation_errors_response,
    )
    @require(
        CanManageEntityOwner(
            msg=l_("You are not allowed to download this questionary."),
            field="_id",
            entity_model=model.Questionary,
        ))
    def download(self, _id, format):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        filename = slugify(questionary, questionary.title)
        response.headerlist.append(
            ("Content-Disposition",
             f"attachment;filename={filename}.{format}"))
        filled_md = self.get_questionary_html(_id)
        unanswered, __ = find_entities_from_html(filled_md)
        output = NamedTemporaryFile()
        with NamedTemporaryFile() as input:
            input.write(
                TemplateOutput(filled_md).safe_substitute(
                    {k: ""
                     for k in unanswered}).encode())
            input.seek(0)
            pypandoc.convert_file(input.name,
                                  format,
                                  format="md",
                                  outputfile=output.name)

        return output

    @staticmethod
    def get_questionary_html(quest_id):
        questionary = model.Questionary.query.get(ObjectId(quest_id))
        if not questionary.document.content:
            return

        output_values, qa_values = dict(), dict()

        for output_dict in questionary.document.content:
            _id = output_dict["content"]
            if (output_dict["content"] in questionary.output_values and
                    questionary.output_values[output_dict["content"]][  # NOQA
                        "evaluation"]):
                output = model.Output.query.get(ObjectId(_id))
                output_values[output.hash] = output.render(
                    questionary.output_values)
            else:
                # this clear useless output placeholder
                output_values[_id] = ""
        safe_template = questionary.document.html
        questionary_with_expanded_output = TemplateOutput(
            safe_template).safe_substitute(output_values)
        questionary_compiled = TemplateAnswer(questionary_with_expanded_output)

        for qa_id, resp in questionary.qa_values.items():
            qa_values[id_to_hash(qa_id,
                                 Qa)] = Markup.escape(resp["qa_response"])

        return Markup(questionary_compiled.safe_substitute(qa_values))

    @expose("json")
    @decode_params("json")
    @validate(
        {
            "_id": QuestionaryExistValidator(required=True),
            "qa_id": QAExistValidator(required=True),
            "qa_response": StringLengthValidator(min=1, strip=False),
        },
        error_handler=validation_errors_response,
    )
    @require(
        CanManageEntityOwner(
            msg=l_("You are not allowed to edit this questionary."),
            field="_id",
            entity_model=model.Questionary,
        ))
    def responde(self, _id=None, qa_id=None, qa_response=None, **kwargs):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        #  Check if the qa response is valid
        qa = model.Qa.query.get(_id=ObjectId(qa_id))

        if qa.type == "single" and qa_response not in qa.answers:
            response.status_code = 412
            return dict(errors={"qa_response": _("Invalid answer")})

        if qa.type == "multi":
            #  check each qa_response if is in qa.answers
            if isinstance(qa_response, str):
                qa_response = [qa_response]

        if not questionary.qa_values:
            order_number = 0
        else:
            order_number = 1 + max([
                questionary.qa_values[elem]["order_number"]
                for elem in questionary.qa_values
            ])
        questionary.qa_values[qa_id] = {
            "qa_response": qa_response,
            "order_number": order_number,
        }
        quest_compiled = questionary.evaluate_questionary

        return dict(
            questionary=questionary,
            quest_compiled=quest_compiled,
            html=self.get_questionary_html(_id),
            recap=questionary.answers,
        )

    @expose("ksweb.templates.questionary.completed")
    @validate(
        {"_id": QuestionaryExistValidator(required=True)},
        error_handler=validation_errors_response,
    )
    def completed(self, _id=None, workspace=None):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        completed = questionary.evaluate_questionary
        if not completed:
            return redirect("/questionary/compile",
                            params=dict(quest_complited=completed))

        questionary_compiled = self.get_questionary_html(_id)
        return dict(questionary_compiled=questionary_compiled)

    @expose("json")
    @decode_params("json")
    @validate(
        {"_id": QuestionaryExistValidator(required=True)},
        error_handler=validation_errors_response,
    )
    @require(
        CanManageEntityOwner(
            msg=l_("You are not allowed to edit this questionary."),
            field="_id",
            entity_model=model.Questionary,
        ))
    def previous_question(self, _id=None, **kwargs):
        questionary = model.Questionary.query.get(_id=ObjectId(_id))
        previous_response = {}

        if questionary.qa_values:
            last_order_number = max([
                questionary.qa_values[qa_val]["order_number"]
                for qa_val in questionary.qa_values
            ])
            last_question_answered = [
                qa_val for qa_val in questionary.qa_values
                if questionary.qa_values[qa_val]["order_number"] ==
                last_order_number
            ][0]
            previous_response = questionary.qa_values[last_question_answered][
                "qa_response"]
            questionary.qa_values.pop(last_question_answered, None)
            DBSession.flush_all()

        return dict(
            questionary=questionary,
            quest_compiled=questionary.evaluate_questionary,
            html=self.get_questionary_html(_id),
            previous_response=previous_response,
            recap=questionary.answers,
        )