Ejemplo n.º 1
0
    def testSMSLogSync(self):
        prev_couch_count = self.getSMSLogCount()
        prev_sql_count = self.getSMSCount()

        # Test Create
        smslog = SMSLog()
        self.setRandomSMSLogValues(smslog)
        smslog.save()

        sleep(1)
        self.assertEqual(self.getSMSLogCount(), prev_couch_count + 1)
        self.assertEqual(self.getSMSCount(), prev_sql_count + 1)

        sms = SMS.objects.get(couch_id=smslog._id)
        self.checkFieldValues(smslog, sms, SMSLog._migration_get_fields())
        self.assertTrue(SMSLog.get_db().get_rev(smslog._id).startswith('1-'))

        # Test Update
        self.setRandomSMSLogValues(smslog)
        smslog.save()

        sleep(1)
        self.assertEqual(self.getSMSLogCount(), prev_couch_count + 1)
        self.assertEqual(self.getSMSCount(), prev_sql_count + 1)
        sms = SMS.objects.get(couch_id=smslog._id)
        self.checkFieldValues(smslog, sms, SMSLog._migration_get_fields())
        self.assertTrue(SMSLog.get_db().get_rev(smslog._id).startswith('2-'))
Ejemplo n.º 2
0
def post(request, domain):
    # TODO: Figure out if this is being used anywhere and remove it if not
    """
    We assume sms sent to HQ will come in the form
    http://hqurl.com?username=%(username)s&password=%(password)s&id=%(phone_number)s&text=%(message)s
    """
    text = request.REQUEST.get('text', '')
    to = request.REQUEST.get('id', '')
    username = request.REQUEST.get('username', '')
    # ah, plaintext passwords....
    # this seems to be the most common API that a lot of SMS gateways expose
    password = request.REQUEST.get('password', '')
    if not text or not to or not username or not password:
        error_msg = 'ERROR missing parameters. Received: %(1)s, %(2)s, %(3)s, %(4)s' % \
                     ( text, to, username, password )
        logging.error(error_msg)
        return HttpResponseBadRequest(error_msg)
    user = authenticate(username=username, password=password)
    if user is None or not user.is_active:
        return HttpResponseBadRequest("Authentication fail")
    msg = SMSLog(
        domain=domain,
        # TODO: how to map phone numbers to recipients, when phone numbers are shared?
        #couch_recipient=id,
        phone_number=to,
        direction=INCOMING,
        date=datetime.now(),
        text=text)
    msg.save()
    return HttpResponse('OK')
Ejemplo n.º 3
0
def send_sms(domain, contact, phone_number, text, metadata=None):
    """
    Sends an outbound SMS. Returns false if it fails.
    """
    if phone_number is None:
        return False
    if isinstance(phone_number, int) or isinstance(phone_number, long):
        phone_number = str(phone_number)
    phone_number = clean_phone_number(phone_number)

    msg = SMSLog(
        domain=domain,
        phone_number=phone_number,
        direction=OUTGOING,
        date = datetime.utcnow(),
        backend_id=None,
        location_id=get_location_id_by_contact(domain, contact),
        text = text
    )
    if contact:
        msg.couch_recipient = contact._id
        msg.couch_recipient_doc_type = contact.doc_type
    add_msg_tags(msg, metadata)

    return queue_outgoing_sms(msg)
Ejemplo n.º 4
0
def message_log_report(request):
    show_dates = True

    datespan = request.datespan
    domains = Domain.get_all()
    for dom in domains:
        dom.sms_incoming = SMSLog.count_incoming_by_domain(dom.name, datespan.startdate_param, datespan.enddate_param)
        dom.sms_outgoing = SMSLog.count_outgoing_by_domain(dom.name, datespan.startdate_param, datespan.enddate_param)
        dom.sms_total = SMSLog.count_by_domain(dom.name, datespan.startdate_param, datespan.enddate_param)

    context = get_hqadmin_base_context(request)

    headers = DataTablesHeader(
        DataTablesColumn("Domain"),
        DataTablesColumn("Incoming Messages", sort_type=DTSortType.NUMERIC),
        DataTablesColumn("Outgoing Messages", sort_type=DTSortType.NUMERIC),
        DataTablesColumn("Total Messages", sort_type=DTSortType.NUMERIC),
    )
    context["headers"] = headers
    context["aoColumns"] = headers.render_aoColumns

    context.update({"domains": domains, "show_dates": show_dates, "datespan": datespan})

    context["layout_flush_content"] = True
    return render(request, "hqadmin/message_log_report.html", context)
Ejemplo n.º 5
0
def send_sms_to_verified_number(verified_number, text):
    """
    Sends an sms using the given verified phone number entry.
    
    verified_number The VerifiedNumber entry to use when sending.
    text            The text of the message to send.
    
    return  True on success, False on failure
    """
    try:
        backend = verified_number.backend
        module = __import__(backend.outbound_module, fromlist=["send"])
        kwargs = backend.outbound_params
        msg = SMSLog(
            couch_recipient_doc_type    = verified_number.owner_doc_type,
            couch_recipient             = verified_number.owner_id,
            phone_number                = "+" + str(verified_number.phone_number),
            direction                   = OUTGOING,
            date                        = datetime.utcnow(),
            domain                      = verified_number.domain,
            text                        = text
        )
        try:
            msg.backend_api = module.API_ID
        except Exception:
            pass
        module.send(msg, **kwargs)
        msg.save()
        return True
    except Exception as e:
        logging.exception("Exception while sending SMS to VerifiedNumber id " + verified_number._id)
        return False
Ejemplo n.º 6
0
def send_sms(domain, id, phone_number, text):
    """
    Sends an outbound SMS. Returns false if it fails.
    """
    if phone_number is None:
        return False
    if isinstance(phone_number, int) or isinstance(phone_number, long):
        phone_number = str(phone_number)
    logging.debug('Sending message: %s' % text)
    phone_number = clean_phone_number(phone_number)
    msg = SMSLog(domain=domain,
                     couch_recipient=id, 
                     couch_recipient_doc_type="CouchUser",
                     phone_number=phone_number,
                     direction=OUTGOING,
                     date = datetime.utcnow(),
                     text = text)
    try:
        api = get_backend_api(msg)
        try:
            msg.backend_api = api.API_ID
        except Exception:
            pass
        api.send(msg)
        msg.save()
        return True
    except Exception:
        logging.exception("Problem sending SMS to %s" % phone_number)
        return False
