Uploading Item Image using Square Connect API - python

I've reviewed the examples posted in the Square Connect API documentation and the examples on GitHub, however, I can't seem to adapt these examples to the guidance on uploading images: http://docs.connect.squareup.com/#post-image
Part of the challenge is working with the Content-Type: multipart/form-data which only the image upload requires so the documentation is non-existent (with the connect-api docs).
My ultimate question is, can Square please post an example of how to upload images? Most relevant would be an example that shows how to update multiple items with images versus just one item. Any help is appreciated.

Thanks for pointing out this gap in the documentation. The function below uses the Requests Python library to upload an image for an item (this library makes multipart/form-data requests significantly simpler). Note that you'll need to install Requests first if you haven't.
import requests
def upload_item_image(item_id, image_path, access_token):
endpoint_path = 'https://connect.squareup.com/v1/' + your location + '/items/' + item_id + '/image'
# Don't include a Content-Type header, because the Requests library adds its own
upload_request_headers = {'Authorization': 'Bearer ' + access_token,
'Accept': 'application/json'}
# Be sure to set the correct MIME type for the image
files = [('image_data', (image_path, open(image_path, 'rb'), "image/jpeg"))]
response = requests.post(endpoint_path, files=files, headers=upload_request_headers)
# Print the response body
print response.text
item_id is the ID of the item you're uploading an image for.
image_path is the relative path to the image you're uploading.
access_token is the access token for the merchant you're acting on behalf of.
It isn't possible to upload images for multiple items in a single request to this endpoint. Instead, send a separate request for each item.

Related

perform download via download button when request_url in browser-inspect does not work

I have almost the question already posted and answered here:
Perform Download via download button in Python
I also followed the instructions, in the answer of the above link.
In my case I want to download the data from the following page:
https://www.smard.de/home/downloadcenter/download-marktdaten#!?downloadAttributes=%7B%22selectedCategory%22:1,%22selectedSubCategory%22:1,%22selectedRegion%22:%22DE%22,%22from%22:1658872800000,%22to%22:1659563999999,%22selectedFileType%22:%22CSV%22%7D
The download-button is the one called "Datei herunterladen" in the lower right corner.
I went into the inspect mode downloaded the file and got the following output in the inspection
But the resulting
Request URL: 'https://www.smard.de/nip-download-manager/nip/download/market-data'
does not help getting the csv-file. Opened in the browser I get: 'The requested URL was rejected.'
On the other hand, it does not even contain the parameters anymore, so it can't be the right download url.
May anyone help to automate this download?
edit
Now I also tried
url = 'https://www.smard.de/nip-download-manager/nip/download/market-data'
json_body = {'format': "CSV",
'language': "de",
'moduleIds': [1001224, 1004066, 1004067, 1004068, 1001223, 1004069, 1004071, 1004070, 1001226, 1001228, 1001227,1001225],
'region': "DE",
'timestamp_from': 1659304800000,
'timestamp_to': 1659391199999,
'type': "discrete"}
x = requests.post(url, json = json_body)
x.content
> b'Exception when parsing incoming request to JSON object.'
So how do I get the csv-file based on this method?
the reason that you're getting "URL Rejected" is because the link specified in the request is not file-specific. The link that the POST request is being made to, contains several files, which are given out based on the body that the request is sent with. If you look into the developer tools, you can see that there is a request payload attached to the request (image attached) . If you want to learn more about sending JSON body data with requests, please take a look at w3 and this thread. I hope that helps!
The json_body of the request-payload was not correct.
And I found an easy way to get the correct one with less effort and less probability to make it wrong.
In the inspect mode after the file is downloaded:
Click on the "Raw"-Button in the upper right corner of the "request"-tab, than you can get the correct payload per copy and paste.
The final solution is:
url = 'https://www.smard.de/nip-download-manager/nip/download/market-data'
payload = {"request_form":[{"format":"CSV","moduleIds":[1001224,1004066,1004067,1004068,1001223,1004069,1004071,1004070,1001226,1001228,1001227,1001225],"region":"DE","timestamp_from":1658872800000,"timestamp_to":1659563999999,"type":"discrete","language":"de"}]}
x = requests.post(url, json = payload)
with open(f'energy_ger.csv', 'wb') as f:
f.write(x.content)

