html5 multiple upload along with ajax - ajax

I am trying to use the multiple upload attribute of HTML5 to upload files.
I know it wouldn't work with IE and fall back to single file upload.
also I found some invalid html tag like min max allows opera to do the same.
I am trying to do the following:
The browse button be capable of selecting multiple files.
But the ajax should send files one by one.
My scenario is something like this:
the user selects 5 files and starts the upload . Now the ajax should firstfile send the first file, then second, and so on.
The server side script does something with the file and returns some data.
now as soon as one file upload is completed it must render that part of the result.
So as the user selects images and starts uploading the results come out as soon as each file is uploaded (and not after all the files are uploaded).
I tried something like this :
function handleFiles(files)
{ alert(files.length); //properly returns the number of files selected
for (var i = 0; i < files.length; i++) {
new FileUpload(files[i])
}
}
function FileUpload(file) {
var reader = new FileReader();
var xhr = new XMLHttpRequest();
this.xhr = xhr;
xhr.open("POST", "portfolio/add_media");
reader.onload = function(evt) {
xhr.sendAsBinary(evt.target.result);
};
reader.readAsBinaryString(file);
}
after reading the tutorial at mozilla but I end up with missing params.
. so can some one suggest me a clean solution to this
Some more details :
When I pass a single file ( with no multiple attribute ) my server recieves :
"image"=>[# < ActionDispatch::Http::UploadedFile:0x10d55be8
#tempfile=#< File:C:/Users/Gaurav/AppData/Local/Temp/RackMultipart20110701-1916-2ly4k2-0>,
#headers="Content-Disposition:
form-data; name=\"picture[image][]\";
filename=\"Desert.jpg\"\r\nContent-Type:
image/jpeg\r\n",
#content_type="image/jpeg",
#original_filename="Desert.jpg">]}}
But when I use multiple attribute and send using xhr I am able to get only one file param. How do I get the rest of the params ? esp the action dispatch thingy

You are simply sending the file data to the server, without encoding it in any way. For the server to know how to process it you need to encode your data properly (multipart/form-data encoding). Easiest way is using a FormData object: https://developer.mozilla.org/En/Using_XMLHttpRequest#Sending_files_using_a_FormData_object. Only that instead of data.append("CustomField", "This is some extra data") you would write data.append("file1", event.target.result).

Related

Checksum Error while uploading files to BackBlaze (B2) using Ajax request

I have spent an awful lot of time trying to upload files to b2 using clientside ajax requests (vue-dropzone.js), and even though I supplied the file's valid sha1 checksum, the b2 server still responds with "checksum did not match data received" with status code 400. I've checked and rechecked the checksums with all the tools I have and I'm still not able to trace the source of the error. Its as if something happens to the file while its in transit or something.
I've uploaded the same files using the command line tool and it works fine but when I upload via ajax using the exact same sha1 checksum it doesn't work.
My questions are:
Does b2 even allow file uploads through ajax?
If it does allow uploads via ajax then what am i doing wrong?
Does the files remain valid when uploaded using "X-Bz-Content-Sha1", " do_not_verify". Cause I've tried that only to get invalid files when I downloaded them back.
Are there other things I need to know about uploading files to b2 using ajax requests
Please view my ajax codes see if I got anything wrong:
sending(file, xhr, formData) {
// This function runs for each file right before they are sent by dropezone.
// This is a good opportunity to insert file specific values
// in this case the file's upload url, name and auth token
let fileName = '';
console.log('this is file type', file.type);
if (file.type.includes('image')) {
fileName = 'images/${uuid.v1()}.png';
} else if (file.type.includes('video')) {
fileName = 'videos/${uuid.v1()}.${file.type.split(' / ')[1]}';
}
const url = appConfig.serverAddress + '/catalog/submitFiles';
console.log('this is sha1_hash', this.uploadInfo.sha1_hash);
// open the xhr request and insert the file's upload url here
xhr.open('Post', this.uploadInfo.url, true);
// set b2's mandatory request headers
// xhr.setRequestHeader(
// 'Authorization',
// 'Bearer ' + store.getters.getUserIdToken,
// );
xhr.setRequestHeader('Authorization', this.uploadInfo.authorizationToken);
xhr.setRequestHeader('X-Bz-Content-Sha1', this.uploadInfo.sha1_hash);
xhr.setRequestHeader('X-Bz-File-Name', fileName);
xhr.setRequestHeader('Content-Type', 'b2/x-auto');
formData = new FormData();
formData.append('files', file);
// the rest will be handled by dropzones upload pipeline
}
You are sending the file using form encoding, which causes the SHA-1 validation to fail since B2 is expecting the raw file data, with no encoding. The doc for b2_upload_file says:
The file to be uploaded is the message body and is not encoded in any way. It is not URL encoded. It is not MIME encoded.
I'm not an expert on vue-dropzone, but I'm guessing you need to just delete the two lines referencing formData. It looks like the default upload pipeline will send the raw file content.

Unable to view PDF attached with ServiceNow table records

I am able to successfully attach PDF file with ServiceNow table record using GlideSysAttachment API and attachment.write() function in script, however whenever I download and try to open same, I get the error shown in below screenshot.
Code snippet
(function execute() {
try{
var rec = new GlideRecord('incident');
var attachment = new GlideSysAttachment();
var incidentSysID = incident.number;
rec.get(incidentSysID);
var fileName = 'Test_Incident.pdf';
var contentType = 'application/pdf'; // Also tried with contentType as 'text/pdf'
var content = pdf_content;
var agr = attachment.write(rec, fileName, contentType, content);<br>
gs.info('The PDF attachment sys_id is: ' + agr);
}catch(err){
gs.log('Got Error: ' + err);
gs.info(err);
}
})()
I also tried "AttachmentCreator" with ecc_queue within script but same error occurs. Below is code for it.
(function execute()
{var attCreator = new GlideRecord('ecc_queue');
attCreator.agent = "AttachmentCreator";
attCreator.topic = "AttachmentCreator";
attCreator.name = "Test.pdf" + ":" + "text/pdf";
//Also tried, "Test.pdf:application/pdf"
attCreator.source = "incident"+":"+ incident.number;
// Record Table name and sys_id of the particular record
var content = pdf_content; // pdf_content is any string variable
var stringUtil = new GlideStringUtil();
var base64String = stringUtil.base64Encode(content);
var isValid=GlideStringUtil.isBase64(base64String);
var base64String= gs.base64Encode(content);
gs.info("Is valid base64 format in ecc_queue ? "+ isValid);
attCreator.payload = base64String; //base64 content of the file
attCreator.insert();
})()
I am able to attach and view excel and word files with similar scripts without any issues. I have checked system properties for attachments but everything looks fine. I am able to view the PDF file uploaded from UI to particular table records however not the one I attach via REST API or scripts.
I have also tried sending encoded data as bytes, base64 or simple string but nothing seems to work. I don't get any errors and attachment id is returned each time on creation of attachment.
After modifying my code slightly for above functions w.r.t scoped application instead of global; I got some information from logs when I debug:
05:38:38.411 Security restricted: File type is not allowed or does not match the content for file Test.pdf
05:38:38.410 Security restricted: MIME type mismatch for file: Test.pdf. Expected type:application/pdf, Actual type: text/plain
05:38:38.394 App:XYZ App x_272539_xyz_ap: Is valid base64 format in ecc_queue ? true
First a comment: This line in your code is accidentally working -- make sure you understand that a task number is not the object sys_id
var incidentSysID = incident.number; // should be incident.sys_id
Next, it's unclear where the PDF content is coming from. IF your complete code is listed, I would expect the errors given as you have noted that pdf_content is "any string variable."
ServiceNow does have a the capability to create a PDF from an HTML argument.
Generating a PDF from HTML
Here's a helpful blog post for getting a PDF (Platform generated) of an existing record:
Love PDF? PDF loves you too

Telegram Bot Random Images (How to send random images with Telegram-Bot)

const TeleBot = require('telebot');
const bot = new TeleBot({
token: 'i9NhrhCQGq7rxaA' // Telegram Bot API token.
});
bot.on(/^([Hh]ey|[Hh]oi|[Hh]a*i)$/, function (msg) {
return bot.sendMessage(msg.from.id, "Hello Commander");
});
var Historiepics = ['Schoolfotos/grr.jpg', 'Schoolfotos/boe.jpg',
'Schoolfotos/tobinsexy.jpg'];
console.log('Historiepics')
console.log(Math.floor(Math.random() * Historiepics.length));
var foto = Historiepics[(Math.floor(Math.random() * Historiepics.length))];
bot.on(/aap/, (msg) => {
return bot.sendPhoto(msg.from.id, foto);
});
bot.start();
The result I'm getting from this is just one picture everytime, but if I ask for another random picture it keeps showing me the same one without change.
I recently figured this out, so I'll drop an answer for anyone that runs into this issue.
The problem is with Telegram's cache. They cache images server side so that they don't have to do multiple requests to the same url. This protects them from potentially getting blacklisted for too many requests, and makes things snappier.
Unfortunately if you're using an API like The Cat API this means you will be sending the same image over and over again. The simplest solution is just to somehow make the link a little different every time. This is most easily accomplished by including the current epoch time as a part of the url.
For your example with javascript this can be accomplished with the following modifications
bot.on(/aap/, (msg) => {
let epoch = (new Date).getTime();
return bot.sendPhoto(msg.from.id, foto + "?time=" + epoch);
});
Or something similar. The main point is, as long as the URL is different you won't receive a cached result. The other option is to download the file and then send it locally. This is what Telebot does if you pass the serverDownload option into sendPhoto.

Export To Excel from Asp Net Web API Controller

I am working on New web application which is Using Web API as Business Layer and Knock out Js as client side frame work to binding. I have a requirement like Pass the certain search criteria to Web API Controller and get the Data from DB and Create and Send the Excel/MS-Word file on the fly as a downloadable content.
I am new to both the Web API and Knock out, I am searching on the Net and get partial solution and I am looking here to get more optimal solution for this use case.
Below is my code:
Client:
function GetExcelFile() {
var $downloadForm = $("<form method='POST'>")
.attr("action", baseUrl + "api/FileHandler/GetExcelFileTest")
.attr("target", "_blank")
$("body").append($downloadForm);
$downloadForm.submit();
$downloadForm.remove();
}
On Button Click having this code snippet to create a form on the fly and Get response from Web API.
Web API Code:
[HttpPost]
public HttpResponseMessage GetExcelFileTest()
{
var response = new HttpResponseMessage();
//Create the file in Web App Physical Folder
string fileName = Guid.NewGuid().ToString() + ".xls";
string filePath = HttpContext.Current.Server.MapPath(String.Format("~/FileDownload/{0}", fileName));
StringBuilder fileContent = new StringBuilder();
//Get Data here
DataTable dt = GetData();
if (dt != null)
{
string str = string.Empty;
foreach (DataColumn dtcol in dt.Columns)
{
fileContent.Append(str + dtcol.ColumnName);
str = "\t";
}
fileContent.Append("\n");
foreach (DataRow dr in dt.Rows)
{
str = "";
for (int j = 0; j < dt.Columns.Count; j++)
{
fileContent.Append(str + Convert.ToString(dr[j]));
str = "\t";
}
fileContent.Append("\n");
}
}
// write the data into Excel file
using (StreamWriter sw = new StreamWriter(fileName.ToString(), false))
{
sw.Write(fileContent.ToString());
}
IFileProvider FileProvider = new FileProvider();
//Get the File Stream
FileStream fileStream = FileProvider.Open(filePath);
//Set response
response.Content = new StreamContent(fileStream);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = fileName;
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/ms-excel");
response.Content.Headers.ContentLength = fileStream.Length;
//Delete the file
//if(File.Exists(filePath))
//{
// File.Delete(filePath);
//}
return response;
}
Using this code I am able to download an Excel File. Still I have some more open questions to make this code optimal.
Q1) I need to Pass view model(Search Criteria) to API Controller Using the dynamically create form ? (OR) Any better ways to get Excel file from Web API.
Q2) I am sure it's not a good way to create Excel file in Physical folder and Get FileStream and send as a respone. How to do on the fly ? OR any other optimal ways.
Please suggest me to do better ways.. Thanks
Q1) You can quite easily pass the view-model, but it's also similarly easy to pull that information from the posted form.
Passing the view-model
If you want to pass the view-model to a WebAPI method then remember that said method must take as a parameter an object with the same properties. So if the object that you wish to post back always has the same properties then it's trivial to build a server-side class with the same properties and receive an instance of that class.
To post back this client-side object you can do something like this (uses jQuery, which I see you're already using):
$.ajax({
contentType: "application/json",
data: my-view-model.toJSON(),
type: "POST",
url: baseUrl + "api/FileHandler/GetExcelFileTest" });
I haven't attached any success or error handlers here because the JavaScript isn't concerned with the return, but you might wish to add some handlers in case an exception is thrown in your WebAPI method. I recommend doing that by adding the following to the above $.ajax() call:
statusCode: {
500: function(jqXhr, textStatus, errorThrown) {
},
[other HTTP error codes]
}
[Read the documentation for the $.ajax() call here.]
One additional tip here: when you call my-view-model.toJSON() (or self.toJSON(), if called from within your view-model) Knockout will first of all determine if your view-model contains a toJSON() method. If so, it will use this method; if not then it will call the browser's implementation of this function. However, the browser's implementation of this function will serialise everything, which can be particularly length if you have, for example, long select lists in your view-model. Therefore, if you wish only to send back a subset of the view-model's properties then define your own toJSON function on your view-model like so:
var toJSON = function() {
return {
Property1: ...,
Property2: ...
};
}
[Read more about converting a view-model to JSON here.]
Posting the form as-is
If you don't wish to expend the effort to do the view-model wiring then you can just post the form exactly like you have in your question. You can then retrieve the values from the form by using
Request.Form["my-field"];
Q2)
You're probably right in pointing out that it's not wise to create the Excel file in the physical folder. However, as far as I'm aware (interested if someone says otherwise) you'll have to use a 3rd-party library for this. Microsoft do offer an Office automation library but I have a suspicion that you also need Office to be installed at the same location.
Creating Excel spreadsheets dynamically is something I've done several times but for the actual creation I use Aspose.Cells, which requires a license. Although I do create a physical version and then delete it, I believe Aspose.Cells may allow you to create it as a stream. But take a look around, there are certainly other libraries which offer Excel automation.
Returning the File from the Server
Calling $.ajax({...}) alone won't allow you to present the user with a "Save as..." dialog. What I do in this situation - and this won't work if you wish to store the generated file only in memory (FileStream, for example) and not on the file system - is to respond to the $.ajax({...}) call with a filename for the generated file.
The next step is to direct the user towards that filename.
So I have something like this in my JavaScript:
$.ajax({
dataType: "json",
type: "GET", // you'll probably want POST in your case
url: ...,
success: function(response) {
if (response && response.Uri && response.Uri.length) {
window.location.href = [root URL] + response.Uri;
}
}
});
But don't be alarmed by this redirect. That window.location.href points directly to a folder on the server, no controller needed. Because the browser then receives a file it presents the "Save as..." dialog while remaining on the same webpage.