Ejemplo n.º 7
0
def post(request, domain):
    # TODO: Figure out if this is being used anywhere and remove it if not
    """
    We assume sms sent to HQ will come in the form
    http://hqurl.com?username=%(username)s&password=%(password)s&id=%(phone_number)s&text=%(message)s
    """
    text = request.REQUEST.get('text', '')
    to = request.REQUEST.get('id', '')
    username = request.REQUEST.get('username', '')
    # ah, plaintext passwords....  
    # this seems to be the most common API that a lot of SMS gateways expose
    password = request.REQUEST.get('password', '')
    if not text or not to or not username or not password:
        error_msg = 'ERROR missing parameters. Received: %(1)s, %(2)s, %(3)s, %(4)s' % \
                     ( text, to, username, password )
        logging.error(error_msg)
        return HttpResponseBadRequest(error_msg)
    user = authenticate(username=username, password=password)
    if user is None or not user.is_active:
        return HttpResponseBadRequest("Authentication fail")
    msg = SMSLog(domain=domain,
                 # TODO: how to map phone numbers to recipients, when phone numbers are shared?
                 #couch_recipient=id, 
                 phone_number=to,
                 direction=INCOMING,
                 date = datetime.now(),
                 text = text)
    msg.save()
    return HttpResponse('OK')     
Ejemplo n.º 8
0
def message_log_report(request):
    show_dates = True

    datespan = request.datespan
    domains = Domain.get_all()
    for dom in domains:
        dom.sms_incoming = SMSLog.count_incoming_by_domain(
            dom.name, datespan.startdate_param, datespan.enddate_param)
        dom.sms_outgoing = SMSLog.count_outgoing_by_domain(
            dom.name, datespan.startdate_param, datespan.enddate_param)
        dom.sms_total = SMSLog.count_by_domain(dom.name,
                                               datespan.startdate_param,
                                               datespan.enddate_param)

    context = get_hqadmin_base_context(request)

    headers = DataTablesHeader(
        DataTablesColumn("Domain"),
        DataTablesColumn("Incoming Messages", sort_type=DTSortType.NUMERIC),
        DataTablesColumn("Outgoing Messages", sort_type=DTSortType.NUMERIC),
        DataTablesColumn("Total Messages", sort_type=DTSortType.NUMERIC))
    context["headers"] = headers
    context["aoColumns"] = headers.render_aoColumns

    context.update({
        "domains": domains,
        "show_dates": show_dates,
        "datespan": datespan
    })

    context['layout_flush_content'] = True
    return render(request, "hqadmin/message_log_report.html", context)
Ejemplo n.º 9
0
def send_sms(domain, contact, phone_number, text, metadata=None):
    """
    Sends an outbound SMS. Returns false if it fails.
    """
    if phone_number is None:
        return False
    if isinstance(phone_number, int) or isinstance(phone_number, long):
        phone_number = str(phone_number)
    phone_number = clean_phone_number(phone_number)

    msg = SMSLog(
        domain=domain,
        phone_number=phone_number,
        direction=OUTGOING,
        date = datetime.utcnow(),
        backend_id=None,
        text = text
    )
    if contact:
        msg.couch_recipient = contact._id
        msg.couch_recipient_doc_type = contact.doc_type
    add_msg_tags(msg, metadata)

    def onerror():
        logging.exception("Problem sending SMS to %s" % phone_number)
    return queue_outgoing_sms(msg, onerror=onerror)
Ejemplo n.º 10
0
def send_sms(domain, contact, phone_number, text, metadata=None):
    """
    Sends an outbound SMS. Returns false if it fails.
    """
    if phone_number is None:
        return False
    if isinstance(phone_number, int) or isinstance(phone_number, long):
        phone_number = str(phone_number)
    phone_number = clean_phone_number(phone_number)

    msg = SMSLog(domain=domain,
                 phone_number=phone_number,
                 direction=OUTGOING,
                 date=datetime.utcnow(),
                 backend_id=None,
                 text=text)
    if contact:
        msg.couch_recipient = contact._id
        msg.couch_recipient_doc_type = contact.doc_type
    add_msg_tags(msg, metadata)

    def onerror():
        logging.exception("Problem sending SMS to %s" % phone_number)

    return queue_outgoing_sms(msg, onerror=onerror)
    def handle(self, *args, **options):
        num_sms = 0

        start_datetime = datetime.datetime(*str_to_int_tuple(args[0:6]))
        end_datetime = datetime.datetime(*str_to_int_tuple(args[6:12]))

        for domain in Domain.get_all():
            key = [domain.name, 'SMSLog']
            sms_docs = SMSLog.get_db().view('sms/by_domain',
                                            reduce=False,
                                            startkey=key + [start_datetime.isoformat()],
                                            endkey=key + [end_datetime.isoformat(), {}],
            )

            for sms_doc in sms_docs:
                sms_log = SMSLog.get(sms_doc['id'])
                if options.get('create', False):
                    SmsBillable.create(sms_log)
                    print 'Created billable for SMSLog %s in domain %s from %s' \
                          % (sms_doc['id'], domain.name, sms_log.date)
                else:
                    print 'Found SMSLog %s in domain %s from %s' \
                          % (sms_doc['id'], domain.name, sms_log.date)
                num_sms += 1

        print 'Number of SMSs in datetime range: %d' % num_sms
Ejemplo n.º 12
0
 def handle(self, *args, **options):
     billables_created = 0
     for domain in Domain.get_all():
         key = [domain.name, 'SMSLog']
         start_date = [datetime.datetime(2014, 1, 1).isoformat()]
         end_date = [datetime.datetime(2014, 1, 24).isoformat()]
         sms_docs = SMSLog.get_db().view('sms/by_domain',
                                         reduce=False,
                                         startkey=key + start_date,
                                         endkey=key + end_date + [{}])
         for sms_doc in sms_docs:
             sms_log = SMSLog.get(sms_doc['id'])
             try:
                 if sms_log.phone_number is not None:
                     parse_phone_number(sms_log.phone_number)
             except PhoneNumberParseException:
                 billables = SmsBillable.objects.filter(log_id=sms_log._id)
                 if len(billables) == 0:
                     SmsBillable.create(sms_log)
                     billables_created += 1
                     print 'created SmsBillable for invalid number %s in domain %s, id=%s'\
                           % (sms_log.phone_number, domain.name, sms_log._id)
                 elif len(billables) > 1:
                     print "Warning: >1 SmsBillable exists for SMSLog with id=%" % sms_log._id
     print 'Number of SmsBillables created: %d' % billables_created
     print 'Completed retrobilling.'
Ejemplo n.º 13
0
 def _get_fake_sms(self, text):
     msg = SMSLog(domain=self.domain,
                  phone_number='+16175555454',
                  direction=OUTGOING,
                  date=datetime.utcnow(),
                  backend_id=self.mobile_backend.get_id,
                  text=text)
     msg.save()
     return msg
Ejemplo n.º 14
0
def incoming(phone_number, text, backend_api, timestamp=None, domain_scope=None, backend_message_id=None, delay=True):
    """
    entry point for incoming sms

    phone_number - originating phone number
    text - message content
    backend_api - backend API ID of receiving sms backend
    timestamp - message received timestamp; defaults to now (UTC)
    domain_scope - if present, only messages from phone numbers that can be
      definitively linked to this domain will be processed; others will be
      dropped (useful to provide security when simulating incoming sms)
    """
    # Log message in message log
    phone_number = clean_phone_number(phone_number)
    msg = SMSLog(
        phone_number = phone_number,
        direction = INCOMING,
        date = timestamp or datetime.utcnow(),
        text = text,
        domain_scope = domain_scope,
        backend_api = backend_api,
        backend_message_id = backend_message_id,
    )
    if settings.SMS_QUEUE_ENABLED:
        msg.processed = False
        msg.datetime_to_process = datetime.utcnow()
        msg.queued_timestamp = msg.datetime_to_process
        msg.save()
        enqueue_directly(msg)
    else:
        msg.processed = True
        msg.save()
        process_incoming(msg, delay=delay)
    return msg