Google Drive thumbnailLink returns 404

This method of getting Google Drive file thumbnails has been working for me but seems to have stopped recently.
All answers I can find online indicate that this is because thumbnailLink requires authorization (eg). However, I'm am accessing the thumbnails with authorized access tokens. I can get the file info using the Drive API "Files: get" with these access tokens but the thumbnailLink returns 404.
print(http)
# <google_auth_httplib2.AuthorizedHttp object at 0x11561d0f0>
# An instance of google_auth_httplib2.AuthorizedHttp
url = 'https://www.googleapis.com/drive/v3/files/%s?fields=thumbnailLink' % file_id
response, content = http.request(url)
data = json.loads(content)
print(data['thumbnailLink'])
# https://docs.google.com/u//feeds/vt?gd=true&id=***fileID***&v=203&s=***&sz=s220
# Works ✓
response, content = http.request(data['thumbnailLink'])
print(response['status'])
# 404
# :(
Also giving a 404 error:
thumbnailLink + "&access_token=" + YOURTOKEN; as suggested here.
Opening thumbnailLink in a browser (logged in to Google as the file owner).
Opening a modified thumbnailLink in a browser - replacing /u// with /u/0/, /u/1/ , /u/2/ (When I open drive as this user the URL is https://drive.google.com/drive/u/1/my-drive)
Does anyone know a reliable way to get Google Drive thumbnail image files?
I believe your goal as follows.
You want to retrieve the thumbnail from the thumbnail link retrieved by the method of "files.get" in Drive API.
From your sample thumbnail link, you want to retrieve the thumbnail from Google Docs (Document, Spreadsheet, and so on).
Issue and workaround:
In the current stage, it seems that the situation of 404 from the thumbnail is the bug. This has already been reported to the Google issue tracker. Ref And it seems that Google side has already been known. Unfortunately, I think that this is the current direct answer. And also, I believe that this issue will be resolved by the future update.
Here, as the current workaround, how about converting it to PDF file and retrieve the thumbnail? In this case, the thumbnail link can be used. The flow of this workaround is as follows.
Convert Google Docs to a PDF file.
The PDF file is created to the same folder of the Google Docs.
Retrieve the thumbnail link from the created PDF file.
When above flow is converted to the python script, it becomes as follows.
Sample script:
Before you use this script, please set the access token and file ID. In this case, in order to request multipart/form-data with the simple script, I used requests library.
import json
import httplib2
import requests
import time
http = httplib2.Http()
access_token = '###' # Please set the access token.
file_id = '###' # Please set the file ID.
headers = {"Authorization": "Bearer " + access_token}
# 1. Retrieve filename and parent ID.
url1 = "https://www.googleapis.com/drive/v3/files/" + file_id + "?fields=*"
res, res1 = http.request(url1, 'GET', headers=headers)
d = json.loads(res1.decode('utf-8'))
# 2. Retrieve PDF data by converting from the Google Docs.
url2 = "https://www.googleapis.com/drive/v3/files/" + file_id + "/export?mimeType=application%2Fpdf"
res, res2 = http.request(url2, 'GET', headers=headers)
# 3. Upload PDF data as a file to the same folder of Google Docs.
para = {'name': d['name'] + '.pdf', 'parents': d['parents']}
files = {
'data': ('metadata', json.dumps(para), 'application/json; charset=UTF-8'),
'file': res2
}
res3 = requests.post(
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart",
headers=headers,
files=files
)
obj = res3.json()
# It seems that this is required to use by creating the thumbnail link from the uploaded file.
time.sleep(5)
# 4. Retrieve thumbnail link of the uploaded PDF file.
url3 = "https://www.googleapis.com/drive/v3/files/" + obj['id'] + "?fields=thumbnailLink"
res, res4 = http.request(url3, 'GET', headers=headers)
data = json.loads(res4.decode('utf-8')) # or data = json.loads(res4)
print(data['thumbnailLink'])
# 5. Retrieve thumbnail.
response, content = http.request(data['thumbnailLink'])
print(response['status'])
print(content)
When you run this script, the Google Docs file is exported as the PDF data, and the PDF data is uploaded to Google Drive and retrieve the thumbnail link.
Note:
In this case, please include the scope of https://www.googleapis.com/auth/drive to the scopes of your access token. Because the file is uploaded.
In order to retrieve the file metadata and export the PDF file and upload the data, the access token is required to be used. But when the thumbnail is retrieved from the thumbnail link, the access token is not required to be used.
After January, 2020, the access token cannot be used with the query parameter of access_token=###.So please use the access token to the request header. Ref
When above issue was resolved, I think that you can use your script.
References:
Files: get
Files: export
Files: create

