예제 #1
0
def sms_notification(self, body, to):
    try:
        nexmo_number_out = settings.ENDAGA['NEXMO_NOTIFICATION_NUMBER']
    except KeyError:
        return # Do nothing if not configured

    nexmo_provider = NexmoProvider(settings.ENDAGA['NEXMO_ACCT_SID'],
                       settings.ENDAGA['NEXMO_AUTH_TOKEN'],
                       settings.ENDAGA['NEXMO_INBOUND_SMS_URL'],
                       None, #outbound_sms_url
                       settings.ENDAGA['NEXMO_INBOUND_VOICE_HOST'])

    nexmo_provider.send(to, nexmo_number_out, body)
예제 #2
0
    def get(self, request, bts_uuid=None, format=None):
        """Return a number that's usable by a BTS.

        We first check for "available" numbers in our database. If there are
        none, we buy a number from a provider, set it up, and return here. We
        have to specify a specific BTS to avoid a race condition when multiple
        BTS register for a number at once.
        """
        if not bts_uuid:
            return Response("No BTS UUID specified.",
                            status=status.HTTP_400_BAD_REQUEST)
        network = get_network_from_user(request.user)
        try:
            bts = models.BTS.objects.get(uuid=bts_uuid, network=network)
        except models.BTS.DoesNotExist:
            return Response("The specified BTS does not belong to the user.",
                            status=status.HTTP_403_FORBIDDEN)
        # First check for available numbers.  If a number is available, it's up
        # for grabs by anyone.
        with transaction.atomic():
            q = models.Number.objects.filter(state__exact="available")
            for n in q:
                # We do this here rather than in the db query since at this
                # time some numbers don't have a country field to query on. Can
                # probably be removed later. -- SH (2014 aug 21)
                # TODO(matt): this potentially sets a lot of numbers as
                #             pending..
                if n.country() == network.number_country:
                    n.state = "pending"
                    n.network = network
                    n.save()
                    n.charge()
                    return Response(int(n.number), status=status.HTTP_200_OK)

        # No number available, so we have to buy one from Nexmo.
        # TODO: Try to buy from multiple vendors
        np = NexmoProvider(
            settings.ENDAGA['NEXMO_ACCT_SID'],
            settings.ENDAGA['NEXMO_AUTH_TOKEN'],
            settings.ENDAGA['NEXMO_INBOUND_SMS_URL'],
            None,  #outbound_sms_url
            settings.ENDAGA['NEXMO_INBOUND_VOICE_HOST'],
            country=network.number_country)
        try:
            # This call creates the new number in the DB as a side effect.
            new_number = np.get_number(bts.network)
            print "New number is %s" % new_number
            return Response(new_number, status=status.HTTP_200_OK)
        except ValueError:
            return Response("Number not available",
                            status=status.HTTP_404_NOT_FOUND)