Ejemplo n.º 15
0
    def testSMSLogSync(self):
        self.deleteAllLogs()
        self.assertEqual(self.getSMSLogCount(), 0)
        self.assertEqual(self.getSMSCount(), 0)

        # Test Create
        smslog = SMSLog()
        self.setRandomSMSLogValues(smslog)
        smslog.save()

        sleep(1)
        self.assertEqual(self.getSMSLogCount(), 1)
        self.assertEqual(self.getSMSCount(), 1)

        sms = SMS.objects.get(couch_id=smslog._id)
        self.checkFieldValues(smslog, sms, SMSLog._migration_get_fields())
        self.assertTrue(SMSLog.get_db().get_rev(smslog._id).startswith('1-'))

        # Test Update
        self.setRandomSMSLogValues(smslog)
        smslog.save()

        sleep(1)
        self.assertEqual(self.getSMSLogCount(), 1)
        self.assertEqual(self.getSMSCount(), 1)
        sms = SMS.objects.get(couch_id=smslog._id)
        self.checkFieldValues(smslog, sms, SMSLog._migration_get_fields())
        self.assertTrue(SMSLog.get_db().get_rev(smslog._id).startswith('2-'))
Ejemplo n.º 16
0
 def create_outgoing_sms(self, backend):
     sms = SMSLog(
         domain=self.domain,
         date=datetime.utcnow(),
         direction='O',
         phone_number='9991234567',
         text='message',
         backend_id=backend.couch_id
     )
     sms.save()
     return sms
 def _get_fake_sms(self, text):
     msg = SMSLog(
         domain=self.domain,
         phone_number='+16175555454',
         direction=OUTGOING,
         date=datetime.utcnow(),
         backend_id=self.mobile_backend.get_id,
         text=text
     )
     msg.save()
     return msg
Ejemplo n.º 18
0
    def main_context(self):
        contacts = CommCareUser.by_domain(self.domain, reduce=True)
        web_users = WebUser.by_domain(self.domain)
        web_users_admins = web_users_read_only = 0
        facilities = SQLLocation.objects.filter(domain=self.domain, location_type__name__iexact='FACILITY')
        admin_role_list = UserRole.by_domain_and_name(self.domain, 'Administrator')
        if admin_role_list:
            admin_role = admin_role_list[0]
        else:
            admin_role = None
        for web_user in web_users:
            dm = web_user.get_domain_membership(self.domain)
            if admin_role and dm.role_id == admin_role.get_id:
                web_users_admins += 1
            else:
                web_users_read_only += 1

        main_context = super(GlobalStats, self).main_context
        entities_reported_stock = SQLLocation.objects.filter(
            domain=self.domain,
            location_type__administrative=False
        ).count()

        context = {
            'root_name': self.root_name,
            'country': SQLLocation.objects.filter(domain=self.domain,
                                                  location_type__name__iexact=self.root_name).count(),
            'region': SQLLocation.objects.filter(domain=self.domain, location_type__name__iexact='region').count(),
            'district': SQLLocation.objects.filter(
                domain=self.domain,
                location_type__name__iexact='district'
            ).count(),
            'entities_reported_stock': entities_reported_stock,
            'facilities': len(facilities),
            'contacts': contacts[0]['value'] if contacts else 0,
            'web_users': len(web_users),
            'web_users_admins': web_users_admins,
            'web_users_read_only': web_users_read_only,
            'products': SQLProduct.objects.filter(domain=self.domain, is_archived=False).count(),
            'product_stocks': StockState.objects.filter(sql_product__domain=self.domain).count(),
            'stock_transactions': StockTransaction.objects.filter(report__domain=self.domain).count(),
            'inbound_messages': SMSLog.count_incoming_by_domain(self.domain),
            'outbound_messages': SMSLog.count_outgoing_by_domain(self.domain)
        }

        if self.show_supply_point_types:
            counts = SQLLocation.objects.values('location_type__name').filter(domain=self.domain).annotate(
                Count('location_type')
            ).order_by('location_type__name')
            context['location_types'] = counts
        main_context.update(context)
        return main_context
Ejemplo n.º 19
0
    def main_context(self):
        contacts = CommCareUser.by_domain(self.domain, reduce=True)
        web_users = WebUser.by_domain(self.domain)
        web_users_admins = web_users_read_only = 0
        facilities = SQLLocation.objects.filter(domain=self.domain, location_type__iexact='FACILITY')

        for web_user in web_users:
            role = web_user.get_domain_membership(self.domain).role
            if role and role.name.lower().startswith('admin'):
                web_users_admins += 1
            else:
                web_users_read_only += 1

        main_context = super(GlobalStats, self).main_context
        location_types = Domain.get_by_name(self.domain).location_types
        administrative_types = [
            location_type.name
            for location_type in location_types
            if not location_type.administrative
        ]
        entities_reported_stock = SQLLocation.objects.filter(
            domain=self.domain,
            location_type__in=administrative_types
        ).count()

        context = {
            'root_name': self.root_name,
            'country': SQLLocation.objects.filter(domain=self.domain,
                                                  location_type__iexact=self.root_name).count(),
            'region': SQLLocation.objects.filter(domain=self.domain, location_type__iexact='region').count(),
            'district': SQLLocation.objects.filter(domain=self.domain, location_type__iexact='district').count(),
            'entities_reported_stock': entities_reported_stock,
            'facilities': len(facilities),
            'contacts': contacts[0]['value'] if contacts else 0,
            'web_users': len(web_users),
            'web_users_admins': web_users_admins,
            'web_users_read_only': web_users_read_only,
            'products': SQLProduct.objects.filter(domain=self.domain).count(),
            'product_stocks': StockState.objects.filter(sql_product__domain=self.domain).count(),
            'stock_transactions': StockTransaction.objects.filter(report__domain=self.domain).count(),
            'inbound_messages': SMSLog.count_incoming_by_domain(self.domain),
            'outbound_messages': SMSLog.count_outgoing_by_domain(self.domain)
        }

        if self.show_supply_point_types:
            counts = SQLLocation.objects.values('location_type').filter(domain=self.domain).annotate(
                Count('location_type')
            ).order_by('location_type')
            context['location_types'] = counts
        main_context.update(context)
        return main_context
