Playframework 2.2.1 Scala - Form bindFromRequest error - scala

I'm trying to register a tuple to a DB and upload the image to Amazon S3.
I divided the code to two parts : 1) Working Code and 2) Non Working Code.
Working code means It works as expected. The image file is uploaded sucessfully to S3.
Non working code is always folding to index_error page which I'm trying to solve but I can't figure out where I'm missing.
Thank you for help!
Working Code
def index = Action {
Ok(views.html.upload_test_index("File Upload In Play"))
}
def uploadFile = Action(parse.multipartFormData) { request =>
request.body.file("fileUpload").map { video =>
val newFile = File.createTempFile("temp-uploaded-", video.filename)
video.ref.moveTo(newFile, true)
new S3Sender(newFile, video.filename).send
}.getOrElse {
Redirect(routes.Application.index)
}
Ok("File has been uploaded")
}
Non Working Code - Controller
val anuncioForm = Form(
tuple(
"label" -> nonEmptyText,
"imgName" -> text
)
)
def createAnuncio = Action(parse.multipartFormData) { implicit request =>
anuncioForm.bindFromRequest.fold(
formWithErrors => BadRequest(views.html.index_error(formWithErrors)),
{
case (label, imgName) =>
request.body.file("imgName").map { imgName =>
val newFile = File.createTempFile("temp-uploaded-", imgName.filename)
val fileName = imgName.filename
imgName.ref.moveTo(newFile, true)
new S3Sender(newFile, fileName).send
Anuncio.create(label, fileName)
}
println("criou")
Redirect(routes.Application.anuncios)
}
)
}
def anuncios = Action {
Ok(views.html.index(Anuncio.all(), anuncioForm))
}
def newAnuncio = Action {
Ok(views.html.create(anuncioForm))
}
Non Working Code - Template
#(anuncioForm: Form[(String, String)])
#import helper._
#main("Criar um novo anuncio") {
#form(action = routes.Application.createAnuncio, 'enctype -> "multipart/form-data") {
#inputText(anuncioForm("label"))
#*<input type="file" name="imgName">*#
#inputFile(anuncioForm("imgName"))
<input type="submit" value="Create">
}
}
Edited
I used the code below to know the error message.
formWithErrors => BadRequest(views.html.index_error(formWithErrors.errorsAsJson))
Surprisingly I got the message below. I can't figure out why this message?!
{"imgName":["This field is required"]}

Do you need to have the file contents as a part of the form itself? You declare the imgName as a text in the form in your controller, but you use it as a input type="file" in your view, which I would imagine is contradictory.
A few things you could take a look at:
how to handle fileupload into a table in play framework? which talks about separating the file from the form as well as an (untested?) single submit for both a form and a file, and possible some other clues
How to include a picture type in a form in Play!2 in Scala? which is doing something similar to what you are doing
http://www.playframework.com/documentation/2.1.2/ScalaFileUpload

Related

Typesafe config: How to iterate over configuration items

