$.ajax inside BeforeUpload Event - Plupload - javascript

This app is an image uploading tool that uploads images directly from client browser to Amazon S3 using Plupload. So far, everything is working good except this issue.
I've this code forBeforeUpload event.
init: {
BeforeUpload: function (up, file) {
$.ajax({
url: '/ServerTime.ashx',
dataType: 'text',
data: { format: "yyyy-MM-dd_HH.mm.ss.fffffff" },
type: 'POST',
cache: false
}).done(function (data) {
console.log("Before setting ImageName: " + data);
imageName = data + ".JPG";
console.log("After setting ImageName: " + imageName);
up.settings.multipart_params = {
'key': key,
'Filename': imageName,
'acl': 'public-read',
'success_action_status': '201',
'AWSAccessKeyId': accessKey,
'policy': policyDocument,
'signature': policySignature
};
});
}
}
However, I've this error when try to upload a file:
HTTP Error. Upload URL might be wrong or doesn't exist.
On Console, it is printing the expected result as follows:
Before setting ImageName: 2014-04-04_13.33.45.1155072
After setting ImageName: 2014-04-04_13.33.45.1155072.JPG
I guess there is something wrong maybe because I'm using AJAX to get time from server. On the other hand, trying the following code is working without any issue.
init: {
BeforeUpload: function (up, file) {
up.settings.multipart_params = {
'key': "This_Is_Folder_Name/This_Is_File_Name.JPG",
'Filename': "This_Is_File_Name.JPG",
'acl': 'public-read',
'success_action_status': '201',
'AWSAccessKeyId': accessKey,
'policy': policyDocument,
'signature': policySignature
};
}
}
Notice that, this time I'm using static names for Filename and key, and there is no AJAX either
I really need help with this issue. Please suggest me. What I'm doing wrong with using AJAX to get server time and use it as file name?
Thanks.

You might be able to override some of their code by doing the following:
init: {
BeforeUpload: function (up, file) {
$.ajax({
url: '/ServerTime.ashx',
dataType: 'text',
data: { format: "yyyy-MM-dd_HH.mm.ss.fffffff" },
type: 'POST',
cache: false
}).done(function (data) {
console.log("Before setting ImageName: " + data);
imageName = data + ".JPG";
console.log("After setting ImageName: " + imageName);
up.settings.multipart_params = {
'key': key,
'Filename': imageName,
'acl': 'public-read',
'success_action_status': '201',
'AWSAccessKeyId': accessKey,
'policy': policyDocument,
'signature': policySignature
};
file.status = plupload.UPLOADING;
up.trigger("UploadFile", file);
});
return false;
}
}
This would cancel their trigger, so you would have to trigger it yourself. Please note, I have not tested this.
EDIT: I'm not sure if up and file are out of scope though...

If you look in the Plupload source code you'll see this:
// Private methods
function uploadNext() {
var file, count = 0, i;
if (this.state == plupload.STARTED) {
// Find first QUEUED file
for (i = 0; i < files.length; i++) {
if (!file && files[i].status == plupload.QUEUED) {
file = files[i];
if (this.trigger("BeforeUpload", file)) {
file.status = plupload.UPLOADING;
this.trigger("UploadFile", file);
}
} else {
count++;
}
}
// All files are DONE or FAILED
if (count == files.length) {
if (this.state !== plupload.STOPPED) {
this.state = plupload.STOPPED;
this.trigger("StateChanged");
}
this.trigger("UploadComplete", files);
}
}
}
The line that says if (this.trigger("BeforeUpload", file)) { will determine whether the return of the trigger call is truthy or falsy. If truthy, it will next trigger "UploadFile". What that means is that the uploading of the file does not wait for asynchronous code to execute in your BeforeUpload function. As soon as that function returns, the upload can begin. Any async ajax call you make inside your BeforeUpload function will resolve after "UploadFile" is triggered.

Related

How to upload files & Get the public url Google Drive Api?

I create a simple website for Uploading files on Google Drive using Google Drive Api.
This is My Code :
$.ajax({
type: "POST",
beforeSend: function(request) {
request.setRequestHeader("Authorization", "Bearer" + " " + localStorage.getItem("accessToken"));
},
url: "https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart&fields=webViewLink",
data:{
uploadType:"media"
},
xhr: function () {
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) {
myXhr.upload.addEventListener('progress', that.progressHandling, false);
}
return myXhr;
},
success: function (data) {
console.log(data);
},
error: function (error) {
console.log(error);
},
async: true,
data: formData,
cache: false,
contentType: false,
processData: false,
timeout: 60000
});
};
Upload.prototype.progressHandling = function (event) {
var percent = 0;
var position = event.loaded || event.position;
var total = event.total;
var progress_bar_id = "#progress-wrp";
if (event.lengthComputable) {
percent = Math.ceil(position / total * 100);
}
// update progressbars classes so it fits your code
$(progress_bar_id + " .progress-bar").css("width", +percent + "%");
$(progress_bar_id + " .status").text(percent + "%");
};
$("#upload").on("click", function (e) {
var file = $("#files")[0].files[0];
var upload = new Upload(file);
// maby check size or type here with upload.getSize() and upload.getType()
// execute upload
upload.doUpload();
});
});
Everything is Oky, But I just want to get the public URL of The files 😭 I just want to show the public url after file uploaded. Help Me Please
after upload the file and getting the fileId:
async function generatePublicUrl(fileId) {
try {
await drive.permissions.create({
fileId: fileId,
requestBody: {
role: "reader",
type: "anyone",
},
});
const result = await drive.files.get({
fileId: fileId,
fields: "webViewLink, webContentLink",
});
return result;
} catch (err) {
console.log(err);
}
}
and after doing that you just put your fileId in the format:
https://drive.google.com/file/d/"yourfileId"/preview
The Google Drive api does not have a method for creating the sharable link.
You will need to manually go to the Google drive website and create your sharable link there and store it in your system.

