def serialize_contact(contact): from temba.contacts.models import URN field_values = {} for field in contact.org.cached_contact_fields.values(): field_values[field.key] = contact.get_field_json(field) # augment URN values with preferred channel UUID as a parameter urn_values = [] for u in contact.urns.order_by("-priority", "id"): # for each URN we include the preferred channel as a query param if there is one if u.channel and u.channel.is_active: scheme, path, query, display = URN.to_parts(u.urn) urn_str = URN.from_parts(scheme, path, query=urlencode({"channel": str(u.channel.uuid)}), display=display) else: urn_str = u.urn urn_values.append(urn_str) return { "uuid": contact.uuid, "id": contact.id, "name": contact.name, "language": contact.language, "urns": urn_values, "groups": [serialize_ref(group) for group in contact.user_groups.filter(is_active=True)], "fields": field_values, }
def parse_contacts(cls, org, json_obj): contacts = [] for contact in json_obj.get(VariableContactAction.CONTACTS): name = contact.get(VariableContactAction.NAME, None) phone = contact.get(VariableContactAction.PHONE, None) contact_uuid = contact.get(VariableContactAction.UUID, None) urns = [] for urn in contact.get(VariableContactAction.URNS, []): scheme = urn.get(VariableContactAction.SCHEME) path = urn.get(VariableContactAction.PATH) if scheme and path: urns.append(URN.from_parts(scheme, path)) if phone: # pragma: needs cover urns.append(URN.from_tel(phone)) contact = Contact.objects.filter(uuid=contact_uuid, org=org).first() if not contact: contact = Contact.get_or_create_by_urns(org, org.created_by, name=None, urns=urns) # if they don't have a name use the one in our action if name and not contact.name: # pragma: needs cover contact.name = name contact.save(update_fields=["name"], handle_update=True) if contact: contacts.append(contact) return contacts
def update_dart_hub9_ext_scheme_urns(apps, schema_editor): ContactURN = apps.get_model('contacts', 'ContactURN') encrypted_urns = ContactURN.objects.filter(channel__channel_type__in=['DA', 'H9']).exclude(identity__icontains="+") for contact_urn in encrypted_urns: contact_urn.scheme = 'ext' contact_urn.identity = URN.from_parts('ext', contact_urn.path) contact_urn.save()
def clean_number(self): # check that our phone number looks sane country = self.data["country"] number = URN.normalize_number(self.data["number"], country) if not URN.validate(URN.from_parts(URN.TEL_SCHEME, number), country): raise forms.ValidationError( _("Please enter a valid phone number")) return number
def clean(self): # first check that our phone number looks sane country = self.cleaned_data["country"] normalized = URN.normalize_number(self.cleaned_data["number"], country) if not URN.validate(URN.from_parts(URN.TEL_SCHEME, normalized), country): raise forms.ValidationError(_("Please enter a valid phone number")) self.cleaned_data["number"] = normalized return self.cleaned_data
def update_dart_hub9_ext_scheme_urns(apps, schema_editor): ContactURN = apps.get_model("contacts", "ContactURN") encrypted_urns = ContactURN.objects.filter( channel__channel_type__in=["DA", "H9"]).exclude( identity__icontains="+") for contact_urn in encrypted_urns: contact_urn.scheme = "ext" contact_urn.identity = URN.from_parts("ext", contact_urn.path) contact_urn.save()
def clean(self): # first check that our phone number looks sane country = self.cleaned_data["country"] normalized = URN.normalize_number(self.cleaned_data["number"], country) if not URN.validate(URN.from_parts(URN.TEL_SCHEME, normalized), country): raise forms.ValidationError( _("Please enter a valid phone number")) self.cleaned_data["number"] = normalized try: resp = requests.post( self.cleaned_data["base_url"] + "/v1/users/login", auth=(self.cleaned_data["username"], self.cleaned_data["password"]), ) if resp.status_code != 200: raise Exception("Received non-200 response: %d", resp.status_code) self.cleaned_data["auth_token"] = resp.json( )["users"][0]["token"] except Exception: raise forms.ValidationError( _("Unable to check WhatsApp enterprise account, please check username and password" )) # check we can access their facebook templates from .type import TEMPLATE_LIST_URL if self.cleaned_data[ "facebook_template_list_domain"] != "graph.facebook.com": response = requests.get( TEMPLATE_LIST_URL % (self.cleaned_data["facebook_template_list_domain"], self.cleaned_data["facebook_business_id"]), params=dict(access_token=self. cleaned_data["facebook_access_token"]), ) if response.status_code != 200: raise forms.ValidationError( _("Unable to access Facebook templates, please check user id and access token and make sure " + "the whatsapp_business_management permission is enabled" )) return self.cleaned_data
def default(self, line): """ Sends a message as the current contact's highest priority URN """ urn = self.contact.get_urn() incoming = Msg.create_incoming(None, URN.from_parts(urn.scheme, urn.path), line, date=timezone.now(), org=self.org) self.echo((Fore.GREEN + "[%s] " + Fore.YELLOW + ">>" + Fore.MAGENTA + " %s" + Fore.WHITE) % (urn.urn, incoming.text)) # look up any message responses outgoing = Msg.all_messages.filter(org=self.org, pk__gt=incoming.pk, direction=OUTGOING).order_by('sent_on') for response in outgoing: self.echo((Fore.GREEN + "[%s] " + Fore.YELLOW + "<<" + Fore.MAGENTA + " %s" + Fore.WHITE) % (urn.urn, response.text))
def serialize_contact(contact): from temba.contacts.models import URN field_values = {} for field in contact.org.cached_contact_fields.values(): field_values[field.key] = contact.get_field_json(field) # augment URN values with preferred channel UUID as a parameter urn_values = [] for u in contact.urns.order_by("-priority", "id"): # for each URN we resolve the preferred channel and include that as a query param channel = contact.org.get_send_channel(contact_urn=u) if channel: scheme, path, query, display = URN.to_parts(u.urn) urn_str = URN.from_parts(scheme, path, query=urlencode( {"channel": str(channel.uuid)}), display=display) else: urn_str = u.urn urn_values.append(urn_str) return { "uuid": contact.uuid, "id": contact.id, "name": contact.name, "language": contact.language, "timezone": "UTC", "urns": urn_values, "groups": [ serialize_group_ref(group) for group in contact.user_groups.filter(is_active=True) ], "fields": field_values, }
def default(self, line): """ Sends a message as the current contact's highest priority URN """ urn = self.contact.get_urn() incoming = Msg.create_incoming(None, URN.from_parts(urn.scheme, urn.path), line, org=self.org) self.echo( (Fore.GREEN + "[%s] " + Fore.YELLOW + ">>" + Fore.MAGENTA + " %s" + Fore.WHITE) % (str(urn), incoming.text) ) # look up any message responses outgoing = Msg.objects.filter(org=self.org, pk__gt=incoming.pk, direction=OUTGOING).order_by("sent_on") for response in outgoing: self.echo( (Fore.GREEN + "[%s] " + Fore.YELLOW + "<<" + Fore.MAGENTA + " %s" + Fore.WHITE) % (str(urn), response.text) )
def reduce_event(event): new_event = copy_keys(event, {"type", "msg"}) if "msg" in new_event: new_event["msg"] = copy_keys(event["msg"], {"text", "urn", "channel", "attachments"}) new_msg = new_event["msg"] # legacy events are re-constructed from real messages which have their text stripped if "text" in new_msg: new_msg["text"] = new_msg["text"].strip() # legacy events have absolute paths for attachments, new have relative if "attachments" in new_msg: abs_prefix = f"https://{settings.AWS_BUCKET_DOMAIN}/" new_msg["attachments"] = [a.replace(abs_prefix, "") for a in new_msg["attachments"]] # new engine events might have params on URNs that we're not interested in if "urn" in new_msg: scheme, path, query, fragment = URN.to_parts(new_msg["urn"]) new_msg["urn"] = URN.from_parts(scheme, path, None, fragment) return new_event
def add_contact_urn(self, scheme, path): urns = [str(u) for u in self.contact.get_urns()] urns.append(URN.from_parts(scheme, path)) self._log_event("contact_urns_changed", urns=urns) return self