Ejemplo n.º 20
0
def send_sms_with_backend(domain, phone_number, text, backend_id):
    msg = SMSLog(domain = domain,
                 phone_number = phone_number,
                 direction = OUTGOING,
                 date = datetime.utcnow(),
                 text = text)
    if backend_id == "MOBILE_BACKEND_MACH":
        try:
            try:
                msg.backend_api = mach_api.API_ID
            except Exception:
                pass
            mach_api.send(msg)
            msg.save()
            return True
        except Exception:
            logging.exception("Exception while sending SMS to %s with backend %s" % (phone_number, backend_id))
            return False
    elif backend_id == "MOBILE_BACKEND_UNICEL":
        try:
            try:
                msg.backend_api = unicel_api.API_ID
            except Exception:
                pass
            unicel_api.send(msg)
            msg.save()
            return True
        except Exception:
            logging.exception("Exception while sending SMS to %s with backend %s" % (phone_number, backend_id))
            return False
    else:
        try:
            backend = MobileBackend.get(backend_id)
        except Exception:
            backend = None
        if backend is None:
            return False
        
        try:
            module = __import__(backend.outbound_module, fromlist=["send"])
            try:
                msg.backend_api = module.API_ID
            except Exception:
                pass
            kwargs = backend.outbound_params
            module.send(msg, **kwargs)
            msg.save()
            return True
        except Exception as e:
            logging.exception("Exception while sending SMS to %s with backend %s" % (phone_number, backend_id))
            return False
Ejemplo n.º 21
0
    def testFRISMSLogSync(self):
        prev_couch_count = self.getSMSLogCount()
        prev_sql_count = self.getSMSCount()

        # Test Create
        smslog = SMSLog()
        self.setRandomSMSLogValues(smslog)
        smslog.save()

        sleep(1)
        smslog = FRISMSLog.get(smslog._id)
        self.setRandomFRISMSLogValues(smslog)
        smslog.save()

        sleep(1)
        self.assertEqual(self.getSMSLogCount(), prev_couch_count + 1)
        self.assertEqual(self.getSMSCount(), prev_sql_count + 1)

        sms = SMS.objects.get(couch_id=smslog._id)
        self.checkFieldValues(smslog, sms, FRISMSLog._migration_get_fields())
        self.assertTrue(FRISMSLog.get_db().get_rev(smslog._id).startswith('2-'))

        # Test Update
        self.setRandomSMSLogValues(smslog)
        self.setRandomFRISMSLogValues(smslog)
        smslog.save()

        sleep(1)
        self.assertEqual(self.getSMSLogCount(), prev_couch_count + 1)
        self.assertEqual(self.getSMSCount(), prev_sql_count + 1)
        sms = SMS.objects.get(couch_id=smslog._id)
        self.checkFieldValues(smslog, sms, FRISMSLog._migration_get_fields())
        self.assertTrue(SMSLog.get_db().get_rev(smslog._id).startswith('3-'))
Ejemplo n.º 22
0
def send_test_message(verified_number, text, metadata=None):
    msg = SMSLog(couch_recipient_doc_type=verified_number.owner_doc_type,
                 couch_recipient=verified_number.owner_id,
                 phone_number="+" + str(verified_number.phone_number),
                 direction=OUTGOING,
                 date=datetime.utcnow(),
                 domain=verified_number.domain,
                 text=text,
                 processed=True,
                 datetime_to_process=datetime.utcnow(),
                 queued_timestamp=datetime.utcnow())
    msg.save()
    add_msg_tags(msg, metadata)
    return True
Ejemplo n.º 23
0
    def tearDown(self):
        SmsBillable.objects.all().delete()
        SmsGatewayFee.objects.all().delete()
        SmsGatewayFeeCriteria.objects.all().delete()
        SmsUsageFee.objects.all().delete()
        SmsUsageFeeCriteria.objects.all().delete()

        self.currency_usd.delete()
        self.other_currency.delete()
        SMSLog.get_db().delete_docs(
            SMSLog.by_domain_asc(generator.TEST_DOMAIN).all())

        SMSBackend.get_db().delete_docs(SMSBackend.get_db().all_docs(
            keys=self.backend_ids.values(), include_docs=True).all())
Ejemplo n.º 24
0
 def testPostToIncomingAscii(self):
     fake_post = {InboundParams.SENDER: str(self.number),
                  InboundParams.MESSAGE: self.message_ascii,
                  InboundParams.TIMESTAMP: datetime.now().strftime(DATE_FORMAT),
                  InboundParams.DCS: self.dcs,
                  InboundParams.UDHI: '0'}
     client = Client()
     response = client.post('/unicel/in/', fake_post)
     self.assertEqual(200, response.status_code)
     self.assertEqual(1, SMSLog.count_by_domain(self.domain))
     log = SMSLog.by_domain_dsc(self.domain).all()[0]
     self.assertEqual(self.message_ascii, log.text)
     self.assertEqual(INCOMING, log.direction)
     self.assertEqual(log.date.strftime(DATE_FORMAT),
                      fake_post[InboundParams.TIMESTAMP])
Ejemplo n.º 25
0
    def tearDown(self):
        SmsBillable.objects.all().delete()
        SmsGatewayFee.objects.all().delete()
        SmsGatewayFeeCriteria.objects.all().delete()
        SmsUsageFee.objects.all().delete()
        SmsUsageFeeCriteria.objects.all().delete()

        self.currency_usd.delete()
        self.other_currency.delete()
        SMSLog.get_db().delete_docs(
            SMSLog.by_domain_asc(generator.TEST_DOMAIN).all()
        )

        for api_id, backend_id in self.backend_ids.iteritems():
            SQLMobileBackend.load(backend_id, is_couch_id=True).delete()
Ejemplo n.º 26
0
def incoming(phone_number,
             text,
             backend_api,
             timestamp=None,
             domain_scope=None,
             backend_message_id=None,
             delay=True,
             backend_attributes=None,
             raw_text=None):
    """
    entry point for incoming sms

    phone_number - originating phone number
    text - message content
    backend_api - backend API ID of receiving sms backend
    timestamp - message received timestamp; defaults to now (UTC)
    domain_scope - if present, only messages from phone numbers that can be
      definitively linked to this domain will be processed; others will be
      dropped (useful to provide security when simulating incoming sms)
    """
    # Log message in message log
    if text is None:
        text = ""
    phone_number = clean_phone_number(phone_number)
    msg = SMSLog(
        phone_number=phone_number,
        direction=INCOMING,
        date=timestamp or datetime.utcnow(),
        text=text,
        domain_scope=domain_scope,
        backend_api=backend_api,
        backend_message_id=backend_message_id,
        raw_text=raw_text,
    )
    if backend_attributes:
        for k, v in backend_attributes.items():
            setattr(msg, k, v)
    if settings.SMS_QUEUE_ENABLED:
        msg.processed = False
        msg.datetime_to_process = datetime.utcnow()
        msg.queued_timestamp = msg.datetime_to_process
        msg.save()
        enqueue_directly(msg)
    else:
        msg.processed = True
        msg.save()
        process_incoming(msg, delay=delay)
    return msg