how to use xml file in ajax chat?

I want to build a website like Facebook style, and for start i am building a chat system using ajax. For now, all the messages that are sent to the chat system are saved in a xml file which looks like this:
<messages>
<message from="jhon" time="2:00">Hi!</message>
</messages>
My question is if it is fine to use the xml file like i do here, or a database is the solution. Can someone explain to me how to use xml in the right way also in the chat or a messages system if it is necessary at all?
Thank you!
I made an exercise (for school) that worked in a simular way:
<post>
<time>15:25</time>
<name>myUserName</name>
<message>testbla</message>
</post>
I used a PHP-script (provided by the teacher) to write in the file (in the format like before) each time there is a new message being sent by the user. While it was working well, there were a few problems I encountered:
In order to keep the chat updated, I had to reload the chat 3600 times per hour. This is no problem. However, because I was using XML, I had to download the file 3600x per hour, which is definitely not an elegant solution; with only a few messages, the site consumed about 20-40 MB data each hour. (you do the math!)
There were also issues with the special chars that conflicted to XML: <, > and &. I had to either escape them, remove them from the user input OR use CDATA to prevent XML from crashing due to syntax errors. (XML is very sensitive for this!) Additional difficulty was to prevent that others could send bad code. Generally, try to eliminate this while updating your XML-file.
With the above in mind, I would recommend searching for a more elegant solution than XML; JSON might be lighter to handle. Alternatively, MYSQL/PHP allow you to send only the last messages, so you don't have to send the whole file over and over again. (I don't have any PHP/MYSQL-expertise at this moment, so I cannot help you with that right now)
You asked how you could make your XML-chat happen. To give you some direction, I will give you some snippets of my code (with jQuery):
/* this function gets chat logs from XML and manipulate the content to a
div used for the chat-content. It is being evaluated each second by
an interval that calls the function each 1000 ms. (not included in this code) */
function getChatLogs() {
var chatLogs = "";
$.ajax({
url: "chat_log.xml",
success: function(data) {
$(data).find("post").each(function() {
var timeMessage = $(this).find("time").text();
var nameSender = $(this).find("name").text();
var contentMessage = $(this).find("message").text();
chatLogs += "<article><time>" + timeMessage + "</time> <strong>" + nameSender + "</strong> <p>" + contentMessage+ "</p></article>";
});
$("#chat").html(chatLogs);
}
});
}
/* this function handles messages being send by the user */
function sendInput(keyCode) {
if(keyCode === 13 && $("#post").val() != "") {
var name = localStorage.getItem("username"); // I used localstorage fo username
var time = currentTime();
var message = $("#post").val();
$.ajax({
type: "POST",
url: "save.php",
data: {"name": name, "time": time, "message": message},
success: function(data) {
$("#post").val(""); // (clear the chat-input)
}
});
}
}
Bonus tip: you XML-file MUST be well formed. You can easily check if this is the case by opening the XML-file straight in Chrome. If there are issues, it will give an error.

Resources