def send_activity_digest_sms(sender, instance, created, **kwargs): """ Uses threadless_router to send the activity digest via SMS to all available contacts associated with the user. This will happen only once when the NotificationVisibility object is created. The default SMS handling provided by rapidsms-alerts is not compatible with threadless router. """ alert_types = [PBFDigestNotification.alert_type, FadamaDigestNotification.alert_type] sent = False if created and instance.notif.alert_type in alert_types: notification = instance.notif contacts = instance.user.contact_set.all() for contact in contacts: connection = contact.default_connection if connection: backend = connection.backend message = OutgoingMessage(connection, notification.text) router = ThreadlessRouter() response = router.outgoing(message) sent = True if sent: # Don't show this notification on the dashboard as we've already sent # it as a text message. instance.delete()
def patient_onetime_message(request, patient_id): """Send a onetime message to a patient. Default to getting it from their feeds but allow editing that.""" patient = get_object_or_404(patients.Patient, pk=patient_id) if request.method == 'POST': form = PatientOnetimeMessageForm(request.POST) if form.is_valid(): message = form.cleaned_data['message'] connection = patient.contact.default_connection msg = OutgoingMessage(connection, message) router = Router() success = True try: router.outgoing(msg) except Exception, e: logger.exception(e) success = False if success: messages.success( request, "Message sent to patient %s" % patient.subject_number) else: messages.error( request, "An error occurred while trying to send the message to patient %s" % patient.subject_number) return redirect('patient-list')
def reimburse(): ''' Start reimbursement process, entailing interaction with special numbers ''' counter = 0 network_name_map = dict([(v, k) for k, v in NAME_NETWORK_MAP.items()]) reimbursements = ReimbursementRecord.objects.exclude( status__in=(ReimbursementRecord.COMPLETED, ReimbursementRecord.ERROR) ) #import pdb;pdb.set_trace() for network, _ in Subscriber.NETWORKS: print 'network: %s'%network if reimbursements.filter( status__in=( ReimbursementRecord.IN_PROGRESS, ReimbursementRecord.QUEUED), subscriber__network=network): continue else: #there is no reimbursement in progress for "network" subscribers = Subscriber.objects.filter(balance__gt=0, network=network) min_time = settings.REIMBURSEMENT_MIN_TIME qualified = qualify(subscribers, min_time) if qualified: subscriber = qualified[0] else: continue network_name = network_name_map.get(network) _amount = max(subscriber.balance, settings.MINIMUM_TRANSFERS.get(network_name)) backend_name = subscriber.get_backend() backend, _ = Backend.objects.get_or_create(name=backend_name) text = subscriber.first_message % { 'number': '0%s'%subscriber.number[-10:], 'amount': _amount, 'pin': settings.NETWORK_PINS.get(network_name) } logging.info('message to send is %s'%text) to_number = REIMBURSEMENT_NUMBERS.get(network_name) if len(to_number) < 11:#If it is a short-code, prefix with 's' to_number = 's%s'%to_number connection, _ = Connection.objects.get_or_create( backend=backend, identity=to_number) msg = OutgoingMessage(connection=connection, template=text) try: msg.send() except: router = Router() #router.start() router.outgoing(msg) ReimbursementRecord.objects.create( subscriber=subscriber, amount=_amount, status=ReimbursementRecord.IN_PROGRESS) counter += 1 return counter
def session_end(sender, **kwargs): session = kwargs['session'] canceled = kwargs['canceled'] message = kwargs['message'] # for convenience PatientSurvey = aremind.apps.adherence.models.PatientSurvey # find the patient connection = session.connection try: patient = Patient.objects.get(contact=connection.contact) except Patient.DoesNotExist: # No patient, this session might not be relevant to this app return survey = PatientSurvey.find_active(patient, QUERY_TYPE_SMS) if not survey: return if canceled: survey.completed(PatientSurvey.STATUS_NOT_COMPLETED) return tree = session.tree entries = session.entries if entries.count() < 1: survey.completed(PatientSurvey.STATUS_NOT_COMPLETED) return entry = entries.all()[0] # Pick the relevant part of the answer text = re.match(ANSWER_RE, entry.text).group(1) num_pills = int(text) if not survey.is_test: aremind.apps.adherence.models.PillsMissed( patient=patient, num_missed=num_pills, source=QUERY_TYPE_SMS).save() survey.completed(PatientSurvey.STATUS_COMPLETE) # After completing survey, tell patient what their current adherence is connection = patient.contact.default_connection adherence = patient.adherence() # integer percentage response_text = _( "Thank you. Your adherence is %(adherence)s%%, as measured by the black study pillbox." ) kwargs = dict(adherence=adherence) if message: message.respond(response_text, **kwargs) else: msg = OutgoingMessage(connection, response_text, **kwargs) router = Router() router.outgoing(msg)
def incoming(backend_name, identity, text): backend = settings.INSTALLED_BACKENDS.get(backend_name, {}) if "HANDLER" in backend: module = try_import(backend['HANDLER']) if module: module.incoming(backend_name, identity, text) else: backend, _ = Backend.objects.get_or_create(name=backend_name) connection, _ = backend.connection_set.get_or_create(identity=identity) message = IncomingMessage(connection, text, datetime.datetime.now()) router = Router() response = router.incoming(message)
def incoming(backend_name, identity, text): backend = settings.INSTALLED_BACKENDS.get(backend_name, {}) if "HANDLER" in backend: module = try_import(backend["HANDLER"]) if module: module.incoming(backend_name, identity, text) else: backend, _ = Backend.objects.get_or_create(name=backend_name) connection, _ = backend.connection_set.get_or_create(identity=identity) message = IncomingMessage(connection, text, datetime.datetime.now()) router = Router() response = router.incoming(message)
def session_end(sender, **kwargs): session = kwargs["session"] canceled = kwargs["canceled"] message = kwargs["message"] # for convenience PatientSurvey = aremind.apps.adherence.models.PatientSurvey # find the patient connection = session.connection try: patient = Patient.objects.get(contact=connection.contact) except Patient.DoesNotExist: # No patient, this session might not be relevant to this app return survey = PatientSurvey.find_active(patient, QUERY_TYPE_SMS) if not survey: return if canceled: survey.completed(PatientSurvey.STATUS_NOT_COMPLETED) return tree = session.tree entries = session.entries if entries.count() < 1: survey.completed(PatientSurvey.STATUS_NOT_COMPLETED) return entry = entries.all()[0] # Pick the relevant part of the answer text = re.match(ANSWER_RE, entry.text).group(1) num_pills = int(text) if not survey.is_test: aremind.apps.adherence.models.PillsMissed(patient=patient, num_missed=num_pills, source=QUERY_TYPE_SMS).save() survey.completed(PatientSurvey.STATUS_COMPLETE) # After completing survey, tell patient what their current adherence is connection = patient.contact.default_connection adherence = patient.adherence() # integer percentage response_text = _("Thank you. Your adherence is %(adherence)s%%, as measured by the black study pillbox.") kwargs = dict(adherence=adherence) if message: message.respond(response_text, **kwargs) else: msg = OutgoingMessage(connection, response_text, **kwargs) router = Router() router.outgoing(msg)
def handle(self, *args, **options): if len(args) != 1: raise CommandError('Please specify %s.' % self.label) message = args[0] all_connections = Connection.objects.all() success = [] failed = [] router = Router() for conn in all_connections: try: router.outgoing(OutgoingMessage(conn, message)) success.append(conn) except Exception, e: print "failed to send to %s because %s" % (conn, e) failed.append(conn)
def save(self): number = self.cleaned_data['number'] backend = self.cleaned_data['backend'] connection, _ = Connection.objects.get_or_create(backend=backend, identity=number) msg = OutgoingMessage(connection, self.cleaned_data['message']) router = Router() return router.backends[backend.name].send(msg)
def start(self): logger.debug("PatientSurvey.start") if self.status != self.STATUS_CREATED: raise SurveyAlreadyStartedException() if self.query_type == QUERY_TYPE_SMS: tree = aremind.apps.adherence.sms.get_tree() aremind.apps.adherence.sms.start_tree_for_patient(tree, self.patient) elif self.query_type == QUERY_TYPE_IVR: url = reverse('patient-ivr-callback', kwargs={'patient_id': self.patient.pk}) backend = Router().backends['tropo'] backend.call_tropo(url, message_type='voice') # tropo will POST to our callback which will continue things else: raise SurveyUnknownQueryTypeException() self.status = self.STATUS_STARTED self.save()
def setUp(self): super(DailyReportTest, self).setUp() group_name = settings.DEFAULT_DAILY_REPORT_GROUP_NAME self.group = self.create_group(data={'name': group_name}) self.test_contact = self.create_contact( data={'email': '*****@*****.**'}) self.group.contacts.add(self.test_contact) self.test_patient = self.create_patient() self.other_patient = self.create_patient() self.unrelated_patient = self.create_patient() self.router = Router()
class TestScript(LegacyTestScript): def setUp(self): backends = {'mockbackend': {"ENGINE": MockBackend}} self.router = Router(apps=self.apps, backends=backends) self.router.join = lambda: None self._init_log(logging.DEBUG) self.backend = self.router.backends["mockbackend"] def sendMessage(self, num, txt, date=None): self.router.debug('sending {0} to {1}'.format(txt, num)) return super(TestScript, self).sendMessage(num, txt, date) def receiveMessage(self): msg = super(TestScript, self).receiveMessage() self.router.debug(msg) return msg def startRouter(self): pass def stopRouter(self): pass
def start_tree_for_patient(tree, patient): """Trigger tree for a given patient. Will result in our sending them the first question in the tree.""" connection = patient.contact.default_connection # if one is in progress, end it Router().get_app('decisiontree').end_sessions(connection) # fake an incoming message from our patient that triggers the tree backend_name = connection.backend.name address = connection.identity incoming(backend_name, address, tree.trigger)
class TestScript(LegacyTestScript): def setUp (self): backends = {'mockbackend': {"ENGINE": MockBackend}} self.router = Router(apps=self.apps, backends=backends) self.router.join = lambda: None self._init_log(logging.DEBUG) self.backend = self.router.backends["mockbackend"] def sendMessage(self, num, txt, date=None): self.router.debug('sending {0} to {1}'.format(txt, num)) return super(TestScript, self).sendMessage(num, txt, date) def receiveMessage(self): msg = super(TestScript, self).receiveMessage() self.router.debug(msg) return msg def startRouter(self): pass def stopRouter(self): pass
def make_fake_message(request, patient_id): """Make up a message for the patient's wisepill device and fake it coming in""" logger.debug('make_fake_message') patient = get_object_or_404(Patient, pk=patient_id) msisdn = patient.wisepill_msisdn if not msisdn: messages.error(request, "Must set patient's MSISDN before we can fake a wisepill message from them") return redirect('patient-list') timestamp = datetime.datetime.now() # 50-50 whether to make a delayed message is_delayed = random.randint(0,99) > 50 if is_delayed: timestamp -= datetime.timedelta(minutes=10) delay_value = "03" if is_delayed else "02" # DDMMYYHHMMSS time_value = timestamp.strftime("%d%m%y%H%M%S") # 50-50 old format or new format new_format = random.randint(0,99) > 50 if new_format: start = "AT={delay_value},".format(**locals()) else: start = "@={delay_value},".format(**locals()) text = start + "CN={msisdn},SN=fake,T={time_value},S=20,B=3800,PC=1,U=fake,M=1,CE=0".format(**locals()) connection = patient.contact.default_connection msg = IncomingMessage(connection=connection, text=text) router = Router() router.incoming(msg) messages.info(request, "Sent fake wisepill message from %s" % patient) return redirect('patient-list')
def make_fake_message(request, patient_id): """Make up a message for the patient's wisepill device and fake it coming in""" logger.debug("make_fake_message") patient = get_object_or_404(Patient, pk=patient_id) msisdn = patient.wisepill_msisdn if not msisdn: messages.error(request, "Must set patient's MSISDN before we can fake a wisepill message from them") return redirect("patient-list") timestamp = datetime.datetime.now() # 50-50 whether to make a delayed message is_delayed = random.randint(0, 99) > 50 if is_delayed: timestamp -= datetime.timedelta(minutes=10) delay_value = "03" if is_delayed else "02" # DDMMYYHHMMSS time_value = timestamp.strftime("%d%m%y%H%M%S") # 50-50 old format or new format new_format = random.randint(0, 99) > 50 if new_format: start = "AT={delay_value},".format(**locals()) else: start = "@={delay_value},".format(**locals()) text = start + "CN={msisdn},SN=fake,T={time_value},S=20,B=3800,PC=1,U=fake,M=1,CE=0".format(**locals()) connection = patient.contact.default_connection msg = IncomingMessage(connection=connection, text=text) router = Router() router.incoming(msg) messages.info(request, "Sent fake wisepill message from %s" % patient) return redirect("patient-list")
def patient_onetime_message(request, patient_id): """Send a onetime message to a patient. Default to getting it from their feeds but allow editing that.""" patient = get_object_or_404(patients.Patient, pk=patient_id) if request.method == 'POST': form = PatientOnetimeMessageForm(request.POST) if form.is_valid(): message = form.cleaned_data['message'] connection = patient.contact.default_connection msg = OutgoingMessage(connection, message) router = Router() success = True try: router.outgoing(msg) except Exception, e: logger.exception(e) success = False if success: messages.success(request, "Message sent to patient %s" % patient.subject_number) else: messages.error(request, "An error occurred while trying to send the message to patient %s" % patient.subject_number) return redirect('patient-list')
def run(self): router = Router() app = router.get_app("aremind.apps.adherence") app.cronjob()
def setUp(self): super(SimpleRouterMixin, self).setUp() backends = {'mockbackend': {"ENGINE": MockBackend}} self.router = Router(backends=backends)
def setUp (self): backends = {'mockbackend': {"ENGINE": MockBackend}} self.router = Router(apps=self.apps, backends=backends) self.router.join = lambda: None self._init_log(logging.DEBUG) self.backend = self.router.backends["mockbackend"]
def run(self, backend_name, identity, text): backend, _ = Backend.objects.get_or_create(name=backend_name) connection, _ = backend.connection_set.get_or_create(identity=identity) message = IncomingMessage(connection, text, datetime.datetime.now()) router = Router() response = router.incoming(message)
def message_report_beneficiary(report, message_text): "Send a message to a user based on a report." template = u'{0} {1}'.format(communicator_prefix(), message_text) message = OutgoingMessage(connection=report.reporter, template=template) router = Router() router.outgoing(message)
def run(self): router = Router() scheduler_callback(router)
def reimbursement_detail(request, number): reimbursements = ReimbursementLog.objects.filter(phone=number).order_by('-reimbursed_on') num_messages = Message.objects.filter(connection__identity=number, direction='I').count() owed = settings.REIMBURSEMENT_RATES[network_for_number(number)] * num_messages - sum([r.amount for r in reimbursements]) from django import forms from django.contrib.admin.widgets import AdminDateWidget class ReimbursementForm(forms.Form): amount = forms.IntegerField() when = forms.DateField(widget=AdminDateWidget, required=False) def clean_amount(self): data = self.cleaned_data['amount'] if data <= 0: raise forms.ValidationError('can\'t be 0 or negative') return data if request.method == 'POST': form = ReimbursementForm(request.POST) if form.is_valid(): entry_date = form.cleaned_data['when'] entry = ReimbursementLog( phone=number, amount=form.cleaned_data['amount'], reimbursed_on=datetime.now() if (not entry_date or entry_date == date.today()) else entry_date, ) entry.save() network_name = network_for_number(number) network = NAME_NETWORK_MAP.get(network_name) try: subscriber = Subscriber.objects.get( number=number[-13:], network=network) except Subscriber.DoesNotExist: pass else: balance = subscriber.balance - form.cleaned_data['amount'] subscriber.balance = max(balance, 0) subscriber.save() #import pdb;pdb.set_trace() backend_name = get_backend_name(network_name) backend, _ = Backend.objects.get_or_create(name=backend_name) try: conn = Connection.objects.get(identity=number, backend=backend) except Exception: #log somewhere? pass else: notice = OutgoingMessage(connection=conn, template=settings.REIMBURSEMENT_NOTICE) router = Router() router.outgoing(notice) return HttpResponseRedirect('/dashboard/reimbursement/') else: form = ReimbursementForm() return render(request, 'dashboard/reimbursement_detail.html', { 'number': disp_number(number), 'network': network_for_number(number), 'owed': owed, 'over': owed < 0, 'over_amt': -owed, 'history': reimbursements, 'form': form, })
def run(self): router = Router() daily_email_callback(router)
def setUp(self): backends = {'mockbackend': {"ENGINE": MockBackend}} self.router = Router(apps=self.apps, backends=backends) self.router.join = lambda: None self._init_log(logging.DEBUG) self.backend = self.router.backends["mockbackend"]