예제 #3
0
파일: api_v2.py 프로젝트: shivkumarsah/ccm
    def post(self, request, msisdn):
        network = get_network_from_user(request.user)
        number = models.Number.objects.get(number=msisdn)
        if (number.network and number.network != network
                and not request.user.is_staff):
            return Response("User is not associated with that Number %s %s." %
                            (number.network.pk, network.pk),
                            status=status.HTTP_403_FORBIDDEN)
        # Must post a valid 'state'.
        valid_states = ('available', 'released')
        if request.POST.get('state', None) not in valid_states:
            return Response("Must post a valid state.",
                            status=status.HTTP_400_BAD_REQUEST)
        # This is a valid request, begin processing.  First check if this is a
        # number-deactivation request.
        if (number.state == 'inuse'
                and request.POST.get('state') == 'available'):
            # Refuse to deactivate a subscriber's last number.
            if (len(models.Number.objects.filter(subscriber=number.subscriber))
                    <= 1):
                message = ("Cannot deactivate a subscriber's last number."
                           "  Instead, delete the subscriber.")
                return Response(message, status=status.HTTP_400_BAD_REQUEST)
            # If it's not the subscriber's only number, send an async post to
            # the BTS to deactivate the number.  Sign the request using JWT.
            bts = number.subscriber.bts
            url = '%s/config/deactivate_number' % bts.inbound_url
            data = {
                'number': msisdn,
                # Add a UUID as a nonce for the message.
                'msgid': str(uuid.uuid4()),
            }
            serializer = itsdangerous.JSONWebSignatureSerializer(bts.secret)
            signed_data = {
                'jwt': serializer.dumps(data),
            }
            tasks.async_post.delay(url, signed_data)
            # Create a 'deactivate_number' UsageEvent.
            now = datetime.datetime.now(pytz.utc)
            reason = 'deactivated phone number: %s' % number.number
            event = models.UsageEvent.objects.create(
                subscriber=number.subscriber,
                date=now,
                bts=bts,
                kind='deactivate_number',
                to_number=number.number,
                reason=reason,
                oldamt=number.subscriber.balance,
                newamt=number.subscriber.balance,
                change=0)
            event.save()
            # Diassociate the Number from its former Subscriber and Network.
            number.subscriber = None
            number.network = None
            number.state = request.POST.get('state')
            number.save()
            return Response("")

        # Check if this is a number-release request.
        if request.POST.get('state') == 'released':
            # User must be staff to do this.
            if not request.user.is_staff:
                return Response("", status=status.HTTP_404_NOT_FOUND)
            # The number must not be 'inuse.'
            if number.state == 'inuse':
                return Response("", status=status.HTTP_400_BAD_REQUEST)
            # The number cannot be associated with a Sub.
            if number.subscriber:
                return Response("", status=status.HTTP_400_BAD_REQUEST)
            # Validation passes, release (cancel) the number.
            nexmo_provider = NexmoProvider(
                settings.ENDAGA['NEXMO_ACCT_SID'],
                settings.ENDAGA['NEXMO_AUTH_TOKEN'],
                settings.ENDAGA['NEXMO_INBOUND_SMS_URL'],
                None,
                settings.ENDAGA['NEXMO_INBOUND_VOICE_HOST'],
                country=number.country_id)
            if nexmo_provider.cancel_number(number.number):
                # Success, delete the number.
                number.delete()
                return Response("", status=status.HTTP_200_OK)
            else:
                print 'deleting number %s failed' % number.number
                return Response("",
                                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # Invalid request.
        return Response("", status=status.HTTP_400_BAD_REQUEST)
예제 #4
0
def downtime_notify(self):
    """Sends out notifcation to a user if a BTS has gone down.
    Runs every `BTS_INACTIVE_TIMEOUT_SECS`
    """
    timeout_secs = settings.ENDAGA['BTS_INACTIVE_TIMEOUT_SECS']

    # get nexmo config
    try:
        nexmo_number_out = settings.ENDAGA['NEXMO_NOTIFICATION_NUMBER']
        nexmo_provider = NexmoProvider(
            settings.ENDAGA['NEXMO_ACCT_SID'],
            settings.ENDAGA['NEXMO_AUTH_TOKEN'],
            settings.ENDAGA['NEXMO_INBOUND_SMS_URL'],
            None,  #outbound_sms_url
            settings.ENDAGA['NEXMO_INBOUND_VOICE_HOST'])
    except KeyError:
        nexmo_number_out = None
        nexmo_provider = None

    # get mailgun config
    try:
        support_email = settings.TEMPLATE_CONSTANTS['SUPPORT_EMAIL']
    except KeyError:
        support_email = None

    for bts in BTS.objects.filter(status='active'):

        # Safety check - should not be hit
        if not bts.last_active:
            continue

        checkin_secs = (django.utils.timezone.now() -
                        bts.last_active).total_seconds()

        # Only send out notifications after one period of no activity, if BTS has 'active' status
        if timeout_secs < checkin_secs:
            data = {
                'bts_uuid_short': bts.uuid[:6],
                'bts_uuid': bts.uuid,
                'bts_nickname': bts.nickname,
            }

            if bts.nickname:
                email_subj = ("Alert open: BTS %s (%s...) offline" %
                              (bts.nickname, bts.uuid[:6]))
            else:
                email_subj = "Alert open: BTS %s offline" % (bts.uuid)
            email_msg = render_to_string("internal/bts_down_email.html", data)
            sms_msg = render_to_string("internal/bts_down_sms.html", data)

            for email in bts.network.notify_emails.split(','):
                email = email.strip()
                if support_email and email:
                    try:
                        send_mail(email_subj, email_msg, support_email,
                                  [email])
                    except Exception as e:
                        # log the error, but ignore it.
                        print(
                            "email fail sub: '%s' msg: '%s' frm: '%s' "
                            "to: '%s' exception: %s" %
                            (email_subj, email_msg, support_email, email, e))

            # We blindly assume the SMS is <140 char
            for number in bts.network.notify_numbers.split(','):
                number = number.strip()
                if nexmo_number_out and nexmo_provider and number:
                    try:
                        nexmo_provider.send(number, nexmo_number_out, sms_msg)
                    except Exception as e:
                        print "sms fail: to: %s from: %s msg: %s" % (
                            number, nexmo_number_out, sms_msg)

            # Mark BTS as inactive
            bts.status = 'inactive'
            bts.save()
            down_event = SystemEvent(date=django.utils.timezone.now(),
                                     bts=bts,
                                     type='bts down')
            down_event.save()