i have a grid with an toolbar and on that toolbar an upload option is added, so the upload is alright and it works , but after the file was uploaded to the server the success function does not react.
here my upload code:
upload: function () {
Ext.create('Ext.window.Window', {
title: 'Upload',
width: 300,
layout: 'fit',
draggable: false,
resizable: false,
modal: true,
bodyPadding: 5,
items: [{
xtype: 'form',
bodyPadding: 10,
frame: true,
items: [{
xtype:'filefield',
name:'file',
fieldLabel: 'File',
buttonText: 'Select File',
labelWidth: 30,
anchor: '100%'
}, {
xtype: 'button',
text: 'Upload',
handler: function(){
var form = this.up('form').getForm();
if(form.isValid()){
form.submit({
method: 'POST',
url: 'http://localhost:3000/upload',
success: function (form, action) {
Ext.Msg.alert('Success', 'Your File has been uploaded.');
console.log(action);
},
failure : function (form,action) {
Ext.Msg.alert('Error', 'Failed to upload file.');
}
})
}
}
}]
}],
}).show();
},
});
and the server response :
app.post('/upload', function(req, res) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Content-Type','application/json; charset=UTF8');
var tmp_path = req.files.file.path;
var newPath = __dirname + '/files/' + req.files.file.name;
fs.rename(tmp_path, newPath, function (err){
if (err) throw err;
});
var path = newPath;
var name = req.files.file.name;
connection.query('SELECT name FROM audio WHERE name = ?', [name] , function(err,result) {
if (result[0]) {
console.log('File already exist');
res.status(400).send(JSON.stringify());
} else {
connection.query('INSERT INTO audio (name, path) VALUES (?,?)', [name,path], function (err,result) {
if (err) throw err;
var test = {
success: true
};
res.send({success:true});
console.log('success');
});
}
});
});
i can provide more code if necessary, thanks in advance
The error message is explicit: your response is lost due to cross-domain iframe issue.
See the doc explanation of how file upload form are handled: a hidden iframe is created to receive the response from the server (because, before HTML5 it was not possible to upload a file using XHR). When the iframe is loaded, Ext parses its content to read the response.
But, it is only allowed for a page to manipulate its iframes content if both are on the same domain, including the port number.
Most probably you're accessing your page at http://localhost/, while you're posting your form to http://localhost:3000. So forbidden: error, and no response for you!
This is a Ext js bug identified by Uberdude in the Sencha Forum.
Description of the problem :
When you make an Ext.Ajax.request with a form containing a file input to be uploaded, or manually set the isUpload option to true, rather than doing a proper Ajax request Ext submits the form in the standard HTML way to a dynamically generated hidden . The json response body is then read out of the iframe to create a faked-up Ajax response. A problem arises if the page making the upload Ajax request has changed its document.domain property, e.g. a page at home.example.com includes resources from static.example.com which it wishes to manipulate with javascript without violating the browser's same-origin-policy, so both set their document.domain to "example.com". If home.example.com then makes an upload Ajax request to a url on the home.example.com server, the iframe into which the response is written will have its document.domain as "home.example.com". Thus when the ExtJS code within Ajax.request on the home.example.com page tries to extract the document body from the iframe, it will be blocked by the same-origin-policy and the response passed to the callback functions will incorrectly have empty responseText.
Work Around :
1. Pass the document.domain to the server when making the upload request.
2. In your server response, add the document.domain in your response text/html.
response.setHeader('Content-Type', 'text/html');
response.write('document.domain = "' + params.__domain + '";');
response.write(JSON.stringify({msg: 'Welcome ' + params.name}));
response.end('');
Detail :
Please refer to :
http://www.sencha.com/forum/showthread.php?136092-Response-lost-from-upload-Ajax-request-to-iframe-if-document.domain-changed
Related
I'm using the below function in Jenkins Shared Library.
/* The below function delete uploads that exist in the server. */
def delete_upload(server_url,each_upload_id,authentication){
def delete_upload_url = server_url + "/api/v1/uploads/" + each_upload_id
def response = httpRequest consoleLogResponseBody: true,
contentType: 'APPLICATION_JSON',
customHeaders: [[maskValue: false, name: 'id ', value: each_upload_id],
[maskValue: false, name: 'Authorization', value: authentication]],
httpMode: 'DELETE', ignoreSslErrors: true, responseHandle: 'NONE', url: delete_upload_url,
validResponseCodes: '100:599'
if(response.status == 202){
def result = readJSON text: """${response.content}"""
return result['message'].toString()
}
else {
throw new Exception("Incorrect upload id! Please give the correct upload id.")
}
}
====================================================================================================
I'm getting below response,
Response Code: HTTP/1.1 202 Accepted
Response:
{"code":202,"message":"Delete Job for file with id 2","type":"INFO"}
Success: Status code 202 is in the accepted range: 100:599
====================================================================================================
Purpose: I'm using the above JSL function to delete a uploads in the web server using upload id.
Requirement:
I need to delete multiple uploads by using multiple upload id's (like each_upload_id in 1,2,3 etc) using this JSL delete function.
Need to pass the upload id's in loops and delete the uploads in the web server.
Any suggestions, please ?
Are you looking for something like this?
def idList = ["1", "2", "3"]
try {
idList.each{ id =>
delete_upload(server_url,id,authentication)
}
} catch(e) {
println "Error occurred!"
}
I intend to download a dynamically generated pdf file using a remote method, the file exists at a particular path and I am using return type "file". My implementation is:
customer.downloadFile = function downloadFile(userId, res, cb){
var reader = fs.createReadStream(__dirname + '/../document.pdf');
cb(null, reader, 'application/pdf');
};
customer.remoteMethod(
'downloadFile',
{
isStatic: true,
accepts: [
{ arg: 'id', type: 'string', required: true },
{ arg: 'res', type: 'object', 'http': { source: 'res' } }
],
returns: [
{ arg: 'body', type: 'file', root: true },
{ arg: 'Content-Type', type: 'string', http: { target: 'header' } }
],
http: {path: '/:id/downloadFile', verb: 'get'}
}
);
The issue with the above code is that the browser although displays the beautiful pdf file container, but instead of the file following error is shown:
Please point out as to what is wrong with the code and how to correct.
Got lead from this URL: https://github.com/strongloop/loopback-swagger/issues/34
Got that working with following:
fs.readFile(fileName, function (err, fileData) {
res.contentType("application/pdf");
res.status(200).send(fileData);
if (!err) {
fs.unlink(fileName);
}
else {
cb(err);
}
});
You should use loopback-component-storage to manage downloadable files.
Files are grouped in so-called containers (Basically, a folder with a single level of hierarchy, not more).
How it is done:
Create a model called container for instance.
Create a storage datasource that uses as connector the loopback-component-storage
Give to container model the datasource storage
That's it. You can upload and download files to/from your container.
With a container, you can store files to a local filesystem, or move later to Cloud solutions.
Hi I am working on upload feature which has been done successfully using fine uploader, but for new functionality for edit i searched for same plugin and found that session can handle this functionality.
but i am not getting view of image in fine uploader section as below is the view i am getting.
I am passing name,uuid and thumbnailUrl as response.
Edited:
At Server Side:
List<PropertyImageEntity> propertyImageEntity=propertyService.getImagesUrlNames(Integer.parseInt(request.getParameter("id")),Constant.PROP_VAL);
for(PropertyImageEntity propertyImagesDetails: propertyImageEntity)
{
ImageDataResponse imageResponseData=new ImageDataResponse();
imageResponseData.setName(propertyImagesDetails.getFilename());
String test=String.valueOf(UUID.randomUUID());
imageResponseData.setUuid(this.uuid);
imageResponseData.setId(String.valueOf(propertyImagesDetails.getImageid()));
imageResponseData.setSize(propertyImagesDetails.getSize());
imageResponseData.setStatus("upload successful");
imageResponseData.setThumbnailUrl(propertyImagesDetails.getUrl());
imageResponse.add(imageResponseData);
}
at client side:
var manualUploader1 = new qq.FineUploader(
{
element : document
.getElementById('fine-uploader-manual-trigger1'),
template : 'qq-template-manual-trigger1',
request : {
endpoint : '/server/uploads?${_csrf.parameterName}=${_csrf.token}&id=${id}'
},
thumbnails : {
placeholders : {
waitingPath : '../assets/js/property/fileupload/placeholders/waiting-generic.png',
notAvailablePath : '../assets/js/property/fileupload/placeholders/not_available-generic.png'
}
},
validation : {
allowedExtensions : [ 'png', 'jpeg', 'jpg' , 'gif'],
itemLimit : 6,
sizeLimit : 100000000
},
autoUpload : false,
debug : true,
callbacks: {
onError: function(id, name, errorReason, xhrOrXdr) {
$("#errorMsg4").html(errorReason);
}
},
session: {
endpoint: '/server/get?id=${id}',
params: {},
customHeaders: {},
refreshOnReset: true
},
messages: {
typeError: jQuery.i18n.prop("invalid.extention.error"),
sizeError: jQuery.i18n.prop("upload.filesize.error"),
noFilesError: jQuery.i18n.prop("nofiles.toupload.error"),
tooManyItemsError: jQuery.i18n.prop("toomany.items.error"),
retryFailTooManyItems: jQuery.i18n.prop("retry.fail.error")
}
});
qq(document.getElementById("trigger-upload1")).attach("click",
function() {
$("#errorMsg4").html("");
manualUploader1.uploadStoredFiles();
});
but response for image url in console showing 200 ok.
Response:
[{"name":"b.png","uuid":"e3a5581e-aee9-4b8d-813f-63e0d400c9bc","thumbnailUrl":"http://192.168.1.68/html/1465290007617b.png","id":"84","size":26507,"status"
:null}]
Console Log:
The above problem was solved by adding cors headers in apache2.conf.
Header set Access-Control-Allow-Origin "*"
Thanks to #Ray for his answer on this post.
I am using Plupload js plugin to upload multiple images in one request. This plugin is working like if someone adding 5 images at a time then post request will go 5 times to upload each of images separately. As we know Post request require unique csrf token but in my case due to same token after one time, post request is failing.
Here is my code ...
<c:set var="csrfTokenVal"><csrf:token-value uri="<%=request.getRequestURI()%>"/></c:set>
<script>
var csrftokenV="${csrfTokenVal}";
$("#uploader").plupload({
// General settings
runtimes : 'html5,flash,silverlight,html4',
url:'/view/SurgeryNotesComponentController?uploadSurgeryImage=true&'+csrftokenN+'='+csrftokenV,
// User can upload no more then 20 files in one go (sets multiple_queues to false)
max_file_count: 10,
chunk_size: '1mb',
// Resize images on clientside if we can
resize : {
width : 600,
height : 610,
quality : 90,
//crop: true // crop to exact dimensions
},
filters : {
// Maximum file size
max_file_size : '1mb',
// Specify what files to browse for
mime_types: [
{title : "Image files", extensions : "jpg,gif,png"},
{title : "Zip files", extensions : "zip"}
]
},
// Rename files by clicking on their titles
rename: true,
// Sort files
sortable: true,
// Enable ability to drag'n'drop files onto the widget (currently only HTML5 supports that)
dragdrop: true,
// Views to activate
views: {
list: true,
thumbs: false, // Show thumbs
active: 'thumbs'
},
init: {
FilesAdded: function(up, files) {
$("#uploader_filelist").show();
},
FileUploaded: function(up, file, info, res) {
var imageObjectArray=$.parseJSON(info.response);
for(i=0;i<imageObjectArray.objectList.length; i++){
$('#showfilelist ul').append("<li><a class='delIcon-image' href='#delete' id='delSurgeryImageIcon'></a><a id=" + imageObjectArray.objectList[i].uid + " class='cboxElement imguid' href='${contextPath}/view/SurgeryNotesComponentController?surgeryImage=true&"+csrftokenN+ "="+ csrftokenV+"&attachmentLocation="+imageObjectArray.objectList[i].attachmentLocation+"' target='_blank'><img src='${contextPath}/view/SurgeryNotesComponentController?surgeryImage=true&"+csrftokenN+ "="+ csrftokenV+"&attachmentLocation="+imageObjectArray.objectList[i].attachmentLocation+"' border='0'>"+"</a> <strong>"+noteAddedMsg+"</strong><span class='image-created'>"+imageObjectArray.objectList[i].formattedDate+" "+byMsg+" "+imageObjectArray.objectList[i].userName+" </span></li>");
}
$("#uploader_filelist").empty().hide();
_SPINE.colorboxOverlay.coloboxPopup();
_SPINE.surgeryNotes.deleteImages();
$(".plupload_done .plupload_file_thumb").removeClass("hide")
},
ChunkUploaded: function (up, file, response) {
response = $.parseJSON(response.response || "null");
if (response.chunk == 3) {
up.stop();
up.start();
}
console.log(file.loaded);
}
},
// Flash settings
flash_swf_url : '${siteAssetsUrl}/assets/spine/js/external/Moxie.swf',
// Silverlight settings../assets/js
silverlight_xap_url : '${siteAssetsUrl}/assets/spine/js/external/Moxie.xap'
});
</script>
Here you can see I am generating scrf token (csrftokenV) and sending it in url to make it post supported.
Now the problem is if I am uploading more than 1 images (lets say 3), then 3 time post request will go. Each time i will get same csrf token and after uploaing first image, furthure images will not work and i will get this exception ....
WARNING: potential cross-site request forgery (CSRF) attack thwarted (user:<anonymous>, ip:127.0.0.1, uri:/**/image, error:request token does not match session token)
Please help me to solve this problem. Thanks
Finally One of my friend had solved the issue. It can't be possible to handle this issue through client side script so we leverage the power of Java. We had updated the csrfToken based on new request and sent it out with response.
Here is a solution ..
private String updateToken(HttpServletRequest request)
{
final HttpSession session = request.getSession(false);
CsrfGuard csrfGuard = CsrfGuard.getInstance();
csrfGuard.updateTokens(request);
String newToken=(String) session.getAttribute(REQUEST_TOKEN);
return newToken;
}
Setting newToken in response ...
response.setResult(this.updateToken(request));
return response;
Now we can change the url in beforeUpload event and set new token in the url.
BeforeUpload: function(up, file)
{
up.settings.url='/view/SurgeryNotesComponentController?uploadSurgeryImage=true&'+csrftokenN+'='+tokenRefresh
}
FileUploaded: function(up, file, info, res)
{
var imageObjectArray=$.parseJSON(info.response);
tokenRefresh=imageObjectArray.result;
}
Trying to create a Sencha-Touch-2 app syncing to a Node.js server; code below.
The server uses another port on the same IP, so this is cross-domain.
(The server uses Mongoose to talk to a MongoDB back-end (not shown))
Using a JSONP Proxy as shown can read data from the server but breaks when writing:
"JSONP proxies can only be used to read data".
I guess the JSONP Proxy writer config is just to write the query and isn't used to write sync (save).
Sencha docs state an Ajax proxy can't go cross-domain, even though a
Cross-domain Ext.Ajax/Ext.data.Connection is discussed in the Sencha forums:
http://www.sencha.com/forum/showthread.php?17691-Cross-domain-Ext.Ajax-Ext.data.Connection
I have found several ways to do a (cross-domain) JSON post (e.g. Mobile Application Using Sencha Touch - JSON Request Generates Syntax Error)
but don't know how to integrate this as a writer in a proxy which syncs my store.
Sencha Touch: ScriptTagProxy url for create/update functionality
seems to offer pointers, but this is ajax and apparently unsuited for cross domain.
I've been reading this forum and elsewhere for a couple of days, but I seem to be stuck. Any help would be much appreciated.
Node.js and restify server
var server = restify.createServer({
name: 'Server',
key: fs.readFileSync(root+'/'+'privatekey.pem'),
certificate: fs.readFileSync(root+'/'+'certificate.pem')
});
server.use(restify.bodyParser());
server.use(restify.queryParser());
function getMessages(req, res, next) {
Model.find(function (err,data) {
res.setHeader('Content-Type', 'text/javascript;charset=UTF-8');
res.send(req.query["callback"] + '({"records":' + JSON.stringify(data) + '});');
});
}
function postMessage(req, res, next) {//not yet tested
var obj = new Model();
obj.name = req.params.name;
obj.description = req.params.description;
obj.date = new Date();
obj.save(function (err) {
if (err) throw err;
console.log('Saved.');
res.send('Saved.');
});
}
server.post(/^\/atapp/, postMessage);
server.get(/^\/atapp/, getMessages);
server.listen(port, ipaddr, function() {
console.log('%s: secure Node server started on %s:%d ...', Date(Date.now()), ipaddr, port);
});
Sencha Touch 2
Model
Ext.define('ATApp.model.User', {
extend: 'Ext.data.Model',
config: {
fields: [
{ name: 'name', type: 'string' },
{ name: 'description', type: 'string' },
{ name: 'date', type: 'date' },
{ name: '_id' }
...
Store
Ext.define('ATApp.store.Data', {
extend: 'Ext.data.Store',
requires: [
'ATApp.model.User',
'Ext.data.proxy.JsonP'
],
config: {
autoLoad: true,
model: 'ATApp.model.User',
storeId: 'Data',
proxy: {
type: 'jsonp',
model: 'ATApp.model.User',
url: 'https://192.168.2.45:13017/atapp',
reader: {
type: 'json',
idProperty: '_id',
rootProperty: 'records',
useSimpleAccessors: true
},
writer: {
type: 'json',
allowSingle: false,
encode: true,
idProperty: '_id',
rootProperty: 'records'
...
Controller
onNewDataRecord: function (view) {
console.log('newDataRecord');
var now = new Date();
var record = Ext.create('ATApp.model.User', {
date: now,
name: '..',
description: '..'
});
var store = Ext.data.StoreManager.lookup('Data')
record.setProxy(store.getProxy());
store.add(record);
this.activateEditor(record);
},
...
In Sencha-Touch-2 apps, the browser prohibits cross-domain AJAX calls (which violate the same-origin security policy). This pertains to different domains, different IP addresses and even different ports on the same IP address. JSONP circumvents this partly by fetching/reading data encapsulated in a script tag in a newly initiated HTTP GET message. In this way the Sencha-Touch-2 JSONP proxy can load a store (fetch/read) from a (cross domain) server. However, the JSONP proxy cannot write data. In 1 and 2 an approach is described which I have adapted.
My solution uses the JSONP proxy to fetch data, but not to store (which it can't). Instead, new records, and records to be saved or deleted are communicated with the server in a newly initiated HTTP GET message. Even though only HTTP GET is used, the server accepts message get (described in the question, above), put, del and new. Get is used by JSONP store/proxy load().
Node.js Server
//routes
server.get(/^\/atapp\/put/, putMessage);
server.get(/^\/atapp\/get/, getMessages);
server.get(/^\/atapp\/del/, delMessage);
server.get(/^\/atapp\/new/, newMessage);
function newMessage(req, res, next) {
var obj = new Model(); // Mongoose create new MongoDB object
obj.save(function (err,data) {
var x = err || data;
res.setHeader('Content-Type', 'text/javascript;charset=UTF-8');
res.send(req.query["callback"] + '({"payload":' + JSON.stringify(x) + '});');
}); // send reply to Sencha-Touch 2 callback
}
function putMessage(req, res, next) {
var q = JSON.parse(req.query.data); // no reply: add error recovery separately
var obj = Model.findByIdAndUpdate(q.key,q.val);
}
function delMessage(req, res, next) {
var key = JSON.parse(req.query.data);
Model.findByIdAndRemove(key); // no reply: add error recovery separately
}
Sencha Controller
New
onNewDataRecord: function (view) {
var control = this;
Ext.Ajax.Crossdomain.request({
url: 'https://192.168.2.45:13017/atapp/new',
rootProperty: 'payload',
scriptTag: true, // see [1](http://code.google.com/p/extjsdyntran/source/browse/trunk/extjsdyntran/WebContent/js/3rdparty/Ext.lib.Ajax.js?r=203)
success: function(r) { // process synchronously after response
var obj = r.payload;
var store = Ext.data.StoreManager.lookup('Data');
var key = obj._id // MongoDB document id
store.load(function(records, operation, success) { // add new record to store
var ind = store.findBy(function(rec,id) {
return rec.raw._id==key;
}); // identify record in store
var record = store.getAt(ind);
control.onEditDataRecord(view,record);
}, this);
}
});
Save
onSaveDataRecord: function (view, record) {
rec = {key:record.data.id, val: {}} // save template
var i; for (i in record.modified) rec.val[i]=record.data[i];
var delta = Ext.encode(rec); // only save modified fields
Ext.Ajax.Crossdomain.request({
url: 'https://192.168.2.45:13017/atapp/put',
params: {
data: delta,
},
rootProperty: 'payload',
scriptTag: true, // Use script tag transport
});
},
Delete
onDelDataRecord: function (view, record) {
var key = record.data.id;
Ext.Ajax.Crossdomain.request({ // delete document in db
url: 'https://192.168.2.45:13017/atapp/del',
params: {
data: Ext.encode(key),
format: 'json'
},
rootProperty: 'payload',
scriptTag: true, // Use script tag transport
});
record.destroy(); // delete record from store
},