Python/GCP sanity check: is this correct means of referencing image stored in GCP Storage in a POST call

Scenario: an image file stored in a GCP bucket need to be sent to a third-party REST endpoint via a POST
Question: Is this really the best pattern? Is there a more efficient less verbose way?
We have images being uploaded by a mobile app to a GCP Storage bucket. When the finalize event for the image upload fires we have a GCP Cloud Function (Python 3) that reacts to this by getting ref to uploaded image, downloads it to a temp file, and then uses that temp file as the image source for the POST. This is our current code and it works, but to my eye seems convoluted with the multiple open commands. More specifically: is there a better way to simply get the image blob from GCP Storage and simply attach it to the POST call without first saving it as a local file and then opening it so it can be attached to the POST?
def third_party_upload(data, context):
# get image from bucket
storage_client = storage.Client()
bucket = storage_client.bucket(data['bucket'])
image_blob = bucket.get_blob(data['name'])
download_path = '/tmp/{}.jpg'.format(str(uuid.uuid4())) #temp image file download location
# save GCP Storage blob as a temp file
with open(download_path, 'wb') as file_obj:
image_blob.download_to_file(file_obj)
# open temp file and send to 3rd-party via rest post call
with open(download_path, 'rb') as img:
files = {'image': (data['name'], img, 'multipart/form-data', {'Expires': '0'}) }
headers = {
'X-Auth-Token': api_key,
'Content-Type': 'image/jpg',
'Accept': 'application/json'
}
# make POST call
response = requests.post(third_party_endpoint, headers=headers, files=files)
print('POST response:', response)
Update: a couple of commenters have mentioned that Signed URLs are a possibility and I agree they are an excellent choice. However we are stuck with a requirement to include the image binary as the POST body. Signed-URLs won't work in this case.
The HTTP method POST requires data. You must provide that data in the HTTP request. There is no magic method to obtain Cloud Storage data except to read it. The process is to read the data from Cloud Storage and then provide that data to the POST request.
If you're able to send a URL to the third-party endpoint instead of the actual image contents, you could use Signed URLs give time-limited access to the image without needing to provide the 3rd party access to the bucket or make the bucket public.
More information here: https://cloud.google.com/storage/docs/access-control/signed-urls

Cannot post images to Slack channel via web hooks utilizing Python requests

I'm attempting to post an image to a Slack channel utilizing web hooks. This basic setup has allowed me to post text to the channel, but I've been unable to post the image. Here's my code:
def posting():
import requests
import json
url = 'https://webhook'
image = {'media': open('trial.jpg', 'rb')}
r = requests.post(url, files=image)
r.json
When I post the text, a web hook bot appears in the channel and posts it. Do I need some further authentication to post? Or is it a matter of Slack having their own API for uploading and wants me to go through that? Or something something bots don't have rights to post images?
I took a look at some other questions here, but they didn't appear to be using web hooks or bots, so I'm not sure if my issue is something involving those.
You can do this through the Slack API using their files.upload method: https://api.slack.com/methods/files.upload
You will need an API auth token for this to work properly. You can set up a testing token or follow the instructions to register your program to get a long term one: https://api.slack.com/web#basics
Also, 'media' doesn't seem to be the right json key to use for file uploads:
http://docs.python-requests.org/en/master/user/quickstart/#post-a-multipart-encoded-file
Here's an example using requests to send an image to a channel. Use '#username' if you want the image to go to a specific user. I've included the content type and header but it should work without them as well.
This will print the response from Slack.
import requests
def post_image(filename, token, channels):
f = {'file': (filename, open(filename, 'rb'), 'image/png', {'Expires':'0'})}
response = requests.post(url='https://slack.com/api/files.upload', data=
{'token': token, 'channels': channels, 'media': f},
headers={'Accept': 'application/json'}, files=f)
return response.text
print post_image(filename='path/to/file.png', token='xxxxx-xxxxxxxxx-xxxx',
channels ='#general')