Populating a dropzone with files from the server - async

I'm trying to populate my dropzone with files I'm getting from the server. I found this post which seems to do what I want, however it seems I can only call this addCustomFile function while in the init function, and not later after I've asychronisily received my data from the server (with the list of files associated with the object I'm viewing).
Dropzone.options.imageDrop = {
url: "upload.php",
previewTemplate: previewTemplate,
params: { taskId: urlParams.get('id')},
init: function() {
this.addCustomFile = function(file, thumbnail_url , response){
this.files.push(file);
this.emit("addedfile", file);
this.emit("thumbnail", file, thumbnail_url);
this.emit("processing", file);
this.emit("success", file, response , false);
this.emit("complete", file);
}
this.addCustomFile ({ //THIS WORKS
processing: true,
accepted: true,
name: "The name",
size: 12345,
type: 'image/jpeg',
status: Dropzone.SUCCESS
}, "fine.jpg", {
status: "success"
})
}
}
let imageDropZone = $("#imageDrop").dropzone();
imageDropZone.addCustomFile ({ //THIS DOESN'T WORK - addCustomFile is not a function
processing: true,
accepted: true,
name: "The name",
size: 12345,
type: 'image/jpeg',
status: Dropzone.SUCCESS
}, "fine.jpg", {
status: "success"
})
Any thoughts on how to best modify this so I can call it in a async function after the dropzone has been created?
I was able to resolve this using promises. I had to define a variable for a promise as well as one for the data that would both be in scope across the code. Then create the promise during the init and resolve it inside my other async call. Updated code below:
var imageLoadDefer; //Variable that will get a promise
var slowLoaded; //Variable that will get loaded with data async
Dropzone.options.imageDrop = {
url: "upload.php",
previewTemplate: previewTemplate,
params: { taskId: urlParams.get('id')},
init: function() {
this.addCustomFile = function(file, thumbnail_url , response){
this.files.push(file);
this.emit("addedfile", file);
this.emit("thumbnail", file, thumbnail_url);
this.emit("processing", file);
this.emit("success", file, response , false);
this.emit("complete", file);
}
//Create the promise using jQuery
imageLoadDefer =$.Deferred();
//Important: Make sure to put this into a variable that can be used in the following function
var imDrop = this;
imageLoadDefer.always(function(){
//promise is resolved and variable is now populated
imDrop.addCustomFile ({ //THIS WORKS NOW, ASYNC
processing: true,
accepted: true,
name: slowLoaded.name,
size: slowLoaded.size,
type: 'image/jpeg',
status: Dropzone.SUCCESS
}, slowLoaded.thumbnail, {
status: "success"
});
});
}
}
let imageDropZone = $("#imageDrop").dropzone();
$.getJSON('images.json', function (data) {
slowLoaded = data;
imageLoadDefer.resolve(); //data loaded so resolve image promise
}

Send file from javascript to Python via Ajax

I'm having a problem sending a file object to python through an ajax call.
I'm using Dropzone just as my "file uploader interface" and I'm sending a call when certain button is pressed.
In python when I try to process the file, it says " 'str' object has no attribute 'seek' "
My JS Code:
...
window.$form_add_file = $("#form_add_file");
var file = dropzone.files[0];
...
var formData = $form_add_file.serializeArray();
if(file){
$modal_add_file.find($drop_add_file).removeClass("error");
var filetype = file.type.split("/")[0].toLowerCase();
var hasFile = checkFileType(filetype);
if(!hasFile) { filetype = "file" }
formData.push(
{ name: "file", value: file },
{ name: "file_type", value: filetype },
{ name: "file_name", value: file.name },
{ name: "file_size", value: file.size }
);
} else {
error = true;
$modal_add_file.find($drop_add_file).addClass("error");
return false;
}
if(!error){
$.ajax({
method: "POST",
url: host + "json.references.new",
data: formData,
cache: false,
dataType: 'json',
success: function(data){
if(data){
if(data.error){
modalMessage($modal_add_file, data.error, "ok");
} else {
refreshData(data);
}
}
},
error: function(error){
modalMessage($modal_add_file, oops_message, "ok");
}
});
}
My Python Code:
try:
file_path = os.path.join(path, file_name)
temp_file_path = file_path + '~'
file.seek(0) # error happen here
with open(temp_file_path, 'wb') as output_file:
shutil.copyfileobj(file, output_file)
os.rename(temp_file_path, file_path)
I've been searching for this on the internet and found nothing yet.
Sorry for the poor english.
Thanks in advance!
seek is a method for file objects, not strings.
I think your code snippet is missing some lines, but if file is supposed to be the file pointed to by file_path then you should first open the file with file = open(file_path, 'rb'). New file objects should start reading at the 0th position, so file.seek(0) should be unnecessary.

unit testing file upload in angular

I am using the nf-file-upload module to upload a file to my backend. The code for the file upload is as follows:
$scope.upload = function (file) {
console.log(file)
Upload.upload({
url: 'http://localhost:3000/fileupload',
data: {file: file[0]},
}).then(function (resp) {
console.log('Success ' + resp.config.data.file.name + ' uploaded. Response: ' + resp.data);
}
The file uploading works great. however, when I create my unit test:
it('should send file to backend for processing', function(){
var mockFile = {file:[{"name":"file.bin", "size":1018, "type":"application/binary"}]};
httpBackend.when('POST', 'http://localhost:3000/fileupload').respond(200, {"filePath":"http://localhost:3000/uploads/file.txt"});
scope.upload(mockFile);
httpBackend.flush();
});
I get an error:
TypeError: undefined is not an object (evaluating 'resp.config.data.file.name')
What am I doing wrong?
The then method using the resp argument. In the normal conditions, you'll receive a object that have the structure:
{
config:{
data: {
file:{
name: 'a name'}
}
}
}
but in your test you don't respond with the same structure.
EDIT:
Ok. I got this. the way that ng-file-uploader returns the data it's not mockable. You don't get the name of the file in the resp.data.config.file.name, Instead, saves the filename in a variable before upload the file.
Like this:
$scope.upload = function (file) {
var fileName = file.name;
Upload.upload({
url: 'http://localhost:3000/fileupload',
data: {file: file[0]},
})
.then(function (resp) {
console.log('Success ' + fileName + ' uploaded. Response: ' + resp.data);
});
};
Check this codepen codepen.io/gpincheiraa/pen/MyrvQK Good luck!
You need to run a digest cycle.
it('should send file to backend for processing', function(){
var mockFile = {file:[{"name":"file.bin", "size":1018, "type":"application/binary"}]};
httpBackend.when('POST', 'http://localhost:3000/fileupload').respond(200, {"filePath":"http://localhost:3000/uploads/file.txt"});
scope.upload(mockFile);
httpBackend.flush();
scope.$digest();
});
This will resolve the promise and trigger the return data.

How to add headers at runtime in fine uploader

I am using fine uploader for uploading file on server, For this I need to make 2 web api calls.
On button click, First web api saving value and returning result in integer, and I need to pass that integer result in header for each file while uploading.
But I am not able to pass values in headers,
code,
uploader = new qq.FineUploader({
element: $('#manual-fine-uploader1')[0],
request: {
endpoint: Url.AddEvaluationFiles,
},
autoUpload: false,
text: {
uploadButton: '<i class="icon-plus icon-white"></i> Select Files'
},
debug: true,
callbacks: {
onSubmit: function (id, fileName) {
},
onStatusChange: function (id, oldStatus, newStatus) {
if (newStatus == "uploading") {
alert("Add header");
}
},
onUpload: function (id, name) {
alert("Onupload");
this.append("RequestId", $("#ReqId").val());
}
}
});
I am calling upload function in success block of first request,
$.ajax({
type: "POST",
url: Url.Details,
data: fileData,
async: false,
success: function (result) {
if (result == 0) {
toastr.error("Please pass user id");
} else {
$("#ReqId").val(result);
alert($("#ReqId").val());
uploader.uploadStoredFiles();
}
},
error: function (err) {
toastr.error("Not able to upload art details");
}
});
Here I want to pass RequestId header in onUpload event, but it's not working, What changes I need to make to make it happen.
The request option has a customHeaders property, that allows you to set any custom header.
Your constructor call should look something like
artistmanualuploader = new qq.FineUploader({
...
request: {
endpoint: "FoaUrl.AddEvaluationFiles",
customHeaders: {
"EvaluationRequestId": $("#CurrentEvaluationReqId").val()
}
},
...
});

Categories

Resources