def test_questionary_invalid_id_validator(self): with test_context(self.app): validator = QuestionaryExistValidator() try: res = validator._validate_python("Invalid") except ValidationError: assert True else: assert False
def test_questionary_not_exist_validator(self): with test_context(self.app): validator = QuestionaryExistValidator() try: res = validator._validate_python("5757ce79c42d752bde919318") except ValidationError: assert True else: assert False
def test_questionary_exist_validator(self): self._login_lawyer() fake_questionary = self._create_fake_questionary('Test_validator') validator = QuestionaryExistValidator() try: res = validator._validate_python(str(fake_questionary._id)) except ValidationError: assert False else: assert True
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)
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)
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, )