def process_confirm(from_imsi, code): """Process a confirmation request. Args: from_imsi: sender's IMSI code: the input confirmation code string """ # Step one: delete all the confirm codes older than some time. db = sqlite3.connect(config_db['pending_transfer_db_path']) db.execute("DELETE FROM pending_transfers" " WHERE time - ? > 600", (time.time(),)) db.commit() # Step two: check if this (from_imsi, code) combo is valid. r = db.execute("SELECT from_acct, to_acct, amount FROM pending_transfers" " WHERE code=? AND from_acct=?", (code, from_imsi)) res = r.fetchone() if res and len(res) == 3: from_imsi, to_imsi, amount = res from_num = subscriber.get_numbers_from_imsi(from_imsi)[0] to_num = subscriber.get_numbers_from_imsi(to_imsi)[0] reason = "SMS transfer from %s to %s" % (from_num, to_num) # Deduct credit from the sender. from_imsi_old_credit = subscriber.get_account_balance(from_imsi) from_imsi_new_credit = int(from_imsi_old_credit) - int(amount) events.create_transfer_event(from_imsi, from_imsi_old_credit, from_imsi_new_credit, reason, from_number=from_num, to_number=to_num) subscriber.subtract_credit(from_imsi, str(int(amount))) # Add credit to the recipient. to_imsi_old_credit = subscriber.get_account_balance(to_imsi) to_imsi_new_credit = int(to_imsi_old_credit) + int(amount) events.create_transfer_event(to_imsi, to_imsi_old_credit, to_imsi_new_credit, reason, from_number=from_num, to_number=to_num) subscriber.add_credit(to_imsi, str(int(amount))) # Humanize credit strings amount_str = freeswitch_strings.humanize_credits(amount) to_balance_str = freeswitch_strings.humanize_credits( to_imsi_new_credit) from_balance_str = freeswitch_strings.humanize_credits( from_imsi_new_credit) # Let the recipient know they got credit. message = gt("You've received %(amount)s credits from %(from_num)s!" " Your new balance is %(new_balance)s.") % { 'amount': amount_str, 'from_num': from_num, 'new_balance': to_balance_str} sms.send(str(to_num), str(config_db['app_number']), str(message)) # Remove this particular the transfer as it's no longer pending. db.execute("DELETE FROM pending_transfers WHERE code=?" " AND from_acct=?", (code, from_imsi)) db.commit() # Tell the sender that the operation succeeded. return True, gt("You've transferred %(amount)s to %(to_num)s. " "Your new balance is %(new_balance)s.") % { 'amount': amount_str, 'to_num': to_num, 'new_balance': from_balance_str} return False, gt("That transfer confirmation code doesn't exist" " or has expired.")
def post(self, request, format=None): needed_fields = ["imsi", "keyword"] if not all(i in request.POST for i in needed_fields): return Response("Missing Args", status=status.HTTP_400_BAD_REQUEST) imsi = request.data['imsi'] keyword = request.data['keyword'] callerid = endaga_sub.get_numbers_from_imsi(imsi)[0] subscriptions = PromoSubscription.objects.filter( contact__imsi__exact=imsi, promo__keyword=keyword) if not subscriptions: send_sms.delay(callerid, '0000', _("You have no %s subscriptions.") % keyword) ret = 'FAIL UNSUBSCRIBE' else: for item in subscriptions: app.control.revoke(str(item.id), terminate=True) subscriptions.delete() msg = _("You are now unsubscribed from your %s promos.") % keyword send_sms.delay(callerid, '0000', msg) ret = 'OK UNSUBSCRIBE' # we should also create an event balance = endaga_sub.get_account_balance(imsi) reason = "Promo Cancel Subscription: %s" % keyword events.create_sms_event(imsi, balance, 0, reason, '555') return Response(ret, status=status.HTTP_200_OK)
def post(self, request): """ POST method for submitting a report """ needed_fields = ["imsi", "keyword", "message"] if not all(i in request.POST for i in needed_fields): return Response("ERROR: Missing arguments.", status=status.HTTP_400_BAD_REQUEST) imsi = request.data['imsi'] try: subscriber = Contact.objects.get(imsi__exact=imsi) except BaseException: send_sms.delay( endaga_sub.get_numbers_from_imsi(imsi)[0], '0000', _("You are currently not registered to the BTS. " "Please register.")) return Response("ERROR: Not registered subscriber.", status=status.HTTP_400_BAD_REQUEST) try: report = Report.objects.filter( Q(keyword=request.data['keyword'].upper()) & Q(status='P'))[0] except BaseException: send_sms.delay( subscriber.callerid, '0000', _("Sorry we can't process your request. " "Invalid keyword.")) return Response("ERROR: Invalid keyword.", status=status.HTTP_400_BAD_REQUEST) new_report = ReportMessages() new_report.sender = subscriber new_report.report = report new_report.message = request.data['message'] new_report.date = timezone.now() new_report.save() send_sms.delay( subscriber.callerid, '0000', _("You have successfully sent a report to %s.") % report.keyword) for manager in report.managers.all(): send_sms.delay( manager.callerid, '0000', _("New report from %(manager)s. " "%(keyword)s:%(msg)s") % ({ 'manager': manager.callerid, 'keyword': report.keyword, 'msg': new_report.message })) return Response('OK CREATED', status=status.HTTP_200_OK)
def post(self, request): """ POST method to send message to service's subscribers. """ needed_fields = ["imsi", "keyword", "message"] if not all(i in request.POST for i in needed_fields): return Response("ERROR: Missing arguments.", status=status.HTTP_400_BAD_REQUEST) imsi = request.data['imsi'] keyword = request.data['keyword'] try: service = Service.objects.filter(keyword=keyword.upper(), status='P')[0] except BaseException: send_sms.delay( endaga_sub.get_numbers_from_imsi(imsi)[0], '0000', _("Sorry we can't process your request. " "Invalid service.")) return Response("ERROR: Invalid service.", status=status.HTTP_400_BAD_REQUEST) # check first if sender is the service manager # if so, propagate message to all service subscribers if service.managers.filter(imsi=request.data['imsi']).exists(): for subscriber in service.subscribers.all(): send_sms.delay(subscriber.callerid, '0000', _("ANNOUNCEMENT: %s") % request.data['message']) return Response('ANNOUNCEMENT SENT', status=status.HTTP_200_OK) else: send_sms.delay( endaga_sub.get_numbers_from_imsi(imsi)[0], '0000', _("You are not allowed to send message to %s's " "subscribers.") % keyword) return Response("ERROR: No administrative privileges to send to " "this %s's subscribers." % keyword, status=status.HTTP_400_BAD_REQUEST)
def post(self, request): """ POST method for subscribing to a service """ needed_fields = ["imsi", "keyword"] if not all(i in request.POST for i in needed_fields): return Response("ERROR: Missing arguments.", status=status.HTTP_400_BAD_REQUEST) imsi = request.data['imsi'] try: subscriber = Contact.objects.get(imsi__exact=imsi) except BaseException: send_sms.delay( endaga_sub.get_numbers_from_imsi(imsi)[0], '0000', _("You are currently not registered to the BTS. " "Please register.")) return Response("ERROR: Not registered subscriber.", status=status.HTTP_404_NOT_FOUND) try: service = Service.objects.filter( keyword=request.data['keyword'].upper(), service_type='P', status='P')[0] except BaseException: send_sms.delay( subscriber.callerid, '0000', _("Sorry we can't process your request. " "Invalid keyword.")) return Response("ERROR: Invalid keyword.", status=status.HTTP_400_BAD_REQUEST) is_subscribed = ServiceSubscribers.objects. \ filter(service=service, subscriber=subscriber).exists() if is_subscribed: send_sms.delay(subscriber.callerid, '0000', _("You are subscribed to %s.") % service.name) return Response('OK STATUS - SUBSCRIBED', status=status.HTTP_200_OK) else: send_sms.delay(subscriber.callerid, '0000', _("You are not subscribed to %s.") % service.name) return Response('OK STATUS - NOT SUBSCRIBED', status=status.HTTP_200_OK)
def post(self, request, format=None): needed_fields = ["keyword", "imsi"] if not all(i in request.POST for i in needed_fields): return Response("Missing Args", status=status.HTTP_400_BAD_REQUEST) imsi = request.data['imsi'] keyword = request.data['keyword'] callerid = endaga_sub.get_numbers_from_imsi(imsi)[0] try: promo = Promo.objects.get(keyword__exact=keyword) msg = promo.description except BaseException: msg = "You have entered an invalid promo keyword." send_sms.delay(callerid, '0000', msg) return Response('OK', status=status.HTTP_200_OK)
def process_transfer(from_imsi, to_imsi, amount): """Process a transfer request. Args: from_imsi: the sender's IMSI to_imsi: the recipient's IMSI amount: an amount of credit to add (type?) Returns: boolean indicating success """ # Error when user tries to transfer to his own account if from_imsi == to_imsi: return False, gt("Transaction Failed. Sharing load to " "your own account is not allowed.") from_balance = int(subscriber.get_account_balance(from_imsi)) # Error when user tries to transfer more credit than they have. if not from_balance or from_balance < amount: return False, gt("Your account doesn't have sufficient funds for" " the transfer.") # Error when user tries to transfer to a non-existent user. # Could be 0! Need to check if doesn't exist. if not to_imsi or (subscriber.get_account_balance(to_imsi) == None): return False, gt("The number you're sending to doesn't exist." " Try again.") # Add the pending transfer. code = '' for _ in range(int(config_db['code_length'])): code += str(random.randint(0, 9)) db = sqlite3.connect(config_db['pending_transfer_db_path']) db.execute("INSERT INTO pending_transfers VALUES (?, ?, ?, ?, ?)", (code, time.time(), from_imsi, to_imsi, amount)) db.commit() db.close() to_num = subscriber.get_numbers_from_imsi(to_imsi)[0] amount_str = freeswitch_strings.humanize_credits(amount) response = gt("Reply to this message with %(code)s to confirm your" " transfer of %(amount)s to %(to_num)s. Code expires in ten" " minutes.") % { 'code': code, 'amount': amount_str, 'to_num': to_num } return True, response
def handle_incoming(from_imsi, request): """Called externally by an FS script. Args: from_imsi: sender's IMSI request: a credit transfer or credit transfer confirmation request """ request = request.strip() # This parses a to_number (length 1 or more) and an amount that can # be formatted using a comma for a thousands seperator and a period for # the decimal place transfer_command = re.compile( r'^(?P<to_number>[0-9]+)' r'\*' r'(?P<amount>[0-9]*(?:,[0-9]{3})*(?:\.[0-9]*)?)$') transfer = transfer_command.match(request) confirm_command = re.compile(r'^(?P<confirm_code>[0-9]{%d})$' % int(config_db['code_length'])) confirm = confirm_command.match(request) _init_pending_transfer_db() if transfer: to_number, amount = transfer.groups() amount = freeswitch_strings.parse_credits(amount).amount_raw # Translate everything into IMSIs. try: to_imsi = subscriber.get_imsi_from_number(to_number) _, resp = process_transfer(from_imsi, to_imsi, amount) except SubscriberNotFound: resp = gt("Invalid phone number: %(number)s" % {'number': to_number}) elif confirm: # The code is the whole request, so no need for groups. code = request.strip() _, resp = process_confirm(from_imsi, code) else: # NOTE: Sent when the user tries to transfer credit with the wrong # format message. resp = gt("To transfer credit, reply with a message in the" " format 'NUMBER*AMOUNT'.") from_number = subscriber.get_numbers_from_imsi(from_imsi)[0] sms.send(str(from_number), str(config_db['app_number']), str(resp))
def post(self, request): """ POST method for opting out from a service """ needed_fields = ["imsi", "keyword"] if not all(i in request.POST for i in needed_fields): return Response("ERROR: Missing arguments.", status=status.HTTP_400_BAD_REQUEST) imsi = request.data['imsi'] keyword = request.data['keyword'] try: subscriber = Contact.objects.get(imsi__exact=imsi) except BaseException: send_sms.delay( endaga_sub.get_numbers_from_imsi(imsi)[0], '0000', _("You are currently not registered to the BTS. " "Please register.")) return Response("ERROR: Not registered subscriber.", status=status.HTTP_400_BAD_REQUEST) try: subscription = ServiceSubscribers.objects.filter( service__keyword__exact=keyword, subscriber__imsi__exact=request.data['imsi'])[0] subscription.delete() send_sms.delay( subscriber.callerid, '0000', _("You have successfully unsubscribed to %s.") % subscription.service.name) return Response('OK UNSUBSCRIBED', status=status.HTTP_200_OK) except BaseException: send_sms.delay( subscriber.callerid, '0000', _("You are not currently subscribed to the service.")) return Response("ERROR: You are not currently subscribed to " "the %s service." % keyword, status=status.HTTP_400_BAD_REQUEST)
def post(self, request, format=None): needed_fields = ["imsi"] if not all(i in request.POST for i in needed_fields): return Response("Missing Args", status=status.HTTP_400_BAD_REQUEST) imsi = request.data['imsi'] keyword = request.data['keyword'] callerid = endaga_sub.get_numbers_from_imsi(imsi)[0] if not keyword: subscriptions = PromoSubscription.objects.filter( contact__imsi__exact=imsi). \ order_by('date_expiration') else: subscriptions = PromoSubscription.objects.filter( contact__imsi__exact=imsi, promo__keyword=keyword). \ order_by('date_expiration') if not subscriptions: send_sms.delay(callerid, '0000', _("You have no %s subscriptions.") % keyword) else: msg = "" try: tz = Config.objects.get(key='timezone').value except Config.DoesNotExist: tz = pytz_timezone('Asia/Manila') for item in subscriptions: msg += "Your %s promo status: \\n" % item.promo.keyword expiry = item.date_expiration. \ astimezone(tz).strftime("%m/%d/%y %I:%M%p") if item.promo.promo_type == 'D' or item.promo.promo_type == 'G': if item.local_sms: msg += "%s local texts discount price: P%s\\n" % ( item.promo.keyword, mc_to_float(item.local_sms)) if item.local_call: msg += "%s local call/min discount price: P%s\\n" % ( item.promo.keyword, mc_to_float(item.local_call)) if item.globe_sms: msg += "%s Globe texts discount price: P%s\\n" % ( item.promo.keyword, mc_to_float(item.globe_sms)) if item.globe_call: msg += "%s Globe call/min discount price: P%s\\n" % ( item.promo.keyword, mc_to_float(item.globe_call)) if item.outside_sms: msg += "%s outside texts discount price: P%s\\n" % ( item.promo.keyword, mc_to_float(item.outside_sms)) if item.outside_call: msg += "%s outside call/min discount price: P%s\\n" % ( item.promo.keyword, mc_to_float(item.outside_call)) elif item.promo.promo_type == 'B': if item.local_sms: msg += "%s local texts: %s\\n" % (item.promo.keyword, item.local_sms) if item.local_call: msg += "%s local call mins: %s\\n" % ( item.promo.keyword, item.local_call) if item.globe_sms: msg += "%s Globe texts: %s\\n" % (item.promo.keyword, item.globe_sms) if item.globe_call: msg += "%s Globe call mins: %s\\n" % ( item.promo.keyword, item.globe_call) if item.outside_sms: msg += "%s outside texts: %s\\n" % (item.promo.keyword, item.outside_sms) if item.outside_call: msg += "%s outside call mins: %s\\n" % ( item.promo.keyword, item.outside_call) elif item.promo.promo_type == 'U': if item.local_sms: msg += "%s unli local texts\\n" % item.promo.keyword if item.local_call: msg += "%s unli local calls\\n" % item.promo.keyword if item.globe_sms: msg += "%s unli Globe texts\\n" % item.promo.keyword if item.globe_call: msg += "%s unli Globe calls\\n" % item.promo.keyword if item.outside_sms: msg += "%s unli outside texts\\n" % item.promo.keyword if item.outside_call: msg += "%s unli outside calls\\n" % item.promo.keyword msg += "Exp: %s\\n" % expiry send_sms.delay(callerid, '0000', msg[:-2]) return Response('OK', status=status.HTTP_200_OK)
def post(self, request): needed_fields = ["imsi", "keyword"] if not all(i in request.POST for i in needed_fields): return Response("Missing Args", status=status.HTTP_400_BAD_REQUEST) imsi = request.data['imsi'] keyword = request.data['keyword'] try: subscriber = Contact.objects.get(imsi__exact=imsi) except BaseException: # subscriber not found in Contacts table send_sms.delay( endaga_sub.get_numbers_from_imsi(imsi)[0], '0000', _("You are not listed in the PCARI-VBTS database. " "Please register.")) return Response("Not Found", status=status.HTTP_404_NOT_FOUND) # We put code to optionally limit promo subscriptions # this depends on the limit type declared in the configs try: limit_type = Config.objects.get(key='promo_limit_type').value except Config.DoesNotExist: limit_type = 'NA' try: max_promo_subscription = int( Config.objects.get(key='max_promo_subscription').value) except Config.DoesNotExist: max_promo_subscription = 1 try: min_balance_required = float( Config.objects.get(key='min_balance_required').value) except Config.DoesNotExist: min_balance_required = 0 # type A: Limit number of subscription per promo if limit_type == 'A': count = PromoSubscription.objects.filter( promo__keyword__exact=keyword, contact=subscriber).count() if count >= max_promo_subscription: send_sms.delay(subscriber.callerid, '0000', _("You have to many promo subscriptions.")) return Response("Too Many Subscriptions", status=status.HTTP_403_FORBIDDEN) # type B: Limit number of subscription for all promos elif limit_type == 'B': count = PromoSubscription.objects.filter( contact=subscriber).count() if count >= max_promo_subscription: send_sms.delay(subscriber.callerid, '0000', _("You have to many promo subscriptions.")) return Response("Too Many Subscriptions", status=status.HTTP_403_FORBIDDEN) else: pass # proceed as usual try: promo = Promo.objects.get(keyword__exact=keyword) except BaseException: # bad promo keyword send_sms.delay(subscriber.callerid, '0000', _("You made a bad promo request.")) return Response("Bad promo request", status=status.HTTP_400_BAD_REQUEST) # check account balance first balance = endaga_sub.get_account_balance(imsi) if balance - promo.price < min_balance_required: send_sms.delay( subscriber.callerid, '0000', _("You do not have sufficient balance to subscribe " "to the %s promo.") % promo.keyword) return Response("Insufficient balance", status=status.HTTP_402_PAYMENT_REQUIRED) # user passes above check, has enough balance, so sign him up! new_subscription = PromoSubscription() new_subscription.promo = promo new_subscription.contact = subscriber # save time as UTC in database new_subscription.date_expiration = timezone.now() + timedelta( promo.validity) new_subscription.local_sms = promo.local_sms new_subscription.local_call = promo.local_call new_subscription.globe_sms = promo.globe_sms new_subscription.globe_call = promo.globe_call new_subscription.outside_sms = promo.outside_sms new_subscription.outside_call = promo.outside_call new_subscription.save() # finally, deduct promo.price from subscriber's balance # price is expressed in millicents endaga_sub.subtract_credit(imsi, str(promo.price)) try: tz = Config.objects.get(key='timezone').value except Config.DoesNotExist: tz = pytz_timezone('Asia/Manila') # present time to subscriber according to defined timezone expiry = new_subscription.date_expiration.astimezone(tz). \ strftime("%m/%d/%y %I:%M%p") # and then lets inform the subscriber send_sms.delay( subscriber.callerid, '0000', _("You are now subscribed to %(keyword)s valid " "until %(expiry)s.") % ({ 'keyword': promo.keyword, 'expiry': expiry })) # and then create a purge task # let's use the PK as the task_id, so that we dont have to create # a new field to store the id. this might be OK for now. purge_entry.apply_async(eta=new_subscription.date_expiration, args=[new_subscription.pk], task_id=str(new_subscription.pk)) # we should also create an event reason = "Promo subscription: %s" % promo.keyword events.create_sms_event(subscriber.imsi, balance, promo.price, reason, '555') return Response('OK SUBSCRIBE', status=status.HTTP_200_OK)
def post(self, request): """ POST method for subscribing to a service """ needed_fields = ["imsi", "keyword"] if not all(i in request.POST for i in needed_fields): return Response("ERROR: Missing arguments.", status=status.HTTP_400_BAD_REQUEST) imsi = request.data['imsi'] try: subscriber = Contact.objects.get(imsi__exact=imsi) except BaseException: send_sms.delay( endaga_sub.get_numbers_from_imsi(imsi)[0], '0000', _("You are currently not registered to the BTS. " "Please register.")) return Response("ERROR: Not registered subscriber.", status=status.HTTP_400_BAD_REQUEST) try: service = Service.objects.filter( keyword=request.data['keyword'].upper(), service_type='P', status='P')[0] except BaseException: send_sms.delay( subscriber.callerid, '0000', _("Sorry we can't process your request. " "Invalid keyword.")) return Response("ERROR: Invalid keyword.", status=status.HTTP_400_BAD_REQUEST) is_duplicate = ServiceSubscribers.objects. \ filter(service=service, subscriber=subscriber).exists() if is_duplicate: send_sms.delay( subscriber.callerid, '0000', _("You are already subscribed to %s.") % service.name) return Response('OK ALREADY SUBSCRIBED', status=status.HTTP_200_OK) else: # check if subscriber has enough balance balance = endaga_sub.get_account_balance(imsi) if balance - service.price < 0: send_sms.delay( subscriber.callerid, '0000', _("You do not have sufficient balance to " "subscribe to %s.") % service.name) return Response("Insufficient balance", status=status.HTTP_402_PAYMENT_REQUIRED) # user passes above check, has enough balance, so sign him up! new_subscription = ServiceSubscribers(subscriber=subscriber, service=service) new_subscription.date_joined = timezone.now() new_subscription.save() # finally, deduct service.price from subscriber's balance # price is expressed in millicents endaga_sub.subtract_credit(imsi, str(service.price)) send_sms.delay( subscriber.callerid, '0000', _("You have successfully subscribed to %s.") % service.name) return Response('OK SUBSCRIBED', status=status.HTTP_200_OK)