class RuleController(RestController): @expose('zenrule.templates.rule') def get_all(self, **kw): rules = Rule.query.find({}).all() return dict(rules=rules) @decode_params('json') @expose('json') @validate({ 'content': StringLengthValidator(min=2), 'name': StringLengthValidator(min=2) }) def post(self, name, content, **kw): rule = Rule(name=name, content=content) return dict(rule=rule._id) @decode_params('json') @expose('json') @validate({ '_id': RuleValidator(required=True), 'content': StringLengthValidator(min=2), 'name': StringLengthValidator(min=2) }) def put(self, _id, name=None, content=None, **kw): rule = Rule.query.find({'_id': ObjectId(_id)}).first() if name: rule.name = name if content: rule.content = content return dict(rule=rule) @decode_params('json') @expose('json') @validate({'_id': RuleValidator(required=True)}) def delete(self, _id, **kw): Rule.query.remove({'_id': ObjectId(_id)}) return dict() @expose('json') def run(self, _id): a = zenroom_exec( """ hello = str("Hello World!") print(hello:string()) """, None, None, None, 1) print(a) print(dir(a)) return dict()
class CategoryController(RestController): allow_only = predicates.has_any_permission('manage', 'lawyer', msg=l_('Only for admin or lawyer')) @expose('json') @validate({ 'id': CategoryExistValidator(required=True), }, error_handler=validation_errors_response) def get_one(self, id, **kw): qa = Category.query.get(_id=ObjectId(id)) return dict(qa=qa) @expose('json') def get_all(self): query = {'_owner': {'$in': [request.identity['user']._id, None]}, 'visible': True} categories = Category.query.find(query).sort('_id').all() return dict(categories=categories) @decode_params('json') @expose('json') @validate({ 'workspace_name': StringLengthValidator(min=2), }, error_handler=validation_errors_response) def create(self, workspace_name=None, **kw): user = request.identity['user'] ws = Category.query.find({'name': str(workspace_name), '_owner': user._id}).first() if ws: response.status_code = 412 return dict(errors={'workspace_name': 'This category already exists'}) workspace = Category( visible=True, name=str(workspace_name), _owner=user._id ) flash(_("Workspace %s successfully created!" % workspace.name)) return dict(workspaces=self.get_all()) @decode_params('json') @expose('json') @validate({ 'workspace_id': CategoryExistValidator(required=True), }, error_handler=validation_errors_response) def delete(self, workspace_id=None, **kw): workspace = Category.query.get(_id=ObjectId(workspace_id)) if not workspace.owner: flash(_('This workspace can not be deleted'), 'warning') return dict(workspaces=self.get_all()) Qa.query.remove({'_category': ObjectId(workspace_id)}) Output.query.remove({'_category': ObjectId(workspace_id)}) Precondition.query.remove({'_category': ObjectId(workspace_id)}) documents = Document.query.find({'_category': ObjectId(workspace_id)}).all() doc = [document._id for document in documents] Questionary.query.remove({'_document': {'$in': doc}}) Document.query.remove({'_id': {'$in': doc}}) Category.query.remove({'_id': ObjectId(workspace_id)}) flash(_("Category and all entities associated deleted")) return dict(workspaces=self.get_all())
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
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 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
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)))
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)
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 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)))
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)
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))
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, )