How to form an anonymous request to Imgur's APIv3

A while ago, I made a python function which took a URL of an image and passed it to Imgur's API v2. Since I've been notified that the v2 API is going to be deprecated, I've attempted to make it using API v3.
As they say in the Imgur API documentation:
[Sending] an authorization header with your client_id along with your requests [...] also works if you'd like to upload images anonymously (without the image being tied to an account). This lets us know which application is accessing the API.**
Authorization: Client-ID YOURCLIENTID
It's unclear to me (especially with the italics they put) whether they mean that the header should be {'Authorization': 'Client-ID ' + clientID}, or {'Authorization: Client-ID ': clientID}, or {'Authorization:', 'Client-ID ' + clientID}, or some other variation...
Either way, I tried and this is what I got (using Python 2.7.3):
def sideLoad(imgURL):
img = urllib.quote_plus(imgURL)
req = urllib2.Request('https://api.imgur.com/3/image',
urllib.urlencode([('image', img),
('key', clientSecret)]))
req.add_header('Authorization', 'Client-ID ' + clientID)
response = urllib2.urlopen(req)
return response.geturl()
This seems to me like it does everything Imgur wants me to do: I've got the right endpoint, passing data to urllib2.Request makes it a POST request according to the Python docs, I'm passing the image parameter with the form-encoded URL, I also tried giving it my client secret as a POST parameter since I got an error saying I need an ID (even though there is no mention of the need for me to use my client secret anywhere in the relevant documentation). I add the Authorization header and it seems to be the right form, so... why am I getting an Error 400: Bad Request?
Side-question: I might be able to debug it myself if I could see the actual error Imgur returns, but because it returns an erroneous HTTP status, Python dies and gives me one of those nauseating stack traces. Is there any way I could have Python stop whining and give me the error message JSON that I know Imgur returns?
Well, I'll be damned. I tried taking out the encoding functions and just straight up forming the string, and I got it to work. I guess Imgur's API expects the non-form-encoded URL?
Oh... or was it because I used both quote_plus() and url_encode(), encoding the URL twice? That seems even more likely...
This is my working solution, at long last, for something that took me a day when I thought it'd take an hour at most:
def sideLoad(imgURL):
img = urllib.quote_plus(imgURL)
req = urllib2.Request('https://api.imgur.com/3/image', 'image=' + img)
req.add_header('Authorization', 'Client-ID ' + clientID)
response = urllib2.urlopen(req)
response = json.loads(response.read())
return str(response[u'data'][u'link'])
It's not a final version, mind you, it still lacks some testing (I'll see whether I can get rid of quote_plus(), or if it's perhaps preferable to use url_encode alone) as well as error handling (especially for big gifs, the most frequent case of failure).
I hope this helps! I searched all over Google, Imgur and Stack Overflow and the information about anonymous usage of APIv3 were confusing (and drowned in a sea of utterly horrifying OAuth2 stuff).
In python 3.4 using urllib I was able to do it like this:
import urllib.request
import json
opener = urllib.request.build_opener()
opener.addheaders = [("Authorization", "Client-ID"+ yourClientId)]
jsonStr = opener.open("https://api.imgur.com/3/image/"+pictureId).read().decode("utf-8")
jsonObj = json.loads(jsonStr)
#jsonObj is a python dictionary of the imgur json response.

Categories