I am trying to create an upload page where I upload a .swf file and then I add the filename to my database. Previously I have been able to achieve this, however, now it seems to give me the error "Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index" My code is as follows:
#{
Page.Title = "Add Game";
//Variables
var GameName = "";
var Tags = "";
var Gamefile = "";
//Required fields
Validation.RequireField("Name", "Please give the game a name.");
Validation.RequireField("file", "Please upload a file.");
//Maximum name length
Validation.Add("Name",
Validator.StringLength(
maxLength: 100,
errorMessage: "Name must be less than 100 characters")
);
//SWF file validation
Validation.Add("file",
Validator.Regex(#"^.*\.(swf|SWF)$", "Invalid filetype, you must upload a .swf flash file")
);
if (IsPost && Validation.IsValid()) {
var db = Database.Open("Surgestuff");
var gCat = "";
var fileData = Request.Files[0];
var fileName = Guid.NewGuid().ToString() + ".swf";
var fileSavePath = Server.MapPath("~/upload/" + fileName);
var AddBy = WebSecurity.CurrentUserName;
gCat=Request["formCat"];
Gamefile = fileName;
fileData.SaveAs(fileSavePath);
var SQLINSERT = "INSERT INTO Games (Name, file_path, Category, AddBy) " + "VALUES (#0, #1, #2, #3)";
db.Execute(SQLINSERT, GameName, Gamefile, gCat, AddBy);
Response.Redirect("~/Games");
}
}
And for some reason, even when i have a file submitted, the
var fileData = Request.Files[0]; gives me that error
The Web Pages 2 Validation helpers do not work with an input type="file". They only work with elements that are included in the Request.Form collection. A file upload appears in the Request.Files collection.
There are a couple of approaches you can take to validate the file upload. You can use ModelState:
if(IsPost && Request.Files[0].ContentLength == 0){
ModelState.AddError("file", "You must choose a file");
}
if (IsPost && Validation.IsValid() && ModelState.IsValid) {
// etc
Or you can add a hidden field, and when the form is submitted, populate its value with that of the file upload via JavaScript. Then you can use the new Validation helpers as you are currently trying to do, but on the hidden field instead.
Related
I want the layer enter image description here
to have the name of the linked file without .eps at the end.
Anyway, I found an answer. So for anyone looking here it is, although it does take to click on every layer, at least you don't have to type it.
function test() {
var sel_itemPlaced = app.activeDocument.selection[0]; // be sure that a linked item (and not an embedded) is selected
var fileName = sel_itemPlaced.file.name;
var textContents = fileName.replace(/\%20/g, " "); //change %20 to spaces
textContents = textContents.replace(/\.[^\.]*$/, ""); //remove extension
var _item = sel_itemPlaced;
while (_item.parent.typename != 'Layer') {
_item = _item.parent;
}
_item.parent.name = textContents;
}
test();
It does work for all placed images and all layers at once:
var images = app.activeDocument.placedItems;
for (var i=0; i<images.length; i++)
images[i].layer.name = images[i].file.name.replace(/\.[^\.]+$/, "");
We are using the MultipartFormDataStreamProviderto save file upload by clients. I have a hard requirement that file size must be greater than 1KB. The easiest thing to do would of course be the save the file to disk and then look at the file unfortunately i can't do it like this. After i save the file to disk i don't have the ability to access it so i need to look at the file before its saved to disk. I've been looking at the properties of the stream provider to try to figure out what the size of the file is but unfortunately i've been unsuccessful.
The test file i'm using is 1025 bytes.
MultipartFormDataStreamProvider.BufferSize is 4096
Headers.ContentDisposition.Size is null
ContentLength is null
Is there a way to determine file size before it's saved to the file system?
Thanks to Guanxi i was able to formulate a solution. I used his code in the link as the basis i just added a little more async/await goodness :). I wanted to add the solution just in case it helps anyone else:
private async Task SaveMultipartStreamToDisk(Guid guid, string fullPath)
{
var user = HttpContext.Current.User.Identity.Name;
var multipartMemoryStreamProvider = await Request.Content.ReadAsMultipartAsync();
foreach (var content in multipartMemoryStreamProvider.Contents)
{
using (content)
{
if (content.Headers.ContentDisposition.FileName != null)
{
var existingFileName = content.Headers.ContentDisposition.FileName.Replace("\"", string.Empty);
Log.Information("Original File name was {OriginalFileName}: {guid} {user}", existingFileName, guid,user);
using (var st = await content.ReadAsStreamAsync())
{
var ext = Path.GetExtension(existingFileName.Replace("\"", string.Empty));
List<string> validExtensions = new List<string>() { ".pdf", ".jpg", ".jpeg", ".png" };
//1024 = 1KB
if (st.Length > 1024 && validExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase))
{
var newFileName = guid + ext;
using (var fs = new FileStream(Path.Combine(fullPath, newFileName), FileMode.Create))
{
await st.CopyToAsync(fs);
Log.Information("Completed writing {file}: {guid} {user}", Path.Combine(fullPath, newFileName), guid, HttpContext.Current.User.Identity.Name);
}
}
else
{
if (st.Length < 1025)
{
Log.Warning("File of length {FileLength} bytes was attempted to be uploaded: {guid} {user}",st.Length,guid,user);
}
else
{
Log.Warning("A file of type {FileType} was attempted to be uploaded: {guid} {user}", ext, guid,user);
}
var responseMessage = new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content =
st.Length < 1025
? new StringContent(
$"file of length {st.Length} does not meet our minumim file size requirements")
: new StringContent($"a file extension of {ext} is not an acceptable type")
};
throw new HttpResponseException(responseMessage);
}
}
}
}
}
You can also read the request contents without using MultipartFormDataStreamProvider. In that case all of the request contents (including files) would be in memory. I have given an example of how to do that at this link.
In this case you can read header for file size or read stream and check the file size. If it satisfy your criteria then only write it to desire location.
I searched around the web & Stack Overflow but didn't find a solution. What I try to do is the following: I get certain attachments via mail that I would like to have as (Plain) text for further processing. My script looks like this:
function MyFunction() {
var threads = GmailApp.search ('label:templabel');
var messages = GmailApp.getMessagesForThreads(threads);
for (i = 0; i < messages.length; ++i)
{
j = messages[i].length;
var messageBody = messages[i][0].getBody();
var messageSubject = messages [i][0].getSubject();
var attach = messages [i][0].getAttachments();
var attachcontent = attach.getContentAsString();
GmailApp.sendEmail("mail", messageSubject, "", {htmlBody: attachcontent});
}
}
Unfortunately this doesn't work. Does anybody here have an idea how I can do this? Is it even possible?
Thank you very much in advance.
Best, Phil
Edit: Updated for DriveApp, as DocsList deprecated.
I suggest breaking this down into two problems. The first is how to get a pdf attachment from an email, the second is how to convert that pdf to text.
As you've found out, getContentAsString() does not magically change a pdf attachment to plain text or html. We need to do something a little more complicated.
First, we'll get the attachment as a Blob, a utility class used by several Services to exchange data.
var blob = attachments[0].getAs(MimeType.PDF);
So with the second problem separated out, and maintaining the assumption that we're interested in only the first attachment of the first message of each thread labeled templabel, here is how myFunction() looks:
/**
* Get messages labeled 'templabel', and send myself the text contents of
* pdf attachments in new emails.
*/
function myFunction() {
var threads = GmailApp.search('label:templabel');
var threadsMessages = GmailApp.getMessagesForThreads(threads);
for (var thread = 0; thread < threadsMessages.length; ++thread) {
var message = threadsMessages[thread][0];
var messageBody = message.getBody();
var messageSubject = message.getSubject();
var attachments = message.getAttachments();
var blob = attachments[0].getAs(MimeType.PDF);
var filetext = pdfToText( blob, {keepTextfile: false} );
GmailApp.sendEmail(Session.getActiveUser().getEmail(), messageSubject, filetext);
}
}
We're relying on a helper function, pdfToText(), to convert our pdf blob into text, which we'll then send to ourselves as a plain text email. This helper function has a variety of options; by setting keepTextfile: false, we've elected to just have it return the text content of the PDF file to us, and leave no residual files in our Drive.
pdfToText()
This utility is available as a gist. Several examples are provided there.
A previous answer indicated that it was possible to use the Drive API's insert method to perform OCR, but it didn't provide code details. With the introduction of Advanced Google Services, the Drive API is easily accessible from Google Apps Script. You do need to switch on and enable the Drive API from the editor, under Resources > Advanced Google Services.
pdfToText() uses the Drive service to generate a Google Doc from the content of the PDF file. Unfortunately, this contains the "pictures" of each page in the document - not much we can do about that. It then uses the regular DocumentService to extract the document body as plain text.
/**
* See gist: https://gist.github.com/mogsdad/e6795e438615d252584f
*
* Convert pdf file (blob) to a text file on Drive, using built-in OCR.
* By default, the text file will be placed in the root folder, with the same
* name as source pdf (but extension 'txt'). Options:
* keepPdf (boolean, default false) Keep a copy of the original PDF file.
* keepGdoc (boolean, default false) Keep a copy of the OCR Google Doc file.
* keepTextfile (boolean, default true) Keep a copy of the text file.
* path (string, default blank) Folder path to store file(s) in.
* ocrLanguage (ISO 639-1 code) Default 'en'.
* textResult (boolean, default false) If true and keepTextfile true, return
* string of text content. If keepTextfile
* is false, text content is returned without
* regard to this option. Otherwise, return
* id of textfile.
*
* #param {blob} pdfFile Blob containing pdf file
* #param {object} options (Optional) Object specifying handling details
*
* #returns {string} id of text file (default) or text content
*/
function pdfToText ( pdfFile, options ) {
// Ensure Advanced Drive Service is enabled
try {
Drive.Files.list();
}
catch (e) {
throw new Error( "To use pdfToText(), first enable 'Drive API' in Resources > Advanced Google Services." );
}
// Set default options
options = options || {};
options.keepTextfile = options.hasOwnProperty("keepTextfile") ? options.keepTextfile : true;
// Prepare resource object for file creation
var parents = [];
if (options.path) {
parents.push( getDriveFolderFromPath (options.path) );
}
var pdfName = pdfFile.getName();
var resource = {
title: pdfName,
mimeType: pdfFile.getContentType(),
parents: parents
};
// Save PDF to Drive, if requested
if (options.keepPdf) {
var file = Drive.Files.insert(resource, pdfFile);
}
// Save PDF as GDOC
resource.title = pdfName.replace(/pdf$/, 'gdoc');
var insertOpts = {
ocr: true,
ocrLanguage: options.ocrLanguage || 'en'
}
var gdocFile = Drive.Files.insert(resource, pdfFile, insertOpts);
// Get text from GDOC
var gdocDoc = DocumentApp.openById(gdocFile.id);
var text = gdocDoc.getBody().getText();
// We're done using the Gdoc. Unless requested to keepGdoc, delete it.
if (!options.keepGdoc) {
Drive.Files.remove(gdocFile.id);
}
// Save text file, if requested
if (options.keepTextfile) {
resource.title = pdfName.replace(/pdf$/, 'txt');
resource.mimeType = MimeType.PLAIN_TEXT;
var textBlob = Utilities.newBlob(text, MimeType.PLAIN_TEXT, resource.title);
var textFile = Drive.Files.insert(resource, textBlob);
}
// Return result of conversion
if (!options.keepTextfile || options.textResult) {
return text;
}
else {
return textFile.id
}
}
The conversion to DriveApp is helped with this utility from Bruce McPherson:
// From: http://ramblings.mcpher.com/Home/excelquirks/gooscript/driveapppathfolder
function getDriveFolderFromPath (path) {
return (path || "/").split("/").reduce ( function(prev,current) {
if (prev && current) {
var fldrs = prev.getFoldersByName(current);
return fldrs.hasNext() ? fldrs.next() : null;
}
else {
return current ? null : prev;
}
},DriveApp.getRootFolder());
}
I have a Google Apps Script for a Google Spreadsheet based on a Google Form that clients fill out online. The script is triggered by OnFormSubmit and generates a pdf based on a Google Doc template and sends the pdf to me by email using MailApp.sendEmail.
This script has been working fine until recently. The script runs successfully but the pdf output is incorrect. It seems like fields that are left blank are now being ignored in the script and so my pdf output shows the value for the next non-blank field. Ugh!
Anybody know what's going on here?
Below is an example of my script:
var docTemplate = "1FZL4rVe0LLpvMtIsq_3-pwv5POllIsyYThjfemkbkfg";
var docName = "Travel Details";
function onFormSubmit(e) {
var last = e.values[1];
var first = e.values[2];
var order = e.values[3];
var date = e.values[4];
var gender = e.values[5];
var email = "example#gmail.com";
var copyId = DocsList.getFileById(docTemplate)
.makeCopy(docName+' for '+last + ', ' + first)
.getId();
var copyDoc = DocumentApp.openById(copyId);
var copyBody = copyDoc.getActiveSection();
copyBody.replaceText('keyLast', last);
copyBody.replaceText('keyFirst', first);
copyBody.replaceText('keyOrder', order);
copyBody.replaceText('keyDate', date);
copyBody.replaceText('keyGender', gender);
copyDoc.saveAndClose();
var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
MailApp.sendEmail(email, subject, "", {htmlBody: office_message, attachments: pdf,
noReply:true});
DocsList.getFileById(copyId).setTrashed(true);
}
Example of the problem: If client leaves date field blank on the form, the gender value in the resulting pdf is put where the date value should be and the value for gender on the pdf shows "undefined".
Any ideas out there?
You should validate the values of all your variables.
if (last === undefined) {
last = 'No Data!'; //re-assign a different value
};
So, you are changing the value of the variable last if it somehow got set to undefined. That way, hopefully the pdf would still show the field.
If there is some bug that just showed up recently, you should report it as a bug. If everything was working fine, and now it's broken, Google may have changed something.
There might be something wrong with your code. I don't know. Have you looked under the "View" menu and the "Execution Transcript" to see if there are any errors? You should also use Logger.log statements: Logger.log('The value of last is: ' + last); to print output to the log. Then you can check what is actually going on.
I am no great coder but I use this script all the time to send pdf's I have never received an undefined if a field was missing. Typically if something is missing, the keygender is replaced with a blank spot and there is no error. In a spreadsheet, typically this means the columns were changed. It used to be timestamp(0), last(1), first(2), order(3), date(4), gender(5) and now their in a different order.
Try the below code it works
//commons errors -
//Triggers are not set
//spaces after Form questions
//e.values dont work when fields are not mandatory and left blank
//e.namedValues dont work for sending emails use e.values[#]
//place holder keys in template dont match
//spelling errors
//Note expect undefined error when de-bugging as values are not defined until form completed and submitted - run first with a small test form as per below
// Get Template
//from Google Docs and name it
var docTemplate = " "; // *** replace with new templae ID if new Template created***
var docName = "Test Script"; //replace with document name
// When Form Gets submitted
function onFormSubmit(e) {
//Get information from the form and set as variables
//var variablename = "static entry or form value"
//Note: var Variablename = e.namedValues["X"]; is taking the value from the spreadsheet by column name so update if spreadsheet or form questions change
//Additions to the form will be added to the end of the spreadsheet regardless of their position in the form
var Timestamp = e.namedValues["Timestamp"];
var full_name = e.namedValues["Name"];
var position = e.namedValues["Position"]
var contact_email = e.namedValues["Contact Email"];
var phone_number = e.namedValues["Telephone Number"];
// Get document template, copy it as a new doc with Name and email, and save the id
var copyId = DocsList.getFileById(docTemplate)
.makeCopy(full_name+' '+docName+' for ' +contact_email+' '+Timestamp)//Update or remove Variablename to create full doc Name
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the documents body section
var copyBody = copyDoc.getActiveSection();
// Replace place holder keys <<namedValues>> in template
//copyBody.replaceText('<<X>>', Variablename); Variables from above
//***Update if template is changed***
copyBody.replaceText('<<Timestamp>>', Timestamp);
copyBody.replaceText('<<Name>>', full_name);
copyBody.replaceText('<<Position>>', position);
copyBody.replaceText('<<Contact Email>>', contact_email);
copyBody.replaceText('<<Telephone Number>>', phone_number);
// Save and close the temporary document
copyDoc.saveAndClose();
// Convert temporary document to PDF by using the getAs blob conversion
var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
{
// Add the data fields to the message
var s = SpreadsheetApp.getActiveSheet();
var columns = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = " ";
// Only include form fields that are not blank
for ( var keys in columns ) {
var key = columns[keys];
if ( e.namedValues[key] && (e.namedValues[key] != "") ) {
message += key+ ' : '+ e.namedValues[key] + "<br>";
}
}}
// Attach PDF and send the email
//***Change the "To" email address when to form goes live***
var to = "youremail#gmail.com";
var senders_name = e.values[1]
var contact_email = e.values[3]
var subject = "Test";
var htmlbody = "text goes here"+
"<br> <br>"+message+
"<br> <br>Submitted By:"+
"<br> <br>"+full_name+
"<br>"+position+
"<br>"+contact_email+
"<br>"+phone_number+
"<br> <br>Generated by Hansmoleman for Compu-Global-Hyper-Mega-Net";
MailApp.sendEmail({
name: senders_name,
to: to,
cc: contact_email,
replyTo: contact_email,
subject: subject,
htmlBody: htmlbody,
attachments: pdf,
});
}
I am trying to upload a file via a form and then save in in SQL as a blob.
I already have my form working fine, my database is fully able to take the blob and I have a controller that take the file, saves it in a local directory:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult FileUpload(int id, HttpPostedFileBase uploadFile)
{
//allowed types
string typesNonFormatted = "text/plain,application/msword,application/pdf,image/jpeg,image/png,image/gif";
string[] types = typesNonFormatted.Split(',');
//
//Starting security check
//checking file size
if (uploadFile.ContentLength == 0 && uploadFile.ContentLength > 10000000)
ViewData["StatusMsg"] = "Could not upload: File too big (max size 10mb) or error while transfering the file.";
//checking file type
else if(types.Contains(uploadFile.ContentType) == false)
ViewData["StatusMsg"] = "Could not upload: Illigal file type!<br/> Allowed types: images, Ms Word documents, PDF, plain text files.";
//Passed all security checks
else
{
string filePath = Path.Combine(HttpContext.Server.MapPath("../Uploads"),
Path.GetFileName(uploadFile.FileName)); //generating path
uploadFile.SaveAs(filePath); //saving file to final destination
ViewData["StatusMsg"] = "Uploaded: " + uploadFile.FileName + " (" + Convert.ToDecimal(uploadFile.ContentLength) / 1000 + " kb)";
//saving file to database
//
//MISSING
}
return View("FileUpload", null);
}
Now all I am missing is putting the file in the database. I could not find anything on the subject... I found some way to do it in a regular website but nothing in MVC2.
Any kind of help would be welcome!
Thank you.
This could help: http://byatool.com/mvc/asp-net-mvc-upload-image-to-database-and-show-image-dynamically-using-a-view/
Since you have HttpPostedFileBase in your controllers method, all you need to do is:
int length = uploadFile.ContentLength;
byte[] tempImage = new byte[length];
myDBObject.ContentType = uploadFile.ContentType;
uploadFile.InputStream.Read(tempImage, 0, length);
myDBObject.ActualImage = tempImage ;
HttpPostedFileBase has a InputStream property
Hope this helps.
Alright thanks to kheit, I finaly got it working. Here's the final solution, it might help someone out there.
This script method takes all the file from a directory and upload them to the database:
//upload all file from a directory to the database as blob
public void UploadFilesToDB(long UniqueId)
{
//directory path
string fileUnformatedPath = "../Uploads/" + UniqueId; //setting final path with unique id
//getting all files in directory ( if any)
string[] FileList = System.IO.Directory.GetFiles(HttpContext.Server.MapPath(fileUnformatedPath));
//for each file in direcotry
foreach (var file in FileList)
{
//extracting file from directory
System.IO.FileStream CurFile = System.IO.File.Open(file, System.IO.FileMode.Open);
long fileLenght = CurFile.Length;
//converting file to a byte array (byte[])
byte[] tempFile = new byte[fileLenght];
CurFile.Read(tempFile, 0, Convert.ToInt32(fileLenght));
//creating new attachment
IW_Attachment CurAttachment = new IW_Attachment();
CurAttachment.attachment_blob = tempFile; //setting actual file
string[] filedirlist = CurFile.Name.Split('\\');//setting file name
CurAttachment.attachment_name = filedirlist.ElementAt(filedirlist.Count() - 1);//setting file name
//uploadind attachment to database
SubmissionRepository.CreateAttachment(CurAttachment);
//deleting current file fromd directory
CurFile.Flush();
System.IO.File.Delete(file);
CurFile.Close();
}
//deleting directory , it should be empty by now
System.IO.Directory.Delete(HttpContext.Server.MapPath(fileUnformatedPath));
}
(By the way IW_Attachment is the name of one of my database table)