Ejemplo n.º 27
0
def send_sms_to_verified_number(verified_number, text, metadata=None):
    """
    Sends an sms using the given verified phone number entry.
    
    verified_number The VerifiedNumber entry to use when sending.
    text            The text of the message to send.
    
    return  True on success, False on failure
    """
    backend = verified_number.backend
    msg = SMSLog(couch_recipient_doc_type=verified_number.owner_doc_type,
                 couch_recipient=verified_number.owner_id,
                 phone_number="+" + str(verified_number.phone_number),
                 direction=OUTGOING,
                 date=datetime.utcnow(),
                 domain=verified_number.domain,
                 backend_id=backend._id,
                 text=text)
    add_msg_tags(msg, metadata)

    def onerror():
        logging.exception("Exception while sending SMS to VerifiedNumber id " +
                          verified_number._id)

    return queue_outgoing_sms(msg, onerror=onerror)
Ejemplo n.º 28
0
def _sms_count(user, startdate, enddate, message_type="SMSLog"):
    """
    Returns a dictionary of messages seen for a given type, user, and date
    range of the format:
    {
        I: inbound_count,
        O: outbound_count
    }
    """
    # utilizable if we want to stick it somewhere else
    start_timestamp = json_format_datetime(startdate)
    end_timestamp = json_format_datetime(enddate)
    ret = {}
    for direction in [INCOMING, OUTGOING]:
        results = (
            SMSLog.get_db()
            .view(
                "sms/by_recipient",
                startkey=[user.doc_type, user._id, message_type, direction, start_timestamp],
                endkey=[user.doc_type, user._id, message_type, direction, end_timestamp],
                reduce=True,
            )
            .all()
        )
        ret[direction] = results[0]["value"] if results else 0

    return ret
Ejemplo n.º 29
0
def send_test_message(verified_number, text, metadata=None):
    msg = SMSLog(
        couch_recipient_doc_type=verified_number.owner_doc_type,
        couch_recipient=verified_number.owner_id,
        phone_number="+" + str(verified_number.phone_number),
        direction=OUTGOING,
        date=datetime.utcnow(),
        domain=verified_number.domain,
        text=text,
        processed=True,
        datetime_to_process=datetime.utcnow(),
        queued_timestamp=datetime.utcnow(),
    )
    msg.save()
    add_msg_tags(msg, metadata)
    return True
Ejemplo n.º 30
0
def handle_domain_specific_delays(msg, domain_object, utcnow):
    """
    Checks whether or not we need to hold off on sending an outbound message
    due to any restrictions set on the domain, and delays processing of the
    message if necessary.

    Returns True if a delay was made, False if not.
    """
    domain_now = ServerTime(utcnow).user_time(domain_object.get_default_timezone()).done()

    if len(domain_object.restricted_sms_times) > 0:
        if not time_within_windows(domain_now, domain_object.restricted_sms_times):
            delay_processing(msg, settings.SMS_QUEUE_DOMAIN_RESTRICTED_RETRY_INTERVAL)
            return True

    if msg.chat_user_id is None and len(domain_object.sms_conversation_times) > 0:
        if time_within_windows(domain_now, domain_object.sms_conversation_times):
            sms_conversation_length = domain_object.sms_conversation_length
            conversation_start_timestamp = utcnow - timedelta(minutes=sms_conversation_length)
            if SMSLog.inbound_entry_exists(msg.couch_recipient_doc_type,
                                           msg.couch_recipient,
                                           conversation_start_timestamp,
                                           utcnow):
                delay_processing(msg, 1)
                return True

    return False
Ejemplo n.º 31
0
    def handle(self, *args, **options):
        if len(args) == 0:
            raise CommandError(
                "Usage: python manage.py fix_smslog_recipient_doc_type <domain1 domain2 ...>"
            )

        for domain in args:
            print "*** Processing Domain %s ***" % domain
            user_cache = {}
            for msg in SMSLog.by_domain_asc(domain).all():
                if msg.couch_recipient:
                    if msg.couch_recipient_doc_type != "CommCareCase":
                        user = None
                        if msg.couch_recipient in user_cache:
                            user = user_cache[msg.couch_recipient]
                        else:
                            try:
                                user = CouchUser.get_by_user_id(
                                    msg.couch_recipient)
                            except Exception:
                                user = None
                            if user is None:
                                print "Could not find user %s" % msg.couch_recipient
                        user_cache[msg.couch_recipient] = user
                        if user and msg.couch_recipient_doc_type != user.doc_type:
                            msg.couch_recipient_doc_type = user.doc_type
                            msg.save()
                else:
                    if msg.couch_recipient_doc_type is not None or msg.couch_recipient is not None:
                        msg.couch_recipient = None
                        msg.couch_recipient_doc_type = None
                        msg.save()
Ejemplo n.º 32
0
 def get_sms_couch_ids(self):
     result = SMSLog.view(
         'sms/by_domain',
         include_docs=False,
         reduce=False,
     ).all()
     return [row['id'] for row in result if row['key'][1] == 'SMSLog']
    def handle(self, *args, **options):
        if len(args) == 0:
            raise CommandError("Usage: python manage.py fix_smslog_recipient_doc_type <domain1 domain2 ...>")

        for domain in args:
            print "*** Processing Domain %s ***" % domain
            user_cache = {}
            for msg in SMSLog.by_domain_asc(domain).all():
                if msg.couch_recipient:
                    if msg.couch_recipient_doc_type != "CommCareCase":
                        user = None
                        if msg.couch_recipient in user_cache:
                            user = user_cache[msg.couch_recipient]
                        else:
                            try:
                                user = CouchUser.get_by_user_id(msg.couch_recipient)
                            except Exception:
                                user = None
                            if user is None:
                                print "Could not find user %s" % msg.couch_recipient
                        user_cache[msg.couch_recipient] = user
                        if user and msg.couch_recipient_doc_type != user.doc_type:
                            msg.couch_recipient_doc_type = user.doc_type
                            msg.save()
                else:
                    if msg.couch_recipient_doc_type is not None or msg.couch_recipient is not None:
                        msg.couch_recipient = None
                        msg.couch_recipient_doc_type = None
                        msg.save()
Ejemplo n.º 34
0
def message_test(request, domain, phone_number):
    if request.method == "POST":
        message = request.POST.get("message", "")
        domain_scope = None if request.couch_user.is_superuser else domain
        try:
            incoming(phone_number, message, "TEST", domain_scope=domain_scope)
        except DomainScopeValidationError:
            messages.error(
                request,
                _("Invalid phone number being simulated. You may only " \
                  "simulate SMS from verified numbers belonging to contacts " \
                  "in this domain.")
            )
        except Exception:
            notify_exception(request)
            messages.error(
                request,
                _("An error has occurred. Please try again in a few minutes " \
                  "and if the issue persists, please contact CommCareHQ " \
                  "Support.")
            )

    context = get_sms_autocomplete_context(request, domain)
    context['domain'] = domain
    context['messagelog'] = SMSLog.by_domain_dsc(domain)
    context['now'] = datetime.utcnow()
    tz = report_utils.get_timezone(request.couch_user.user_id, domain)
    context['timezone'] = tz
    context['timezone_now'] = datetime.now(tz=tz)
    context['layout_flush_content'] = True
    context['phone_number'] = phone_number
    return render(request, "sms/message_tester.html", context)
