def create(self, request, *args, **kwargs): """ Sends a websocket message to the user with the corresponding internal number """ response = super(CallViewSet, self).create(request, *args, **kwargs) called_user = LilyUser.objects.filter( internal_number=request.data['internal_number'], tenant_id=request.user.tenant_id ).first() if not called_user: return response caller_number = parse_phone_number(request.data['caller_number']) account, contact = search_number(called_user.tenant_id, caller_number) # If a account with this number has been found, show information about and link to this account. if account: data = { 'destination': 'account', 'icon': static('app/images/notification_icons/account.png'), 'params': { 'name': account.name, 'number': caller_number, 'id': account.id, }, } # There is no account for the number, but if there is a contact, show information about and link to it. elif contact: data = { 'destination': 'contact', 'icon': static('app/images/notification_icons/contact.png'), 'params': { 'name': contact.full_name, 'number': caller_number, 'id': contact.id, }, } # If no account or contact has been found, use the name provided by VoIPGRID. else: data = { 'destination': 'create', 'icon': static('app/images/notification_icons/add-account.png'), 'params': { 'name': request.data.get('caller_name'), 'number': caller_number, }, } # Sends the data as a notification event to the user who picked up the phone. Group('user-%s' % called_user.id).send({ 'text': json.dumps({ 'event': 'notification', 'data': data, }), }) return response
def get(self, request, *args, **kwargs): number = kwargs.get('number', None) if number: # For now we'll always convert the phone number to a certain format. # In the future we might change how we handle phone numbers. number = parse_phone_number(number) response = { 'data': { 'accounts': [], 'contacts': [], }, } results = search_number(self.request.user.tenant_id, number) # Return only the primary keys of the accounts and contacts for account in results['data']['accounts']: response['data']['accounts'].append(account.id) for contact in results['data']['contacts']: response['data']['contacts'].append(contact.id) return HttpResponse(anyjson.dumps(response), content_type='application/json; charset=utf-8')
def search_number(tenant_id, number, return_related=True): """ If the phone number belongs to an account, this returns the first account and all its contacts Else if the number belongs to a contact, this returns the first contact and all its accounts """ phone_number = parse_phone_number(number) accounts = Account.objects.filter(phone_numbers__number=phone_number, is_deleted=False) contacts = Contact.objects.filter(phone_numbers__number=phone_number, is_deleted=False) accounts_result = [] contacts_result = [] if accounts: accounts_result = [accounts[0]] if return_related: contacts_result = accounts[0].contacts.filter(is_deleted=False) elif contacts: contacts_result = [contacts[0]] if return_related: accounts_result = contacts[0].accounts.filter(is_deleted=False) return { 'data': { 'accounts': accounts_result, 'contacts': contacts_result, }, }
def save(self, *args, **kwargs): # Save raw input as number only (for searching) self.number = parse_phone_number(self.raw_input) if len(self.number) > 0: # Overwrite user input self.raw_input = self.number # reserved field for future display based on locale return super(PhoneNumber, self).save(*args, **kwargs)
def get(self, request, *args, **kwargs): number = kwargs.get("number", None) if number: # For now we'll always convert the phone number to a certain format. # In the future we might change how we handle phone numbers. number = parse_phone_number(number) results = self._search_number(number) return HttpResponse(anyjson.dumps(results), content_type="application/json; charset=utf-8")
def get(self, request, *args, **kwargs): number = kwargs.get('number', None) if number: # For now we'll always convert the phone number to a certain format. # In the future we might change how we handle phone numbers. number = parse_phone_number(number) results = self._search_number(number) return HttpResponse(anyjson.dumps(results), content_type='application/json; charset=utf-8')
def _create_phone(self, instance, type, number, other_type=None): """ Creates PhoneNumber for given instance Arguments: instance (instance): instance to add PhoneNumber to type (str): kind of phone number number (str): unformatted phone number other_type (str) optional: given if not default phone number type """ if number and len(number) > 2: phone_kwargs = dict() phone_kwargs['type'] = type phone_kwargs['other_type'] = other_type phone_kwargs['number'] = parse_phone_number(number) phone_kwargs['tenant_id'] = self.tenant_pk phone_number_list = instance.phone_numbers.filter(**phone_kwargs) if not phone_number_list.exists(): # Other types are ugly for phonenumbers. if other_type is not None: phone_kwargs['type'] = phone_kwargs['other_type'] phone_kwargs['other_type'] = None # Recheck if it exists without the othertype. if not instance.phone_numbers.filter(**phone_kwargs).exists(): phone_number = PhoneNumber.objects.create(**phone_kwargs) instance.phone_numbers.add(phone_number) else: # Keep first in list and delete all the others. for i, phone_number in enumerate(phone_number_list): if i == 0: # When othertype given set normal type instead for save. if other_type is not None: phone_number.type = phone_number.other_type phone_kwargs['type'] = phone_number.other_type phone_number.other_type = None phone_kwargs['other_type'] = None if not instance.phone_numbers.filter( **phone_kwargs).exists(): phone_number.save() else: phone_number.delete()
def _create_phone(self, instance, type, raw_input, other_type=None): """ Creates PhoneNumber for given instance Arguments: instance (instance): instance to add PhoneNumber to type (str): kind of phone number raw_input (str): unformatted phone number other_type (str) optional: given if not default phone number type """ if raw_input and len(raw_input) > 2: phone_kwargs = dict() phone_kwargs['type'] = type phone_kwargs['other_type'] = other_type phone_kwargs['raw_input'] = parse_phone_number(raw_input) phone_kwargs['tenant_id'] = self.tenant_pk phone_number_list = instance.phone_numbers.filter(**phone_kwargs) if not phone_number_list.exists(): # Other types are ugly for phonenumbers. if other_type is not None: phone_kwargs['type'] = phone_kwargs['other_type'] phone_kwargs['other_type'] = None # Recheck if it exists without the othertype. if not instance.phone_numbers.filter(**phone_kwargs).exists(): phone_number = PhoneNumber.objects.create(**phone_kwargs) instance.phone_numbers.add(phone_number) else: # Keep first in list and delete all the others. for i, phone_number in enumerate(phone_number_list): if i == 0: # When othertype given set normal type instead for save. if other_type is not None: phone_number.type = phone_number.other_type phone_kwargs['type'] = phone_number.other_type phone_number.other_type = None phone_kwargs['other_type'] = None if not instance.phone_numbers.filter(**phone_kwargs).exists(): phone_number.save() else: phone_number.delete()
def get(self, request, *args, **kwargs): number = kwargs.get('number', None) if number: # For now we'll always convert the phone number to a certain format. # In the future we might change how we handle phone numbers. number = parse_phone_number(number) results = self._search_number(number) response_format = request.GET.get('format') if response_format and response_format.lower() == 'grid': name = '' internal_number = results.get('internal_number', '') result = search_number(request.user.tenant_id, number, False) data = result.get('data') accounts = data.get('accounts') contacts = data.get('contacts') if contacts: name = contacts[0].full_name elif accounts: name = accounts[0].name if name: response = 'status=ACK&callername=%s' % name if internal_number: response += '&destination=%s' % internal_number else: response = 'status=NAK' return HttpResponse(response, content_type='text/plain; charset=utf-8') else: user = results.get('user') if user: results['user'] = user.id return HttpResponse(anyjson.dumps(results), content_type='application/json; charset=utf-8')
def search_number(tenant_id, number): """ Return the first account the number belongs to, otherwise if there is, return the first contact with that number. """ contact = None phone_number = parse_phone_number(number) account = Account.objects.filter(phone_numbers__number=phone_number, tenant=tenant_id, is_deleted=False).only('id', 'name').first() if not account: contact = Contact.objects.filter(phone_numbers__number=phone_number, tenant=tenant_id, is_deleted=False).only( 'id', 'first_name', 'last_name').first() return account, contact
def search_number(tenant_id, number): """ Return the first account the number belongs to, otherwise if there is, return the first contact with that number. """ contact = None phone_number = parse_phone_number(number) account = Account.objects.filter( phone_numbers__number=phone_number, tenant=tenant_id, is_deleted=False ).only('id', 'name').first() if not account: contact = Contact.objects.filter( phone_numbers__number=phone_number, tenant=tenant_id, is_deleted=False ).only('id', 'first_name', 'last_name').first() return account, contact
def get(self, request, *args, **kwargs): phone_number = kwargs.get('number', None) if phone_number: # For now we'll always convert the phone number to a certain format. # In the future we might change how we handle phone numbers. phone_number = parse_phone_number(phone_number) results = self._get_user_internal_number(phone_number) response_format = request.GET.get('format') if response_format and response_format.lower() == 'grid': name = None internal_number = results.get('internal_number', '') account, contact = search_number(request.user.tenant_id, phone_number) if contact: name = contact.full_name elif account: name = account.name if name: response = 'status=ACK&callername=%s' % name if internal_number: response += '&destination=%s' % internal_number else: response = 'status=NAK' return HttpResponse(response, content_type='text/plain; charset=utf-8') else: user = results.get('user') if user: results['user'] = user.id return HttpResponse(anyjson.dumps(results), content_type='application/json; charset=utf-8')
def import_contact(row, tenant_id, headers): # The following set of fields should be present as headers in the uploaded file. required_fields = {u'first name', u'last name'} # The following set of fields are optional. optional_fields = {u'company name', u'email address', u'phone number', u'address', u'postal code', u'city', u'twitter', u'linkedin', u'mobile'} # The following headers are present in the uploaded file. available_in_upload = set(headers) optional_in_upload = optional_fields & available_in_upload extra_in_upload = available_in_upload - (required_fields | optional_fields) first_name = row.get(u'first name') last_name = row.get(u'last name') full_name = u'{0} {1}'.format(first_name, last_name) contact = new_or_existing_contact(row, tenant_id, optional_in_upload) account = None email_address = None phone_number = None address = None twitter = None linkedin = None mobile = None try: # Use atomic to rollback all intermediate database actions if an error occurs in just one of them. with transaction.atomic(): # All the extra fields excluding 'company' that are present in the upload are placed in the description # field. description = u'' extra_in_upload_wo_company = set(extra_in_upload) extra_in_upload_wo_company.discard(u'company name') for field in extra_in_upload_wo_company: if row.get(field): description += '{0}: {1}\n'.format(field.capitalize(), row.get(field)) contact.description = description contact.save() if u'company name' in optional_in_upload and row.get(u'company name'): company_name = row.get(u'company name') # Not using get_or_create() to make use of the skip_signal construction. try: account = Account.objects.get(name=company_name, tenant_id=tenant_id, is_deleted=False) except Account.DoesNotExist: account_status = AccountStatus.objects.get(name='Relation', tenant_id=tenant_id) account = Account( name=company_name, tenant_id=tenant_id, status=account_status ) account.skip_signal = True account.save() if u'email address' in optional_in_upload and row.get(u'email address'): formatted_email_address = row.get(u'email address').lower() if not contact.email_addresses.filter(email_address=formatted_email_address).exists(): email_address = EmailAddress( email_address=formatted_email_address, status=EmailAddress.PRIMARY_STATUS, tenant_id=tenant_id ) email_address.skip_signal = True email_address.save() if u'phone number' in optional_in_upload and row.get(u'phone number'): formatted_phone_number = parse_phone_number(row.get(u'phone number')) if not contact.phone_numbers.filter(number=formatted_phone_number).exists(): phone_number = PhoneNumber( number=formatted_phone_number, tenant_id=tenant_id ) phone_number.skip_signal = True phone_number.save() # An Address consists of multiple, optional fields. So create or update the instance. if u'address' in optional_in_upload and row.get(u'address'): address = Address( address=row.get(u'address'), type='visiting', tenant_id=tenant_id ) address.skip_signal = True address.save() if u'postal code' in optional_in_upload and row.get(u'postal code'): if address: address.postal_code = row.get(u'postal code') else: address = Address( postal_code=row.get(u'postal code'), type='visiting', tenant_id=tenant_id ) address.skip_signal = True address.save() if u'city' in optional_in_upload and row.get(u'city'): if address: address.city = row.get(u'city') else: address = Address( city=row.get(u'city'), type='visiting', tenant_id=tenant_id ) address.skip_signal = True address.save() if u'twitter' in optional_in_upload and row.get(u'twitter'): twitter = SocialMedia( name='twitter', username=row.get(u'twitter'), profile_url='https://twitter.com/{0}'.format(row.get(u'twitter')), tenant_id=tenant_id ) twitter.skip_signal = True twitter.save() if u'linkedin' in optional_in_upload and row.get(u'linkedin'): linkedin = SocialMedia( name='linkedin', username=row.get(u'linkedin'), profile_url='https://www.linkedin.com/in/{0}'.format(row.get(u'linkedin')), tenant_id=tenant_id ) linkedin.skip_signal = True linkedin.save() if u'mobile' in optional_in_upload and row.get(u'mobile'): formatted_phone_number = parse_phone_number(row.get(u'mobile')) if not contact.phone_numbers.filter(number=formatted_phone_number).exists(): mobile = PhoneNumber( number=formatted_phone_number, tenant_id=tenant_id, type='mobile' ) mobile.skip_signal = True mobile.save() except Exception as e: # On an exception all database actions are rolled back. Because of the skip_signal=True no row is added to the # search index. logger.error(u'Import error for {}: {}'.format(full_name, e)) else: if email_address: email_address.skip_signal = False email_address.save() contact.email_addresses.add(email_address) if phone_number: phone_number.skip_signal = False phone_number.save() contact.phone_numbers.add(phone_number) if address: address.skip_signal = False address.save() contact.addresses.add(address) if twitter: twitter.skip_signal = False twitter.save() contact.social_media.add(twitter) if linkedin: linkedin.skip_signal = False linkedin.save() contact.social_media.add(linkedin) if account: account.skip_signal = False account.save() if not Function.objects.filter(account=account, contact=contact).exists(): Function.objects.create(account=account, contact=contact) if mobile: mobile.skip_signal = False mobile.save() contact.phone_numbers.add(mobile) contact.skip_signal = False contact.save()
def import_account(row, tenant_id, headers): # The following set of fields should be present as headers in the uploaded file. required_fields = {u'company name'} # The following set of fields are optional. optional_fields = {u'website', u'email address', u'phone number', u'twitter', u'address', u'postal code', u'city'} # The following headers are present in the uploaded file. available_in_upload = set(headers) optional_in_upload = optional_fields & available_in_upload extra_in_upload = available_in_upload - (required_fields | optional_fields) company_name = row.get(u'company name') website = None email_address = None phone_number = None twitter = None address = None try: # Use atomic to rollback all intermediate database actions if an error occurs in just one of them. with transaction.atomic(): description = '' # All the extra fields that are present in the upload are placed in the description field. for field in extra_in_upload: description += '{0}: {1}\n'.format(field, row.get(field)) # Not using get_or_create() to make use of the skip_signal construction. try: account = Account.objects.get(name=company_name, tenant_id=tenant_id) if description: new_description = '{0}\n{1}'.format(account.description.strip(), description) account.description = new_description account.skip_signal = True account.save() except Account.DoesNotExist: account_status = AccountStatus.objects.get(name='Relation', tenant_id=tenant_id) account = Account( name=company_name, tenant_id=tenant_id, status=account_status, description=description ) account.skip_signal = True account.save() if u'website' in optional_in_upload and row.get(u'website'): website = Website( website=row.get(u'website'), is_primary=True, account=account, tenant_id=tenant_id ) website.skip_signal = True website.save() if u'email address' in optional_in_upload and row.get(u'email address'): formatted_email_address = row.get(u'email address').lower() if not account.email_addresses.filter(email_address=formatted_email_address).exists(): email_address = EmailAddress( email_address=formatted_email_address, status=EmailAddress.PRIMARY_STATUS, tenant_id=tenant_id ) email_address.skip_signal = True email_address.save() if u'phone number' in optional_in_upload and row.get(u'phone number'): formatted_phone_number = parse_phone_number(row.get(u'phone number')) phone_number = PhoneNumber( number=formatted_phone_number, tenant_id=tenant_id ) phone_number.skip_signal = True phone_number.save() if u'twitter' in optional_in_upload and row.get(u'twitter'): twitter = SocialMedia( name='twitter', username=row.get(u'twitter'), profile_url='https://twitter.com/{0}'.format(row.get(u'twitter')), tenant_id=tenant_id ) twitter.skip_signal = True twitter.save() # An Address consists of multiple, optional fields. So create or update the instance. if u'address' in optional_in_upload and row.get(u'address'): address = Address( address=row.get(u'address'), type='visiting', tenant_id=tenant_id ) address.skip_signal = True address.save() if u'postal code' in optional_in_upload and row.get(u'postal code'): if address: address.postal_code = row.get(u'postal code') else: address = Address( postal_code=row.get(u'postal code'), type='visiting', tenant_id=tenant_id ) address.skip_signal = True address.save() if u'city' in optional_in_upload and row.get(u'city'): if address: address.city = row.get(u'city') else: address = Address( city=row.get(u'city'), type='visiting', tenant_id=tenant_id ) address.skip_signal = True address.save() except Exception as e: # On an exception all database actions are rolled back. Because of the skip_signal=True no data is added to the # search index. logger.error(u'Import error {} for {}'.format(e, company_name)) else: if website: website.skip_signal = False website.save() account.websites.add(website) if email_address: email_address.skip_signal = False email_address.save() account.email_addresses.add(email_address) if phone_number: phone_number.skip_signal = False phone_number.save() account.phone_numbers.add(phone_number) if twitter: twitter.skip_signal = False twitter.save() account.social_media.add(twitter) if address: address.skip_signal = False address.save() account.addresses.add(address) account.skip_signal = False account.save()
def new_or_existing_contact(row, tenant_id, optional_in_upload): """ Determine if Lily needs to create a new contact with the given row or that it should update a current contact. """ account = None email_address = None formatted_phone_number = None first_name = row.get(u'first name') last_name = row.get(u'last name') if u'company name' in optional_in_upload and row.get(u'company name'): company_name = row.get(u'company name') try: account = Account.objects.get(name=company_name, tenant_id=tenant_id, is_deleted=False) except Account.DoesNotExist: pass if u'email address' in optional_in_upload and row.get(u'email address'): email_address = row.get(u'email address').lower() if u'phone number' in optional_in_upload and row.get(u'phone number'): formatted_phone_number = parse_phone_number(row.get(u'phone number')) # Regard as a existing contact when there is one in the database with the given name in combination with the # email address and / or phone number. qs = Contact.objects.filter( first_name=first_name, last_name=last_name, tenant_id=tenant_id, is_deleted=False ) if account: qs = qs.filter( functions__account=account ) if email_address and formatted_phone_number: qs = qs.filter( Q(email_addresses__email_address=email_address) | Q(phone_numbers__number=formatted_phone_number) ) elif email_address: qs = qs.filter(email_addresses__email_address=email_address) elif formatted_phone_number: qs = qs.filter(phone_numbers__number=formatted_phone_number) contact = qs.first() if not contact: # There was no existing contact, so instantiate a new one. contact = Contact( first_name=first_name, last_name=last_name, tenant_id=tenant_id ) # Skip the signal at this moment, so on a rollback the instance isn't still in the search index. contact.skip_signal = True return contact
def set_view_output(self): """ Create a generic json format for account information based on the json from Dataprovider. """ phone_number_limit = 5 email_limit = 5 address_limit = 3 # Expected api output is json self.api_output = json.loads(self.api_output) # Return 404 when the api returned an error if self.api_output.get('error'): raise Http404() # Return error message when nothing was found if self.api_output.get('total') == 0: raise Exception( _('I\'m so sorry, I couldn\'t find any data for this website.') ) # Filter useful data result = self.api_output['data'][0] # Get company name company = result.get('company') # Get website description description = result.get('description') # Get the keywords and convert to list tags = result.get('keywords') if tags: tags = result.get('keywords').strip().rstrip(',').split(',') # Get email addresses and convert to a list if needed emails = result.get('emailaddresses', []) or [] if not isinstance(emails, list): emails = [emails] # Determine primary email since Dataprovider doesn't provide it primary_email = None if emails: primary_email = self._get_primary_email(emails) # Set primary email to the first in the list emails.index(primary_email) emails.remove(primary_email) emails.insert(0, primary_email) # Limit number of emails emails = emails[:email_limit] phone_numbers = [] # Get primary phone number and convert to a nicer representation phone_number = result.get('phonenumber') if phone_number: phone_number = parse_phone_number(phone_number) phone_numbers.append(phone_number) # Get phone numbers and convert to list if needed raw_phone_numbers = result.get('phonenumbers', []) or [] if not isinstance(raw_phone_numbers, list): raw_phone_numbers = [raw_phone_numbers] # Convert all phone numbers to a nicer representation for raw_phone_number in raw_phone_numbers: phone_numbers.append(parse_phone_number(raw_phone_number)) # Limit number of phonenumbers phone_numbers = phone_numbers[:phone_number_limit] # Get what kind of company it is (e.g. LLC) legalentity = result.get('legalentity') # Get the VAT (Value Added Tax) identifaction number taxnumber = result.get('taxnumber') # Get bank account number bankaccountnumber = result.get('bankaccountnumber') # Get the CoC (Chamber of Commerce) number cocnumber = result.get('cocnumber') # Get the IBAN (Internation Bank Account Number) iban = result.get('iban') # Get the BIC (Bank Identifier Code) bic = result.get('bic') # Try to parse the address address = result.get('address') if address: street, street_number, complement = parse_address(address) else: street, street_number, complement = None, None, None # Make the full address addresses = [] if address or result.get('city') or result.get( 'zipcode') or result.get('country'): addresses = [{ 'street': street, 'street_number': street_number, 'complement': complement, 'city': result.get('city'), 'country': result.get('country'), 'postal_code': result.get('zipcode'), }] addresses = addresses[:address_limit] # Build dict with account information self.view_output = { 'name': company, 'description': description, 'tags': tags, 'email_addresses': emails, 'primary_email': primary_email, 'phone_numbers': phone_numbers, 'phone_number': phone_number, 'addresses': addresses, 'legalentity': legalentity, 'taxnumber': taxnumber, 'bankaccountnumber': bankaccountnumber, 'cocnumber': cocnumber, 'iban': iban, 'bic': bic, } return json.dumps(self.view_output)
def set_view_output(self): """ Create a generic json format for account information based on the json from Dataprovider. """ # Expected api output is json self.api_output = anyjson.deserialize(self.api_output) # Return 404 when the api returned an error if self.api_output.get('error'): raise Http404() # Return error message when nothing was found if self.api_output.get('total') == 0: raise Exception(_('I\'m so sorry, I couldn\'t find any data for this website.')) # Filter useful data result = self.api_output['data'][0] # Get company name company = result.get('company') # Get website description description = result.get('description') # Get the keywords and convert to list tags = result.get('keywords') if tags: tags = result.get('keywords').strip().rstrip(',').split(',') # Get email addresses and convert to a list if needed emails = result.get('emailaddresses', []) or [] if not isinstance(emails, list): emails = [emails] # Determine primary email since Dataprovider doesn't provide it primary_email = None if emails: primary_email = self.get_primary_email(emails) # Get phone numbers and convert to list if needed raw_phone_numbers = result.get('phonenumbers', []) or [] if not isinstance(raw_phone_numbers, list): raw_phone_numbers = [raw_phone_numbers] # Convert all phone numbers to a nicer representation phone_numbers = [] for raw_phone_number in raw_phone_numbers: phone_numbers.append(parse_phone_number(raw_phone_number)) # Get primary phone number and convert to a nicer representation phone_number = result.get('phonenumber') if phone_number: phone_number = parse_phone_number(result.get('phonenumber')) # Get what kind of company it is (e.g. LLC) legalentity = result.get('legalentity') # Get the VAT (Value Added Tax) identifaction number taxnumber = result.get('taxnumber') # Get bank account number bankaccountnumber = result.get('bankaccountnumber') # Get the CoC (Chamber of Commerce) number cocnumber = result.get('cocnumber') # Get the IBAN (Internation Bank Account Number) iban = result.get('iban') # Get the BIC (Bank Identifier Code) bic = result.get('bic') # Try to parse the address address = result.get('address') if address: street, street_number, complement = parse_address(address) else: street, street_number, complement = None, None, None # Make the full address addresses = [] if address or result.get('city') or result.get('zipcode') or result.get('country'): addresses = [{ 'street': street, 'street_number': street_number, 'complement': complement, 'city': result.get('city'), 'country': result.get('country'), 'postal_code': result.get('zipcode'), }] # Build dict with account information self.view_output = { 'name': company, 'description': description, 'tags': tags, 'emails': emails, 'primary_email': primary_email, 'phone_numbers': phone_numbers, 'phone_number': phone_number, 'addresses': addresses, 'legalentity': legalentity, 'taxnumber': taxnumber, 'bankaccountnumber': bankaccountnumber, 'cocnumber': cocnumber, 'iban': iban, 'bic': bic, } return anyjson.serialize(self.view_output)
def _get_account_information(self, api_output): """ Create a dict with account information based on the json response from Dataprovider. """ phone_number_limit = 5 email_limit = 5 address_limit = 3 # Expected API output is json. api_output_json = json.loads(api_output) # Return 404 when the api returned an error. if api_output_json.get('error'): raise Http404(api_output_json.get('error')) # Return error message when nothing was found. if api_output_json.get('total') == 0: raise APIException(_('I\'m so sorry, I couldn\'t find any data for this website.')) # Filter useful data. result = api_output_json['data'][0] # Get the keywords and convert to list. tags = result.get('keywords') if tags: tags = result.get('keywords').strip().rstrip(',').split(',') # Get email addresses as a list. emails = list(result.get('emailaddresses', [])) # Determine primary email since Dataprovider doesn't provide it. primary_email = None if emails: primary_email = self._get_primary_email(emails) # Set primary email to the first in the list. emails.index(primary_email) emails.remove(primary_email) emails.insert(0, primary_email) phone_numbers = [] # Get primary phone number and convert to a nicer representation. phone_number = result.get('phonenumber') if phone_number: phone_number = parse_phone_number(phone_number) phone_numbers.append(phone_number) # Get phone numbers as a list. raw_phone_numbers = list(result.get('phonenumbers', [])) # Convert all phone numbers to a nicer representation. for raw_phone_number in raw_phone_numbers: phone_numbers.append(parse_phone_number(raw_phone_number)) # Try to parse the address. address = result.get('address') address_line = '' if address: # Construct address_line, instead of assigning address to address_line directly, # because parse_address() also santizes the result. street, street_number, complement = parse_address(address) if street: address_line = street if street_number: address_line += ' ' + street_number if complement: address_line += complement # Make the full address. addresses = [] if address or result.get('city') or result.get('zipcode') or result.get('country'): addresses = [{ 'address': address_line, 'city': result.get('city'), 'country': result.get('country'), 'postal_code': result.get('zipcode'), }] # Get social media profiles. social_profiles = result.get('socialprofiles') # Group profiles by platform. # Disregards the other platforms provided by Dataprovider: Facebook, Google Plus and Pinterest. social_media = {} for profile in social_profiles: if profile.startswith('twitter.com/'): if 'twitter' not in social_media: social_media['twitter'] = [] social_media['twitter'].append(profile) elif profile.startswith('www.linkedin.com/in/'): if 'linkedin' not in social_media: social_media['linkedin'] = [] social_media['linkedin'].append(profile) primary_twitter = '' if 'twitter' in social_media: primary_twitter = self._get_primary_profile(social_media['twitter'], result.get('company')) primary_linkedin = '' if 'linkedin' in social_media: primary_linkedin = self._get_primary_profile(social_media['linkedin'], result.get('company')) # Build dict with account information. account_information = { 'name': result.get('company'), 'description': result.get('description'), 'tags': tags, 'email_addresses': emails[:email_limit], 'primary_email': primary_email, 'phone_numbers': phone_numbers[:phone_number_limit], 'phone_number': phone_number, 'addresses': addresses[:address_limit], 'legalentity': result.get('legalentity'), 'taxnumber': result.get('taxnumber'), 'bankaccountnumber': result.get('bankaccountnumber'), 'cocnumber': result.get('cocnumber'), 'iban': result.get('iban'), 'bic': result.get('bic'), 'social_media_profiles': social_media, 'twitter': primary_twitter, 'linkedin': primary_linkedin, } return account_information
def _get_account_information(self, json): """ Create a dict with account information based on the json response from Dataprovider. """ phone_number_limit = 5 email_limit = 5 address_limit = 3 # Return 404 when the api returned an error. if json.get('error'): raise Http404(json.get('error')) if json.get('total') == 0: # No results from Dataprovider so return an empty list. return [] # Filter useful data. try: # Lookup API returns data as a dict. result = json['data'][0] except (KeyError, IndexError): # Enrich API returns a single hit. result = json['data'] if not result: # No results from Dataprovider so return an empty list. return [] # Get the keywords and convert to list. tags = result.get('keywords') if tags: tags = [tag.strip() for tag in tags.split(',')] tags = filter(None, tags) # Remove empty tags. # Get email addresses as a list. emails = list(result.get('emailaddresses', [])) # Determine primary email since Dataprovider doesn't provide it. primary_email = None if emails: primary_email = self._get_primary_email(emails) # Set primary email to the first in the list. emails.index(primary_email) emails.remove(primary_email) emails.insert(0, primary_email) phone_numbers = [] # Get primary phone number and convert to a nicer representation. phone_number = result.get('phonenumber') if phone_number: phone_number = parse_phone_number(phone_number) phone_numbers.append(phone_number) # Get phone numbers as a list. raw_phone_numbers = list(result.get('phonenumbers', [])) # Convert all phone numbers to a nicer representation. for raw_phone_number in raw_phone_numbers: phone_numbers.append(parse_phone_number(raw_phone_number)) # Try to parse the address. address = result.get('address') address_line = '' if address: # Construct address_line, instead of assigning address to address_line directly, # because parse_address() also santizes the result. street, street_number, complement = parse_address(address) if street: address_line = street if street_number: address_line += ' ' + street_number if complement: address_line += complement # Make the full address. addresses = [] if address or result.get('city') or result.get('zipcode') or result.get('country'): # There are some exceptions on the country codes, so make sure results of Dataprovider conform to the # ISO 3166-1 alpha-2 standard we use. mapping = { 'UK': 'GB', 'EL': 'GR', } country = mapping.get(result.get('country'), result.get('country')) if result.get('country') else '' addresses = [{ 'address': address_line, 'city': result.get('city', ''), 'country': country, 'postal_code': result.get('zipcode', ''), }] # Get social media profiles. social_profiles = result.get('socialprofiles') # Group profiles by platform. # Disregards the other platforms provided by Dataprovider: Facebook, Google Plus and Pinterest. social_media = {} if social_profiles: for profile in social_profiles: if profile.startswith('twitter.com/'): if 'twitter' not in social_media: social_media['twitter'] = [] social_media['twitter'].append(profile) elif profile.startswith('www.linkedin.com/in/'): if 'linkedin' not in social_media: social_media['linkedin'] = [] social_media['linkedin'].append(profile) primary_twitter = '' if 'twitter' in social_media: primary_twitter = self._get_primary_profile(social_media['twitter'], result.get('company')) primary_linkedin = '' if 'linkedin' in social_media: primary_linkedin = self._get_primary_profile(social_media['linkedin'], result.get('company')) description = result.get('description') website = result.get('hostname') # Build dict with account information. account_information = { 'name': result.get('company'), 'description': description, 'tags': tags, 'email_addresses': emails[:email_limit], 'primary_email': primary_email, 'phone_numbers': phone_numbers[:phone_number_limit], 'phone_number': phone_number, 'addresses': addresses[:address_limit], 'legalentity': result.get('legalentity'), 'taxnumber': result.get('taxnumber'), 'bankaccountnumber': result.get('bankaccountnumber'), 'cocnumber': result.get('cocnumber'), 'iban': result.get('iban'), 'bic': result.get('bic'), 'social_media_profiles': social_media, 'twitter': primary_twitter, 'linkedin': primary_linkedin, 'primary_website': website, } return account_information
def _get_account_information(self, api_output): """ Create a dict with account information based on the json response from Dataprovider. """ phone_number_limit = 5 email_limit = 5 address_limit = 3 # Expected API output is json. api_output_json = json.loads(api_output) # Return 404 when the api returned an error. if api_output_json.get('error'): raise Http404(api_output_json.get('error')) # Return error message when nothing was found. if api_output_json.get('total') == 0: raise APIException( _('I\'m so sorry, I couldn\'t find any data for this website.') ) # Filter useful data. result = api_output_json['data'][0] # Get the keywords and convert to list. tags = result.get('keywords') if tags: tags = result.get('keywords').strip().rstrip(',').split(',') # Get email addresses as a list. emails = list(result.get('emailaddresses', [])) # Determine primary email since Dataprovider doesn't provide it. primary_email = None if emails: primary_email = self._get_primary_email(emails) # Set primary email to the first in the list. emails.index(primary_email) emails.remove(primary_email) emails.insert(0, primary_email) phone_numbers = [] # Get primary phone number and convert to a nicer representation. phone_number = result.get('phonenumber') if phone_number: phone_number = parse_phone_number(phone_number) phone_numbers.append(phone_number) # Get phone numbers as a list. raw_phone_numbers = list(result.get('phonenumbers', [])) # Convert all phone numbers to a nicer representation. for raw_phone_number in raw_phone_numbers: phone_numbers.append(parse_phone_number(raw_phone_number)) # Try to parse the address. address = result.get('address') address_line = '' if address: # Construct address_line, instead of assigning address to address_line directly, # because parse_address() also santizes the result. street, street_number, complement = parse_address(address) if street: address_line = street if street_number: address_line += ' ' + street_number if complement: address_line += complement # Make the full address. addresses = [] if address or result.get('city') or result.get( 'zipcode') or result.get('country'): addresses = [{ 'address': address_line, 'city': result.get('city'), 'country': result.get('country'), 'postal_code': result.get('zipcode'), }] # Get social media profiles. social_profiles = result.get('socialprofiles') # Group profiles by platform. # Disregards the other platforms provided by Dataprovider: Facebook, Google Plus and Pinterest. social_media = {} for profile in social_profiles: if profile.startswith('twitter.com/'): if 'twitter' not in social_media: social_media['twitter'] = [] social_media['twitter'].append(profile) elif profile.startswith('www.linkedin.com/in/'): if 'linkedin' not in social_media: social_media['linkedin'] = [] social_media['linkedin'].append(profile) primary_twitter = '' if 'twitter' in social_media: primary_twitter = self._get_primary_profile( social_media['twitter'], result.get('company')) primary_linkedin = '' if 'linkedin' in social_media: primary_linkedin = self._get_primary_profile( social_media['linkedin'], result.get('company')) # Build dict with account information. account_information = { 'name': result.get('company'), 'description': result.get('description'), 'tags': tags, 'email_addresses': emails[:email_limit], 'primary_email': primary_email, 'phone_numbers': phone_numbers[:phone_number_limit], 'phone_number': phone_number, 'addresses': addresses[:address_limit], 'legalentity': result.get('legalentity'), 'taxnumber': result.get('taxnumber'), 'bankaccountnumber': result.get('bankaccountnumber'), 'cocnumber': result.get('cocnumber'), 'iban': result.get('iban'), 'bic': result.get('bic'), 'social_media_profiles': social_media, 'twitter': primary_twitter, 'linkedin': primary_linkedin, } return account_information
def create(self, request, *args, **kwargs): """ Sends a websocket message to the user with the corresponding internal number """ response = super(CallViewSet, self).create(request, *args, **kwargs) called_user = LilyUser.objects.filter( internal_number=request.data['internal_number'], tenant_id=request.user.tenant_id ).first() if not called_user: return response caller_number = parse_phone_number(request.data['caller_number']) result = search_number(called_user.tenant_id, caller_number) search_data = result.get('data', {}) accounts = search_data['accounts'] contacts = search_data['contacts'] # If a single accounts with this number has been found, show information about and link to this account. if accounts and len(accounts) == 1: data = { 'destination': 'account', 'icon': static('app/images/notification_icons/account.png'), 'params': { 'name': accounts[0].name, 'number': caller_number, 'id': accounts[0].id, }, } # If there are also contacts, change the title. If there's only one contact, we prepend this contacts # name, else we append "Somebody from" if contacts: if len(contacts) > 1: data['params']['name'] = 'Somebody from %s' % data['params']['name'] else: data['params']['name'] = '%s from %s' % (contacts[0].full_name, data['params']['name']) # If there are contacts but no accounts, show information about and link to the first contact. elif contacts: data = { 'destination': 'contact', 'icon': static('app/images/notification_icons/contact.png'), 'params': { 'name': contacts[0].full_name, 'number': caller_number, 'id': contacts[0].id, }, } # If no account or contact has been found, use the name provided by VoIPGRID. else: data = { 'destination': 'create', 'icon': static('app/images/notification_icons/add-account.png'), 'params': { 'name': request.data.get('caller_name'), 'number': caller_number, }, } # Sends the data as a notification event to the user who picked up the phone. Group('user-%s' % called_user.id).send({ 'text': json.dumps({ 'event': 'notification', 'data': data, }), }) return response
def set_view_output(self): """ Create a generic json format for account information based on the json from Dataprovider. """ phone_number_limit = 5 email_limit = 5 address_limit = 3 # Expected api output is json self.api_output = json.loads(self.api_output) # Return 404 when the api returned an error if self.api_output.get("error"): raise Http404() # Return error message when nothing was found if self.api_output.get("total") == 0: raise Exception(_("I'm so sorry, I couldn't find any data for this website.")) # Filter useful data result = self.api_output["data"][0] # Get company name company = result.get("company") # Get website description description = result.get("description") # Get the keywords and convert to list tags = result.get("keywords") if tags: tags = result.get("keywords").strip().rstrip(",").split(",") # Get email addresses and convert to a list if needed emails = result.get("emailaddresses", []) or [] if not isinstance(emails, list): emails = [emails] # Determine primary email since Dataprovider doesn't provide it primary_email = None if emails: primary_email = self._get_primary_email(emails) # Set primary email to the first in the list emails.index(primary_email) emails.remove(primary_email) emails.insert(0, primary_email) # Limit number of emails emails = emails[:email_limit] phone_numbers = [] # Get primary phone number and convert to a nicer representation phone_number = result.get("phonenumber") if phone_number: phone_number = parse_phone_number(phone_number) phone_numbers.append(phone_number) # Get phone numbers and convert to list if needed raw_phone_numbers = result.get("phonenumbers", []) or [] if not isinstance(raw_phone_numbers, list): raw_phone_numbers = [raw_phone_numbers] # Convert all phone numbers to a nicer representation for raw_phone_number in raw_phone_numbers: phone_numbers.append(parse_phone_number(raw_phone_number)) # Limit number of phonenumbers phone_numbers = phone_numbers[:phone_number_limit] # Get what kind of company it is (e.g. LLC) legalentity = result.get("legalentity") # Get the VAT (Value Added Tax) identifaction number taxnumber = result.get("taxnumber") # Get bank account number bankaccountnumber = result.get("bankaccountnumber") # Get the CoC (Chamber of Commerce) number cocnumber = result.get("cocnumber") # Get the IBAN (Internation Bank Account Number) iban = result.get("iban") # Get the BIC (Bank Identifier Code) bic = result.get("bic") # Try to parse the address address = result.get("address") if address: street, street_number, complement = parse_address(address) else: street, street_number, complement = None, None, None # Make the full address addresses = [] if address or result.get("city") or result.get("zipcode") or result.get("country"): addresses = [ { "street": street, "street_number": street_number, "complement": complement, "city": result.get("city"), "country": result.get("country"), "postal_code": result.get("zipcode"), } ] addresses = addresses[:address_limit] # Build dict with account information self.view_output = { "name": company, "description": description, "tags": tags, "email_addresses": emails, "primary_email": primary_email, "phone_numbers": phone_numbers, "phone_number": phone_number, "addresses": addresses, "legalentity": legalentity, "taxnumber": taxnumber, "bankaccountnumber": bankaccountnumber, "cocnumber": cocnumber, "iban": iban, "bic": bic, } return json.dumps(self.view_output)