HubSpot API - Search contact by phone - api

I understand that HubSpot api provides an endpoint to search contact by name or email?
Is there a way to search a contact by phone number with the API?

For an online tool with a free trial, you can try Acho. Our company uses it to fetch data from HubSpot and use its built-in search bar to search for a specific contact that we need.

Below Python code works on my side.
This page looks very useful.
Cheers!
import hubspot
from pprint import pprint
from hubspot.crm.deals import PublicObjectSearchRequest, ApiException
api_key = "your api key"
test_search_url = f'https://api.hubapi.com/crm/v3/objects/contact/search?hapikey='+api_key
headers = {"Content-Type": "application/json"}
payload = {
"filterGroups": [
{
"filters": [
{
"propertyName": "phone",
"operator": "EQ",
"value": "1234567"
}
]
}
],
"properties": [
"firstname", "lastname", "email", "hs_object_id"
]
}
res = requests.post(test_search_url, headers=headers, data=json.dumps(payload))
res.json()
####Output####
# {'total': 1,
# 'results': [{'id': '13701',
# 'properties': {'createdate': '2022-02-10T07:27:18.733Z',
# 'email': 'adi#XXX.com',
# 'firstname': 'XXX K.',
# 'hs_object_id': '13701',
# 'lastmodifieddate': '2022-02-10T07:28:01.033Z',
# 'lastname': None},
# 'createdAt': '2022-02-10T07:27:18.733Z',
# 'updatedAt': '2022-02-10T07:28:01.033Z',
# 'archived': False}]
# }

I have a function for exactly that written in Python.
The function returns an array of contact's IDs, but you can retrieve other properties if you want, you have to add them in properties=["id"]
from hubspot import HubSpot
from hubspot.crm.contacts import ApiException
from hubspot.crm.contacts import PublicObjectSearchRequest
def get_contacts_by_phone(phone):
api_client = HubSpot()
api_client = HubSpot(access_token=YOUR_TOKEN)
public_object_search_request = PublicObjectSearchRequest(
filter_groups=[],
sorts=[{"propertyName": "phone", "direction": "DESCENDING"}],
properties=["id"],
query=phone,
limit=100,
)
try:
api_response = api_client.crm.contacts.search_api.do_search(
public_object_search_request=public_object_search_request
)
print(api_response)
contacts_ids = []
for contact in api_response.results:
contacts_ids.append(contact.id)
return contacts_ids
except ApiException as e:
print("Exception when calling search_api->do_search: %s\n" % e)

Related

drf-yasg Swagger documentation does not recognize authorized users

