def get_context_data(self, **kwargs): context = super(ContactCRUDL.Import, self).get_context_data(**kwargs) context['task'] = None context['group'] = None context['show_form'] = True analytics.track(self.request.user.username, 'temba.contact_imported') task_id = self.request.REQUEST.get('task', None) if task_id: tasks = ImportTask.objects.filter(pk=task_id, created_by=self.request.user) if tasks: task = tasks[0] context['task'] = task context['show_form'] = False context['results'] = json.loads(task.import_results) if task.import_results else dict() groups = ContactGroup.user_groups.filter(import_task=task) if groups: context['group'] = groups[0] elif not task.status() in ['PENDING', 'RUNNING', 'STARTED']: context['show_form'] = True return context
def form_valid(self, form): user = self.request.user org = user.get_org() groups = form.cleaned_data["groups"] # first archive all catch all message triggers with matching groups Trigger.objects.filter( org=org, groups__in=groups, trigger_type=Trigger.TYPE_CATCH_ALL, is_active=True ).update(is_archived=True) # then create a new catch all trigger trigger = Trigger.objects.create( created_by=user, modified_by=user, org=org, trigger_type=Trigger.TYPE_CATCH_ALL, flow=form.cleaned_data["flow"], ) # add all the groups we are relevant for for group in groups: trigger.groups.add(group) analytics.track(self.request.user.username, "temba.trigger_created_catchall") response = self.render_to_response(self.get_context_data(form=form)) response["REDIRECT"] = self.get_success_url() return response
def form_valid(self, form): user = self.request.user org = user.get_org() groups = form.cleaned_data['groups'] # first archive all catch all message triggers with matching groups Trigger.objects.filter(org=org, groups__in=groups, trigger_type=Trigger.TYPE_CATCH_ALL, is_active=True).update(is_archived=True) # then create a new catch all trigger trigger = Trigger.objects.create( created_by=user, modified_by=user, org=org, trigger_type=Trigger.TYPE_CATCH_ALL, flow=form.cleaned_data['flow']) # add all the groups we are relevant for for group in groups: trigger.groups.add(group) analytics.track(self.request.user.username, 'temba.trigger_created_catchall') response = self.render_to_response( self.get_context_data(form=form)) response['REDIRECT'] = self.get_success_url() return response
def form_valid(self, form): keyword = form.cleaned_data['keyword'] join_group = form.cleaned_data['action_join_group'] start_flow = form.cleaned_data['flow'] send_msg = form.cleaned_data['response'] org = self.request.user.get_org() group_flow = Flow.create_join_group(org, self.request.user, join_group, send_msg, start_flow) Trigger.objects.create(created_by=self.request.user, modified_by=self.request.user, org=self.request.user.get_org(), keyword=keyword, trigger_type=Trigger.TYPE_KEYWORD, flow=group_flow) analytics.track(self.request.user.username, 'temba.trigger_created_register', dict(name=join_group.name)) response = self.render_to_response( self.get_context_data(form=form)) response['REDIRECT'] = self.get_success_url() return response
def form_valid(self, form): analytics.track(self.request.user.username, 'temba.trigger_created_schedule') schedule = Schedule.objects.create(created_by=self.request.user, modified_by=self.request.user) if form.starts_never(): schedule.reset() elif form.stopped(): schedule.reset() elif form.starts_now(): schedule.next_fire = timezone.now() - timedelta(days=1) schedule.repeat_period = 'O' schedule.repeat_days = 0 schedule.status = 'S' schedule.save() else: # Scheduled case schedule.status = 'S' schedule.repeat_period = form.cleaned_data['repeat_period'] start_time = form.get_start_time() if start_time: schedule.next_fire = start_time # create our recurrence if form.is_recurring(): days = None if 'repeat_days' in form.cleaned_data: days = form.cleaned_data['repeat_days'] schedule.repeat_days = days schedule.repeat_hour_of_day = schedule.next_fire.hour schedule.repeat_minute_of_hour = schedule.repeat_minute_of_hour schedule.repeat_day_of_month = schedule.next_fire.day schedule.save() recipients = self.form.cleaned_data['omnibox'] trigger = Trigger.objects.create( flow=self.form.cleaned_data['flow'], org=self.request.user.get_org(), schedule=schedule, trigger_type=Trigger.TYPE_SCHEDULE, created_by=self.request.user, modified_by=self.request.user) for group in recipients['groups']: trigger.groups.add(group) for contact in recipients['contacts']: trigger.contacts.add(contact) self.post_save(trigger) response = self.render_to_response( self.get_context_data(form=form)) response['REDIRECT'] = self.get_success_url() return response
def form_valid(self, form): keyword = form.cleaned_data["keyword"] join_group = form.cleaned_data["action_join_group"] start_flow = form.cleaned_data["flow"] send_msg = form.cleaned_data["response"] org = self.request.user.get_org() group_flow = Flow.create_join_group(org, self.request.user, join_group, send_msg, start_flow) Trigger.objects.create( created_by=self.request.user, modified_by=self.request.user, org=self.request.user.get_org(), keyword=keyword, trigger_type=Trigger.TYPE_KEYWORD, flow=group_flow, ) analytics.track(self.request.user.username, "temba.trigger_created", dict(type="register")) response = self.render_to_response( self.get_context_data(form=form)) response["REDIRECT"] = self.get_success_url() return response
def form_valid(self, form): user = self.request.user org = user.get_org() # first archive all missed call triggers Trigger.objects.filter(org=org, trigger_type=Trigger.TYPE_MISSED_CALL, is_active=True).update(is_archived=True) # then create a new missed call trigger Trigger.objects.create( created_by=user, modified_by=user, org=org, trigger_type=Trigger.TYPE_MISSED_CALL, flow=form.cleaned_data["flow"], ) analytics.track(self.request.user.username, "temba.trigger_created", dict(type="missed_call")) response = self.render_to_response( self.get_context_data(form=form)) response["REDIRECT"] = self.get_success_url() return response
def render_to_response(self, context, **response_kwargs): analytics.track(self.request.user.username, 'temba.contact_exported') user = self.request.user org = user.get_org() group = None group_id = self.request.REQUEST.get('g', None) if group_id: groups = ContactGroup.user_groups.filter(pk=group_id, org=org) if groups: group = groups[0] host = self.request.branding['host'] export = ExportContactsTask.objects.create(created_by=user, modified_by=user, org=org, group=group, host=host) export_contacts_task.delay(export.pk) from django.contrib import messages if not getattr(settings, 'CELERY_ALWAYS_EAGER', False): messages.info(self.request, _("We are preparing your export. ") + _("We will e-mail you at %s when it is ready.") % self.request.user.username) else: export = ExportContactsTask.objects.get(id=export.pk) dl_url = reverse('assets.download', kwargs=dict(type='contact_export', identifier=export.pk)) messages.info(self.request, _("Export complete, you can find it here: %s (production users will get an email)") % dl_url) return HttpResponseRedirect(reverse('contacts.contact_list'))
def track_org_channel_counts(now=None): """ Run daily, logs to our analytics the number of incoming and outgoing messages/ivr messages per org that had more than one message received or sent in the previous day. This helps track engagement of orgs. """ now = now or timezone.now() yesterday = (now.astimezone(pytz.utc) - timedelta(days=1)).date() stats = [ dict(key="temba.msg_incoming", count_type=ChannelCount.INCOMING_MSG_TYPE), dict(key="temba.msg_outgoing", count_type=ChannelCount.OUTGOING_MSG_TYPE), dict(key="temba.ivr_incoming", count_type=ChannelCount.INCOMING_IVR_TYPE), dict(key="temba.ivr_outgoing", count_type=ChannelCount.OUTGOING_IVR_TYPE), ] # calculate each stat and track for stat in stats: org_counts = ( Org.objects.filter( channels__counts__day=yesterday, channels__counts__count_type=stat["count_type"] ).annotate(count=Sum("channels__counts__count")) ).prefetch_related("administrators") for org in org_counts: if org.administrators.all(): track(org.administrators.all()[0], stat["key"], dict(count=org.count))
def send_to_flow_node(org_id, user_id, text, **kwargs): from django.contrib.auth.models import User from temba.contacts.models import Contact from temba.orgs.models import Org from temba.flows.models import FlowStep org = Org.objects.get(pk=org_id) user = User.objects.get(pk=user_id) simulation = kwargs.get('simulation', 'false') == 'true' step_uuid = kwargs.get('s', None) qs = Contact.objects.filter(org=org, is_blocked=False, is_stopped=False, is_active=True, is_test=simulation) steps = FlowStep.objects.filter( run__is_active=True, step_uuid=step_uuid, left_on=None, run__flow__org=org).distinct('contact').select_related('contact') contact_uuids = [f.contact.uuid for f in steps] contacts = qs.filter(uuid__in=contact_uuids).order_by('name') recipients = list(contacts) broadcast = Broadcast.create(org, user, text, recipients) broadcast.send(expressions_context={}) analytics.track(user.username, 'temba.broadcast_created', dict(contacts=len(contacts), groups=0, urns=0))
def send_to_flow_node(org_id, user_id, text, **kwargs): from django.contrib.auth.models import User from temba.contacts.models import Contact from temba.orgs.models import Org from temba.flows.models import FlowRun org = Org.objects.get(pk=org_id) user = User.objects.get(pk=user_id) node_uuid = kwargs.get("s", None) runs = FlowRun.objects.filter(org=org, current_node_uuid=node_uuid, is_active=True) contact_ids = list( Contact.objects.filter( org=org, status=Contact.STATUS_ACTIVE, is_active=True).filter( id__in=runs.values_list("contact", flat=True)).values_list( "id", flat=True)) if contact_ids: broadcast = Broadcast.create(org, user, text, contact_ids=contact_ids) broadcast.send_async() analytics.track(user, "temba.broadcast_created", dict(contacts=len(contact_ids), groups=0, urns=0))
def form_valid(self, form): analytics.track(self.request.user.username, "temba.trigger_created_schedule") schedule = Schedule.objects.create(created_by=self.request.user, modified_by=self.request.user) if form.starts_never(): schedule.reset() elif form.stopped(): schedule.reset() elif form.starts_now(): schedule.next_fire = timezone.now() - timedelta(days=1) schedule.repeat_period = "O" schedule.repeat_days = 0 schedule.status = "S" schedule.save() else: # Scheduled case schedule.status = "S" schedule.repeat_period = form.cleaned_data["repeat_period"] start_time = form.get_start_time() if start_time: schedule.next_fire = start_time # create our recurrence if form.is_recurring(): days = None if "repeat_days" in form.cleaned_data: days = form.cleaned_data["repeat_days"] schedule.repeat_days = days schedule.repeat_hour_of_day = schedule.next_fire.hour schedule.repeat_minute_of_hour = schedule.repeat_minute_of_hour schedule.repeat_day_of_month = schedule.next_fire.day schedule.save() recipients = self.form.cleaned_data["omnibox"] trigger = Trigger.objects.create( flow=self.form.cleaned_data["flow"], org=self.request.user.get_org(), schedule=schedule, trigger_type=Trigger.TYPE_SCHEDULE, created_by=self.request.user, modified_by=self.request.user, ) for group in recipients["groups"]: trigger.groups.add(group) for contact in recipients["contacts"]: trigger.contacts.add(contact) self.post_save(trigger) response = self.render_to_response(self.get_context_data(form=form)) response["REDIRECT"] = self.get_success_url() return response
def form_valid(self, form): self.form = form user = self.request.user simulation = self.request.REQUEST.get('simulation', 'false') == 'true' omnibox = self.form.cleaned_data['omnibox'] has_schedule = self.form.cleaned_data['schedule'] groups = list(omnibox['groups']) contacts = list(omnibox['contacts']) urns = list(omnibox['urns']) recipients = list() if simulation: # when simulating make sure we only use test contacts for contact in contacts: if contact.is_test: recipients.append(contact) else: for group in groups: recipients.append(group) for contact in contacts: recipients.append(contact) for urn in urns: recipients.append(urn) schedule = Schedule.objects.create( created_by=user, modified_by=user) if has_schedule else None broadcast = Broadcast.create(user.get_org(), user, self.form.cleaned_data['text'], recipients, schedule=schedule) if not has_schedule: self.post_save(broadcast) super(BroadcastCRUDL.Send, self).form_valid(form) analytics.track( self.request.user.username, 'temba.broadcast_created', dict(contacts=len(contacts), groups=len(groups), urns=len(urns))) if '_format' in self.request.REQUEST and self.request.REQUEST[ '_format'] == 'json': data = dict(status="success", redirect=reverse('msgs.broadcast_schedule_read', args=[broadcast.pk])) return HttpResponse(json.dumps(data), content_type='application/json') else: if self.form.cleaned_data['schedule']: return HttpResponseRedirect( reverse('msgs.broadcast_schedule_read', args=[broadcast.pk])) return HttpResponseRedirect(self.get_success_url())
def claim_number(self, user, phone_number, country, role): auth_id = self.request.session.get(Channel.CONFIG_PLIVO_AUTH_ID, None) auth_token = self.request.session.get(Channel.CONFIG_PLIVO_AUTH_TOKEN, None) org = user.get_org() plivo_uuid = generate_uuid() callback_domain = org.get_brand_domain() app_name = "%s/%s" % (callback_domain.lower(), plivo_uuid) message_url = "https://" + callback_domain + "%s" % reverse('handlers.plivo_handler', args=['receive', plivo_uuid]) answer_url = "https://" + settings.AWS_BUCKET_DOMAIN + "/plivo_voice_unavailable.xml" headers = http_headers(extra={'Content-Type': "application/json"}) create_app_url = "https://api.plivo.com/v1/Account/%s/Application/" % auth_id response = requests.post(create_app_url, json=dict(app_name=app_name, answer_url=answer_url, message_url=message_url), headers=headers, auth=(auth_id, auth_token)) if response.status_code in [201, 200, 202]: plivo_app_id = response.json()['app_id'] else: # pragma: no cover plivo_app_id = None plivo_config = {Channel.CONFIG_PLIVO_AUTH_ID: auth_id, Channel.CONFIG_PLIVO_AUTH_TOKEN: auth_token, Channel.CONFIG_PLIVO_APP_ID: plivo_app_id, Channel.CONFIG_CALLBACK_DOMAIN: org.get_brand_domain()} plivo_number = phone_number.strip('+ ').replace(' ', '') response = requests.get("https://api.plivo.com/v1/Account/%s/Number/%s/" % (auth_id, plivo_number), headers=headers, auth=(auth_id, auth_token)) if response.status_code != 200: response = requests.post("https://api.plivo.com/v1/Account/%s/PhoneNumber/%s/" % (auth_id, plivo_number), headers=headers, auth=(auth_id, auth_token)) if response.status_code != 201: # pragma: no cover raise Exception(_("There was a problem claiming that number, please check the balance on your account.")) response = requests.get("https://api.plivo.com/v1/Account/%s/Number/%s/" % (auth_id, plivo_number), headers=headers, auth=(auth_id, auth_token)) if response.status_code == 200: response = requests.post("https://api.plivo.com/v1/Account/%s/Number/%s/" % (auth_id, plivo_number), json=dict(app_id=plivo_app_id), headers=headers, auth=(auth_id, auth_token)) if response.status_code != 202: # pragma: no cover raise Exception(_("There was a problem updating that number, please try again.")) phone_number = '+' + plivo_number phone = phonenumbers.format_number(phonenumbers.parse(phone_number, None), phonenumbers.PhoneNumberFormat.NATIONAL) channel = Channel.create(org, user, country, 'PL', name=phone, address=phone_number, config=plivo_config, uuid=plivo_uuid) analytics.track(user.username, 'temba.channel_claim_plivo', dict(number=phone_number)) return channel
def form_valid(self, form): self.form = form user = self.request.user org = user.get_org() simulation = self.request.GET.get("simulation", "false") == "true" omnibox = self.form.cleaned_data["omnibox"] has_schedule = self.form.cleaned_data["schedule"] step_uuid = self.form.cleaned_data.get("step_node", None) text = self.form.cleaned_data["text"] groups = list(omnibox["groups"]) contacts = list(omnibox["contacts"]) urns = list(omnibox["urns"]) if step_uuid: from .tasks import send_to_flow_node get_params = {k: v for k, v in self.request.GET.items()} get_params.update({"s": step_uuid}) send_to_flow_node.delay(org.pk, user.pk, text, **get_params) if "_format" in self.request.GET and self.request.GET["_format"] == "json": return HttpResponse(json.dumps(dict(status="success")), content_type="application/json") else: return HttpResponseRedirect(self.get_success_url()) # if simulating only use the test contact if simulation: groups = [] urns = [] for contact in contacts: if contact.is_test: contacts = [contact] break schedule = Schedule.objects.create(created_by=user, modified_by=user) if has_schedule else None broadcast = Broadcast.create( org, user, text, groups=groups, contacts=contacts, urns=urns, schedule=schedule, status=QUEUED ) if not has_schedule: self.post_save(broadcast) super().form_valid(form) analytics.track( self.request.user.username, "temba.broadcast_created", dict(contacts=len(contacts), groups=len(groups), urns=len(urns)), ) if "_format" in self.request.GET and self.request.GET["_format"] == "json": data = dict(status="success", redirect=reverse("msgs.broadcast_schedule_read", args=[broadcast.pk])) return HttpResponse(json.dumps(data), content_type="application/json") else: if self.form.cleaned_data["schedule"]: return HttpResponseRedirect(reverse("msgs.broadcast_schedule_read", args=[broadcast.pk])) return HttpResponseRedirect(self.get_success_url())
def form_valid(self, form): self.form = form user = self.request.user org = user.get_org() step_uuid = self.form.cleaned_data.get("step_node", None) text = self.form.cleaned_data["text"] has_schedule = False if step_uuid: from .tasks import send_to_flow_node get_params = {k: v for k, v in self.request.GET.items()} get_params.update({"s": step_uuid}) send_to_flow_node.delay(org.pk, user.pk, text, **get_params) else: omnibox = omnibox_deserialize(org, self.form.cleaned_data["omnibox"]) has_schedule = self.form.cleaned_data["schedule"] groups = list(omnibox["groups"]) contacts = list(omnibox["contacts"]) urns = list(omnibox["urns"]) schedule = Schedule.create_blank_schedule(org, user) if has_schedule else None broadcast = Broadcast.create( org, user, text, groups=groups, contacts=contacts, urns=urns, schedule=schedule, status=QUEUED, template_state=Broadcast.TEMPLATE_STATE_UNEVALUATED, ) if not has_schedule: self.post_save(broadcast) super().form_valid(form) analytics.track( self.request.user.username, "temba.broadcast_created", dict(contacts=len(contacts), groups=len(groups), urns=len(urns)), ) if "HTTP_X_PJAX" in self.request.META: success_url = "hide" if has_schedule: success_url = reverse("msgs.broadcast_schedule_read", args=[broadcast.pk]) response = self.render_to_response(self.get_context_data()) response["Temba-Success"] = success_url return response return HttpResponseRedirect(self.get_success_url())
def form_valid(self, form): self.form = form user = self.request.user org = user.get_org() simulation = self.request.GET.get('simulation', 'false') == 'true' omnibox = self.form.cleaned_data['omnibox'] has_schedule = self.form.cleaned_data['schedule'] step_uuid = self.form.cleaned_data.get('step_node', None) text = self.form.cleaned_data['text'] groups = list(omnibox['groups']) contacts = list(omnibox['contacts']) urns = list(omnibox['urns']) recipients = list() if step_uuid: from .tasks import send_to_flow_node get_params = {k: v for k, v in self.request.GET.items()} get_params.update({'s': step_uuid}) send_to_flow_node.delay(org.pk, user.pk, text, **get_params) if '_format' in self.request.GET and self.request.GET['_format'] == 'json': return HttpResponse(json.dumps(dict(status="success")), content_type='application/json') else: return HttpResponseRedirect(self.get_success_url()) if simulation: # when simulating make sure we only use test contacts for contact in contacts: if contact.is_test: recipients.append(contact) else: for group in groups: recipients.append(group) for contact in contacts: recipients.append(contact) for urn in urns: recipients.append(urn) schedule = Schedule.objects.create(created_by=user, modified_by=user) if has_schedule else None broadcast = Broadcast.create(org, user, text, recipients, schedule=schedule) if not has_schedule: self.post_save(broadcast) super(BroadcastCRUDL.Send, self).form_valid(form) analytics.track(self.request.user.username, 'temba.broadcast_created', dict(contacts=len(contacts), groups=len(groups), urns=len(urns))) if '_format' in self.request.GET and self.request.GET['_format'] == 'json': data = dict(status="success", redirect=reverse('msgs.broadcast_schedule_read', args=[broadcast.pk])) return HttpResponse(json.dumps(data), content_type='application/json') else: if self.form.cleaned_data['schedule']: return HttpResponseRedirect(reverse('msgs.broadcast_schedule_read', args=[broadcast.pk])) return HttpResponseRedirect(self.get_success_url())
def form_valid(self, form): analytics.track(self.request.user.username, 'temba.trigger_created_schedule') schedule = Schedule.objects.create(created_by=self.request.user, modified_by=self.request.user) if form.starts_never(): schedule.reset() elif form.stopped(): schedule.reset() elif form.starts_now(): schedule.next_fire = timezone.now() - timedelta(days=1) schedule.repeat_period = 'O' schedule.repeat_days = 0 schedule.status = 'S' schedule.save() else: # Scheduled case schedule.status = 'S' schedule.repeat_period = form.cleaned_data['repeat_period'] start_time = form.get_start_time() if start_time: schedule.next_fire = start_time # create our recurrence if form.is_recurring(): days = None if 'repeat_days' in form.cleaned_data: days = form.cleaned_data['repeat_days'] schedule.repeat_days = days schedule.repeat_hour_of_day = schedule.next_fire.hour schedule.repeat_day_of_month = schedule.next_fire.day schedule.save() recipients = self.form.cleaned_data['omnibox'] trigger = Trigger.objects.create(flow=self.form.cleaned_data['flow'], org=self.request.user.get_org(), schedule=schedule, trigger_type=SCHEDULE_TRIGGER, created_by=self.request.user, modified_by=self.request.user) for group in recipients['groups']: trigger.groups.add(group) for contact in recipients['contacts']: trigger.contacts.add(contact) self.post_save(trigger) response = self.render_to_response(self.get_context_data(form=form)) response['REDIRECT'] = self.get_success_url() return response
def claim_number(self, user, phone_number, country, role): auth_id = self.request.session.get(Channel.CONFIG_PLIVO_AUTH_ID, None) auth_token = self.request.session.get(Channel.CONFIG_PLIVO_AUTH_TOKEN, None) org = user.get_org() plivo_uuid = generate_uuid() app_name = "%s/%s" % (settings.TEMBA_HOST.lower(), plivo_uuid) client = plivo.RestAPI(auth_id, auth_token) message_url = "https://" + settings.TEMBA_HOST + "%s" % reverse('handlers.plivo_handler', args=['receive', plivo_uuid]) answer_url = "https://" + settings.AWS_BUCKET_DOMAIN + "/plivo_voice_unavailable.xml" plivo_response_status, plivo_response = client.create_application(params=dict(app_name=app_name, answer_url=answer_url, message_url=message_url)) if plivo_response_status in [201, 200, 202]: plivo_app_id = plivo_response['app_id'] else: # pragma: no cover plivo_app_id = None plivo_config = {Channel.CONFIG_PLIVO_AUTH_ID: auth_id, Channel.CONFIG_PLIVO_AUTH_TOKEN: auth_token, Channel.CONFIG_PLIVO_APP_ID: plivo_app_id} plivo_number = phone_number.strip('+ ').replace(' ', '') plivo_response_status, plivo_response = client.get_number(params=dict(number=plivo_number)) if plivo_response_status != 200: plivo_response_status, plivo_response = client.buy_phone_number(params=dict(number=plivo_number)) if plivo_response_status != 201: # pragma: no cover raise Exception(_("There was a problem claiming that number, please check the balance on your account.")) plivo_response_status, plivo_response = client.get_number(params=dict(number=plivo_number)) if plivo_response_status == 200: plivo_response_status, plivo_response = client.modify_number(params=dict(number=plivo_number, app_id=plivo_app_id)) if plivo_response_status != 202: # pragma: no cover raise Exception(_("There was a problem updating that number, please try again.")) phone_number = '+' + plivo_number phone = phonenumbers.format_number(phonenumbers.parse(phone_number, None), phonenumbers.PhoneNumberFormat.NATIONAL) channel = Channel.create(org, user, country, 'PL', name=phone, address=phone_number, config=plivo_config, uuid=plivo_uuid) analytics.track(user.username, 'temba.channel_claim_plivo', dict(number=phone_number)) return channel
def form_valid(self, form): self.form = form user = self.request.user org = user.get_org() omnibox = self.form.cleaned_data["omnibox"] has_schedule = self.form.cleaned_data["schedule"] step_uuid = self.form.cleaned_data.get("step_node", None) text = self.form.cleaned_data["text"] groups = list(omnibox["groups"]) contacts = list(omnibox["contacts"]) urns = list(omnibox["urns"]) if step_uuid: from .tasks import send_to_flow_node get_params = {k: v for k, v in self.request.GET.items()} get_params.update({"s": step_uuid}) send_to_flow_node.delay(org.pk, user.pk, text, **get_params) if "_format" in self.request.GET and self.request.GET["_format"] == "json": return HttpResponse(json.dumps(dict(status="success")), content_type="application/json") else: return HttpResponseRedirect(self.get_success_url()) schedule = Schedule.create_blank_schedule(org, user) if has_schedule else None broadcast = Broadcast.create( org, user, text, groups=groups, contacts=contacts, urns=urns, schedule=schedule, status=QUEUED, template_state=Broadcast.TEMPLATE_STATE_UNEVALUATED, ) if not has_schedule: self.post_save(broadcast) super().form_valid(form) analytics.track( self.request.user.username, "temba.broadcast_created", dict(contacts=len(contacts), groups=len(groups), urns=len(urns)), ) if "_format" in self.request.GET and self.request.GET["_format"] == "json": data = dict(status="success", redirect=reverse("msgs.broadcast_schedule_read", args=[broadcast.pk])) return HttpResponse(json.dumps(data), content_type="application/json") else: if self.form.cleaned_data["schedule"]: return HttpResponseRedirect(reverse("msgs.broadcast_schedule_read", args=[broadcast.pk])) return HttpResponseRedirect(self.get_success_url())
def form_valid(self, form): user = self.request.user org = user.get_org() Trigger.objects.create(created_by=user, modified_by=user, org=org, trigger_type=Trigger.TYPE_FOLLOW, flow=form.cleaned_data['flow'], channel=form.cleaned_data['channel']) analytics.track(self.request.user.username, 'temba.trigger_created_follow') response = self.render_to_response(self.get_context_data(form=form)) response['REDIRECT'] = self.get_success_url() return response
def pre_save(self, obj): anon = User.objects.get(id=-1) obj = super(LeadCRUDL.Create, self).pre_save(obj) obj.created_by = anon obj.modified_by = anon if self.request.user.is_anonymous(): analytics.identify(obj.email, dict(email=obj.email, plan='None', segment=randint(1, 10), brand=self.request.branding['slug'])) analytics.track(obj.email, 'temba.org_lead') return obj
def pre_save(self, obj): anon = get_anonymous_user() obj = super(LeadCRUDL.Create, self).pre_save(obj) obj.created_by = anon obj.modified_by = anon if self.request.user.is_anonymous(): analytics.identify(obj.email, dict(email=obj.email, plan='None', segment=randint(1, 10), brand=self.request.branding['slug'])) analytics.track(obj.email, 'temba.org_lead') return obj
def form_valid(self, form): try: cleaned_data = form.cleaned_data org = self.request.user.get_org() for key in cleaned_data: if key.startswith('field_'): idx = key[6:] label = cleaned_data["label_%s" % idx] field = cleaned_data[key] show_in_table = cleaned_data["show_%s" % idx] value_type = cleaned_data['type_%s' % idx] if field == '__new_field': if label: analytics.track(self.request.user.username, 'temba.contactfield_created') key = ContactField.make_key(label) ContactField.get_or_create( org, key, label, show_in_table=show_in_table, value_type=value_type) else: if label: ContactField.get_or_create( org, field.key, label, show_in_table=show_in_table, value_type=value_type) else: ContactField.hide_field(org, field.key) if 'HTTP_X_PJAX' not in self.request.META: return HttpResponseRedirect(self.get_success_url()) else: # pragma: no cover return self.render_to_response( self.get_context_data( form=form, success_url=self.get_success_url(), success_script=getattr(self, 'success_script', None))) except IntegrityError as e: # pragma: no cover message = str(e).capitalize() errors = self.form._errors.setdefault( forms.forms.NON_FIELD_ERRORS, forms.util.ErrorList()) errors.append(message) return self.render_to_response( self.get_context_data(form=form))
def form_valid(self, form): user = self.request.user org = user.get_org() self.object = Trigger.create( org, user, Trigger.TYPE_NEW_CONVERSATION, form.cleaned_data["flow"], form.cleaned_data["channel"] ) analytics.track(self.request.user.username, "temba.trigger_created", dict(type="new_conversation")) response = self.render_to_response(self.get_context_data(form=form)) response["REDIRECT"] = self.get_success_url() return response
def form_valid(self, form): user = self.request.user org = user.get_org() self.object = Trigger.create( org, user, Trigger.TYPE_NEW_CONVERSATION, form.cleaned_data["flow"], form.cleaned_data["channel"] ) analytics.track(self.request.user.username, "temba.trigger_created_new_conversation") response = self.render_to_response(self.get_context_data(form=form)) response["REDIRECT"] = self.get_success_url() return response
def claim_number(self, user, phone_number, country, role): org = user.get_org() client = org.get_twilio_client() twilio_phones = client.api.incoming_phone_numbers.stream( phone_number=phone_number) channel_uuid = uuid4() # create new TwiML app callback_domain = org.get_brand_domain() twilio_phone = next(twilio_phones, None) if not twilio_phone: raise Exception( _("Only existing Twilio WhatsApp number are supported")) phone = phonenumbers.format_number( phonenumbers.parse(phone_number, None), phonenumbers.PhoneNumberFormat.NATIONAL) number_sid = twilio_phone.sid org_config = org.config config = { Channel.CONFIG_NUMBER_SID: number_sid, Channel.CONFIG_ACCOUNT_SID: org_config[Org.CONFIG_TWILIO_SID], Channel.CONFIG_AUTH_TOKEN: org_config[Org.CONFIG_TWILIO_TOKEN], Channel.CONFIG_CALLBACK_DOMAIN: callback_domain, } role = Channel.ROLE_SEND + Channel.ROLE_RECEIVE channel = Channel.create( org, user, country, "TWA", name=phone, address=phone_number, role=role, config=config, uuid=channel_uuid, schemes=[WHATSAPP_SCHEME], ) analytics.track(user.username, "temba.channel_claim_twilio_whatsapp", properties=dict(number=phone_number)) return channel
def pre_save(self, obj): anon = User.objects.get(username=settings.ANONYMOUS_USER_NAME) obj = super(LeadCRUDL.Create, self).pre_save(obj) obj.created_by = anon obj.modified_by = anon if self.request.user.is_anonymous(): analytics.identify( obj.email, dict(email=obj.email, plan="None", segment=randint(1, 10), brand=self.request.branding["slug"]), ) analytics.track(obj.email, "temba.org_lead") return obj
def form_valid(self, form): user = self.request.user org = user.get_org() trigger = Trigger.objects.create(created_by=user, modified_by=user, org=org, trigger_type=Trigger.TYPE_NEW_CONVERSATION, flow=form.cleaned_data['flow'], channel=form.cleaned_data['channel']) trigger.archive_conflicts(user) trigger.channel.set_fb_call_to_action_payload(Channel.GET_STARTED) analytics.track(self.request.user.username, 'temba.trigger_created_new_conversation') response = self.render_to_response(self.get_context_data(form=form)) response['REDIRECT'] = self.get_success_url() return response
def test_track(self, mock_get_backends): good = MagicMock() mock_get_backends.return_value = [BadBackend(), good] analytics.track(self.user, "foo_created", {"foo_id": 234}) good.track.assert_called_once_with(self.user, "foo_created", {"foo_id": 234}) good.track.reset_mock() # anonymous user is a noop analytics.track(AnonymousUser(), "foo_created", {"foo_id": 234}) good.track.assert_not_called()
def form_valid(self, form): user = self.request.user org = user.get_org() trigger = Trigger.objects.create(created_by=user, modified_by=user, org=org, keyword=form.cleaned_data['keyword'], trigger_type=Trigger.TYPE_USSD_PULL, flow=form.cleaned_data['flow'], channel=form.cleaned_data['channel']) trigger.archive_conflicts(user) analytics.track(self.request.user.username, 'temba.trigger_created_ussd') response = self.render_to_response(self.get_context_data(form=form)) response['REDIRECT'] = self.get_success_url() return response
def form_valid(self, form): user = self.request.user org = user.get_org() self.object = Trigger.create(org, user, Trigger.TYPE_FOLLOW, form.cleaned_data["flow"], form.cleaned_data["channel"]) analytics.track(self.request.user.username, "temba.trigger_created_follow") response = self.render_to_response( self.get_context_data(form=form)) response["REDIRECT"] = self.get_success_url() return response
def form_valid(self, form): self.form = form user = self.request.user simulation = self.request.REQUEST.get("simulation", "false") == "true" omnibox = self.form.cleaned_data["omnibox"] has_schedule = self.form.cleaned_data["schedule"] groups = list(omnibox["groups"]) contacts = list(omnibox["contacts"]) urns = list(omnibox["urns"]) recipients = list() if simulation: # when simulating make sure we only use test contacts for contact in contacts: if contact.is_test: recipients.append(contact) else: for group in groups: recipients.append(group) for contact in contacts: recipients.append(contact) for urn in urns: recipients.append(urn) schedule = Schedule.objects.create(created_by=user, modified_by=user) if has_schedule else None broadcast = Broadcast.create( user.get_org(), user, self.form.cleaned_data["text"], recipients, schedule=schedule ) if not has_schedule: self.post_save(broadcast) super(BroadcastCRUDL.Send, self).form_valid(form) analytics.track( self.request.user.username, "temba.broadcast_created", dict(contacts=len(contacts), groups=len(groups), urns=len(urns)), ) if "_format" in self.request.REQUEST and self.request.REQUEST["_format"] == "json": data = dict(status="success", redirect=reverse("msgs.broadcast_schedule_read", args=[broadcast.pk])) return HttpResponse(json.dumps(data), content_type="application/json") else: if self.form.cleaned_data["schedule"]: return HttpResponseRedirect(reverse("msgs.broadcast_schedule_read", args=[broadcast.pk])) return HttpResponseRedirect(self.get_success_url())
def form_valid(self, form): user = self.request.user org = user.get_org() self.object = Trigger.create(org, user, Trigger.TYPE_NEW_CONVERSATION, form.cleaned_data['flow'], form.cleaned_data['channel']) analytics.track(self.request.user.username, 'temba.trigger_created_new_conversation') response = self.render_to_response( self.get_context_data(form=form)) response['REDIRECT'] = self.get_success_url() return response
def render_to_response(self, context, **response_kwargs): analytics.track(self.request.user.username, 'temba.contact_exported') user = self.request.user org = user.get_org() group = None group_id = self.request.REQUEST.get('g', None) if group_id: groups = ContactGroup.user_groups.filter(pk=group_id, org=org) if groups: group = groups[0] host = self.request.branding['host'] # is there already an export taking place? existing = ExportContactsTask.objects.filter(org=org, is_finished=False, created_on__gt=timezone.now() - timedelta(hours=24))\ .order_by('-created_on').first() # if there is an existing export, don't allow it if existing: messages.info(self.request, _("There is already an export in progress, started by %s. You must wait " "for that export to complete before starting another." % existing.created_by.username)) # otherwise, off we go else: export = ExportContactsTask.objects.create(created_by=user, modified_by=user, org=org, group=group, host=host) export_contacts_task.delay(export.pk) if not getattr(settings, 'CELERY_ALWAYS_EAGER', False): messages.info(self.request, _("We are preparing your export. We will e-mail you at %s when it is ready.") % self.request.user.username) else: export = ExportContactsTask.objects.get(id=export.pk) dl_url = reverse('assets.download', kwargs=dict(type='contact_export', identifier=export.pk)) messages.info(self.request, _("Export complete, you can find it here: %s (production users will get an email)") % dl_url) return HttpResponseRedirect(reverse('contacts.contact_list'))
def render_to_response(self, context, **response_kwargs): analytics.track(self.request.user.username, 'temba.contact_exported') user = self.request.user org = user.get_org() group = None group_id = self.request.REQUEST.get('g', None) if group_id: groups = ContactGroup.user_groups.filter(pk=group_id, org=org) if groups: group = groups[0] host = self.request.branding['host'] # is there already an export taking place? existing = ExportContactsTask.objects.filter(org=org, is_finished=False, created_on__gt=timezone.now() - timedelta(hours=24))\ .order_by('-created_on').first() # if there is an existing export, don't allow it if existing: messages.info(self.request, _("There is already an export in progress, started by %s. You must wait " "for that export to complete before starting another." % existing.created_by.username)) # otherwise, off we go else: export = ExportContactsTask.objects.create(created_by=user, modified_by=user, org=org, group=group, host=host) export_contacts_task.delay(export.pk) if not getattr(settings, 'CELERY_ALWAYS_EAGER', False): messages.info(self.request, _("We are preparing your export. We will e-mail you at %s when it is ready.") % self.request.user.username) else: export = ExportContactsTask.objects.get(id=export.pk) dl_url = reverse('assets.download', kwargs=dict(type='contact_export', pk=export.pk)) messages.info(self.request, _("Export complete, you can find it here: %s (production users will get an email)") % dl_url) return HttpResponseRedirect(reverse('contacts.contact_list'))
def form_valid(self, form): self.form = form user = self.request.user simulation = self.request.REQUEST.get('simulation', 'false') == 'true' omnibox = self.form.cleaned_data['omnibox'] has_schedule = self.form.cleaned_data['schedule'] schedule = Schedule.objects.create(created_by=user, modified_by=user) if has_schedule else None broadcast = Broadcast.create(user, self.form.cleaned_data['text'], schedule=schedule) groups = list(omnibox['groups']) contacts = list(omnibox['contacts']) urns = list(omnibox['urns']) recipients = list() if simulation: # when simulating make sure we only use test contacts for contact in contacts: if contact.is_test: recipients.append(contact) else: for group in groups: recipients.append(group) for contact in contacts: recipients.append(contact) for urn in urns: recipients.append(urn) broadcast.set_recipients(*recipients) if not has_schedule: self.post_save(broadcast) super(BroadcastCRUDL.Send, self).form_valid(form) analytics.track(self.request.user.username, 'temba.broadcast_created', dict(contacts=len(contacts), groups=len(groups), urns=len(urns))) if '_format' in self.request.REQUEST and self.request.REQUEST['_format'] == 'json': data = dict(status="success", redirect=reverse('msgs.broadcast_schedule_read', args=[broadcast.pk])) return HttpResponse(json.dumps(data), content_type='application/json') else: if self.form.cleaned_data['schedule']: return HttpResponseRedirect(reverse('msgs.broadcast_schedule_read', args=[broadcast.pk])) return HttpResponseRedirect(self.get_success_url())
def form_valid(self, form): keyword = form.cleaned_data['keyword'] join_group = form.cleaned_data['action_join_group'] start_flow = form.cleaned_data['flow'] send_msg = form.cleaned_data['response'] group_flow = Flow.create_join_group_flow(self.request.user, join_group, send_msg, start_flow) Trigger.objects.create(created_by=self.request.user, modified_by=self.request.user, org=self.request.user.get_org(), keyword=keyword, trigger_type=KEYWORD_TRIGGER, flow=group_flow) analytics.track(self.request.user.username, 'temba.trigger_created_register', dict(name=join_group.name)) response = self.render_to_response(self.get_context_data(form=form)) response['REDIRECT'] = self.get_success_url() return response
def form_valid(self, form): user = self.request.user org = user.get_org() # first archive all catch all message triggers Trigger.objects.filter(org=org, trigger_type=CATCH_ALL_TRIGGER, is_active=True).update(is_archived=True) # then create a new catch all trigger Trigger.objects.create(created_by=user, modified_by=user, org=org, trigger_type=CATCH_ALL_TRIGGER, flow=form.cleaned_data['flow']) analytics.track(self.request.user.username, 'temba.trigger_created_catchall') response = self.render_to_response(self.get_context_data(form=form)) response['REDIRECT'] = self.get_success_url() return response
def form_valid(self, form): user = self.request.user org = user.get_org() self.object = Trigger.create( org, user, Trigger.TYPE_USSD_PULL, form.cleaned_data["flow"], form.cleaned_data["channel"], keyword=form.cleaned_data["keyword"], ) analytics.track(self.request.user.username, "temba.trigger_created_ussd") response = self.render_to_response(self.get_context_data(form=form)) response["REDIRECT"] = self.get_success_url() return response
def form_valid(self, form): user = self.request.user org = user.get_org() self.object = Trigger.create( org, user, Trigger.TYPE_REFERRAL, form.cleaned_data["flow"], form.cleaned_data["channel"], referrer_id=form.cleaned_data["referrer_id"], ) analytics.track(self.request.user.username, "temba.trigger_created", dict(type="referral")) response = self.render_to_response(self.get_context_data(form=form)) response["REDIRECT"] = self.get_success_url() return response
def form_valid(self, form): user = self.request.user org = user.get_org() self.object = Trigger.create(org, user, Trigger.TYPE_USSD_PULL, form.cleaned_data['flow'], form.cleaned_data['channel'], keyword=form.cleaned_data['keyword']) analytics.track(self.request.user.username, 'temba.trigger_created_ussd') response = self.render_to_response( self.get_context_data(form=form)) response['REDIRECT'] = self.get_success_url() return response
def render_to_response(self, context, **response_kwargs): analytics.track(self.request.user.username, 'temba.contact_exported') user = self.request.user org = user.get_org() group = None group_id = self.request.REQUEST.get('g', None) if group_id: groups = ContactGroup.objects.filter(pk=group_id, org=org) if groups: group = groups[0] host = self.request.branding['host'] export = ExportContactsTask.objects.create(created_by=user, modified_by=user, org=org, group=group, host=host) export_contacts_task.delay(export.pk) from django.contrib import messages if not getattr(settings, 'CELERY_ALWAYS_EAGER', False): messages.info( self.request, _("We are preparing your export. ") + _("We will e-mail you at %s when it is ready.") % self.request.user.username) else: export = ExportContactsTask.objects.get(id=export.pk) dl_url = "file://%s/%s" % (settings.MEDIA_ROOT, export.filename) messages.info( self.request, _("Export complete, you can find it here: %s (production users will get an email)" ) % dl_url) return HttpResponseRedirect(reverse('contacts.contact_list'))
def send_to_flow_node(org_id, user_id, text, **kwargs): from django.contrib.auth.models import User from temba.contacts.models import Contact from temba.orgs.models import Org from temba.flows.models import FlowRun org = Org.objects.get(pk=org_id) user = User.objects.get(pk=user_id) simulation = kwargs.get("simulation", "false") == "true" node_uuid = kwargs.get("s", None) runs = FlowRun.objects.filter(org=org, current_node_uuid=node_uuid, is_active=True) contact_ids = ( Contact.objects.filter(org=org, is_blocked=False, is_stopped=False, is_active=True, is_test=simulation) .filter(id__in=runs.values_list("contact", flat=True)) .values_list("id", flat=True) ) broadcast = Broadcast.create(org, user, text, contact_ids=contact_ids) broadcast.send(expressions_context={}) analytics.track(user.username, "temba.broadcast_created", dict(contacts=len(contact_ids), groups=0, urns=0))
def form_valid(self, form): keyword = form.cleaned_data["keyword"] join_group = form.cleaned_data["action_join_group"] start_flow = form.cleaned_data["flow"] send_msg = form.cleaned_data["response"] org = self.request.user.get_org() group_flow = Flow.create_join_group(org, self.request.user, join_group, send_msg, start_flow) Trigger.objects.create( created_by=self.request.user, modified_by=self.request.user, org=self.request.user.get_org(), keyword=keyword, trigger_type=Trigger.TYPE_KEYWORD, flow=group_flow, ) analytics.track(self.request.user.username, "temba.trigger_created_register", dict(name=join_group.name)) response = self.render_to_response(self.get_context_data(form=form)) response["REDIRECT"] = self.get_success_url() return response
def form_valid(self, form): user = self.request.user org = user.get_org() # first archive all missed call triggers Trigger.objects.filter(org=org, trigger_type=Trigger.TYPE_MISSED_CALL, is_active=True).update( is_archived=True ) # then create a new missed call trigger Trigger.objects.create( created_by=user, modified_by=user, org=org, trigger_type=Trigger.TYPE_MISSED_CALL, flow=form.cleaned_data["flow"], ) analytics.track(self.request.user.username, "temba.trigger_created_missed_call") response = self.render_to_response(self.get_context_data(form=form)) response["REDIRECT"] = self.get_success_url() return response
def form_valid(self, form): try: cleaned_data = form.cleaned_data org = self.request.user.get_org() for key in cleaned_data: if key.startswith('field_'): idx = key[6:] label = cleaned_data["label_%s" % idx] field = cleaned_data[key] show_in_table = cleaned_data["show_%s" % idx] value_type = cleaned_data['type_%s' % idx] if field == '__new_field': if label: analytics.track(self.request.user.username, 'temba.contactfield_created') key = ContactField.make_key(label) ContactField.get_or_create(org, key, label, show_in_table=show_in_table, value_type=value_type) else: if label: ContactField.get_or_create(org, field.key, label, show_in_table=show_in_table, value_type=value_type) else: ContactField.hide_field(org, field.key) if 'HTTP_X_PJAX' not in self.request.META: return HttpResponseRedirect(self.get_success_url()) else: # pragma: no cover return self.render_to_response(self.get_context_data(form=form, success_url=self.get_success_url(), success_script=getattr(self, 'success_script', None))) except IntegrityError as e: # pragma: no cover message = str(e).capitalize() errors = self.form._errors.setdefault(forms.forms.NON_FIELD_ERRORS, forms.utils.ErrorList()) errors.append(message) return self.render_to_response(self.get_context_data(form=form))
def claim_number(self, user, phone_number, country, role): org = user.get_org() client = org.get_twilio_client() twilio_phones = client.api.incoming_phone_numbers.stream(phone_number=phone_number) channel_uuid = uuid4() # create new TwiML app callback_domain = org.get_brand_domain() new_receive_url = "https://" + callback_domain + reverse("courier.t", args=[channel_uuid, "receive"]) new_status_url = ( "https://" + callback_domain + reverse("handlers.twilio_handler", args=["status", channel_uuid]) ) new_voice_url = "https://" + callback_domain + reverse("handlers.twilio_handler", args=["voice", channel_uuid]) new_app = client.api.applications.create( friendly_name="%s/%s" % (callback_domain.lower(), channel_uuid), sms_url=new_receive_url, sms_method="POST", voice_url=new_voice_url, voice_fallback_url="https://" + settings.TEMBA_HOST+settings.MEDIA_URL+ "voice_unavailable.xml", voice_fallback_method="GET", status_callback=new_status_url, status_callback_method="POST", ) is_short_code = len(phone_number) <= 6 if is_short_code: short_codes = client.api.short_codes.stream(short_code=phone_number) short_code = next(short_codes, None) if short_code: number_sid = short_code.sid app_url = "https://" + callback_domain + "%s" % reverse("courier.t", args=[channel_uuid, "receive"]) client.api.short_codes.get(number_sid).update(sms_url=app_url, sms_method="POST") role = Channel.ROLE_SEND + Channel.ROLE_RECEIVE phone = phone_number else: # pragma: no cover raise Exception( _( "Short code not found on your Twilio Account. " "Please check you own the short code and Try again" ) ) else: twilio_phone = next(twilio_phones, None) if twilio_phone: client.api.incoming_phone_numbers.get(twilio_phone.sid).update( voice_application_sid=new_app.sid, sms_application_sid=new_app.sid ) else: # pragma: needs cover twilio_phone = client.api.incoming_phone_numbers.create( phone_number=phone_number, voice_application_sid=new_app.sid, sms_application_sid=new_app.sid ) phone = phonenumbers.format_number( phonenumbers.parse(phone_number, None), phonenumbers.PhoneNumberFormat.NATIONAL ) number_sid = twilio_phone.sid org_config = org.config config = { Channel.CONFIG_APPLICATION_SID: new_app.sid, Channel.CONFIG_NUMBER_SID: number_sid, Channel.CONFIG_ACCOUNT_SID: org_config[ACCOUNT_SID], Channel.CONFIG_AUTH_TOKEN: org_config[ACCOUNT_TOKEN], Channel.CONFIG_CALLBACK_DOMAIN: callback_domain, } channel = Channel.create( org, user, country, "T", name=phone, address=phone_number, role=role, config=config, uuid=channel_uuid ) analytics.track(user.username, "temba.channel_claim_twilio", properties=dict(number=phone_number)) return channel
def form_valid(self, form): analytics.track(self.request.user.username, "temba.trigger_created_keyword") return super().form_valid(form)
def claim_number(self, user, phone_number, country, role): org = user.get_org() client = org.get_nexmo_client() org_config = org.config app_id = org_config.get(NEXMO_APP_ID) nexmo_phones = client.get_numbers(phone_number) is_shortcode = False # try it with just the national code (for short codes) if not nexmo_phones: parsed = phonenumbers.parse(phone_number, None) shortcode = str(parsed.national_number) nexmo_phones = client.get_numbers(shortcode) if nexmo_phones: is_shortcode = True phone_number = shortcode # buy the number if we have to if not nexmo_phones: try: client.buy_nexmo_number(country, phone_number) except Exception as e: raise Exception( _( "There was a problem claiming that number, " "please check the balance on your account. " + "Note that you can only claim numbers after " "adding credit to your Nexmo account." ) + "\n" + str(e) ) channel_uuid = generate_uuid() callback_domain = org.get_brand_domain() new_receive_url = "https://" + callback_domain + reverse("courier.nx", args=[channel_uuid, "receive"]) nexmo_phones = client.get_numbers(phone_number) features = [elt.upper() for elt in nexmo_phones[0]["features"]] role = "" if "SMS" in features: role += Channel.ROLE_SEND + Channel.ROLE_RECEIVE if "VOICE" in features: role += Channel.ROLE_ANSWER + Channel.ROLE_CALL # update the delivery URLs for it try: client.update_nexmo_number(country, phone_number, new_receive_url, app_id) except Exception as e: # pragma: no cover # shortcodes don't seem to claim right on nexmo, move forward anyways if not is_shortcode: raise Exception( _("There was a problem claiming that number, please check the balance on your account.") + "\n" + str(e) ) if is_shortcode: phone = phone_number nexmo_phone_number = phone_number else: parsed = phonenumbers.parse(phone_number, None) phone = phonenumbers.format_number(parsed, phonenumbers.PhoneNumberFormat.INTERNATIONAL) # nexmo ships numbers around as E164 without the leading + nexmo_phone_number = phonenumbers.format_number(parsed, phonenumbers.PhoneNumberFormat.E164).strip("+") config = { Channel.CONFIG_NEXMO_APP_ID: app_id, Channel.CONFIG_NEXMO_APP_PRIVATE_KEY: org_config[NEXMO_APP_PRIVATE_KEY], Channel.CONFIG_NEXMO_API_KEY: org_config[NEXMO_KEY], Channel.CONFIG_NEXMO_API_SECRET: org_config[NEXMO_SECRET], Channel.CONFIG_CALLBACK_DOMAIN: callback_domain, } channel = Channel.create( org, user, country, "NX", name=phone, address=phone_number, role=role, config=config, bod=nexmo_phone_number, uuid=channel_uuid, tps=1, ) analytics.track(user.username, "temba.channel_claim_nexmo", dict(number=phone_number)) return channel
def form_valid(self, form): analytics.track(self.request.user.username, 'temba.trigger_created_keyword') return super(TriggerCRUDL.Keyword, self).form_valid(form)
def claim_number(self, user, phone_number, country, role): auth_id = self.request.session.get(Channel.CONFIG_PLIVO_AUTH_ID, None) auth_token = self.request.session.get(Channel.CONFIG_PLIVO_AUTH_TOKEN, None) org = user.get_org() plivo_uuid = generate_uuid() callback_domain = org.get_brand_domain() app_name = "%s/%s" % (callback_domain.lower(), plivo_uuid) message_url = "https://" + callback_domain + "%s" % reverse("courier.pl", args=[plivo_uuid, "receive"]) answer_url = "https://" + settings.TEMBA_HOST+settings.MEDIA_URL+ "plivo_voice_unavailable.xml" headers = http_headers(extra={"Content-Type": "application/json"}) create_app_url = "https://api.plivo.com/v1/Account/%s/Application/" % auth_id response = requests.post( create_app_url, json=dict(app_name=app_name, answer_url=answer_url, message_url=message_url), headers=headers, auth=(auth_id, auth_token), ) if response.status_code in [201, 200, 202]: plivo_app_id = response.json()["app_id"] else: # pragma: no cover plivo_app_id = None plivo_config = { Channel.CONFIG_PLIVO_AUTH_ID: auth_id, Channel.CONFIG_PLIVO_AUTH_TOKEN: auth_token, Channel.CONFIG_PLIVO_APP_ID: plivo_app_id, Channel.CONFIG_CALLBACK_DOMAIN: org.get_brand_domain(), } plivo_number = phone_number.strip("+ ").replace(" ", "") response = requests.get( "https://api.plivo.com/v1/Account/%s/Number/%s/" % (auth_id, plivo_number), headers=headers, auth=(auth_id, auth_token), ) if response.status_code != 200: response = requests.post( "https://api.plivo.com/v1/Account/%s/PhoneNumber/%s/" % (auth_id, plivo_number), headers=headers, auth=(auth_id, auth_token), ) if response.status_code != 201: # pragma: no cover raise Exception( _("There was a problem claiming that number, please check the balance on your account.") ) response = requests.get( "https://api.plivo.com/v1/Account/%s/Number/%s/" % (auth_id, plivo_number), headers=headers, auth=(auth_id, auth_token), ) if response.status_code == 200: response = requests.post( "https://api.plivo.com/v1/Account/%s/Number/%s/" % (auth_id, plivo_number), json=dict(app_id=plivo_app_id), headers=headers, auth=(auth_id, auth_token), ) if response.status_code != 202: # pragma: no cover raise Exception(_("There was a problem updating that number, please try again.")) phone_number = "+" + plivo_number phone = phonenumbers.format_number( phonenumbers.parse(phone_number, None), phonenumbers.PhoneNumberFormat.NATIONAL ) channel = Channel.create( org, user, country, "PL", name=phone, address=phone_number, config=plivo_config, uuid=plivo_uuid ) analytics.track(user.username, "temba.channel_claim_plivo", dict(number=phone_number)) return channel