def content_route(request, route_slug=None): if request.is_ajax(): return get_page(request) session = get_object_or_404(Session, route_slug=route_slug) if (not session.is_open and session.program and session.program.programuseraccess_set.filter( user=request.user).exists()): return HttpResponseRedirect(settings.HOME_URL) context = {'session': session.id, 'node': 0} engine = Engine(user=request.user, context=context, push=True, is_interactive=True) engine.run() context = { 'program': session.program, 'title': session.display_title, 'api': reverse('content_api'), } return render(request, 'session.html', context)
def init_session(session_id, user_id, push=False): '''Initialize a given session from start and traverse on behalf of user''' context = { 'session': session_id, 'node': 0, } if not push: context['stack'] = [] engine = Engine(user_id=user_id, context=context, push=push) if not engine.user.is_active: return _('Inactive user, no action taken') engine.run() if engine.session.trigger_login: engine.user.send_login_link() message = _('Session initialized and login e-mail sent') else: message = _('Session initialized') return message
def test_flow(self): # test init with session and node context, a common pattern context = { 'session': self.session_activate.id, 'node': 0, } engine = Engine(user=self.user, context=context) self.assertEqual(engine.session, self.session_activate) page = engine.run() token = token_generator.make_token(self.user.id) default_data = { 'From': '+4799999999', 'Body': 'no', } primafon_data = { 'from': '4799999999', 'body': 'no', } Request = namedtuple('Request', 'method body POST') request = Request(method='POST', body=json.dumps(primafon_data), POST=default_data) receive_sms(request)
def test_complex_session(self): context = { 'session': self.session_complex.id, 'node': 0, } engine = Engine(user=self.user, context=context) # retroactively monkey patch StatefulAnonymousUser def send_email(self, subject=None, message=None, html_message=None): self.data['mail'] = message self.save() def send_sms(self, message=None): self.data['sms'] = message self.save() StatefulAnonymousUser.send_email = send_email StatefulAnonymousUser.send_sms = send_sms # we expect this to cascade through a number of nodes page = engine.run() # having tried to send an email and sms (normally pass for StatefulAnonymousUser), # which we have monkey patched, saves to user data, which saves to session self.assertEqual(self.session['user_data']['mail'], 'Email content') self.assertEqual(self.session['user_data']['sms'], 'SMS content') # then registering the user, registered_user = engine.user self.assertIsNotNone(registered_user) self.assertFalse(registered_user.is_anonymous()) # having set password for the user, self.assertTrue(registered_user.check_password('hunter2')) # then enrolled the user if registered, program_user = self.program.users.first() self.assertEqual(program_user, registered_user) # then not get stuck in an infinite loop on enroll, # then followed the normal edge from second expression to first page (asserted above) self.assertEqual(page, self.page_first_complex) # the next edge is a session node, should return the first page of that node page = engine.run(next=True) self.assertEqual(page, self.page_first)
def transition(session_id, node_id, user_id, stack=None): '''A task to schedule an Engine transition''' context = {'session': session_id, 'node': node_id, 'stack': stack or []} engine = Engine(user_id=user_id, context=context) if not engine.user.is_active: return _('Inactive user, no action taken') node = engine.transition(node_id) message = _('%(session)s transitioned to node %(node)s') % { 'session': engine.session.title, 'node': getattr(node, 'name', node_id) } return message
def test_snippet(self): # re-init user self.session = {} self.user = StatefulAnonymousUser(session=self.session) self.user.data = {} context = { 'session': self.session_hub.id, 'node': 0, } engine = Engine(user=self.user, context=context) page = engine.run() # we've visited processing session and set value self.assertEqual(self.user.data['somevar'], 'some value') # stack is now empty self.assertEqual(self.user.data['stack'], []) # we're on page_first self.assertEqual(page, self.page_first)
def test_run(self): # test init with session and node context, a common pattern context = { 'session': self.session_simple.id, 'node': 0, } engine = Engine(user=self.user, context=context) self.assertEqual(engine.session, self.session_simple) self.assertEqual(self.user.data['session'], self.session_simple.id) self.assertEqual(self.user.data['node'], 0) # test run, will transition from start and return the first page page = engine.run() self.assertEqual(page, self.page_first) # repeated run will return the same page page = engine.run() self.assertEqual(page, self.page_first) # repeated run with next will return the second page page = engine.run(next=True) self.assertEqual(page, self.page_second) self.assertEqual(self.user.data['session'], self.session_simple.id) self.assertEqual(self.user.data['node'], 2) # test init with push, will push current session and node to stack context = { 'session': self.session_empty.id, 'node': 0, } engine = Engine(user=self.user, context=context, push=True) self.assertEqual(engine.session, self.session_empty) self.assertEqual(self.user.data['session'], self.session_empty.id) self.assertEqual(self.user.data['node'], 0) self.assertEqual(self.user.data['stack'], [(self.session_simple.id, 2)]) # run with pop will return to previous session and node engine.run(pop=True) self.assertEqual(engine.session, self.session_simple) self.assertEqual(self.user.data['session'], self.session_simple.id) self.assertEqual(self.user.data['node'], 2)
def get_page(request): context = {} if request.method == 'POST': post_data = json.loads(request.body) if request.body else {} context.update(post_data) # admin page preview support page_id = request.GET.get('page_id') if request.user.is_staff and page_id: page = get_object_or_404(Page, id=page_id) page.update_html(request.user) page.dead_end = True page.stacked = False # engine selection else: next = request.GET.get('next') pop = request.GET.get('pop') engine = Engine(user=request.user, context=context, is_interactive=True) page = engine.run(next=next, pop=pop) if not page: raise Http404 response = { 'title': page.display_title, 'data': page.data, 'dead_end': page.dead_end, 'stacked': page.stacked } return JsonResponse(response)
def test_init(self): context = { 'session': self.session_empty.id, 'node': 0, 'expression_somevar': '1 + 1', 'other_var': 'value', 'undefined': None, } engine = Engine(user=self.user, context=context) # test that user data is set (or not set) from context self.assertEqual(self.user.data['somevar'], 2) self.assertEqual(self.user.data['other_var'], 'value') self.assertEqual(self.user.data.get('undefined', 'no value'), 'no value') # test that session is loaded and initialized self.assertEqual(engine.session, self.session_empty) self.assertEqual(engine.nodes, {}) self.assertEqual(engine.edges, [])
def receive_sms(request): '''Receive sms message from user, process through Engine and respond''' reply = '' response = '' sender = '' body = '' dst = '' src = '' debug_logger = logging.getLogger('debug') now = timezone.now() if request.method == 'POST': debug_logger.debug('received post %s', request.POST) if settings.SMS_SERVICE == 'Twilio' or settings.SMS_SERVICE == 'Console': sender = request.POST.get('From') body = request.POST.get('Body') if settings.SMS_SERVICE == 'Plivo': sender = '+' + request.POST.get('From') dst = request.POST.get('From') src = request.POST.get('To') body = request.POST.get('Text') if settings.SMS_SERVICE == 'Primafon': data = json.loads(request.body) sender = '+' + data['from'] dst = data['from'] src = '12345678' body = data['body'] try: user = User.objects.get(phone=sender) debug_logger.debug('got user %r', user) except: user = None reply = _('Sorry, I\'m not sure who this is.') if user: reply_session = user.data.get('reply_session') reply_node = user.data.get('reply_node') reply_var = user.data.get('reply_variable') if reply_session and reply_node and reply_var: log_event.send(user, domain='user', actor=user, variable=reply_var, pre_value=user.data.get(reply_var, ''), post_value=body) try: context = { 'session': reply_session, 'node': reply_node, reply_var: body, } engine = Engine(user=user, context=context) debug_logger.debug('prepared engine') del engine.user.data['reply_session'] del engine.user.data['reply_node'] del engine.user.data['reply_variable'] debug_logger.debug('deleted reply vars') engine.transition(reply_node) debug_logger.debug('finished engine transitions') engine.user.save() debug_logger.debug('saved user %s', engine.user) except Exception as e: reply = _( 'Sorry, there was an error processing your SMS. ' 'Our technicians have been notified and will try to fix it.' ) else: debug_logger.debug('no data received') reply = _('No data received.') if settings.SMS_SERVICE == 'Twilio': response = twiml.Response() if reply: response.message(reply) if settings.SMS_SERVICE == 'Plivo': response = plivoxml.Response() if reply and src and dst: response.addMessage(reply, src=src, dst=dst) debug_logger.debug('finished request') return HttpResponse(response, content_type='text/xml')