In my Play application I've a configuration like this:
social {
twitter {
url="https://twitter.com"
logo="images/twitter.png"
}
facebook {
url="https://www.facebook.com"
logo="images/facebook.png"
}
}
Ho do I iterate over all the social entries to get url and logo for each entry?
<table border="0" cellspacing="0" cellpadding="2"><tr>
#configuration.getConfig("social").map { config =>
#for(item <- config.entrySet) {
<td><a href="item.getString("url")">
<img src="#routes.Assets.at("item.getString("logo")").absoluteURL()" width="24" height="24"/></a></td>
}
}
</table>
Of course, item.getString in the snippet here above does not work... it just shows what I'm trying to achieve.
The final objective would be to be able to add any further social url without having to modify the page template.
If you change the config to:
"social" : [
{
name="twitter",
url="https://twitter.com",
logo="images/twitter.png"
},
{
name="facebook",
url="https://www.facebook.com",
logo="images/facebook.png"
}
]
You could do it like this:
#(message: String)(implicit request: RequestHeader)
#import play.api.Play.current
<table border="0" cellspacing="0" cellpadding="2"><tr>
#current.configuration.getConfigList("social").get.map { config =>
<td><a href="#config.getString("url")">
<img src="#routes.Assets.at(config.getString("logo").get).absoluteURL()" width="24" height="24"/></a></td>
}
</table>
For posterity, here's another way to iterate over a nested config like you had. I prefer that format to the array one and I'd rather make my config cleaner than the code.
import collection.JavaConversions._
val socialConfig = ConfigFactory.load.getConfig("social")
socialConfig.root.map { case (name: String, configObject: ConfigObject) =>
val config = configObject.toConfig
println(config.getString("url"))
println(config.getString("logo"))
}
I'm sure the OP could convert this into a Twirl template. That's about as clean as I can get it.
In case you're using Java, for a config like:
"social" : [
{
name="twitter",
url="https://twitter.com",
logo="images/twitter.png"
},
{
name="facebook",
url="https://www.facebook.com",
logo="images/facebook.png"
}
]
this will work:
ConfigList socials = ConfigFactory().load.getList("social")
for (ConfigValue cv : socials) {
Config c = ((ConfigObject)cv).toConfig();
System.out.println(c.getString("url"));
System.out.println(c.getString("logo"));
}
socialConfig.root.map does not work.
Here is my solution -
private val firstSegmentRE = """^(\w+)[\.*].*$""".r
// convert "aaa.bbb.ccc" to "aaa"
private def parseFirstSegment(fullPath: String) : Option[String] = {
if (fullPath.contains("."))
fullPath match {
case firstSegmentRE(segment) => Some(segment)
case _ => None
}
else
Some(fullPath)
}
// for all keys in white list get a map of key -> config
protected def subConfigMap(config: Config, whiteList: List[String],
configName: String) : ErrorOr[Map[String, Config]] = {
// This will traverse the whole config and flatten down to the leaves..
val leafKeys : List[String] =
config.entrySet()
.asScala
.map(e => e.getKey)
.toList
// Remove all after the first dot
val nextLevelKeys : List[String] =
leafKeys.map(parseFirstSegment)
.collect {
case Some(firstSegment) => firstSegment
}
.distinct
val keysToSearch = nextLevelKeys.filter(whiteList.contains)
// we have a list of valid first level children
// parse out subconfigs and convert to map
keysToSearch.traverseErrorOr( key =>
extractSubConfig(config, key, configName).map((key, _))
)
.map(_.toMap)
}
Where extractSubConfig is a method which produces an ERROR / Config (a scalaz disjunction) and traverseErrorOr is a method to traverse a list and either process all the elements or fail and return failed disjunction if failed at any point. This method can be done without scalaz, just posting an answer to help people if they want.
Since collection.JavaConversions has since been deprecated in favor of collection.JavaConverters (and this question is the top result on a search for how to iterate through a Typesafe Config in Scala), I wanted to suggest a more modern version of Cole's great answer:
import collection.JavaConverters._
val socialConfig = ConfigFactory.load.getConfig("social")
for ( (name: String, configObject: ConfigObject) <- socialConfig.root.asScala) {
println(name) // prints "twitter" or "facebook"
val config = configObject.toConfig
println(config.getString("url"))
println(config.getString("logo"))
}
To be clear, socialConfig.root.asScala yields a standard Scala Map[String, ConfigObject] and you can iterate over it however you'd like.
import collection.JavaConversions._
val socialConfig = ConfigFactory.load.getConfig("social")
val socialConfigMap = socialConfig
.root()
.entrySet()
.asScala
.map(socialEntry => {
println(socialEntry.getKey)
val socialEntryConfig = socialEntry.getValue.asInstanceOf[ConfigObject].toConfig
println(socialEntryConfig.getString("url"))
println(socialEntryConfig.getString("logo"))
})
For the config mentioned originally in question:
social {
twitter {
url="https://twitter.com"
logo="images/twitter.png"
}
facebook {
url="https://www.facebook.com"
logo="images/facebook.png"
}
}
A solution in Java is:
val socialConfig = ConfigFactory.load.getConfig("social");
ConfigList socials = socialConfig.getList("social");
Map<String, Object> map = socials.root().unwrapped();
for (Map.Entry<String, Object> cv : map.entrySet()) {
Map<String, String> c = (Map<String, String>)cv.getValue();
System.out.println(cv.getKey());
System.out.println(c.getOrDefault("url", ""));
System.out.println(c.getOrDefault("logo", ""));
}

how to attach multiple files to email using scala and liftweb