Ejemplo n.º 35
0
    def send_sms(self, msg, delay=True, *args, **kwargs):
        phone_number = strip_plus(msg.phone_number)
        if not phone_number.startswith("63"):
            raise MegamobileException("Only Filipino phone numbers are supported")
        phone_number = phone_number[2:]

        text = msg.text.encode("utf-8")

        pid = None
        if msg.in_reply_to:
            original_msg = SMSLog.get(msg.in_reply_to)
            pid = getattr(original_msg, "megamobile_pid", None)
        pid = pid or DEFAULT_PID
        setattr(msg, "megamobile_pid", pid)
        msg.save()

        params = urlencode({
            "pid" : pid,
            "cel" : phone_number,
            "msg" : text,
            "src" : self.source_identifier,
        })
        api_account_name = quote(self.api_account_name)
        url = "http://api.mymegamobile.com/%s?%s" % (api_account_name, params)
        response = urlopen(url, timeout=settings.SMS_GATEWAY_TIMEOUT).read()
Ejemplo n.º 36
0
    def send(self, msg, delay=True, *args, **kwargs):
        phone_number = strip_plus(msg.phone_number)
        if not phone_number.startswith("63"):
            raise MegamobileException(
                "Only Filipino phone numbers are supported")
        phone_number = phone_number[2:]

        text = msg.text.encode("utf-8")

        pid = None
        if msg.in_reply_to:
            original_msg = SMSLog.get(msg.in_reply_to)
            pid = getattr(original_msg, "megamobile_pid", None)
        pid = pid or DEFAULT_PID
        setattr(msg, "megamobile_pid", pid)
        msg.save()

        params = urlencode({
            "pid": pid,
            "cel": phone_number,
            "msg": text,
            "src": self.source_identifier,
        })
        api_account_name = quote(self.api_account_name)
        url = "http://api.mymegamobile.com/%s?%s" % (api_account_name, params)
        response = urlopen(url, timeout=settings.SMS_GATEWAY_TIMEOUT).read()
Ejemplo n.º 37
0
 def get_sms_couch_ids(self):
     result = SMSLog.view(
         'sms/by_domain',
         include_docs=False,
         reduce=False,
     ).all()
     return [row['id'] for row in result if row['key'][1] == 'SMSLog']
Ejemplo n.º 38
0
def handle_domain_specific_delays(msg, domain_object, utcnow):
    """
    Checks whether or not we need to hold off on sending an outbound message
    due to any restrictions set on the domain, and delays processing of the
    message if necessary.

    Returns True if a delay was made, False if not.
    """
    domain_now = tz_utils.adjust_datetime_to_timezone(utcnow, pytz.utc.zone,
        domain_object.default_timezone)

    if len(domain_object.restricted_sms_times) > 0:
        if not time_within_windows(domain_now, domain_object.restricted_sms_times):
            delay_processing(msg, settings.SMS_QUEUE_DOMAIN_RESTRICTED_RETRY_INTERVAL)
            return True

    if msg.chat_user_id is None and len(domain_object.sms_conversation_times) > 0:
        if time_within_windows(domain_now, domain_object.sms_conversation_times):
            sms_conversation_length = domain_object.sms_conversation_length
            conversation_start_timestamp = utcnow - timedelta(minutes=sms_conversation_length)
            if SMSLog.inbound_entry_exists(msg.couch_recipient_doc_type,
                                           msg.couch_recipient,
                                           conversation_start_timestamp,
                                           utcnow):
                delay_processing(msg, 1)
                return True

    return False
Ejemplo n.º 39
0
def _sms_count(user, startdate, enddate, message_type='SMSLog'):
    """
    Returns a dictionary of messages seen for a given type, user, and date
    range of the format:
    {
        I: inbound_count,
        O: outbound_count
    }
    """
    # utilizable if we want to stick it somewhere else
    start_timestamp = json_format_datetime(startdate)
    end_timestamp = json_format_datetime(enddate)
    ret = {}
    for direction in [INCOMING, OUTGOING]:
        results = SMSLog.get_db().view("sms/by_recipient",
                                       startkey=[
                                           user.doc_type, user._id,
                                           message_type, direction,
                                           start_timestamp
                                       ],
                                       endkey=[
                                           user.doc_type, user._id,
                                           message_type, direction,
                                           end_timestamp
                                       ],
                                       reduce=True).all()
        ret[direction] = results[0]['value'] if results else 0

    return ret
    def handle(self, *labels, **options):
        db = SMSLog.get_db()

        # active_domains = db.view(
        #     "sms/by_domain",
        #     reduce=True,
        #     group_level=1,
        # ).all()
        # active_domains = [d['key'][0] for d in active_domains]
        active_domains = ['pathfinder']
        startkey = lambda d: [d, "SMSLog", "2013-08-01"]
        endkey = lambda d: [d, "SMSLog", "2013-10-15"]

        for domain in active_domains:
            data = db.view(
                "sms/by_domain",
                reduce=False,
                startkey=startkey(domain),
                endkey=endkey(domain),
            ).all()
            sms_ids = [d['id'] for d in data]
            for doc in iter_docs(db, sms_ids):
                sms_log = SMSLog.wrap(doc)
                if not sms_log.billed and sms_log.backend_api in [
                    'MACH',
                    # 'TROPO',
                    # 'UNICEL',
                ]:
                    # we're going to assume the SMS messages were sent successfully
                    # at the time they were actually sent
                    successful_responses = {
                        'MACH': "MACH RESPONSE +OK 01 message queued (dest=%s)" % sms_log.phone_number,
                        'TROPO': "<success>true</success>",
                        'UNICEL': "success",
                    }
                    print "Retroactively billing SMLog %s in domain %s" % (sms_log._id, sms_log.domain)
                    try:
                        create_billable_for_sms(
                            sms_log,
                            sms_log.backend_api,
                            delay=False,
                            response=successful_responses[sms_log.backend_api],
                        )
                    except Exception as e:
                        print "Retroactive bill was not successful due to error: %s" % e
                        logging.exception(e)
Ejemplo n.º 41
0
def process_sms(message_id):
    """
    message_id - _id of an SMSLog entry
    """
    # Note that Redis error/exception notifications go out from the
    # run_sms_queue command, so no need to send them out here
    # otherwise we'd get too many emails.
    rcache = cache_core.get_redis_default_cache()
    if not isinstance(rcache, RedisCache):
        return
    try:
        client = rcache.raw_client
    except NotImplementedError:
        return

    utcnow = datetime.utcnow()
    # Prevent more than one task from processing this SMS, just in case
    # the message got enqueued twice.
    message_lock = get_lock(client, "sms-queue-processing-%s" % message_id)

    if message_lock.acquire(blocking=False):
        msg = SMSLog.get(message_id)

        if message_is_stale(msg, utcnow):
            msg.set_system_error(ERROR_MESSAGE_IS_STALE)
            message_lock.release()
            return

        if msg.direction == OUTGOING:
            domain_object = Domain.get_by_name(msg.domain, strict=True)
            if handle_domain_specific_delays(msg, domain_object, utcnow):
                message_lock.release()
                return

        requeue = False
        # Process inbound SMS from a single contact one at a time
        recipient_block = msg.direction == INCOMING
        if (isinstance(msg.processed, bool)
            and not msg.processed
            and not msg.error
            and msg.datetime_to_process < utcnow):
            if recipient_block:
                recipient_lock = get_lock(client, 
                    "sms-queue-recipient-phone-%s" % msg.phone_number)
                recipient_lock.acquire(blocking=True)

            if msg.direction == OUTGOING:
                requeue = handle_outgoing(msg)
            elif msg.direction == INCOMING:
                handle_incoming(msg)
            else:
                msg.set_system_error(ERROR_INVALID_DIRECTION)

            if recipient_block:
                recipient_lock.release()
        message_lock.release()
        if requeue:
            process_sms.delay(message_id)