I've set up DRF-YASG documentation for my Django project, but the endpoints that require authentication show no parameters (fields to fill) even when logged as an authorized user.
swagger ui
In fact, none of my endpoints show their respective parameter fields in the UI.
Here are my REST_FRAMEWORK settings in settings.py :
REST_FRAMEWORK = {
"NON_FIELD_ERRORS_KEY": "errors",
"DEFAULT_AUTHENTICATION_CLASSES":(
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.TokenAuthentication"
),
"DEFAULT_PERMISSON_CLASSES":(
"rest_framework.permissions.IsAuthenticated"
)
}
and urls.py:
from django.contrib import admin
from django.urls import path, include, re_path
from EmployeeApp import views
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
schema_view = get_schema_view(
openapi.Info(
title="Snippets API",
default_version='v1',
description="Test description",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="contact#snippets.local"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=[permissions.AllowAny],
)
urlpatterns = [
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0),
name='schema-json'),
path('', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
path('admin/', admin.site.urls),
path('', views.api_home),
path('api/', include('EmployeeApp.urls')),
path('api/auth/', include('accounts.urls')),
]
I am using standard token authentication and here are my views.
from django.contrib.auth import authenticate
from .serializers import SignUpSerializer, UserSerializer
from rest_framework import generics, status
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.views import APIView
from drf_yasg.utils import swagger_auto_schema
class SignUpView(generics.GenericAPIView):
serializer_class = SignUpSerializer
def post(self, request: Request):
data = request.data
serializer = self.serializer_class(data=data)
if serializer.is_valid():
serializer.save()
response = {
"message": "User Created Successfully",
"data": serializer.data
}
return Response(data=response, status=status.HTTP_201_CREATED)
return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class LoginView(APIView):
#swagger_auto_schema(request_body=UserSerializer)
def post(self, request: Request):
email = request.data.get('email')
password = request.data.get('password')
user = authenticate(email=email, password=password)
if user:
response = {
"message": "Login Successful",
"token": user.auth_token.key
}
return Response(data=response, status=status.HTTP_200_OK)
else:
return Response(data={"message": "Invalid username or password"},
status=status.HTTP_401_UNAUTHORIZED)
def get(self, request: Request):
content = {
"user": str(request.user),
"auth": str(request.auth)
}
return Response(data=content, status=status.HTTP_200_OK)
In Postman everything works as expected, but in the Swagger documentation the authenticated user is not being recognized and the parameter fields on endpoints are missing.
Not sure if these two issues are connected, but I would apprechiate any type of helpful input on this!
I have tested the endpoints with direct Postman requests and everything works as expected.
Here is the endpoint to Create(POST) a company as a logged User:
class CompanyCreate(APIView):
permission_classes = [IsAuthenticated]
#swagger_auto_schema(
operation_summary="Create a company",
operation_description="This allows logged-in user to create a company"
)
def post(self, request):
company_name_exists = Companies.objects.filter(company_name=request.data['company_name']).exists()
if company_name_exists:
raise ValidationError("Company with the same name already exists")
data = {**request.data, 'user_id': request.auth.user_id}
serializer = CompanySerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
and it's serializer:
class CompanySerializer(serializers.ModelSerializer):
user_id = serializers.IntegerField(write_only=True)
class Meta:
model = Companies
fields = ('user_id', 'company_name', 'company_description', 'company_logo')
def create(self, validated_data):
company, is_created = Companies.objects.get_or_create(
company_name=validated_data['company_name'],
company_description=validated_data['company_description'],
company_logo=validated_data['company_logo'],
user_id=validated_data['user_id'],
)
return company
I've attached `
#swagger_auto_schema(request_body=UserSerializer)
`
to my login endpoint and it gives me a filed to put the request body data in a JSON format.
enter image description here
that works, but it still does not show the Swagger UI parameter fields and the auth does not persist when I try to test endpoints that require it.

Add value to select list in Jira cloud using python and API

I'm trying to add new values to a multiple select custom field.
I'm getting 401 response.
The code taken from Atlassian documentation .
Anyone knows why? maybe it is something with the authentication method?
import requests
from requests.auth import HTTPBasicAuth
import json
customers_id = "10163"
contextId = "int64"
url = "https://MY_DOMAIN.atlassian.net/rest/api/3/field/{customers_id}/context/{contextId}/option"
auth = HTTPBasicAuth("MY_EMAIL", "MY_API_TOKEN")
headers = {
"Accept": "application/json",
"Content-Type": "application/json"
}
payload = json.dumps( {
"options": [
{
"disabled": "false",
"value": "Manhattan"
},
{
"disabled": "false",
"value": "The Electric City"
}
]
} )
response = requests.request(
"POST",
url,
data=payload,
headers=headers,
auth=auth
)
print(json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",",": ")))
You have "int64" which is a string, it should be 12345 or whatever your contextID is.
There might be something else going on here also:
401 is Returned if the authentication credentials are incorrect or missing.
Is this your own Jira Cloud instance or one managed by someone else as you need the following permissions - Permissions required: Administer Jira global permission. So you may not have sufficient rights to make this call?

How to customize URI in Scrapy with non built in storage URI parameters

I want to customize the Scrapy feed URI to s3 to include the dimensions of the uploaded file. Currently I have the following in settings.py file:
FEEDS = {
's3://path-to-file/file_to_have_dimensions.csv': {
'format': 'csv',
'encoding': 'utf8',
'store_empty': False,
'indent': 4,
}
}
But would like to have something like the following:
NUMBER_OF_ROWS_IN_CSV = file.height()
FEEDS = {
f's3://path-to-files/file_to_have_dimensions_{NUMBER_OF_ROWS_IN_CSV}.csv': {
'format': 'csv',
'encoding': 'utf8',
'store_empty': False,
'indent': 4,
}
}
Note that I would like the number of rows to be inserted automatically.
Is this possible to do this solely through changing settings.py, or is it required to change other parts of the scrapy code?
The feed file is created when the spider starts running at which point the number of items is not yet know. However, when the spider finishes running, it calls a method named closed from which you can access the spider stats, settings and also you can perform any other tasks that you want to run after the spider has finished scraping and saving items.
In the case below i renamed the feed file from intial_file.csv to final_file_{item_count}.csv.
As you cannot rename files in s3,I use the boto3 library to copy the initial_file to a new file and name it with the item_count value included in the file name and then delete the initial file.
import scrapy
import boto3
class SampleSpider(scrapy.Spider):
name = 'sample'
start_urls = [
'http://quotes.toscrape.com/',
]
custom_settings = {
'FEEDS': {
's3://path-to-file/initial_file.csv': {
'format': 'csv',
'encoding': 'utf8',
'store_empty': False,
'indent': 4,
}
}
}
def parse(self, response):
for quote in response.xpath('//div[#class="quote"]'):
yield {
'text': quote.xpath('./span[#class="text"]/text()').extract_first(),
'author': quote.xpath('.//small[#class="author"]/text()').extract_first(),
'tags': quote.xpath('.//div[#class="tags"]/a[#class="tag"]/text()').extract()
}
def closed(self, reason):
item_count = self.crawler.stats.get_value('item_scraped_count')
try:
session = boto3.Session(aws_access_key_id = 'awsAccessKey', aws_secret_access_key = 'awsSecretAccessKey')
s3 = session.resource('s3')
s3.Object('my_bucket', f'path-to-file/final_file_{item_count}.csv').copy_from(CopySource = 'my_bucket/path-to-file/initial_file.csv')
s3.Object('my_bucket', 'path-to-file/initial_file.csv').delete()
except:
self.logger.info("unable to rename s3 file")

Resolve Discord-Tag get Discord-ID programmatically

I want to add a function to my userprofiles where users can enter their discord tag and if they do so, I want to resolve this to a link to their discordprofile so that users only have to click on the discordtag to open the profile in discord.
For that I need the ID. What Request do I need to send to the discord api in order to get the user ID for the entered tag?
After some experiments with discord friend sending. I found out that you can actually obtain user the user ID by sending friend request.
Here's how:
Make a add request friend request to example#1234
Make another request to the relationship(AKA friend) list to get all pending "friends" with ID, username, avatar... This list actually contains all of the actual friends from the person that sent a friend request.
To find the requested username in the friend list, all you need is a loop searching for the corresponding username + discriminator.
Output the ID(if that's what you wanted), after the username and discriminator match.
Delete the pending request.
Here's a python script I wrote that will output the ID of the user with inputs of username, discriminator, and an user token(used for sending an authorized friend request):
import requests
import json
# inputs
username = 'asdf'
discriminator = '1234'
TOKEN = 'ONLY USER TOKEN'
url = 'https://discord.com/api/v8/users/#me/relationships'
headers = {
"authorization": TOKEN
}
# setting up a payload for sending friend request.
payload = {
'username': username,
'discriminator': discriminator
}
requests.post(url, json=payload, headers=headers) # step 1
result = requests.get(url, headers=headers).json() # step 2
if hasattr(result, 'message'):
print('Invalid user token')
else:
user_id = None
for client in result: # step 3: a loop for finding the the username in the friend list
if f'{client["user"]["username"]}#{client["user"]["discriminator"]}' == f'{username}#{discriminator}':
user_id = client['id'] # step 4: save the user ID after finding it in the friend list
break
if user_id is None: # if no match is found then the user with that username and discriminator does not exist.
print('user not found')
else:
url = f'https://discord.com/api/v8/users/#me/relationships/{user_id}'
requests.delete(url, headers=headers) # step 5: delete the pending request
print(user_id) # print out the user ID
And here's the data structure of the requested json from step 2:
[
{
"id": "12345678901",
"type": 1,
"nickname": null,
"user": {
"id": "12345678901",
"username": "example1",
"avatar": "1234567890abcdef",
"discriminator": "1234",
"public_flags": 123
}
},
{
"id": "12345678902",
"type": 1,
"nickname": null,
"user": {
"id": "12345678902",
"username": "example2",
"avatar": "1234567890abcdef",
"discriminator": "1234",
"public_flags": 123
}
},
{
"id": "12345678903",
"type": 1,
"nickname": null,
"user": {
"id": "12345678903",
"username": "example3",
"avatar": "1234567890abcdef",
"discriminator": "1234",
"public_flags": 123
}
}
]
Downside:
You have to use an user token for sending the friend request.
Updates:
10/4/2020: Added in error detection for invalid token and invalid username.

How to send POST request?

I found this script online:
import httplib, urllib
params = urllib.urlencode({'number': 12524, 'type': 'issue', 'action': 'show'})
headers = {"Content-type": "application/x-www-form-urlencoded",
"Accept": "text/plain"}
conn = httplib.HTTPConnection("bugs.python.org")
conn.request("POST", "", params, headers)
response = conn.getresponse()
print response.status, response.reason
302 Found
data = response.read()
data
'Redirecting to http://bugs.python.org/issue12524'
conn.close()
But I don't understand how to use it with PHP or what everything inside the params variable is or how to use it. Can I please have a little help with trying to get this to work?
If you really want to handle with HTTP using Python, I highly recommend Requests: HTTP for Humans. The POST quickstart adapted to your question is:
>>> import requests
>>> r = requests.post("http://bugs.python.org", data={'number': '12524', 'type': 'issue', 'action': 'show'})
>>> print(r.status_code, r.reason)
200 OK
>>> print(r.text[:300] + '...')
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>
Issue 12524: change httplib docs POST example - Python tracker
</title>
<link rel="shortcut i...
>>>
This is a solution without any external pip dependencies, but works only in Python 3+ (Python 2 won't work):
from urllib.parse import urlencode
from urllib.request import Request, urlopen
url = 'https://httpbin.org/post' # Set destination URL here
post_fields = {'foo': 'bar'} # Set POST fields here
request = Request(url, urlencode(post_fields).encode())
json = urlopen(request).read().decode()
print(json)
Sample output:
{
"args": {},
"data": "",
"files": {},
"form": {
"foo": "bar"
},
"headers": {
"Accept-Encoding": "identity",
"Content-Length": "7",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "Python-urllib/3.3"
},
"json": null,
"origin": "127.0.0.1",
"url": "https://httpbin.org/post"
}
You can't achieve POST requests using urllib (only for GET), instead try using requests module, e.g.:
Example 1.0:
import requests
base_url="www.server.com"
final_url="/{0}/friendly/{1}/url".format(base_url,any_value_here)
payload = {'number': 2, 'value': 1}
response = requests.post(final_url, data=payload)
print(response.text) #TEXT/HTML
print(response.status_code, response.reason) #HTTP
Example 1.2:
>>> import requests
>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.post("http://httpbin.org/post", data=payload)
>>> print(r.text)
{
...
"form": {
"key2": "value2",
"key1": "value1"
},
...
}
Example 1.3:
>>> import json
>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}
>>> r = requests.post(url, data=json.dumps(payload))
Use requests library to GET, POST, PUT or DELETE by hitting a REST API endpoint. Pass the rest api endpoint url in url, payload(dict) in data and header/metadata in headers
import requests, json
url = "bugs.python.org"
payload = {"number": 12524,
"type": "issue",
"action": "show"}
header = {"Content-type": "application/x-www-form-urlencoded",
"Accept": "text/plain"}
response_decoded_json = requests.post(url, data=payload, headers=header)
response_json = response_decoded_json.json()
print(response_json)
Your data dictionary conteines names of form input fields, you just keep on right their values to find results.
form view
Header configures browser to retrieve type of data you declare.
With requests library it's easy to send POST:
import requests
url = "https://bugs.python.org"
data = {'#number': 12524, '#type': 'issue', '#action': 'show'}
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept":"text/plain"}
response = requests.post(url, data=data, headers=headers)
print(response.text)
More about Request object: https://requests.readthedocs.io/en/master/api/
If you don't want to use a module you have to install like requests, and your use case is very basic, then you can use urllib2
urllib2.urlopen(url, body)
See the documentation for urllib2 here: https://docs.python.org/2/library/urllib2.html.
You can use the request library to make a post request.
If you have a JSON string in the payload you can use json.dumps(payload) which is the expected form of payload.
import requests, json
url = "http://bugs.python.org/test"
payload={
"data1":1234,'data2':'test'
}
headers = {
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers, data=json.dumps(payload))
print(response.text , response.status_code)