I'm trying to attach multiple files I'm writing REST Service for that but the files are not loading
my code look like below:-
HTML:-
<form action="DemoEmailAttachment" method="post">
To: <input type="text" name="to"><br>
Subject: <input type="text" name="subject"><br>
Body:<textarea rows="4" cols="50" name="body"></textarea><br>
AttachFiles:<input type="file" name="fileupload" multiple="multiple"><br>
<input type="submit" value="Send">
</form>
SCALA:-
object demoAttachment {
def sendAtchMail(request: Req) = {
val obj = request._params
println(obj)
LiftRules.handleMimeFile = OnDiskFileParamHolder.apply
val fileupload = request.uploadedFiles
println(fileupload)
val to = (obj.get("to").get)(0).split(",")
val subject = obj.get("subject").get
val body = obj.get("body").get
case class CSVFile(bytes: Array[Byte],filename:String,mime:String )
var data = Array[Byte]()
println(data.length)
val ls = fileupload.map(c => c match {
case ff:OnDiskFileParamHolder => { ff.fileStream.read(data)
val attach = CSVFile(data,ff.fileName,ff.mimeType)
val msg = XHTMLPlusImages(<p>Please research the enclosed. </p>,PlusImageHolder(attach.filename, attach.mime, attach.bytes))
Mailer.sendMail(
From("536#gmail.com"),
Subject(subject(0)),
To(to(0)),
msg
)
}
case _ => "there are no files"
} )
"success"
}
}
The XHTMLPlusImages constructor takes a vararg for the attachment parameter. So, just pass in multiple attachments, like this:
XHTMLPlusImages(NodeSeq, attach1, attach2, attach3, ...)
Also, you should verify that data actually contains what you are looking send. Unless I am mistaken, the way you are reading the data from the stream will only read in however many bytes your Array[Byte] can hold, which is probably 0. There is a good answer here that discusses reading from the InputStream to a ByteArray.

validation of fields in a form in scala with lift frame work

I am working with the Lift framework and Scala. I have a form to sign up to my application, and I want to validate all the fields in it. I have a snippet where I access my form values, and one validation class where I wrote my validation functions. The following code is what I've tried so far. In my Snippet:
if(validationClassObject.validateName(first_name)){
if(validationClassObject.validateName(last_name)){
if(validationClassObject.validateEmail(email)){
if(validationClassObject.validateUserName(name)){
// Adding values to the DB
S.redirectTo("/")
}
else{
S.notice("Invalid User Name")
}
}
else{
S.notice("Invalid Mail Id")
}
}
else{
S.notice("Invalid Last name")
}
}
else{
S.notice("Invalid First Name")
}
In the validationClass I wrote the validation code looks like:
//function for validating mail address
def validateEmail(email: String): Boolean =
"""(\w+)#([\w\.]+)""".r.unapplySeq(email).isDefined
//code for validating remaining fileds like above
This is working, but I know this is not the best way of coding this operation in Scala. How could I modify my code in a more scalable way? How can I use case classes here?
You could do:
def av[T,V](validationFunction: => Boolean, error: => T)(f: => V)={
if(!validationFunction) error
else f
}
def v[V](validationFunction: => Boolean, error: => String)(f: => V)=av(validationFunction,S.notice(error))(f)
import validationCalssObject._
v(validateName(last_name),"Invalid Last name"){v(validateName(name),"Invalid User Name"){...}}
av is a abstract method with T and V as result types for the error function and continue function f. v is the more specific function what expects a string for error and encapsulates the notice() call. we give f as the part in the curly braces v(validation, errormsg){/*todo when there is no problem*/}.
I can't do formatting in comments so I'll post a new answer.
def badName() = if ("name" == "") Some("bad name") else None
def badEmail() = if ("email" == "") Some("bad email") else None
val verifications = List[() => Option[String]](badName, badEmail)
val failed = verifications.flatMap(_())
if (failed.nonEmpty) {
// handle failed
} else {
// your custom logic here
}
if (badName) S.notice
else if (badEmail) S.notice
else if (badDay) S.notice
else { // everything OK...
// return a JsCmd or what else do you wanted here
}
An alternative solution can be written using Option and flatMap, without these all "if"-s hardcoded. If you're interested in that -- ask..

Uploading multiple large files and other form data in playframework 2/scala

