I've already asked the GAS community but I was advised to continue asking here...
So far I'm able to connect to BOX and get a list of files and I can download a file from BOX as well.
The whole idea is to download a file using BOX API, edit it and upload it back as a new file version using the BOX API.
I'm unable to make the last part working as it gives me error code 400.
Here is the function.
function uploadNewFileVersion() {
//767694355309 testing
var boxFileId="767694355309";
var newVerFile = DriveApp.getFileById("1sK-jcaJoD0WaAcixKtlHA85pf6t8M61v").getBlob();
var confirmAuthorization = getBoxService_().getAccessToken();
//var parent = { "id": "0" };
//"name": "apiNewVersion.xlsx",
//"parent": parent,
var payload = {
"file": newVerFile
}
var headers = {
'Authorization': 'Bearer ' + confirmAuthorization
}
var options = {
"method": "post",
"muteHttpExceptions": true,
"contentType": "multipart/form-data",
"headers": headers,
"payload": payload
}
var apiHtml = "https://upload.box.com/api/2.0/files/"+boxFileId+"/content/";
var response = UrlFetchApp.fetch(apiHtml, options);
Logger.log(response.getResponseCode());
var a = 1;
}
The boxFileId is the file on the box.
The newVerFile is the one downloaded from Box and updated. I need to make it as a new version of the Box file.
Could you please advise?
Thank you!
PEtr
I think parent and name is optional so I commented it out.
If I don't getBlob, then it returns 415 istead.
I believe your goal and situation as follows.
You want to upload a file of Google Drive using Box API with Google Apps Script.
From your question, I cannot find the official document of the method of API that you want to use. But, from the endpoint https://upload.box.com/api/2.0/files/"+boxFileId+"/content/ in your script, I guessed that you wanted to use "Upload file version".
Values of your access token and file ID are valid for using the API.
If my understanding of your question is correct, how about the following modification?
Modification points:
When I saw the official document of "Upload file version", I confirmed the following sample curl. In this case, it is considered that when the following curl command is converted to Google Apps Script, the request might work.
$ curl -i -X POST "https://upload.box.com/api/2.0/files/12345/content" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: multipart/form-data" \
-F attributes="{"name":"Contract.pdf", "parent":{"id":"11446498"}}" \
-F file=#<FILE_NAME>
From the curl command, it is found that attributes and file are sent as form and files.
And, I thought that attributes="{"name":"Contract.pdf", "parent":{"id":"11446498"}}" might should be attributes="{\"name\":\"Contract.pdf\", \"parent\":{\"id\":\"11446498\"}}".
When I saw your current script, it seems that multipart/form-data is used for contentType. In this case, boundary in the request body is required to be included. Fortunately, at UrlFetchApp, in the case of multipart/form-data, when contentType is not used, the content type is automatically included in the request header. I think that in your case, this can be used.
In your script, attributes="{"name":"Contract.pdf", "parent":{"id":"11446498"}}" is not included. But I thought that you might use it in the future script. So in this answer, this is also included.
When above points are reflected and the sample curl command on the official document is converted to Google Apps Script, the script becomes as follows.
Sample script:
Please copy and paste the following script to the script editor and set the variables, and run the function of myFunction. By this, the request same with the sample curl is requested with Google Apps Script.
function myFunction() {
const accessToken = "###"; // Please set your access token.
const fileId = "###"; // Please set your fileId.
const fileBlob = DriveApp.getFileById("1sK-jcaJoD0WaAcixKtlHA85pf6t8M61v").getBlob();
const metadata = {name: "Contract.pdf", parent: {id: "11446498"}}; // Please set your file metadata.
const params = {
method: "post",
headers: {Authorization: `Bearer ${accessToken}`},
payload: {
attributes: JSON.stringify(metadata),
file: fileBlob,
},
muteHttpExceptions: true,
};
const url = `https://upload.box.com/api/2.0/files/${fileId}/content`;
const res = UrlFetchApp.fetch(url, params);
console.log(res.getContentText());
}
I could confirm that above sample script is the same request with above sample curl.
If you don't want to use the file metadata, please remove the line of attributes: JSON.stringify(metadata), from payload.
Note:
In this case, the maximum data size ("URL Fetch POST size") of UrlFetchApp is 50 MB. Please be careful this. Ref
About the limitation of file upload of Box API, please check https://developer.box.com/guides/uploads/.
If your access token and file ID are invalid, I think that an error occurs. So please be careful this.
References:
Upload file version
Class UrlFetchApp
Related
I want to download file that can be in any format viz. pdf, jpeg, png, xlsx, csv etc. The download API on backend using pyramid framework is sending FileResponse as below:
def delivery_item_download_view(request, *args, **kw):
context = request.context
item_row = context.item_row
if item_row and item_row["deleted_at"] is None:
print(request.upload_dir+'/'+item_row["file_name"]+'.'+item_row["file_extension"])
response = FileResponse(
request.upload_dir+'/'+item_row["file_name"]+'.'+item_row["file_extension"],
request=request,
)
response.headers["attachment"] = item_row["name"];
return response
This, when executed using POSTMAN works as expected giving file as output. However,when tried implementing same using ReactJS, it's not working as expected. My client-code is as below:
onDownloadItem= (item) => {
console.log("item id is:", item.item_id)
var apiBaseUrl = "https://dev.incodax.com/api/deliveries_items/"+ item.item_id+ "/download";
fetch(apiBaseUrl, {
method: "GET",
}).then((res) => {
fileDownload(res,item.file_name)
console.log(res)
})
}
This fileDownload function simply downloading file but with no content inside. In downloaded file I could see something like:
[object Response]
I am getting 200 response from server. So I dont't think there is any issue with server side code. How can I handle it on client?
Thanks in advance
Will it suit you if you just redirected user to link to file? Browser will automatically handle it and download it.
The issue is in your fileDownload function which you do not post here. It's not clear what the first parameter is supposed to be but likely it is not the response object. Likely you at least need to pull the body out of the response and save that! The response body can be converted to a buffer object which could work (again it depends on what fileDownload is expecting):
res.arrayBuffer().then(buffer => {
fileDownload(buffer, item.file_name);
});
I am trying to upload image to my FTP.
what i have achived so far is in this plnkr
my cordova file transfer looks like
$scope.upload =function(){
var options = {
fileKey: "file",
fileName: "gopi",
chunkedMode: false,
mimeType: "image/jpeg",
params : {'user_token':'Chandru#123', 'user_email':'wepopusers'} // directory represents remote directory, fileName represents final remote file name
};
console.log(options);
$cordovaFileTransfer.upload('ftp://308.3d8.myftpupload.com/', MyService.getImgPath(), options)
.then(function(result) {
// Success!
console.log(result);
console.log("SUCCESS: " + JSON.stringify(result.response));
alert('ftp success');
}, function(err) {
// Error
console.log(err);
alert('ftp fail');
console.log("ERROR: " + JSON.stringify(err));
}, function (progress) {
// constant progress updates
console.log(progress);
});
};
My response of my error function for cordova file looks like
FileTransferError {code: 2, source: "file:///storage/sdcard0/Android/data/com.ionicframework.camera108827/cache/1462186990291.jpg", target: "ftp://308.3d8.myftpupload.com/", http_status: null, body: null…}body: nullcode: 2exception: nullhttp_status: nullsource: "file:///storage/sdcard0/Android/data/com.ionicframework.camera108827/cache/1462186990291.jpg"target: "ftp://308.3d8.myftpupload.com/"proto: Object
I have button TakePicture which will take the pic and show to the user and also I have a function to upload using cordovafiletransfer $scope.upload .
my ftp host is ftp://308.3d8.myftpupload.com/ username and password is given in my coding in this i have a folder name called gopi where my image should store.
my path of the image taken is in imageURI parameter so i used services to set the path.
steps I’m in confusion
1) I am not able to understand the var options object in cordova file transfer plugin.
2) I am not getting any erro while remote debugging but i am only invoking my error funtion in my cordova file transfer.
How can i update my taken image to FTP using IONIC
UPDATE
Thanks to gandhi's answer https://github.com/xfally/cordova-plugin-ftp some how i managed to connect to ftp without multipart.
but sill facing error in this
$window.cordova.plugin.ftp.upload("/ping", "/gopi/ping", function(percent) {
i don't know what to in the first argument and second.
$window.cordova.plugin.ftp.upload("/default.prop", "/gopi/default.prop", function(percent) {
the above line success fully posted to my ftp but i am not able to post my image which is stored in my ping variable.
https://plnkr.co/edit/ETGmdl4B0d5dlHWdJQ9m?p=info
The answer to your first question is available in the official documentation of file transfer plugin. The excerpt is as follow,
options: Optional parameters (Object). Valid keys:
fileKey: The name of the form element. Defaults to file. (DOMString)
fileName: The file name to use when saving the file on the server. Defaults to image.jpg. (DOMString)
httpMethod: The HTTP method to use - either PUT or POST. Defaults to POST. (DOMString)
mimeType: The mime type of the data to upload. Defaults to image/jpeg. (DOMString)
params: A set of optional key/value pairs to pass in the HTTP request. (Object, key/value - DOMString)
chunkedMode: Whether to upload the data in chunked streaming mode. Defaults to true. (Boolean)
headers: A map of header name/header values. Use an array to specify more than one value. On iOS, FireOS, and Android, if a header named Content-Type is present, multipart form data will NOT be used. (Object)
Check out this link for more info.
For your second question, try getting the error code in the error callback function and try to narrow down the problem.
Update: I guess ftp upload is not possible using file transfer plugin. The plugin definition itself states "The FileTransfer object provides a way to upload files using an HTTP multi-part POST or PUT request, and to download files"
You may have to look at this for ftp client for ftp uploads.
I am generating in server side a pre-signed URL request with the following parameters for GeneratePresignedUrlRequest : bucket, key, expiration = in 1 hour and method = PUT.
In my Angular app, I am uploading the file using ng-file-upload
Upload.http({
url: $scope.signedUrl,
method: "PUT",
headers : {
'Content-Type': $scope.file.type
},
data: $scope.file
});
The problem is that I always have a 403 response unless I set the type of the file in GeneratePresignedUrlRequest.contentType.
The problem is that I can't predict in advance what type of file the user will choose (image/png, image/jpeg, text/plain...).
How can I generate a pre-signed url that accept all kinds of content-type ? I tried setting it to null, it keeps sending 403 errors.
Thanks.
I just ran into this problem, and just got it working. Replace your Upload.http code with the following:
var reader = new FileReader();
var xhr = new XMLHttpRequest();
xhr.open("PUT", $scope.signedUrl);
reader.onload = function(evt) {
xhr.send(evt.target.result);
};
reader.readAsArrayBuffer($scope.file);
The problem ends up being that S3 is looking for a specific Content-Type (binary/octet-stream), which it infers when you omit the Content-Type header.
The value from the Content-Type header is a mandatory component of the signature. It isn't possible to pre-sign a PUT URL without knowing the value that will be sent.
A POST upload is more flexible, since you can allow any Content-Type in the signed policy.
One possible solution might be if you keep track of the extension?
eg: ends with ".jpg" -> content type = "image/jpeg", end with ".zip" -> content type = "application/octet-stream".
Ref: get the filename of a fileupload in a document through javascript
I am trying to do HTTP post to a google form, from a C program in my device. For a legacy form, the active form submission URL looks like below. I used these text to do a URL encoded HTTP/1.1 POST, which was successful.
https://spreadsheets.google.com/formResponse?formkey=FORMKEY&ifq&entry.0.single=ENTRY1&entry.2.single=ENTRY2&submit=Submit
For the new google form (whichever you create from google drive now), below is the active submit URL. When I use this for HTTP post, I get the Bad Request with error Code 400.
https://docs.google.com/forms/d/FORMKEY/formResponse?entry.1252261890=ENTRY1&entry.1890412746=ENTRY2
What has changed between old and new google form? I see similar problem faced by somebody elsewhere but no solution so far. Thanks for your help.
This is a javascript (google apps script) POST that is working on a current form (with one field!) Pperhaps you can get what you need from this:
function sendHttpPost() {
var fish = "I am a mackerel";
var payload =
{
"entry.2071121932" : fish
};
// Because payload is a JavaScript object, it will be interpreted as
// an HTML form. (We do not need to specify contentType; it will
// automatically default to either 'application/x-www-form-urlencoded'
// or 'multipart/form-data')
var options =
{
"method" : "POST",
"payload" : payload,
"muteHttpExceptions": true
};
var response = UrlFetchApp.fetch("https://docs.google.com/forms/d/this is the form ... key/formResponse", options);
Logger.log(response.getContentText())
}
All the documentation I have found related to creating a new file and putting the new file in a user's Google Drive folder is achieved with the user uploading a file and having the python script use MediaFileUpload to gather the file and put it in Drive.
I want to create a new file in my GAE code, and put that. For example my code renders a new XML string after hitting database, and I would like to take that string, make it a file and put in Google Drive.
Anyone working with something like this?
You should use a MediaInMemoryUpload instead, which is designed for this exact purpose. You can pass a string and a MIME type.
media = MediaInMemoryUpload('some data', 'text/plain')
Use following code, content is the string you're going to put. You don't have to use MediaFileUpload and python client library.
def update(content, file_id):
url = 'https://www.googleapis.com/upload/drive/v2/files/%s?uploadType=media' % file_id
headers = {
'Content-Type': 'text/plain',
'Content-Length': str(len(content)),
'Authorization': 'Bearer <oauth2 token>'
}
response = urlfetch.fetch(url, payload=content, method='PUT', headers=headers)
assert response.status_code == 200
return response.content