I am trying to upload an image to Etsy through the API. However, the example on their website is given in PHP which I don't know how to code. I only know how to work with Python. On their website it says:
Image uploads can be performed using a POST request with the Content-Type: multipart/form-dataheader, following RFC1867.
Their example which is in PHP
// You must define the constants OAUTH_CONSUMER_KEY and OAUTH_CONSUMER_SECRET
// You must also assign values to the variables $access_token, $access_token_secret,
// $listing_id and $filename, and $mimetype.
// Your image file is assumed to be in the same directory as this code.
$oauth = new OAuth(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET);
$oauth->enableDebug();
$oauth->setToken($access_token, $access_token_secret);
try {
$source_file = dirname(realpath(__FILE__)) ."/$filename";
$url = "https://openapi.etsy.com/v2/listings/".$listing_id."/images";
$params = array('#image' => '#'.$source_file.';type='.$mimetype);
$oauth->fetch($url, $params, OAUTH_HTTP_METHOD_POST);
$json = $oauth->getLastResponse();
print_r(json_decode($json, true));
} catch (OAuthException $e) {
// You may want to recover gracefully here...
print $oauth->getLastResponse()."\n";
print_r($oauth->debugInfo);
die($e->getMessage());
}
In API doc it says
HTTP Method = POST
URI = /listings/:listing_id/images
This is what I have so far in Python:
client_secret=client_secret,resource_owner_key=resource_owner_key,resource_owner_secret=resource_owner_secret)
url = 'https://openapi.etsy.com/v2/listings'
payload = {'listing_id':'2343432434', 'images': :('test1.jpg', open('test1.jpg', 'rb'), 'image/jpeg')}
result = etsy.post(uri, params=payload)
When I run this code I get an 403 error. How can I fix my code so that it functions correctly? I have looked at other examples and just can't seem to make it work.
Related
I have a web application in which a map is being displayed. Right now all the markers are being passed via one API (http:3000/example) created in a node/express server. My goal is to read the user location that is retrieved from the frontend and use that as part of the query params to respond with only a selection of markers for the map based on algorithm written in python.
Main.js (Frontend)
async function callAPIAndUpdateMap(queryParams) {
const api = `http://localhost:3000/example?lat=${userCurrentPosition.lat}&lng=${userCurrentPosition.lng}${queryParams}`;
const listExampleEndpoint = new URL(api);
const response = await fetch(listExampleEndpoint);
exampleList = await response.json();
//todo: check if we need to remove all markers and put the updated new ones
let markers = drawMarkers();
new markerClusterer.MarkerClusterer({
map,
markers,
});
}
The function is called with params if selected by the user further down in the main.js file
function confirmFilter() {
appliedFilters = unconfirmedFilters;
let queryParams = ``;
appliedFilters.forEach((element) => {
queryParams += `&${element}=true`;
});
callAPIAndUpdateMap(queryParams);
let filterWrapper = document.getElementById("filter-wrapper");
filterWrapper.classList.add("hidden");
let filterButton = document.getElementById("filter-button");
let resetFilterIcon = document.getElementById("reset-filter");
if (appliedFilters.length != 0) {
filterButton.classList.add("active-map-button");
resetFilterIcon.classList.remove("hidden");
resetFilterIcon.classList.add("active-icon");
} else {
filterButton.classList.remove("active-map-button");
resetFilterIcon.classList.add("hidden");
resetFilterIcon.classList.remove("active-icon");
}
}
I am honestly a bit lost on how to read this request from a python file and then respond with data back. I have though about two different methods but I am not sure either would work.
Flask
I read the API get request using flask and respond directly in the python file
Python file triggered from Node.js
I read the get request from the Python file and apply the Algorithm and print a JSON dump that is triggered from a Node File
Python file that I am working with at the moment
import sys
import json
import requests
url = "http://3000/example"
r = requests.get(url, params=location)
data = r.json()
resp = {
"Response": 200,
"Message": "hello from Python File",
"Data":data
}
print(json.dumps(resp))
# using system module in python to send to node js
sys.stdout.flush()
The problem statement I have in hand is, I am trying to automate the process of downloading reports from Power BI and send it to the various WhatsApp contacts with the help of Python.
Is this possible?
I found the Microsoft REST APIs which can be used to download the reports but I am getting lost in trying to configure my credentials and other things.
Check the reply in the following case Power BI API - How can I get reports from app.powerbi.com?
If you want to do this using an API, you will need Export Report In Group REST API. To use it, you need to acquire an access token and add it to your request header. You can acquire it by calling some of the AcuireToken methods from ADAL.
You can use code like this (please note there is no error checking in the example):
string clientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; // Obtain at https://dev.powerbi.com/apps
string redirectUri = "https://login.live.com/oauth20_desktop.srf";
string resourceUri = "https://analysis.windows.net/powerbi/api";
string authorityUri = "https://login.windows.net/common/oauth2/authorize";
AuthenticationContext authContext = new AuthenticationContext(authorityUri, new TokenCache()); // PM> Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory
var authenticationResult = await authContext.AcquireTokenAsync(resourceUri, clientId, new Uri(redirectUri), new PlatformParameters(PromptBehavior.Auto));
var accessToken = authenticationResult.AccessToken);
string powerBIApiUrl = "https://api.powerbi.com/v1.0/myorg/groups/{groupId}/reports/{reportKey}/Export"; // Replace groupId and reportKey with actual values
var request = WebRequest.Create(powerBIApiUrl) as HttpWebRequest;
request.KeepAlive = true;
request.Method = "GET";
request.ContentLength = 0;
request.ContentType = "application/json";
request.Headers.Add("Authorization", $"Bearer {accessToken}");
using (HttpWebResponse httpResponse = request.GetResponse() as System.Net.HttpWebResponse)
{
//Read httpResponse.GetResponseStream() to get the .pbix file
}
Also, there are other useful links:
https://community.powerbi.com/t5/Developer/Power-BI-REST-API-using-postman-generate-embed-token/m-p/310153#M9157
https://www.sqlshack.com/how-to-access-power-bi-rest-apis-programmatically/
I'm trying to replace a Google slides shape filled with a placeholder text with an image via API. The image in question is allocated in a team Drive unit. I've read several solutions like this and this, and I have tried to set the permissions in the image as "reader" and "anyone with link", both via API and manually, and nothing works. I get a "Access to the provided image was forbidden" error everytime. However, I can download the image wihout problems via API and without giving extra permissions.
I'm using v3 of the Drive API and v1 for Slides API.
Below is the code I'm using:
def replace_shape_with_image(slides_service, url, presentation_id, contains_text):
requests = [
{
"replaceAllShapesWithImage": {
"imageUrl": url,
"replaceMethod": "CENTER_INSIDE",
"containsText": {
"text": "{{" + contains_text + "}}",
}
}
}]
body = {
'requests': requests
}
response = slides_service.presentations().batchUpdate(presentationId=presentation_id,body=body).execute()
return response
def create_public_permissions(drive_service, file_id):
request = drive_service.permissions().create(
fileId=file_id,
supportsAllDrives=True,
fields='id, type, role',
body={
'role':'reader',
'type':'anyone'
}
)
response = request.execute()
return response
file_id = '123'
presentation_id = '789'
# drive_service = etc
# slides_service = etc
create_public_permissions(drive_service, file_id) # Here I put the actual service object and file ID. Manually verified and it works
url = f'https://drive.google.com/uc?export=download&id={file_id}'
# also tried url = https://drive.google.com/uc?id={file_id}&export=download
replace_shape_with_image(slides_service, url, presentation_id, 'test') # shape in slide has "test" as text
The following error is returned:
googleapiclient.errors.HttpError: <HttpError 400 when requesting
https://slides.googleapis.com/v1/presentations/1cDSov4IKFHSyzaXjFYNYPB7EYlMMtInamYv0AwXiazw:batchUpdate?alt=json
returned "Invalid requests[0].replaceAllShapesWithImage: Access to the
provided image was forbidden.">
For downloading the file I use this code, which works without problem:
import io
from googleapiclient.http import MediaIoBaseDownload
tmp_file_path = r'C:\Users\me\tmp\testimage.png'
fh = io.FileIO(tmp_file_path, 'wb')
downloader = MediaIoBaseDownload(fh, request)
done = False
while done is False:
status, done = downloader.next_chunk()
I know there have been changes in the Drive API recently (over the last year), and most questions about this are old and the solutions are deprecated, and more recent ones doesn't seem to work for me. Any ideas in how to solve this issue, if possible?
Thanks in advance!
It's known issue: https://issuetracker.google.com/issues/150933939
As it was happening with one of our projects, we figured out that error is thrown not for all Google Drive images, but for random ones when using replaceAllShapesWithImage Slides API request.
Only possible workaround is to wrap your requests code in try / catch and use some placeholder image in case replaceAllShapesWithImage requests are keep failing.
Example code (in Google Apps Script):
var slideImageNotFoundPlaceholder = 'https://example.com/../placeholder.png';
try {
Slides.Presentations.batchUpdate({'requests': slidesReqs}, presentationFileId);
}
catch(err)
{
// loop all requests
for (var i = 0; i < slidesReqs.length; i++)
{
// update replaceAllShapesWithImage requests
if (slidesReqs[i].replaceAllShapesWithImage)
{
// replace with image not found placeholder
slidesReqs[i].replaceAllShapesWithImage.imageUrl = slideImageNotFoundPlaceholder;
}
}
Slides.Presentations.batchUpdate({'requests': slidesReqs}, presentationFileId);
}
It is not perfect solution, but all other requests are getting executed, so you won't have your presentations being totally failed.
P.S. hopefully Google will fix Google Drive images being used in Slides API, so "star" the issue linked in the beginning of the answer to make it happen faster.
I am trying to upload a file using python requests to my java/scala spring rest server. I am getting the following response:
{"timestamp":1454331913056,"status":400,"error":"Bad Request","exception":"org.springframework.web.bind.MissingServletRequestParameterException","message":"Required MultipartFile parameter 'image' is not present","path":"/parking_api/images"}
my server code:
#RequestMapping(value = Array("/parking_api/images"), method = Array(RequestMethod.POST)) def images(#RequestParam("image") image: MultipartFile) = {
if (image.isEmpty){
// handle empty
new ResponseEntity(response, HttpStatus.BAD_REQUEST
} else {
// process
new ResponseEntity(response, HttpStatus.OK)
}
}
My client code:
requests.post(parking_webservice_address, files={"image": ("image", open(event.pathname, "rb"), "image/jpeg")})
I have tried:
setting files parameter in python code to just {"image":open(...)} instead of tuple
passing image data loaded to memory using open(...).read() to files parameter in python code
setting CommonsMultipartResolver in server like this
#Bean(name="multipartResolver")
public CommonsMultipartResolver multipartResolver(){
return new CommonsMultipartResolver();
}
setting multipart headers manually, but then it server expects boundary which is missing as things get from bad to worse
None of these options have worked for me. What am I missing?
I spent all this morning looking for a clear example on how to upload a picture taken with an iPhone to the blobstore, but without succeed.
Currently I have my iPhone app developed, which can send pics to the server in PHP, with this code in the server:
// Function to upload a photo in a file and save data in the DB
function upload($photoData, $descr, $phone) {
// Folder to upload data
$path = $_SERVER['DOCUMENT_ROOT']."/program/data/";
// Check if there was no error during the file upload
if ($photoData['error'] == 0) {
$result = query("INSERT INTO pics(descr, phone) VALUES('%s','%s')", $descr, $phone);
if (!$result['error']) {
// Inserted in the database, go on with file storage
// Obtain database link (in lib.php)
global $link;
// Get the last automatically generated ID
$idPhoto = mysqli_insert_id($link);
// Move the temporarily stored file to a convenient location
if (move_uploaded_file($photoData['tmp_name'], $path.$idPhoto.".jpg")) {
// File moved, all good, generate thumbnail
thumb($path.$idPhoto.".jpg", 180);
print json_encode(array('successful' => 1));
} else {
errorJson('Upload on server problem');
}
} else {
errorJson('Save database problem: '.$result['error']);
}
} else {
errorJson('Upload malfunction.');
}
}
The part in Objective-C that makes this works is (I'm using AFNetworking and the object API sharedInstance is an AFJSONRequestOperation class):
// Upload the image and the description to the web service
[[API sharedInstance] commandWithParams:[NSMutableDictionary dictionaryWithObjectsAndKeys:
#"upload", #"command",
UIImageJPEGRepresentation(originalPhoto, 70), #"file",
description, #"descr",
phoneNumber, #"phone",
nil]
onCompletion:^(NSDictionary *json) {
// Finished and response from server
if (![json objectForKey:#"error"]) {
// Success
[[[UIAlertView alloc]initWithTitle:#"Info"
message:#"Thanks"
delegate:nil
cancelButtonTitle:#"Dismiss"
otherButtonTitles: nil] show];
// Send a notification so the main view can reload the data
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateStream" object:nil];
} else {
// Error
NSString* errorMsg = [json objectForKey:#"error"];
[UIAlertView error:errorMsg];
}
}];
This works fine and the images are saved on the server. But I want to make the same with datastore, which you can't save files. So I made a webpage to practice on save images, and I can upload images without any problem in the blobstore from an standard web form. This is the code I'm using to save it in GAE (forget about my own helper classes or functions like PicturePageHandler or render_page):
# Get and post for the create page
class Create(PicturePageHandler, blobstore_handlers.BlobstoreUploadHandler):
def get(self):
if self.user_logged_in():
# The session for upload a file must be new every reload page
uploadUrl = blobstore.create_upload_url('/addPic')
self.render_page("addPicture.htm", form_action=uploadUrl)
def post(self):
if self.user_logged_in():
# Create a dictionary with the values, we will need in case of error
templateValues = self.template_from_request()
# Test if all data form is valid
testErrors = check_fields(self)
if testErrors[0]:
# No errors, save the object
try:
# Get the file and upload it
uploadFiles = self.get_uploads('picture')
# Get the key returned from blobstore, for the first element
blobInfo = uploadFiles[0]
# Add the key and the permanent url to the template
templateValues['blobKey'] = blobInfo.key()
templateValues['servingUrl'] = images.get_serving_url(blobInfo.key(), size=None)
# Save all
pic = Picture.save(self.user.key, **templateValues)
if pic is None:
logging.error('Picture save error.')
self.redirect("/myPics")
except:
self.render_page("customMessage.htm", custom_msg=_("Problems while uploading the picture."))
else:
# Errors, render the page again, with the values, and showing the errors
templateValues = custom.prepare_errors(templateValues, testErrors[1])
# The session for upload a file must be new every reload page
templateValues['form_action'] = blobstore.create_upload_url('/addPic')
self.render_page("addPicture.htm", **templateValues)
My questions are:
Can I still using my Objective-C JSON call to upload a picture to the server or must I completely change the way to upload the picture?
How can I change the Python server code to get the picture from the JSON, if it is possible?
It's not exactly what you're after, but this might help:
http://brunofuster.wordpress.com/2011/03/11/uploading-an-image-from-iphone-to-appengine-blobstore-using-vraptor/