I am trying to upload multiple large files in the play framework using scala. I'm still a scala and play noob.
I got some great code from here which got me 90% of the way, but now I'm stuck again.
The main issue I have now is that I can only read the file data, not any other data that's been uploaded, and after poking around the play docs I'm unclear as to how to get at that from here. Any Suggestions appreciated!
def directUpload(projectId: String) = Secured(parse.multipartFormData(myFilePartHandler)) { implicit request =>
Ok("Done");
}
def myFilePartHandler: BodyParsers.parse.Multipart.PartHandler[MultipartFormData.FilePart[Result]] = {
parse.Multipart.handleFilePart {
case parse.Multipart.FileInfo(partName, filename, contentType) =>
println("Handling Streaming Upload:" + filename + "/" + partName + ", " + contentType);
//Set up the PipedOutputStream here, give the input stream to a worker thread
val pos: PipedOutputStream = new PipedOutputStream();
val pis: PipedInputStream = new PipedInputStream(pos);
val worker: UploadFileWorker = new UploadFileWorker(pis,contentType.get);
worker.start();
//Read content to the POS
play.api.libs.iteratee.Iteratee.fold[Array[Byte], PipedOutputStream](pos) { (os, data) =>
os.write(data)
os
}.mapDone { os =>
os.close()
worker.join()
if( worker.success )
Ok("uplaod done. Size: " + worker.size )
else
Status(503)("Upload Failed");
}
}
}
You have to handle the data part. As you can guess (or look up in the documentation) the function to handle the data part ist called: handleFilePart.
def myFilePartHandler: BodyParsers.parse.Multipart.PartHandler[MultipartFormData.FilePart[Result]] = {
parse.Multipart.handleFilePart {
// ...
}
parse.Multipart.handleFilePart {
// ...
}
}
Another way would be the handlePart method. Check the documentation for more details.

Lift Scala - Redirect not working for Two Phased Form

I have a two stage form which im trying to implement in Lift Scala. I have the first stage of the form working but the second stage is not working as expected.
The first form asks the user for some input, on submission this will take the user to the second form with the details from the first form shown. The user can enter some text in the textfield and then click submit to view the form results. The second form should be made available to any other users so that they can enter a description for the title given by the initial user.
The way it should work is as follows - user 1 adds a title (form phase one), another user can enter a description (form phase two) and then submit the form to view the results. However, when a user enters the description on form phase two and clicks submit - nothing happens. No redirect and no error.
Any help on this is much appreciated.
My code is below, is this the correct approach?
class TwoPhaseForm extends DispatchSnippet with Logger {
def dispatch : DispatchIt = {
case "addformphaseone" => addformphaseone _
case "viewformphaseone" => viewformphaseone _
case "addformphasetwo" => addformphasetwo _
case "viewresults" => viewresults _
}
object currentAccountVar extends RequestVar[Entry]({
Entry.create.author(User.currentUser.open_!)
})
def currentAccount = currentAccountVar.is
//The first part of the form
def addformphaseone (xhtml : NodeSeq) : NodeSeq = {
def doSave () = {
currentAccount.validate match {
case Nil =>
currentAccount.save
S.redirectTo("/viewformphaseone?id=" + currentAccount.id)
case x => S.error(x)
}
}
val acct = currentAccount
bind("entry", xhtml,
"id" -> SHtml.hidden(() => currentAccountVar(acct)),
"title" -> SHtml.text(currentAccount.title.is, currentAccount.title(_)),
"submit" -> SHtml.submit("Submit", doSave))
}
//view the details from form phase one
def viewformphaseone(xhtml : NodeSeq) : NodeSeq = {
val t = Entry.find(S.param("id"))
t.map(t =>
bind("entry", xhtml,
"title" -> t.title.toString,
)) openOr <span>Not found!</span> <b>Not found!</b>
}
//Second phase of the form
def addformphasetwo (xhtml : NodeSeq) : NodeSeq = {
def doSave () = {
currentAccount.validate match {
case Nil =>
currentAccount.save
S.redirectTo("/results")
case x => S.error(x)
}
}
val t = Entry.find(S.param("id"))
t.map(t =>
bind("entry", xhtml,
"desc" -> SHtml.text(currentAccount.desc.is, currentAccount.desc(_)),
"submit" -> SHtml.submit("Submit", doSave)
)) openOr <span>Not found!</span> <b>Not found!</b>
}
//view the results from both forms
def viewresults(xhtml : NodeSeq) : NodeSeq = {
val t = Entry.find(S.param("id"))
t.map(t =>
bind("entry", xhtml,
"title" -> t.title.toString,
"desc" -> t.desc.toString,
)) openOr <span>Not found!</span> <b>Not found!</b>
}
}
a typical school boy error. from the "Exploring Lift book":
If the form attribute is included with a value of either “POST” or “GET”, then an appropriate form tag will be emitted into the XHTML using the specified submission method. If you omit this tag from a snippet that generates a form, the form elements will display but the form won’t submit.
I had missed the form="POST" tag in my html file. Hence the form was not being submited