Ejemplo n.º 42
0
def process_sms(message_id):
    """
    message_id - _id of an SMSLog entry
    """
    # Note that Redis error/exception notifications go out from the
    # run_sms_queue command, so no need to send them out here
    # otherwise we'd get too many emails.
    rcache = cache_core.get_redis_default_cache()
    if not isinstance(rcache, RedisCache):
        return
    try:
        client = rcache.raw_client
    except NotImplementedError:
        return

    utcnow = datetime.utcnow()
    # Prevent more than one task from processing this SMS, just in case
    # the message got enqueued twice.
    message_lock = get_lock(client, "sms-queue-processing-%s" % message_id)

    if message_lock.acquire(blocking=False):
        msg = SMSLog.get(message_id)

        if message_is_stale(msg, utcnow):
            set_error(msg, ERROR_MESSAGE_IS_STALE)
            message_lock.release()
            return

        if msg.direction == OUTGOING:
            domain_object = Domain.get_by_name(msg.domain, strict=True)
            if handle_domain_specific_delays(msg, domain_object, utcnow):
                message_lock.release()
                return

        requeue = False
        # Process inbound SMS from a single contact one at a time
        recipient_block = msg.direction == INCOMING
        if (isinstance(msg.processed, bool)
            and not msg.processed
            and not msg.error
            and msg.datetime_to_process < utcnow):
            if recipient_block:
                recipient_lock = get_lock(client, 
                    "sms-queue-recipient-phone-%s" % msg.phone_number)
                recipient_lock.acquire(blocking=True)

            if msg.direction == OUTGOING:
                requeue = handle_outgoing(msg)
            elif msg.direction == INCOMING:
                handle_incoming(msg)
            else:
                set_error(msg, ERROR_INVALID_DIRECTION)

            if recipient_block:
                recipient_lock.release()
        message_lock.release()
        if requeue:
            process_sms.delay(message_id)
Ejemplo n.º 43
0
    def rows(self):
        startdate = json_format_datetime(self.datespan.startdate_utc)
        enddate = json_format_datetime(self.datespan.enddate_utc)
        data = SMSLog.by_domain_date(self.domain, startdate, enddate)
        result = []

        username_map = {
        }  # Store the results of username lookups for faster loading

        direction_map = {
            INCOMING: _("Incoming"),
            OUTGOING: _("Outgoing"),
        }

        # Retrieve message log options
        message_log_options = getattr(settings, "MESSAGE_LOG_OPTIONS", {})
        abbreviated_phone_number_domains = message_log_options.get(
            "abbreviated_phone_number_domains", [])
        abbreviate_phone_number = (self.domain
                                   in abbreviated_phone_number_domains)

        for message in data:
            if message.direction == OUTGOING and not message.processed:
                continue
            recipient_id = message.couch_recipient
            if recipient_id in [None, ""]:
                username = "******"
            elif recipient_id in username_map:
                username = username_map.get(recipient_id)
            else:
                username = "******"
                try:
                    if message.couch_recipient_doc_type == "CommCareCase":
                        username = CommCareCase.get(recipient_id).name
                    else:
                        username = CouchUser.get_by_user_id(
                            recipient_id).username
                except Exception:
                    pass

                username_map[recipient_id] = username

            phone_number = message.phone_number
            if abbreviate_phone_number and phone_number is not None:
                phone_number = phone_number[0:7] if phone_number[
                    0:1] == "+" else phone_number[0:6]

            timestamp = tz_utils.adjust_datetime_to_timezone(
                message.date, pytz.utc.zone, self.timezone.zone)
            result.append([
                self._fmt_timestamp(timestamp),
                self._fmt(username),
                self._fmt(phone_number),
                self._fmt(direction_map.get(message.direction, "-")),
                self._fmt(message.text),
            ])

        return result
Ejemplo n.º 44
0
 def get_items_to_be_processed(self, utcnow):
     # We're just querying for ids here, so no need to limit
     entries = SMSLog.view(
         "sms/queued_sms",
         startkey="1970-01-01T00:00:00Z",
         endkey=json_format_datetime(utcnow),
         include_docs=False
     ).all()
     return entries
Ejemplo n.º 45
0
    def main_context(self):
        contacts = CommCareUser.by_domain(self.domain, reduce=True)
        web_users = WebUser.by_domain(self.domain, reduce=True)

        main_context = super(GlobalStats, self).main_context
        context = {
            'supply_points': SQLLocation.objects.filter(domain=self.domain).count(),
            'facilities': SQLLocation.objects.filter(domain=self.domain, location_type__iexact='FACILITY').count(),
            'contacts': contacts[0]['value'] if contacts else 0,
            'web_users': web_users[0]['value'] if web_users else 0,
            'products': SQLProduct.objects.filter(domain=self.domain).count(),
            'product_stocks': StockState.objects.filter(sql_product__domain=self.domain).count(),
            'stock_transactions': StockTransaction.objects.filter(report__domain=self.domain).count(),
            'inbound_messages': SMSLog.count_incoming_by_domain(self.domain),
            'outbound_messages': SMSLog.count_outgoing_by_domain(self.domain)
        }
        main_context.update(context)
        return main_context
Ejemplo n.º 46
0
 def get_last_outbound_sms(self, doc_type, contact_id):
     sms = SMSLog.view("sms/by_recipient",
                       startkey=[doc_type, contact_id, "SMSLog", "O", {}],
                       endkey=[doc_type, contact_id, "SMSLog", "O"],
                       descending=True,
                       include_docs=True,
                       reduce=False,
                       ).first()
     return sms
Ejemplo n.º 47
0
 def get_sms_and_call_couch_count(self):
     result = SMSLog.view(
         'sms/by_domain',
         include_docs=False,
         reduce=True,
     ).all()
     if result:
         return result[0]['value']
     return 0
Ejemplo n.º 48
0
 def tearDown(self):
     SmsBillable.objects.all().delete()
     SmsGatewayFee.objects.all().delete()
     SmsGatewayFeeCriteria.objects.all().delete()
     SmsUsageFee.objects.all().delete()
     SmsUsageFeeCriteria.objects.all().delete()
     self.currency_usd.delete()
     for log in SMSLog.by_domain_asc(generator.TEST_DOMAIN):
         log.delete()
