def get_message(self, chat, next_lesson, is_additional, *args, **kwargs) -> Message: # TODO implement Stack-like interface answers_stack = chat.state.get_data_attr('answers_stack') if answers_stack: answer = answers_stack.pop() chat.state.set_data_attr('answers_stack', answers_stack) chat.state.save_json_data() if waffle.switch_is_active('compound_faq_answer'): text1 = md2html(f'Here\'s my answer to your question \"{answer.get("faq_title")}\"') text2 = md2html(answer.get('text')) text = text1 + text2 else: text = answer.get('text') _data = { 'chat': chat, 'text': mark_safe(text), 'owner': chat.user, 'input_type': 'options', 'kind': 'button', 'is_additional': is_additional } message = Message(**_data) message.save() return message
def get_message(self, chat, next_lesson, is_additional, *args, **kwargs) -> Message: threads = chat.enroll_code.courseUnit.unit.unitlesson_set.filter( order__isnull=False).order_by('order') has_updates = {'enabled': False, 'thread_id': None} for thread in threads: # TODO: move to a dedicated util response_msg = chat.message_set.filter( lesson_to_answer_id=thread.id, kind='response', contenttype='response', content_id__isnull=False).last() if not response_msg: continue response = response_msg.content is_need_help = response.status in (None, NEED_HELP_STATUS, NEED_REVIEW_STATUS) if is_need_help and thread.updates_count(chat) > 0: has_updates.update({'thread_id': thread.id}) chat.state.set_data_attr('next_update', has_updates) chat.state.save_json_data() break if has_updates['thread_id']: unitStatus = chat.state.get_data_attr('unitStatus') next_lesson = unitStatus.get_next_lesson() if not next_lesson: text = f'You have completed this thread. I have posted new messages to help you in the thread "{thread.lesson.title}". Would you like to view these updates now?' else: text1 = f'You have completed this thread. I have posted new messages to help you in the thread "{thread.lesson.title}". Would you like to view these updates now?' text2 = "*If you don't want to view them now, I'll ask you again once you have completed your next thread.*" text = md2html(text1) + md2html(text2) else: text = md2html('Now you can move to the next lesson') _data = { 'chat': chat, 'text': mark_safe(text), 'owner': chat.user, 'input_type': 'options', 'kind': 'button', 'sub_kind': 'transition', 'is_additional': is_additional } message = Message(**_data) message.save() return message
def get_sidebar_html(self): ''' :return: Return stripped html text (ho html tags) ''' # html = self.get_html() # return html.split("\n")[0] p = re.compile(r'<.*?>') raw_html = self.text or self.content.text raw_html = raw_html.split("\n")[0] html = mark_safe(md2html(raw_html)) stripped_text = p.sub('', html) return stripped_text
def get_html(self): html = None if self.content_id: if self.contenttype == 'chatdivider': html = self.content.text elif self.contenttype == 'response': if self.input_type == 'text': html = self.content.text else: html = EVAL_OPTIONS[self.content.selfeval] elif self.contenttype == 'unitlesson': if self.content.kind == UnitLesson.MISUNDERSTANDS: html = mark_safe(md2html('**%s** \n %s' % (self.content.lesson.title, self.content.lesson.text))) elif self.input_type == 'options' and self.text: html = STATUS_OPTIONS[self.text] else: html = mark_safe(md2html(self.content.lesson.text)) elif self.contenttype == 'uniterror': html = self.get_errors() else: html = self.text return html
def test_get_resources_message_by_id(self): """ Test get resources message by id from /resources response. Checks that returned content fits resources API documentation. """ enroll_code = EnrollUnitCode.get_code(self.courseunit) self.client.login(username='******', password='******') chat_id = self.client.get( reverse('chat:chat_enroll', args=(enroll_code,)), follow=True ).context['chat_id'] response = self.client.get(reverse('chat:resources-list'), {'chat_id': chat_id}, follow=True) json_content = json.loads(response.content) resource_response = self.client.get( reverse('chat:resources-detail', args=(json_content['breakpoints'][0]['ul'],)), {'chat_id': chat_id} ) self.assertEquals(resource_response.status_code, 200) resource_response = self.client.get( reverse('chat:resources-detail', args=(json_content['breakpoints'][1]['ul'],)), {'chat_id': chat_id} ) self.assertEquals(resource_response.status_code, 200) json_content = json.loads(resource_response.content) self.assertIsInstance(json_content['input'], dict) self.assertIsInstance(json_content['addMessages'], list) self.assertEquals(len(json_content['addMessages']), 3) self.assertIn('nextMessagesUrl', json_content) self.assertIsNone(json_content['nextMessagesUrl']) self.assertIn('id', json_content) self.assertEquals(json_content['addMessages'][0]['name'], self.resource_unitlesson.addedBy.username) self.assertEquals(json_content['addMessages'][0]['type'], 'breakpoint') self.assertEquals(json_content['addMessages'][0]['html'], self.resource_unitlesson.lesson.title) self.assertEquals(json_content['addMessages'][1]['type'], 'message') self.assertEquals( json_content['addMessages'][1]['html'], md2html(self.resource_unitlesson.lesson.text) ) self.assertEquals(json_content['addMessages'][2]['type'], 'message') self.assertEquals(json_content['addMessages'][2]['html'], END.help) self.assertIn('url', json_content['input']) self.assertIn('includeSelectedValuesFromMessages', json_content['input']) self.assertIn('html', json_content['input']) self.assertIn('type', json_content['input']) self.assertIn('options', json_content['input'])
def get_message(self, chat, next_lesson, is_additional, *args, **kwargs) -> Message: # TODO implement Stack-like interface resolutions_stack = chat.state.get_data_attr('resolutions_stack') if resolutions_stack: resolution = resolutions_stack.pop() chat.state.set_data_attr('resolutions_stack', resolutions_stack) chat.state.save_json_data() _data = { 'chat': chat, 'text': mark_safe(md2html(resolution.get('text'))), 'owner': chat.user, 'input_type': 'options', 'kind': 'button', 'is_additional': is_additional } message = Message(**_data) message.save() return message
def get_message(self, chat, next_lesson, is_additional, *args, **kwargs) -> Message: em_resolutions = chat.state.get_data_attr('em_resolutions') if em_resolutions: em = em_resolutions.pop() chat.state.set_data_attr('resolutions_stack', em['resolutions']) chat.state.set_data_attr('em_resolutions', em_resolutions) chat.state.save_json_data() _data = { 'chat': chat, 'text': mark_safe(md2html(f'**{em.get("em_title")}** \n {em.get("em_text")}')), 'owner': chat.user, 'input_type': 'options', 'kind': 'button', 'is_additional': is_additional } message = Message(**_data) message.save() return message
def test_content(self): """ Check that history content fits API documentation. """ enroll_code = EnrollUnitCode.get_code(self.courseunit) self.client.login(username='******', password='******') chat_id = self.client.get( reverse('chat:chat_enroll', args=(enroll_code,)), follow=True ).context['chat_id'] response = self.client.get(reverse('chat:history'), {'chat_id': chat_id}, follow=True) json_content = json.loads(response.content) self.assertIsInstance(json_content['input'], dict) self.assertIsInstance(json_content['addMessages'], list) self.assertEquals(len(json_content['addMessages']), 4) self.assertEquals(json_content['addMessages'][0]['name'], self.unitlesson.addedBy.username) self.assertEquals(json_content['addMessages'][0]['html'], self.unitlesson.lesson.title) self.assertEquals(json_content['addMessages'][1]['type'], 'message') self.assertEquals( json_content['addMessages'][1]['html'], md2html(self.unitlesson.lesson.text) ) self.assertEquals(json_content['addMessages'][2]['type'], 'message')
def get_message(self, chat, next_lesson, is_additional, *args, **kwargs) -> Message: faq_answers = chat.state.get_data_attr('faq_answers') if faq_answers: faq = faq_answers.pop() answers = faq['answers'] for answer in answers: answer['faq_title'] = (faq.get('faq_title', '')) chat.state.set_data_attr('answers_stack', answers) chat.state.set_data_attr('faq_answers', faq_answers) chat.state.save_json_data() _data = { 'chat': chat, 'text': mark_safe(md2html(f'**{faq.get("faq_title")}** \n {faq.get("faq_text")}')), 'owner': chat.user, 'input_type': 'options', 'kind': 'button', 'is_additional': is_additional } message = Message(**_data) message.save() return message
def get_html(self): if self.kind in ('get_faq_answer', ) or (self.kind == 'add_faq' and self.input_type == 'options'): return self.text.capitalize() if self.text else 'No' if self.kind in ('ask_faq_understanding', ): return STATUS_OPTIONS.get(self.text, 'Still confused, need help') if self.kind == 'abort': return self.get_aborts() html = self.text if self.content_id: if self.contenttype == 'chatdivider': html = self.content.text elif self.contenttype == 'response' and self.sub_kind == 'faq': html = '<b>' + self.content.title + '</b><br>' + self.content.text \ if self.content.title else self.content.text elif self.contenttype == 'response': sub_kind = self.content.sub_kind if sub_kind and sub_kind == Lesson.MULTIPLE_CHOICES and not self.content.confidence: # no confidence and no selfeval if sub_kind == Lesson.MULTIPLE_CHOICES: html = self.render_my_choices() return html if sub_kind and self.content.confidence and self.content.selfeval and not self.text: # if look history - we already have confidence and selfeval so just return msg text if self.input_type == 'options': html = self.render_my_choices() return html if self.input_type == 'text': if self.sub_kind == 'add_faq': html = self.text else: html = mark_safe(md2html(self.content.text)) if self.content.attachment: # display svg inline html += mark_safe(self.content.get_html()) else: CONF_CHOICES = dict(Response.CONF_CHOICES) is_chat_fsm = ( self.chat and self.chat.state and self.chat.state.fsmNode.fsm.fsm_name_is_one_of( 'chat') # TODO: add livechat here ) values = list(CONF_CHOICES.values()) + list( EVAL_OPTIONS.values()) text_in_values = self.text in values if is_chat_fsm and not self.text: if self.content.selfeval: # confidence is before selfeval html = EVAL_OPTIONS.get( self.content.selfeval, 'Self evaluation not completed yet') elif self.content.confidence: html = CONF_CHOICES.get( self.content.confidence, 'Confidence not settled yet') elif is_chat_fsm and self.text and not text_in_values: html = EVAL_OPTIONS.get( self.text, dict(Response.CONF_CHOICES).get( self.text, self.text)) elif self.contenttype == 'unitlesson': # Get FAQ for the UnitLesson if self.kind == 'faqs': html = self.get_faqs() elif self.content.kind == UnitLesson.MISUNDERSTANDS: html = mark_safe( md2html('**Re: %s** \n %s' % (self.content.lesson.title, self.content.lesson.text))) elif self.input_type == 'options' and self.text: # and not self.content.lesson.sub_kind: html = STATUS_OPTIONS[self.text] elif self.content.lesson.sub_kind and self.content.lesson.sub_kind == Lesson.MULTIPLE_CHOICES: # render unitlesson (question) - answer if self.content.kind in ('part', 'resol'): html = mark_safe( md2html( self.content.lesson.get_choices_wrap_text())) html += self.get_choices() elif self.content.lesson.sub_kind == Lesson.CANVAS and self.content.lesson.kind == Lesson.ORCT_QUESTION: # adds canvas to draw svg image messages = self.chat.message_set.filter(id__gt=self.id) lesson_kwargs = {} try: response = messages[0].content lesson_kwargs['disabled'] = response.attachment.url except (AttributeError, IndexError, ValueError): pass html = mark_safe(md2html(self.content.lesson.text)) html += self.content.lesson.get_html(**lesson_kwargs) elif (self.content.kind == 'answers' and self.content.parent.sub_kind and self.content.parent.sub_kind == Lesson.MULTIPLE_CHOICES): if not self.response_to_check.selfeval: correct = self.content.parent.lesson.get_correct_choices( ) html = self.render_choices(correct, []) elif self.response_to_check.selfeval and self.response_to_check.confidence: correct = self.content.parent.lesson.get_correct_choices( ) html = self.render_choices(correct, []) elif self.content.kind == 'answers' and self.content.parent.lesson.sub_kind == Lesson.NUMBERS: # TODO add tests for this case html = mark_safe( md2html("Expected value {value}. \n\n{text}".format( value=self.content.lesson.number_value, text=self.content.lesson.text))) else: if self.content.lesson.url: raw_html = '`Read more <{0}>`_ \n\n{1}'.format( self.content.lesson.url, self.content.lesson.text) else: raw_html = self.content.lesson.text html = mark_safe(md2html(raw_html)) if ( self.content.lesson.sub_kind == Lesson.CANVAS or (self.content.parent and self.content.parent.sub_kind == Lesson.CANVAS) ) and self.content.lesson.attachment and self.content.lesson.kind != Lesson.ORCT_QUESTION: # append svg attachment to the message html += mark_safe(self.content.lesson.get_html()) if (self.kind != 'faqs' and self.content.lesson.attachment and self.content.lesson.sub_kind != Lesson.CANVAS and not (self.content.parent and self.content.parent.sub_kind == Lesson.CANVAS) ) or (self.kind != 'faqs' and self.content.lesson.kind == Lesson.ERROR_MODEL and self.content.lesson.attachment): html += '<img src="{}" alt=""/>'.format( self.content.lesson.attachment.url) elif self.contenttype == 'uniterror': html = self.get_errors() if html is None: html = 'Answer please' return html
def get_message(self, chat, request, current=None, message=None): stack_pattern = QUESTION_STACK_PATTERN.format(request.user.id, chat.id) is_additional = chat.state.fsmNode.fsm.fsm_name_is_one_of('additional', 'resource') next_lesson = chat.state.unitLesson if self.node_name_is_one_of('LESSON'): input_type = 'custom' kind = next_lesson.lesson.kind try: if is_additional: raise UnitLesson.DoesNotExist unitStatus = chat.state.get_data_attr('unitStatus') next_ul = unitStatus.unit.unitlesson_set.get(order=unitStatus.order+1) # Add CONTINUE button here if (next_ul and next_ul.lesson.kind in SIMILAR_KINDS and kind in SIMILAR_KINDS or next_ul.lesson.kind == Lesson.ORCT_QUESTION): input_type = 'options' kind = 'button' except UnitLesson.DoesNotExist: pass message = Message.objects.get_or_create( contenttype='unitlesson', content_id=next_lesson.id, chat=chat, owner=chat.user, input_type=input_type, kind=kind, is_additional=is_additional)[0] if self.name == 'ASK': SUB_KIND_TO_KIND_MAP = { 'choices': 'button', } SUBKIND_TO_INPUT_TYPE_MAP = { 'choices': 'options', } sub_kind = next_lesson.lesson.sub_kind _data = { 'contenttype': 'unitlesson', 'content_id': next_lesson.id, 'chat': chat, 'owner': chat.user, 'input_type': 'custom', # SUBKIND_TO_INPUT_TYPE_MAP.get(sub_kind, 'custom'), 'kind': next_lesson.lesson.kind, # SUB_KIND_TO_KIND_MAP.get(sub_kind, next_lesson.lesson.kind), 'is_additional': is_additional } if not self.fsm.fsm_name_is_one_of('live_chat'): message = Message.objects.get_or_create(**_data)[0] else: message = Message(**_data) message.save() find_crit = { "stack_id": stack_pattern } c_chat_stack().update_one( find_crit, {"$push": {"stack": next_lesson.id}}, upsert=True) # Fallback method to pass ul_id's throught messages if request.session.get(stack_pattern): if isinstance(request.session[stack_pattern], list): request.session[stack_pattern].append(next_lesson.id) else: request.session[stack_pattern] = [request.session[stack_pattern]] request.session[stack_pattern].append(next_lesson.id) else: request.session[stack_pattern] = [next_lesson.id] if self.node_name_is_one_of('ABORTS'): message = Message.objects.create( owner=chat.user, chat=chat, kind='message', input_type='custom', is_additional=is_additional, text=self.title ) if self.node_name_is_one_of('GET_ABORTS'): message = Message.objects.get_or_create( contenttype='NoneType', kind='abort', input_type='options', chat=chat, owner=chat.user, userMessage=False, is_additional=is_additional)[0] if self.node_name_is_one_of('GET_ANSWER'): find_crit = { "stack_id": stack_pattern } stack = None try: document = c_chat_stack().find_and_modify( query=find_crit, update={"$pop": {"stack": 1}}) stack = document.get('stack', []) except ConnectionFailure: pass if request.session.get(stack_pattern): if isinstance(request.session[stack_pattern], list): fallback_ul_id = request.session[stack_pattern].pop() elif isinstance(request.session[stack_pattern], int): fallback_ul_id = request.session[stack_pattern] else: fallback_ul_id = current.id unit_lesson_id = stack.pop() if stack else fallback_ul_id lesson_to_answer = UnitLesson.objects.filter(id=unit_lesson_id).first() _data = { 'contenttype': 'response', 'input_type': 'text', 'lesson_to_answer': lesson_to_answer, 'chat': chat, 'owner': chat.user, 'kind': 'response', 'userMessage': True, 'is_additional': is_additional } if lesson_to_answer.lesson.sub_kind == 'choices': _data.update(dict( input_type='options', )) if not self.fsm.fsm_name_is_one_of('live_chat'): message = Message.objects.get_or_create(**_data)[0] else: message = Message(**_data) message.save() if self.node_name_is_one_of('CONFIDENCE'): # current here is Response instance if isinstance(current, Response): response_to_chk = current answer = current.unitLesson.get_answers().first() else: response_to_chk = message.response_to_check if not message.lesson_to_answer: answer = message.response_to_check.unitLesson.get_answers().first() else: answer = message.lesson_to_answer.get_answers().first() message = Message.objects.create( # get_or_create contenttype='unitlesson', response_to_check=response_to_chk, input_type='custom', text=self.title, chat=chat, owner=chat.user, kind=answer.kind, is_additional=is_additional) if self.node_name_is_one_of('GET_CONFIDENCE'): _data = dict( contenttype='response', content_id=message.response_to_check.id, input_type='options', chat=chat, owner=chat.user, kind='response', userMessage=True, is_additional=is_additional, ) # here was Message.objects.create for all fsm's except live_chat. for live_chat fsm here was get_or_create message = Message(**_data) message.save() if self.node_name_is_one_of('CORRECT_ANSWER'): lesson = message.response_to_check.unitLesson.lesson if chat.is_live else message.content.unitLesson.lesson correct_choices = lesson.get_correct_choices() if correct_choices: correct_title = lesson.get_choice_title(correct_choices[0][0]) correct_description = lesson.get_choice_description(correct_choices[0][0]) else: answer = message.content.unitLesson.get_answers().first() correct_title = answer.lesson.title if answer else 'Answer title' correct_description = mark_safe(md2html(answer.lesson.text)) if answer else 'Answer description' message = Message.objects.create( owner=chat.user, chat=chat, kind='message', input_type='custom', is_additional=is_additional, text=""" <b>You got it right, the correct answer is: {}</b> <br> {} """ .format(correct_title, correct_description) ) if self.node_name_is_one_of('INCORRECT_ANSWER'): lesson = message.response_to_check.unitLesson.lesson if chat.is_live else message.content.unitLesson.lesson correct_choices = lesson.get_correct_choices() if correct_choices: correct_title = lesson.get_choice_title(correct_choices[0][0]) correct_description = lesson.get_choice_description(correct_choices[0][0]) else: answer = message.content.unitLesson.get_answers().first() correct_title = answer.lesson.title if answer else 'Answer title' correct_description = mark_safe(md2html(answer.lesson.text)) if answer else 'Answer description' message = Message.objects.create( owner=chat.user, chat=chat, lesson_to_answer=message.response_to_check.unitLesson if chat.is_live else message.content.unitLesson, response_to_check=message.response_to_check if chat.is_live else current, kind='message', input_type='custom', is_additional=is_additional, text=""" <b>The correct answer is: {}</b> <br> {} """ .format(correct_title, correct_description) ) if self.node_name_is_one_of('INCORRECT_CHOICE'): lesson = message.lesson_to_answer.lesson selected = [int(i) for i in message.response_to_check.text.split('[selected_choices] ')[1].split()] incorrect_description = lesson.get_choice_description(selected[0]) if selected else '' my_choices = [] for i, c in message.response_to_check.lesson.get_choices(): if i in selected: my_choices.append(c.split(' ', 1)[1]) if not my_choices: my_choices.append('Nothing') message = Message.objects.create( owner=chat.user, chat=chat, kind='message', input_type='custom', is_additional=is_additional, text=""" <b>You selected: {}</b> <br> {} """ .format( my_choices[0] if len(my_choices) == 1 else '<br>' + ''.join(['<h3>{}</h3>'.format(_) for _ in my_choices]), incorrect_description ) ) # here was Message.objects.create for all fsm's except live_chat. for live_chat fsm here was get_or_create if self.node_name_is_one_of("WAIT_ASSESS"): if isinstance(current, Response): resp_to_chk = current else: resp_to_chk = message.response_to_check message = Message.objects.get_or_create( chat=chat, text=self.title, kind='button', response_to_check=resp_to_chk, is_additional=is_additional, owner=chat.user, )[0] if self.node_name_is_one_of('ASSESS'): # current here is Response instance if isinstance(current, Response): response_to_chk = current answer = current.unitLesson.get_answers().first() else: response_to_chk = message.response_to_check if not message.lesson_to_answer: answer = message.response_to_check.unitLesson.get_answers().first() else: answer = message.lesson_to_answer.get_answers().first() message = Message.objects.get_or_create( contenttype='unitlesson', response_to_check=response_to_chk, input_type='custom', content_id=answer.id, chat=chat, owner=chat.user, kind=answer.kind, is_additional=is_additional)[0] if self.node_name_is_one_of('GET_ASSESS'): _data = dict( contenttype='response', content_id=message.response_to_check.id if message.response_to_check else None, input_type='options', chat=chat, owner=chat.user, kind='response', userMessage=True, is_additional=is_additional ) # here was Message.objects.create for all fsm's except live_chat. for live_chat fsm here was get_or_create message = Message(**_data) message.save() if self.node_name_is_one_of('GRADING'): GraderClass = GRADERS.get(message.content.unitLesson.lesson.sub_kind) if GraderClass: grader = GraderClass(message.content.unitLesson, message.content) # grade method must be called to actually do the work grader.grade text = 'Your answer is {}!'.format(grader.message) else: text = "No such grader! Grading could not be applied." message = Message.objects.create( owner=chat.user, chat=chat, kind='message', input_type='custom', is_additional=is_additional, text=text ) if self.node_name_is_one_of('STUDENTERROR'): resolve_message = Message.objects.filter( contenttype='unitlesson', content_id=next_lesson.id, chat=chat, owner=chat.user, input_type='custom', kind='message', timestamp__isnull=True, is_additional=True).first() message = Message.objects.get_or_create( contenttype='unitlesson', content_id=resolve_message.student_error.errorModel.id, chat=chat, owner=chat.user, student_error=resolve_message.student_error, input_type='options', kind='button', is_additional=True)[0] if self.node_name_is_one_of('RESOLVE'): message = Message.objects.filter( contenttype='unitlesson', content_id=next_lesson.id, chat=chat, owner=chat.user, input_type='custom', kind='message', timestamp__isnull=True, is_additional=True).first() if self.node_name_is_one_of('HELP_RESOLVE'): message = Message.objects.get_or_create( contenttype='unitlesson', content_id=next_lesson.id, chat=chat, owner=chat.user, input_type='options', kind='button', timestamp__isnull=True, is_additional=True)[0] if self.node_name_is_one_of('MESSAGE_NODE'): message = Message.objects.get_or_create( chat=chat, owner=chat.user, text=chat.state.fsmNode.title, student_error=message.student_error, input_type='custom', kind='message', is_additional=True)[0] if self.node_name_is_one_of('END', 'IF_RESOURCES', 'NEED_HELP_MESSAGE', 'ASSESS_QUESTION_MESSAGE'): if not self.help: text = self.get_help(chat.state, request=None) else: text = self.help message = Message.objects.create( response_to_check=message.response_to_check, chat=chat, owner=chat.user, text=text, input_type='custom', kind='message', is_additional=True) if self.node_name_is_one_of('GET_RESOLVE'): message = Message.objects.create( contenttype='unitlesson', content_id=next_lesson.id, input_type='options', chat=chat, owner=chat.user, student_error=message.student_error, kind='response', userMessage=True, is_additional=is_additional) if self.node_name_is_one_of('ERRORS'): message = Message.objects.get_or_create( chat=chat, owner=chat.user, text='''''' '''Here are the most common blindspots people reported when comparing their answer vs. ''' '''the correct answer. Check the box(es) that seem relevant to your answer (if any).''', kind='message', input_type='custom', is_additional=is_additional)[0] if self.node_name_is_one_of('GET_ERRORS'): uniterror = UnitError.get_by_message(message) message = Message.objects.get_or_create( contenttype='uniterror', content_id=uniterror.id, input_type='options', chat=chat, kind='uniterror', owner=chat.user, userMessage=False, is_additional=is_additional)[0] if self.node_name_is_one_of('TITLE'): divider = ChatDivider(text=next_lesson.lesson.title, unitlesson=next_lesson) divider.save() message = Message.objects.get_or_create( contenttype='chatdivider', content_id=divider.id, input_type='custom', type='breakpoint', chat=chat, owner=chat.user, kind='message', is_additional=is_additional)[0] if self.node_name_is_one_of('START_MESSAGE'): message = Message.objects.create( input_type='options', text=self.title, chat=chat, owner=chat.user, kind='button', is_additional=is_additional) if self.node_name_is_one_of('DIVIDER'): divider = ChatDivider(text=self.title) divider.save() message = Message.objects.get_or_create( contenttype='chatdivider', content_id=divider.id, input_type='custom', type='breakpoint', chat=chat, owner=chat.user, kind='message', is_additional=is_additional)[0] if self.node_name_is_one_of('START') and self.fsm.fsm_name_is_one_of('live_chat'): message = Message.objects.get_or_create( chat=chat, text=self.title, kind='button', is_additional=is_additional, owner=chat.user, )[0] if self.name in ( 'GET_UNIT_NAME_TITLE', 'GET_UNIT_QUESTION', 'GET_UNIT_ANSWER', 'GET_HAS_UNIT_ANSWER', ): _data = dict( chat=chat, owner=chat.user, input_type='text', kind='response', userMessage=True, is_additional=is_additional ) if isinstance(current, UnitLesson): _data['content_id'] = current.id # _data['text'] = current.lesson.title _data['contenttype'] = 'unitlesson' elif message and message.content: # _data['text'] = "current.lesson" _data['content_id'] = message.content_id _data['contenttype'] = message.contenttype # content_id = current.id if current else None message = Message.objects.create(**_data) if self.name in ('START', 'UNIT_NAME_TITLE', 'NOT_A_QUESTION') and self.fsm.fsm_name_is_one_of('chat_add_lesson'): text = "**{}** \n\n{}".format(self.title, getattr(self, 'help', '') or '') _data = dict( chat=chat, text=text, input_type='custom', kind='message', is_additional=is_additional, owner=chat.user, ) message = Message.objects.create(**_data) if self.name in ('UNIT_QUESTION', 'UNIT_ANSWER') and self.fsm.fsm_name_is_one_of('chat_add_lesson'): text = "**{}** \n\n{}".format(self.title, getattr(self, 'help', '') or '') _data = dict( chat=chat, text=text, input_type='custom', kind='message', is_additional=is_additional, owner=chat.user, ) if message and message.content_id: _data['content_id'] = message.content_id _data['contenttype'] = 'unitlesson' elif isinstance(current, UnitLesson): _data['content_id'] = current.id _data['contenttype'] = 'unitlesson' message = Message.objects.create(**_data) if self.name in ('HAS_UNIT_ANSWER', 'WELL_DONE'): text = "**{}** \n\n{}".format(self.title, getattr(self, 'help', '') or '') _data = dict( chat=chat, text=text, input_type='options', kind='message', owner=chat.user, userMessage=False, is_additional=is_additional ) if message and message.content_id: _data['content_id'] = message.content_id _data['contenttype'] = 'unitlesson' message = Message.objects.create(**_data) if self.name in ('WELL_DONE',): text = "**{}** \n\n{}".format(self.title, getattr(self, 'help', '') or '') _data = dict( chat=chat, text=text, input_type='options', kind='button', owner=chat.user, userMessage=False, is_additional=is_additional ) if message and message.content_id: _data['content_id'] = message.content_id _data['contenttype'] = 'unitlesson' message = Message.objects.create(**_data) # wait for RECYCLE node and any node starting from WAIT_ except WAIT_ASSESS if is_wait_node(self.name): lookup = dict( chat=chat, text=self.title, kind='button', is_additional=False, owner=chat.user ) message = Message.objects.get_or_create(**lookup)[0] return message
def get_html(self): if self.kind == 'abort': return self.get_aborts() html = self.text if self.is_in_fsm_node('chat_add_lesson'): if self.contenttype == 'chatdivider': html = self.content.text else: return mark_safe(md2html(self.text or '')) if self.content_id: if self.contenttype == 'chatdivider': html = self.content.text elif self.contenttype == 'response': sub_kind = self.content.sub_kind if sub_kind and sub_kind == Lesson.MULTIPLE_CHOICES and not self.content.confidence: # no confidence and no selfeval if sub_kind == Lesson.MULTIPLE_CHOICES: html = self.render_my_choices() return html if sub_kind and self.content.confidence and self.content.selfeval and not self.text: # if look history - we already have confidence and selfeval so just return msg text if self.input_type == 'options': html = self.render_my_choices() return html if self.input_type == 'text': html = mark_safe(md2html(self.content.text)) if self.content.attachment: # display svg inline html += mark_safe(self.content.get_html()) else: CONF_CHOICES = dict(Response.CONF_CHOICES) is_chat_fsm = ( self.chat and self.chat.state and self.chat.state.fsmNode.fsm.fsm_name_is_one_of('chat') # TODO: add livechat here ) values = CONF_CHOICES.values() + EVAL_OPTIONS.values() text_in_values = self.text in values if is_chat_fsm and not self.text: if self.content.selfeval: # confidence is before selfeval html = EVAL_OPTIONS.get( self.content.selfeval, 'Self evaluation not completed yet' ) elif self.content.confidence: html = CONF_CHOICES.get( self.content.confidence, 'Confidence not settled yet' ) elif is_chat_fsm and self.text and not text_in_values: html = EVAL_OPTIONS.get( self.text, dict(Response.CONF_CHOICES).get( self.text, self.text ) ) elif self.contenttype == 'unitlesson': if self.content.kind == UnitLesson.MISUNDERSTANDS: html = mark_safe( md2html( '**Re: %s** \n %s' % (self.content.lesson.title, self.content.lesson.text) ) ) elif self.input_type == 'options' and self.text: # and not self.content.lesson.sub_kind: html = STATUS_OPTIONS[self.text] elif self.content.lesson.sub_kind and self.content.lesson.sub_kind == Lesson.MULTIPLE_CHOICES: # render unitlesson (question) - answer if self.content.kind == 'part': html = mark_safe( md2html( self.content.lesson.get_choices_wrap_text() ) ) html += self.get_choices() elif self.content.lesson.sub_kind == Lesson.CANVAS and self.content.lesson.kind == Lesson.ORCT_QUESTION: # adds canvas to draw svg image messages = self.chat.message_set.filter(id__gt=self.id) lesson_kwargs = {} try: response = messages[0].content lesson_kwargs['disabled'] = response.attachment.url except (AttributeError, IndexError, ValueError): pass html = mark_safe(md2html(self.content.lesson.text)) html += self.content.lesson.get_html(**lesson_kwargs) elif (self.content.kind == 'answers' and self.content.parent.sub_kind and self.content.parent.sub_kind == Lesson.MULTIPLE_CHOICES ): if not self.response_to_check.selfeval: correct = self.content.parent.lesson.get_correct_choices() html = self.render_choices(correct, []) elif self.response_to_check.selfeval and self.response_to_check.confidence: correct = self.content.parent.lesson.get_correct_choices() html = self.render_choices(correct, []) elif self.content.kind == 'answers' and self.content.parent.lesson.sub_kind == Lesson.NUMBERS: # TODO add tests for this case html = mark_safe( md2html( u"Expected value {value}. \n\n{text}".format( value=self.content.lesson.number_value, text=self.content.lesson.text ) ) ) else: if self.content.lesson.url: raw_html = u'`Read more <{0}>`_ \n\n{1}'.format( self.content.lesson.url, self.content.lesson.text ) else: raw_html = self.content.lesson.text html = mark_safe(md2html(raw_html)) if (self.content.lesson.sub_kind == Lesson.CANVAS or (self.content.parent and self.content.parent.sub_kind == Lesson.CANVAS) ) and self.content.lesson.attachment and self.content.lesson.kind != Lesson.ORCT_QUESTION: # append svg attachment to the message html += mark_safe(self.content.lesson.get_html()) if (self.content.lesson.attachment and self.content.lesson.sub_kind != Lesson.CANVAS and not (self.content.parent and self.content.parent.sub_kind == Lesson.CANVAS)): html += u'<img src="{}" alt=""/>'.format(self.content.lesson.attachment.url) elif self.contenttype == 'uniterror': html = self.get_errors() if html is None: html = 'Answer please' return html
def get_message(self, chat, request, current=None, message=None): stack_pattern = QUESTION_STACK_PATTERN.format(request.user.id, chat.id) faq_response_pattern = QUESTION_STACK_PATTERN.format(request.user.id, chat.id) is_additional = chat.state.fsmNode.fsm.fsm_name_is_one_of('additional', 'resource') next_lesson = chat.state.unitLesson if hasattr(self._plugin, 'get_message'): return self._plugin.get_message(chat, next_lesson, is_additional, node=self) if self.node_name_is_one_of('LESSON'): input_type = 'custom' kind = next_lesson.lesson.kind try: if is_additional: raise UnitLesson.DoesNotExist unitStatus = chat.state.get_data_attr('unitStatus') next_ul = unitStatus.unit.unitlesson_set.get(order=unitStatus.order+1) # Add CONTINUE button here if (next_ul and next_ul.lesson.kind in SIMILAR_KINDS and kind in SIMILAR_KINDS or next_ul.lesson.kind == Lesson.ORCT_QUESTION): input_type = 'options' kind = 'button' except UnitLesson.DoesNotExist: pass message = Message.objects.get_or_create( contenttype='unitlesson', content_id=next_lesson.id, chat=chat, owner=chat.user, input_type=input_type, kind=kind, is_additional=is_additional)[0] if self.name == 'ASK': SUB_KIND_TO_KIND_MAP = { 'choices': 'button', } SUBKIND_TO_INPUT_TYPE_MAP = { 'choices': 'options', } sub_kind = next_lesson.lesson.sub_kind _data = { 'contenttype': 'unitlesson', 'content_id': next_lesson.id, 'chat': chat, 'owner': chat.user, 'input_type': 'custom', # SUBKIND_TO_INPUT_TYPE_MAP.get(sub_kind, 'custom'), 'kind': next_lesson.lesson.kind, # SUB_KIND_TO_KIND_MAP.get(sub_kind, next_lesson.lesson.kind), 'is_additional': is_additional } if not self.fsm.fsm_name_is_one_of('live_chat'): message, created = Message.objects.get_or_create(**_data) else: message = Message(**_data) message.save() find_crit = { "stack_id": stack_pattern } c_chat_stack().update_one( find_crit, {"$push": {"stack": next_lesson.id}}, upsert=True) # Fallback method to pass ul_id's throught messages if request.session.get(stack_pattern): if isinstance(request.session[stack_pattern], list): request.session[stack_pattern].append(next_lesson.id) else: request.session[stack_pattern] = [request.session[stack_pattern]] request.session[stack_pattern].append(next_lesson.id) else: request.session[stack_pattern] = [next_lesson.id] if self.name == 'ADDITIONAL_ASK': SUB_KIND_TO_KIND_MAP = { 'choices': 'button', } SUBKIND_TO_INPUT_TYPE_MAP = { 'choices': 'options', } sub_kind = next_lesson.lesson.sub_kind _data = { 'contenttype': 'unitlesson', 'content_id': next_lesson.id, 'chat': chat, 'owner': chat.user, 'input_type': 'custom', # SUBKIND_TO_INPUT_TYPE_MAP.get(sub_kind, 'custom'), 'kind': 'message', # SUB_KIND_TO_KIND_MAP.get(sub_kind, next_lesson.lesson.kind), 'is_additional': is_additional } if not self.fsm.fsm_name_is_one_of('live_chat'): message, created = Message.objects.get_or_create(**_data) else: message = Message(**_data) message.save() find_crit = { "stack_id": stack_pattern } c_chat_stack().update_one( find_crit, {"$push": {"stack": next_lesson.id}}, upsert=True) # Fallback method to pass ul_id's throught messages if request.session.get(stack_pattern): if isinstance(request.session[stack_pattern], list): request.session[stack_pattern].append(next_lesson.id) else: request.session[stack_pattern] = [request.session[stack_pattern]] request.session[stack_pattern].append(next_lesson.id) else: request.session[stack_pattern] = [next_lesson.id] if self.node_name_is_one_of('ABORTS'): message = Message.objects.create( owner=chat.user, chat=chat, kind='message', input_type='custom', is_additional=is_additional, text=self.title ) if self.node_name_is_one_of('GET_ABORTS'): message = Message.objects.get_or_create( contenttype='NoneType', kind='abort', input_type='options', chat=chat, owner=chat.user, userMessage=False, is_additional=is_additional)[0] if self.node_name_is_one_of('GET_ANSWER'): find_crit = { "stack_id": stack_pattern } stack = None try: document = c_chat_stack().find_and_modify( query=find_crit, update={"$pop": {"stack": 1}}) stack = document.get('stack', []) except ConnectionFailure: pass if request.session.get(stack_pattern): if isinstance(request.session[stack_pattern], list): fallback_ul_id = request.session[stack_pattern].pop() elif isinstance(request.session[stack_pattern], int): fallback_ul_id = request.session[stack_pattern] else: fallback_ul_id = current.id unit_lesson_id = stack.pop() if stack else fallback_ul_id lesson_to_answer = UnitLesson.objects.filter(id=unit_lesson_id).first() _data = { 'contenttype': 'response', 'input_type': 'text', 'lesson_to_answer': lesson_to_answer, 'chat': chat, 'owner': chat.user, 'kind': 'response', 'userMessage': True, 'is_additional': is_additional } if lesson_to_answer.lesson.sub_kind == 'choices': _data.update(dict( input_type='options', )) if not self.fsm.fsm_name_is_one_of('live_chat'): message = Message.objects.get_or_create(**_data)[0] else: message = Message(**_data) message.save() if self.node_name_is_one_of('ADDITIONAL_GET_ANSWER'): find_crit = { "stack_id": stack_pattern } stack = None try: document = c_chat_stack().find_and_modify( query=find_crit, update={"$pop": {"stack": 1}}) stack = document.get('stack', []) except ConnectionFailure: pass if request.session.get(stack_pattern): if isinstance(request.session[stack_pattern], list): fallback_ul_id = request.session[stack_pattern].pop() elif isinstance(request.session[stack_pattern], int): fallback_ul_id = request.session[stack_pattern] else: fallback_ul_id = current.id unit_lesson_id = stack.pop() if stack else fallback_ul_id lesson_to_answer = UnitLesson.objects.filter(id=unit_lesson_id).first() _data = { 'contenttype': 'response', 'input_type': 'text', 'lesson_to_answer': lesson_to_answer, 'chat': chat, 'owner': chat.user, 'kind': 'response', 'userMessage': True, 'is_additional': is_additional } if lesson_to_answer.lesson.sub_kind == 'choices': _data.update(dict( input_type='options', )) if not self.fsm.fsm_name_is_one_of('live_chat'): message = Message.objects.get_or_create(**_data)[0] else: message = Message(**_data) message.save() if self.node_name_is_one_of('CONFIDENCE'): # current here is Response instance if isinstance(current, Response): response_to_chk = current answer = current.unitLesson.get_answers().first() else: response_to_chk = message.response_to_check if not message.lesson_to_answer: answer = message.response_to_check.unitLesson.get_answers().first() else: answer = message.lesson_to_answer.get_answers().first() message = Message.objects.create( # get_or_create contenttype='unitlesson', response_to_check=response_to_chk, input_type='custom', text=self.title, chat=chat, owner=chat.user, kind=answer.kind, is_additional=is_additional) if self.node_name_is_one_of('ADDITIONAL_CONFIDENCE'): # current here is Response instance if isinstance(current, Response): response_to_chk = current answer = current.unitLesson.get_answers().first() else: response_to_chk = message.response_to_check if not message.lesson_to_answer: answer = message.response_to_check.unitLesson.get_answers().first() else: answer = message.lesson_to_answer.get_answers().first() message = Message.objects.create( # get_or_create contenttype='unitlesson', response_to_check=response_to_chk, input_type='custom', text=self.title, chat=chat, owner=chat.user, kind=answer.kind, is_additional=is_additional) if self.node_name_is_one_of('GET_CONFIDENCE'): _data = dict( contenttype='response', content_id=message.response_to_check.id, input_type='options', chat=chat, owner=chat.user, kind='response', userMessage=True, is_additional=is_additional, ) # here was Message.objects.create for all fsm's except live_chat. for live_chat fsm here was get_or_create message = Message(**_data) message.save() if self.node_name_is_one_of('ADDITIONAL_GET_CONFIDENCE'): _data = dict( contenttype='response', content_id=message.response_to_check.id, input_type='options', chat=chat, owner=chat.user, kind='response', userMessage=True, is_additional=is_additional, ) # here was Message.objects.create for all fsm's except live_chat. for live_chat fsm here was get_or_create message = Message(**_data) message.save() if self.node_name_is_one_of('CORRECT_ANSWER'): lesson = message.response_to_check.unitLesson.lesson if chat.is_live else message.content.unitLesson.lesson correct_choices = lesson.get_correct_choices() if correct_choices: correct_title = lesson.get_choice_title(correct_choices[0][0]) correct_description = lesson.get_choice_description(correct_choices[0][0]) else: answer = message.content.unitLesson.get_answers().first() correct_title = answer.lesson.title if answer else 'Answer title' correct_description = mark_safe(md2html(answer.lesson.text)) if answer else 'Answer description' message = Message.objects.create( owner=chat.user, chat=chat, kind='message', input_type='custom', is_additional=is_additional, text=""" <b>You got it right, the correct answer is: {}</b> <br> {} """ .format(correct_title, correct_description) ) if self.node_name_is_one_of('ADDITIONAL_CORRECT_ANSWER'): lesson = message.response_to_check.unitLesson.lesson if chat.is_live else message.content.unitLesson.lesson correct_choices = lesson.get_correct_choices() if correct_choices: correct_title = lesson.get_choice_title(correct_choices[0][0]) correct_description = lesson.get_choice_description(correct_choices[0][0]) else: answer = message.content.unitLesson.get_answers().first() correct_title = answer.lesson.title if answer else 'Answer title' correct_description = mark_safe(md2html(answer.lesson.text)) if answer else 'Answer description' message = Message.objects.create( owner=chat.user, chat=chat, kind='message', input_type='custom', is_additional=is_additional, text=""" <b>You got it right, the correct answer is: {}</b> <br> {} """ .format(correct_title, correct_description) ) if self.node_name_is_one_of('INCORRECT_ANSWER'): lesson = message.response_to_check.unitLesson.lesson if chat.is_live else message.content.unitLesson.lesson correct_choices = lesson.get_correct_choices() if correct_choices: correct_title = lesson.get_choice_title(correct_choices[0][0]) correct_description = lesson.get_choice_description(correct_choices[0][0]) else: answer = message.content.unitLesson.get_answers().first() correct_title = answer.lesson.title if answer else 'Answer title' correct_description = mark_safe(md2html(answer.lesson.text)) if answer else 'Answer description' message = Message.objects.create( owner=chat.user, chat=chat, lesson_to_answer=message.response_to_check.unitLesson if chat.is_live else message.content.unitLesson, response_to_check=message.response_to_check if chat.is_live else current, kind='message', input_type='custom', is_additional=is_additional, text=""" <b>The correct answer is: {}</b> <br> {} """ .format(correct_title, correct_description) ) if self.node_name_is_one_of('ADDITIONAL_INCORRECT_ANSWER'): lesson = message.response_to_check.unitLesson.lesson if chat.is_live else message.content.unitLesson.lesson correct_choices = lesson.get_correct_choices() if correct_choices: correct_title = lesson.get_choice_title(correct_choices[0][0]) correct_description = lesson.get_choice_description(correct_choices[0][0]) else: answer = message.content.unitLesson.get_answers().first() correct_title = answer.lesson.title if answer else 'Answer title' correct_description = mark_safe(md2html(answer.lesson.text)) if answer else 'Answer description' message = Message.objects.create( owner=chat.user, chat=chat, lesson_to_answer=message.response_to_check.unitLesson if chat.is_live else message.content.unitLesson, response_to_check=message.response_to_check if chat.is_live else current, kind='message', input_type='custom', is_additional=is_additional, text=""" <b>The correct answer is: {}</b> <br> {} """ .format(correct_title, correct_description) ) if self.node_name_is_one_of('INCORRECT_CHOICE'): lesson = message.lesson_to_answer.lesson selected = [int(i) for i in message.response_to_check.text.split('[selected_choices] ')[1].split()] incorrect_description = lesson.get_choice_description(selected[0]) if selected else '' my_choices = [] for i, c in message.response_to_check.lesson.get_choices(): if i in selected: my_choices.append(c.split(' ', 1)[1]) if not my_choices: my_choices.append('Nothing') message = Message.objects.create( owner=chat.user, chat=chat, kind='message', input_type='custom', is_additional=is_additional, text=""" <b>You selected: {}</b> <br> {} """ .format( my_choices[0] if len(my_choices) == 1 else '<br>' + ''.join( ['<h3>{}</h3>'.format(_) for _ in my_choices]), incorrect_description ) ) if self.node_name_is_one_of('ADDITIONAL_INCORRECT_CHOICE'): lesson = message.lesson_to_answer.lesson selected = [int(i) for i in message.response_to_check.text.split('[selected_choices] ')[1].split()] incorrect_description = lesson.get_choice_description(selected[0]) if selected else '' my_choices = [] for i, c in message.response_to_check.lesson.get_choices(): if i in selected: my_choices.append(c.split(' ', 1)[1]) if not my_choices: my_choices.append('Nothing') message = Message.objects.create( owner=chat.user, chat=chat, kind='message', input_type='custom', is_additional=is_additional, text=""" <b>You selected: {}</b> <br> {} """ .format( my_choices[0] if len(my_choices) == 1 else '<br>' + ''.join( ['<h3>{}</h3>'.format(_) for _ in my_choices]), incorrect_description ) ) # here was Message.objects.create for all fsm's except live_chat. for live_chat fsm here was get_or_create if self.node_name_is_one_of("WAIT_ASSESS"): if isinstance(current, Response): resp_to_chk = current else: resp_to_chk = message.response_to_check message = Message.objects.get_or_create( chat=chat, text=self.title, kind='button', response_to_check=resp_to_chk, is_additional=is_additional, owner=chat.user, )[0] if self.node_name_is_one_of('ASSESS'): # current here is Response instance if isinstance(current, Response): response_to_chk = current answer = current.unitLesson.get_answers().first() else: response_to_chk = message.response_to_check if not message.lesson_to_answer: answer = message.response_to_check.unitLesson.get_answers().first() else: answer = message.lesson_to_answer.get_answers().first() message = Message.objects.get_or_create( contenttype='unitlesson', response_to_check=response_to_chk, input_type='custom', content_id=answer.id, chat=chat, owner=chat.user, kind=answer.kind, is_additional=is_additional)[0] if self.node_name_is_one_of('ADDITIONAL_ASSESS'): # current here is Response instance if isinstance(current, Response): response_to_chk = current answer = current.unitLesson.get_answers().first() else: response_to_chk = message.response_to_check if not message.lesson_to_answer: answer = message.response_to_check.unitLesson.get_answers().first() else: answer = message.lesson_to_answer.get_answers().first() message = Message.objects.get_or_create( contenttype='unitlesson', response_to_check=response_to_chk, input_type='custom', content_id=answer.id, chat=chat, owner=chat.user, kind=answer.kind, is_additional=is_additional)[0] if self.node_name_is_one_of('GET_ASSESS'): _data = dict( contenttype='response', content_id=message.response_to_check.id if message.response_to_check else None, input_type='options', chat=chat, owner=chat.user, kind='response', userMessage=True, is_additional=is_additional ) # here was Message.objects.create for all fsm's except live_chat. for live_chat fsm here was get_or_create message = Message(**_data) message.save() if self.node_name_is_one_of('ADDITIONAL_GET_ASSESS'): _data = dict( contenttype='response', content_id=message.response_to_check.id if message.response_to_check else None, input_type='options', chat=chat, owner=chat.user, kind='response', userMessage=True, is_additional=is_additional ) # here was Message.objects.create for all fsm's except live_chat. for live_chat fsm here was get_or_create message = Message(**_data) message.save() if self.node_name_is_one_of('GRADING'): GraderClass = GRADERS.get(message.content.unitLesson.lesson.sub_kind) if GraderClass: grader = GraderClass(message.content.unitLesson, message.content) # grade method must be called to actually do the work grader.grade text = 'Your answer is {}!'.format(grader.message) else: text = "No such grader! Grading could not be applied." message = Message.objects.create( owner=chat.user, chat=chat, kind='message', input_type='custom', is_additional=is_additional, text=text ) if self.node_name_is_one_of('ADDITIONAL_GRADING'): GraderClass = GRADERS.get(message.content.unitLesson.lesson.sub_kind) if GraderClass: grader = GraderClass(message.content.unitLesson, message.content) # grade method must be called to actually do the work grader.grade text = 'Your answer is {}!'.format(grader.message) else: text = "No such grader! Grading could not be applied." message = Message.objects.create( owner=chat.user, chat=chat, kind='message', input_type='custom', is_additional=is_additional, text=text ) if self.node_name_is_one_of('STUDENTERROR'): resolve_message = Message.objects.filter( contenttype='unitlesson', content_id=next_lesson.id, chat=chat, owner=chat.user, input_type='custom', kind='message', timestamp__isnull=True, is_additional=True).first() message = Message.objects.get_or_create( contenttype='unitlesson', content_id=resolve_message.student_error.errorModel.id, chat=chat, owner=chat.user, student_error=resolve_message.student_error, input_type='options', kind='button', is_additional=True)[0] c_chat_stack().update_one( {"stack_id": stack_pattern}, {"$set": {"additional_stack": { "em_id": resolve_message.student_error.errorModel.id, "student_error_id": resolve_message.student_error.id }}}, upsert=True) if self.node_name_is_one_of('RESOLVE'): SUB_KIND_TO_KIND_MAP = { 'choices': 'button', } SUBKIND_TO_INPUT_TYPE_MAP = { 'choices': 'options', } sub_kind = next_lesson.lesson.sub_kind _data = { 'contenttype': 'unitlesson', 'content_id': next_lesson.id, 'chat': chat, 'owner': chat.user, 'input_type': 'custom', # SUBKIND_TO_INPUT_TYPE_MAP.get(sub_kind, 'custom'), 'kind': 'message', # SUB_KIND_TO_KIND_MAP.get(sub_kind, next_lesson.lesson.kind), 'is_additional': is_additional } if not self.fsm.fsm_name_is_one_of('live_chat'): filter_data = _data.copy() filter_data.update({'timestamp__isnull': True}) message = Message.objects.filter(**filter_data).first() if not message: message = Message.objects.create(**_data) else: message = Message(**_data) message.save() if next_lesson.lesson.kind == 'orct': c_chat_stack().update_one( {"stack_id": stack_pattern}, {"$push": {"stack": next_lesson.id}}, upsert=True) # Fallback method to pass ul_id's throught messages if request.session.get(stack_pattern): if isinstance(request.session[stack_pattern], list): request.session[stack_pattern].append(next_lesson.id) else: request.session[stack_pattern] = [request.session[stack_pattern]] request.session[stack_pattern].append(next_lesson.id) else: request.session[stack_pattern] = [next_lesson.id] if self.node_name_is_one_of('HELP_RESOLVE'): message = Message.objects.get_or_create( contenttype='unitlesson', content_id=next_lesson.id, chat=chat, owner=chat.user, input_type='options', kind='button', timestamp__isnull=True, is_additional=True)[0] if self.node_name_is_one_of('MESSAGE_NODE'): additional_info = c_chat_stack().find_one( {"stack_id": stack_pattern}, {"additional_stack": 1, "_id": 0}).get("additional_stack") student_error_id, _ = additional_info.get('student_error_id'), additional_info.get('em_id') # FIXME message = Message.objects.get_or_create( chat=chat, owner=chat.user, text=chat.state.fsmNode.title, student_error=StudentError.objects.filter(id=student_error_id).first(), input_type='custom', kind='message', is_additional=True)[0] if self.node_name_is_one_of( 'END', 'IF_RESOURCES', 'NEED_HELP_MESSAGE', 'ASSESS_QUESTION_MESSAGE', 'ADDITIONAL_ASSESS_QUESTION_MESSAGE' ): if not self.help: text = self.get_help(chat.state, request=None) else: text = self.help message = Message.objects.create( response_to_check=message.response_to_check, chat=chat, owner=chat.user, text=text, input_type='custom', kind='message', is_additional=True) if self.node_name_is_one_of('GREAT_MESSAGE', 'HOPENESS_MESSAGE', 'ORCT_LETS_START_MESSAGE'): if not self.help: text = self.get_help(chat.state, request=None) else: text = self.help message = Message.objects.create( response_to_check=message.response_to_check, chat=chat, owner=chat.user, text=text, input_type='custom', kind='message', is_additional=True) if self.node_name_is_one_of('GET_RESOLVE'): message = Message.objects.create( contenttype='unitlesson', content_id=next_lesson.id, input_type='options', chat=chat, owner=chat.user, student_error=message.student_error, kind='response', userMessage=True, is_additional=is_additional) if self.node_name_is_one_of('ERRORS'): message = Message.objects.get_or_create( chat=chat, owner=chat.user, text='''''' '''Here are the most common blindspots people reported when comparing their answer vs. ''' '''the correct answer. Check the box(es) that seem relevant to your answer (if any).''', kind='message', input_type='custom', is_additional=is_additional)[0] if self.node_name_is_one_of('GET_ERRORS'): uniterror = UnitError.get_by_message(message) message = Message.objects.get_or_create( contenttype='uniterror', content_id=uniterror.id, input_type='options', chat=chat, kind='uniterror', owner=chat.user, userMessage=False, is_additional=is_additional)[0] if self.node_name_is_one_of('SHOW_FAQS'): is_new = chat.state.get_data_attr('updates') if 'updates' in chat.state.load_json_data() else None message = Message.objects.create( contenttype='unitlesson', content_id=next_lesson.id, input_type='options', chat=chat, kind='faqs', owner=chat.user, userMessage=False, is_new=is_new, is_additional=is_additional) if self.node_name_is_one_of('TITLE'): divider = ChatDivider(text=next_lesson.lesson.title, unitlesson=next_lesson) divider.save() message = Message.objects.get_or_create( contenttype='chatdivider', content_id=divider.id, input_type='custom', type='breakpoint', chat=chat, owner=chat.user, kind='message', is_additional=is_additional)[0] if self.node_name_is_one_of('START_MESSAGE',): message = Message.objects.create( input_type='options', text=self.title, chat=chat, owner=chat.user, kind='button', is_additional=is_additional) if self.node_name_is_one_of('DIVIDER'): divider = ChatDivider(text=self.title) divider.save() message = Message.objects.get_or_create( contenttype='chatdivider', content_id=divider.id, input_type='custom', type='breakpoint', chat=chat, owner=chat.user, kind='message', is_additional=is_additional)[0] if self.node_name_is_one_of('START') and self.fsm.fsm_name_is_one_of('live_chat'): message = Message.objects.get_or_create( chat=chat, text=self.title, kind='button', is_additional=is_additional, owner=chat.user, )[0] if self.name in ( 'GET_UNIT_NAME_TITLE', 'GET_UNIT_QUESTION', 'GET_UNIT_ANSWER', 'GET_HAS_UNIT_ANSWER', ): _data = dict( chat=chat, owner=chat.user, input_type='text', kind='response', userMessage=True, is_additional=is_additional ) if isinstance(current, UnitLesson): _data['content_id'] = current.id # _data['text'] = current.lesson.title _data['contenttype'] = 'unitlesson' elif message and message.content: # _data['text'] = "current.lesson" _data['content_id'] = message.content_id _data['contenttype'] = message.contenttype # content_id = current.id if current else None message = Message.objects.create(**_data) if self.name in ('HAS_UNIT_ANSWER', 'WELL_DONE'): text = "**{}** \n\n{}".format(self.title, getattr(self, 'help', '') or '') _data = dict( chat=chat, text=text, input_type='options', kind='message', owner=chat.user, userMessage=False, is_additional=is_additional ) if message and message.content_id: _data['content_id'] = message.content_id _data['contenttype'] = 'unitlesson' message = Message.objects.create(**_data) if self.name in ('WELL_DONE', 'ASK_NEW_FAQ', 'GET_NEW_FAQ'): text = "**{}** \n\n{}".format(self.title, getattr(self, 'help', '') or '') _data = dict( chat=chat, text=text, input_type='options', kind='button', owner=chat.user, userMessage=False, is_additional=is_additional ) if message and message.content_id: _data['content_id'] = message.content_id _data['contenttype'] = 'unitlesson' message = Message.objects.create(**_data) if self.name in ('ADDING_FAQ',): ul_id = c_chat_context().find_one({"chat_id": chat.id}).get('actual_ul_id') unitLesson = UnitLesson.objects.filter(id=ul_id).first() faq_response = Response.objects.create( unitLesson=unitLesson, lesson=unitLesson.lesson, kind=Response.STUDENT_QUESTION, course=self.load_json_id_dict(chat.state.data).get('course'), is_preview=chat.enroll_code.isPreview, is_test=chat.enroll_code.isTest, author=chat.user, needsEval=True) c_chat_stack().update_one( {"stack_id": faq_response_pattern}, {"$push": {"stack": faq_response.id}}, upsert=True) _data = dict( chat=chat, text=self.title, input_type='options', kind='button', owner=chat.user, userMessage=False, is_additional=is_additional ) message = Message.objects.create(**_data) if self.name in ( 'NEW_FAQ_TITLE', ): ul_id = c_chat_context().find_one({"chat_id": chat.id}).get('actual_ul_id') unitLesson = UnitLesson.objects.filter(id=ul_id).first() faq_response = Response.objects.create( unitLesson=unitLesson, lesson=unitLesson.lesson, kind=Response.STUDENT_QUESTION, course=self.load_json_id_dict(chat.state.data).get('course'), is_preview=chat.enroll_code.isPreview, is_test=chat.enroll_code.isTest, author=chat.user, needsEval=True) c_chat_stack().update_one( {"stack_id": faq_response_pattern}, {"$push": {"stack": faq_response.id}}, upsert=True) _data = dict( chat=chat, owner=chat.user, text=self.title, input_type='custom', kind='message', userMessage=False, is_additional=is_additional ) message = Message.objects.create(**_data) if self.name in ( 'ASK_NEW_FAQ', ): _data = dict( chat=chat, owner=chat.user, text=self.title, input_type='custom', kind='message', userMessage=False, is_additional=is_additional ) message = Message.objects.create(**_data) if self.name in ('WILL_TRY_MESSAGE', 'F**K', 'MSG_FOR_INQUIRY', 'WILL_TRY_MESSAGE_2', 'SELECT_NEXT_FAQ', 'WILL_TRY_MESSAGE_3', 'SHOW_FAQ_ANSWERS', 'INTRO_MSG'): text = None if self.name == 'SHOW_FAQ_ANSWERS': ul_id = c_chat_context().find_one({"chat_id": chat.id}).get('actual_ul_id') actual_faq_id = c_chat_context().find_one( {"chat_id": chat.id}).get('actual_faq_id', None) faq_answers = c_faq_data().find_one( { "chat_id": chat.id, "ul_id": ul_id, "faqs.{}.answers.done".format(actual_faq_id): False} ).get('faqs').get(actual_faq_id).get('answers') for i in faq_answers: if not i.get('done'): answer = Response.objects.filter(id=i.get('answer_id')).first() text = "<b>{}</b><br>{}".format(answer.title, answer.text) if answer else None c_faq_data().update_one( { "chat_id": chat.id, "ul_id": ul_id, "faqs.{}.answers.answer_id".format(actual_faq_id): i.get('answer_id') }, {"$set": {"faqs.{}.answers.$.done".format(actual_faq_id): True}} ) break _data = dict( chat=chat, owner=chat.user, text=text or self.title, input_type='custom', kind='message', userMessage=False, is_additional=is_additional ) message = Message.objects.create(**_data) if self.name in ( 'NEW_FAQ_DESCRIPTION', 'ASK_FOR_FAQ_ANSWER', 'ASK_UNDERSTANDING', 'FAQ' ): _data = dict( chat=chat, owner=chat.user, text=self.title, input_type='custom', kind='message', userMessage=False, is_additional=is_additional ) message = Message.objects.create(**_data) if self.name in ('GET_NEW_FAQ_TITLE', 'GET_NEW_FAQ_DESCRIPTION'): if self.name == 'GET_NEW_FAQ_TITLE': try: faq_response_id = c_chat_stack().find_one({"stack_id": faq_response_pattern}).get('stack')[-1] except IndexError: faq_response_id = None else: document = c_chat_stack().find_and_modify( query={"stack_id": faq_response_pattern}, update={"$pop": {"stack": 1}}) stack = document.get('stack', []) faq_response_id = stack.pop() if stack else None _data = dict( contenttype='response', content_id=faq_response_id, chat=chat, input_type='text', kind='response', sub_kind='add_faq', owner=chat.user, userMessage=True, is_additional=is_additional ) message = Message.objects.create(**_data) if self.name in ('GET_NEW_FAQ',): _data = dict( input_type='options', chat=chat, owner=chat.user, kind='add_faq', sub_kind='add_faq', userMessage=True, is_additional=is_additional, ) message = Message.objects.create(**_data) if self.name in ('GET_FOR_FAQ_ANSWER',): _data = dict( input_type='options', chat=chat, owner=chat.user, kind='get_faq_answer', sub_kind='get_faq_answer', userMessage=True, is_additional=is_additional, ) message = Message.objects.create(**_data) if self.name in ('SHOW_FAQ_BY_ONE',): ul_id = c_chat_context().find_one({"chat_id": chat.id}).get('actual_ul_id') try: # TODO change to the Assignment expressions in Python3.8 faq_data = c_faq_data().find_one({"chat_id": chat.id, "ul_id": ul_id}) faqs = faq_data.get('faqs', {}) if faq_data else {} faq_id = None for key, value in list(faqs.items()): if not value.get('status').get('done', False): faq_id = key break except IndexError: faq_id = None if faq_id: c_faq_data().update_one( {"chat_id": chat.id, "ul_id": ul_id}, {"$set": {"faqs.{}.status.done".format(faq_id): True}}) c_chat_context().update_one( {"chat_id": chat.id}, {"$set": {"actual_faq_id": faq_id}}, upsert=True ) _data = dict( contenttype='response', content_id=int(faq_id), kind='response', sub_kind='faq', chat=chat, owner=chat.user, userMessage=False, is_additional=is_additional, ) message = Message.objects.create(**_data) if self.name in ('GET_UNDERSTANDING',): _data = dict( kind='ask_faq_understanding', input_type='options', chat=chat, owner=chat.user, userMessage=True, is_additional=is_additional, ) message = Message.objects.create(**_data) # wait for RECYCLE node and any node starting from WAIT_ except WAIT_ASSESS if is_wait_node(self.name): lookup = dict( chat=chat, text=self.title, kind='button', is_additional=False, owner=chat.user ) message = Message.objects.get_or_create(**lookup)[0] return message