Ejemplo n.º 49
0
    def rows(self):
        startdate = json_format_datetime(self.datespan.startdate_utc)
        enddate = json_format_datetime(self.datespan.enddate_utc)
        data = SMSLog.by_domain_date(self.domain, startdate, enddate)
        result = []

        direction_map = {
            INCOMING: _("Incoming"),
            OUTGOING: _("Outgoing"),
        }

        # Retrieve message log options
        message_log_options = getattr(settings, "MESSAGE_LOG_OPTIONS", {})
        abbreviated_phone_number_domains = message_log_options.get(
            "abbreviated_phone_number_domains", [])
        abbreviate_phone_number = (self.domain
                                   in abbreviated_phone_number_domains)

        contact_cache = {}

        for message in data:
            if message.direction == OUTGOING and not message.processed:
                continue
            recipient_id = message.couch_recipient
            doc = None
            if recipient_id not in [None, ""]:
                try:
                    if message.couch_recipient_doc_type == "CommCareCase":
                        doc = CommCareCase.get(recipient_id)
                    else:
                        doc = CouchUser.get_by_user_id(recipient_id)
                except Exception:
                    pass

            if doc:
                doc_info = get_doc_info(doc.to_json(), self.domain,
                                        contact_cache)
            else:
                doc_info = None

            phone_number = message.phone_number
            if abbreviate_phone_number and phone_number is not None:
                phone_number = phone_number[0:7] if phone_number[
                    0:1] == "+" else phone_number[0:6]

            timestamp = tz_utils.adjust_datetime_to_timezone(
                message.date, pytz.utc.zone, self.timezone.zone)
            result.append([
                self._fmt_timestamp(timestamp),
                self._fmt_contact_link(message, doc_info),
                self._fmt(phone_number),
                self._fmt(direction_map.get(message.direction, "-")),
                self._fmt(message.text),
            ])

        return result
Ejemplo n.º 50
0
def arbitrary_messages_by_backend_and_direction(backend_ids,
                                                phone_number=None,
                                                domain=None,
                                                directions=DIRECTIONS):
    phone_number = phone_number or TEST_NUMBER
    domain = domain or TEST_DOMAIN
    messages = []
    for api_id, instance_id in backend_ids.items():
        for direction in directions:
            sms_log = SMSLog(direction=direction,
                             phone_number=phone_number,
                             domain=domain,
                             backend_api=api_id,
                             backend_id=instance_id,
                             text=arbitrary_message(),
                             date=datetime.datetime.utcnow())
            sms_log.save()
            messages.append(sms_log)
    return messages
Ejemplo n.º 51
0
def messaging(request, domain, template="sms/default.html"):
    context = get_sms_autocomplete_context(request, domain)
    context['domain'] = domain
    context['messagelog'] = SMSLog.by_domain_dsc(domain)
    context['now'] = datetime.utcnow()
    tz = report_utils.get_timezone(request.couch_user.user_id, domain)
    context['timezone'] = tz
    context['timezone_now'] = datetime.now(tz=tz)
    context['layout_flush_content'] = True
    return render(request, template, context)
Ejemplo n.º 52
0
 def getSMSLogCount(self):
     result = SMSLog.view(
         'sms/by_domain',
         startkey=[self.domain, 'SMSLog'],
         endkey=[self.domain, 'SMSLog', {}],
         include_docs=False,
         reduce=True,
     ).all()
     if result:
         return result[0]['value']
     return 0
Ejemplo n.º 53
0
    def tearDown(self):
        for smslog in SMSLog.view(
                'sms/by_domain',
                startkey=[self.domain, 'SMSLog'],
                endkey=[self.domain, 'SMSLog', {}],
                include_docs=True,
                reduce=False,
        ).all():
            smslog.delete()

        SMS.objects.filter(domain=self.domain).delete()
Ejemplo n.º 54
0
 def handle(self, *labels, **options):
     messages = SMSLog.view("sms/migrate_smslog_2012_04", include_docs=True)
     print "Migrating MessageLog to SMSLog"
     for message in messages:
         try:
             message.doc_type = "SMSLog"
             message.base_doc = "MessageLog"
             message.couch_recipient_doc_type = "CouchUser"
             message.save()
         except Exception as e:
             print "There was an error migrating message %s." % (
                 message._id)
 def handle(self, *args, **options):
     missing_domain_billables = SmsBillable.objects.filter(
         Q(domain=u'') | Q(domain=None))
     for billable in missing_domain_billables:
         msg_log = SMSLog.get(billable.log_id)
         billable.domain = msg_log.domain
         if billable.domain:
             billable.save()
             print "Updated Billable from %s for domain %s" % (
                 billable.date_created, billable.domain)
         else:
             print "could not find a domain in SMSLog %s." % billable.log_id
Ejemplo n.º 56
0
def process_sms(message_id):
    """
    message_id - _id of an SMSLog entry
    """
    client = get_redis_client()
    utcnow = datetime.utcnow()
    # Prevent more than one task from processing this SMS, just in case
    # the message got enqueued twice.
    message_lock = get_lock(client, "sms-queue-processing-%s" % message_id)

    if message_lock.acquire(blocking=False):
        msg = SMSLog.get(message_id)

        if message_is_stale(msg, utcnow):
            msg.set_system_error(SMS.ERROR_MESSAGE_IS_STALE)
            release_lock(message_lock, True)
            return

        if msg.direction == OUTGOING:
            if msg.domain:
                domain_object = Domain.get_by_name(msg.domain, strict=True)
            else:
                domain_object = None
            if domain_object and handle_domain_specific_delays(msg, domain_object, utcnow):
                release_lock(message_lock, True)
                return

        requeue = False
        # Process inbound SMS from a single contact one at a time
        recipient_block = msg.direction == INCOMING
        if (isinstance(msg.processed, bool)
            and not msg.processed
            and not msg.error
            and msg.datetime_to_process < utcnow):
            if recipient_block:
                recipient_lock = get_lock(client, 
                    "sms-queue-recipient-phone-%s" % msg.phone_number)
                recipient_lock.acquire(blocking=True)

            if msg.direction == OUTGOING:
                requeue = handle_outgoing(msg)
            elif msg.direction == INCOMING:
                handle_incoming(msg)
            else:
                msg.set_system_error(SMS.ERROR_INVALID_DIRECTION)

            if recipient_block:
                release_lock(recipient_lock, True)

        release_lock(message_lock, True)
        if requeue:
            process_sms.delay(message_id)
 def setUp(self):
     self.domain = 'mockdomain'
     all_logs = SMSLog.by_domain_asc(self.domain).all()
     for log in all_logs:
         log.delete()
     self.user = '******'
     self.password = '******'
     self.number = 5555551234
     self.couch_user = WebUser.create(self.domain, self.user, self.password)
     self.couch_user.add_phone_number(self.number)
     self.couch_user.save()
     self.dcs = '8'
     self.message_ascii = 'It Works'
     self.message_utf_hex = '0939093F0928094D092609400020091509300924093E00200939094800200907093800200938092E092F00200915093E092E002009390948003F'