how to attach multiple files to email using scala and liftweb - scala

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.

Related

[Play]Don't use multiple parameters in a route for display a view that takes multiple parameters

I'm writing a Play 2.3.2 application in Scala.
In My application I'm using a form representing an Integer range(start, finish).
The range class is written as following:
case class Range (
startDate: Long,
finishDate: Long)
I've defined a form like the following:
val rangeForm: Form[Range] = Form (
mapping(
"startDate" -> longNumber(min = 0, max = System.currentTimeMillis()),
"finishDate" -> longNumber(min = 0, max = System.currentTimeMillis())
)(Range.apply)(Range.unapply)
)
In my StatisticsController class I've defined three four:
calculateStatisticsOnRange(range: Range): Future[(Double, Int)]: that calculate the number and average of click of the user in a range;
getCalculateStatisticsOnRangeForm that display the form
calculateGoodAdvicesHtml that check if the form has errors
displayStatistics(average: Double, count:Int) that display the result of the search.
My form view is implemented like:
#(rangeForm: Form[recommendationsystem.models.Range])
#recommendationsystem.views.html.main("Insert a range")(recommendationsystem.views.html.nav.navbar("statistics")) {
<h1>Insert here the range</h1>
<div class="container">
#helper.form(action = recommendationsystem.controllers.manager.routes.StatisticsController.calculateGoodAdvicesHtml()) {
<label for="startDate">Start Date:</label>
<input type="number" class="form-control" placeholder = "start"
name="startDate" value="#rangeForm("startDate")" />
<input type="number" class="form-control" placeholder="finish"
name="finishDate" value="#rangeForm("finishDate")" />
<button type="submit" class="btn btn-default">Search</button>
}
</div>
}
My controller methods are implemented like:
def getCalculateStatisticsOnRangeForm = Action {
Ok(recommendationsystem.views.html.manager.statistics.forms.rangeform(rangeForm))
}
def calculateGoodAdvicesHtml = Action.async { implicit request =>
val form = rangeForm.bindFromRequest
form.fold(
errors => Future{BadRequest(recommendationsystem.views.html.manager.statistics.forms.rangeform(errors))},
range => {calculateStatisticsOnRange(range) flatMap {result => Future{Redirect(routes.StatisticsController.displayStatistics(result._1, result._2))}}}
)
}
def displayStatistics(average: Double, count:Int) = Action{
Ok(recommendationsystem.views.html.manager.statistics.goodadvise(average, count))
}
In my route file I've the following routes:
GET /statistics/good #recommendationsystem.controllers.manager.StatisticsController.getCalculateStatisticsOnRangeForm
POST /statistics/good #recommendationsystem.controllers.manager.StatisticsController.calculateGoodAdvicesHtml
POST /statistics/good/json #recommendationsystem.controllers.manager.StatisticsController.calculateGoodAdvicesJson
GET /statistics/:average/:count #recommendationsystem.controllers.manager.StatisticsController.displayStatistics(average: Double, count: Int)
I don't like to pass multiple parameters in the route of /statistics/:average/:count, there is an other way to make that?

Playframework 2.2.1 Scala - Form bindFromRequest error

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

Lift (Scala) form validation

I have a question for which I couldn't find an answer anywhere in the web. I have a lift-based web application written on Scala. There is a form in my application which is driven by a snippet. I use Mapper for my models, and I use override def validations ... to define model's validation parameters. The template code looks like this:
<form class="lift:GroupManager.addGroup?form=POST&action=add">
<div class="row collapse" style="width: 30em">
<div class="small-8 columns">
<span class="group-name prefix radius"></span>
</div>
<div class="small-4 columns">
<span class="submit button small postfix radius">Add New Group</span>
</div>
</div>
</span>
</form>
The snippet code:
def addGroup = {
object groupName extends RequestVar[String]("")
def doAddGroup() = {
val group = Group.create.createdAt(new java.util.Date).groupName(groupName.is)
group.validate match {
case Nil => {
group.save
S.notice("Group '" + group.groupName.is + "' has been added successfully")
}
case errors:List[FieldError] => {
S.error(errors)
}
}
}
".group-name" #> SHtml.text(groupName.is, groupName(_), "id" -> "group-name") &
".submit" #> SHtml.submit("Add group", doAddGroup)
}
The model's validations override:
object groupName extends MappedString(this, 700) {
override def dbColumnName = "group_name"
override def dbNotNull_? = true
override def validations = valMinLen(1, S.?("Group name should not be empty!")) _ ::
valMaxLen(700, S.?("Group name should not be more than 700 characters long!")) _ ::
valUnique(S.?("Group name should be unique!")) _ ::
super.validations
}
Now everything is perfect except the fact that when invalid data is provided, S.error is used to inform user about problems. What I want to do is to highlight the form element (by applying class="error") in which the data is invalid and add a <span> element with the error message in front of the form element. Is there a simple way to do that with Lift framework? Or I should just traverse through errors:List[FieldError] and fetch field information from that array, which does not seem too elegant to me?

Play framework if else case Not working

Play framework if else case is not working here
If userprofile.useraccountid, useraccount.id have the same value then not views that id user on view page
my code in the view..
#(userprofiles: List[UserProfile],myFriend:models.MyFriend,userprofile:models.UserProfile,useraccount:models.UserAccount)
#helper.form(action = routes.Application.createMyFriend) {
<br/><br/><br/>
#for(userprofile <- userprofiles){
#if(userprofile.useraccountid != useraccount.id) {
<img src="#routes.Assets.at("images/img2.png")" width="200" height="200" />
<br>
<h5>#userprofile.name</h5>
<h5>#userprofile.useraccountid</h5>=<h5>#useraccount.id</h5>
<h6>#userprofile.gender</h6>
<h6>#userprofile.date_of_birth</h6>
<div class="actions">
<input type="submit" class="btn primary" value="+1 Add As Friend" title="Send Friend Request">
</div>
<br/>
}
}
}
when checking the condition the database values are views in the view page and
#if(userprofile.useraccountid != useraccount.id)
if change the condition to
#if(userprofile.useraccountid == useraccount.id)
Nothing will in the view page.
In this code when run the program the code section
<h5>#userprofile.useraccountid</h5>=<h5>#useraccount.id</h5>
The id's are same here , and that show in the view then the idea is not false.. for example 15=15.
Here the 2 id are same but the checking in the if case is not work properly... or the coding is not right.
Edit
This is in application
def listMyFriend = Action { implicit request =>
var cid=request.session.get("userId")
println("aa",cid)
if (request.session.get("userId") == None) {
Results.Redirect("/")
}
else {
val userprofiles:UserProfile=null
val userprofileId = request.session.get("userId").get.toLong//userProfileId
val userprofile = UserProfile.findUserByAccountId(userprofileId).get
println(userprofile)
/* val myfriendId = request.session.get("myFriendId").get.toLong//myFriendId
val myfriend = MyFriend.friendidByUserIsAccepted(myfriendId,true)
println(myfriend)*/
myFriendForm.bindFromRequest.fold(
errors => BadRequest(views.html.myFriend(errors, userprofile,myfriend,myfrnd)),
myFriend => {
println("errors")
val myFriendOpt = UserProfile.myFriend(userprofile.id.get)
println(myFriendOpt)
myFriendOpt match {
case None =>
}
Results.Redirect("/myFriend")
})
}
}
You have shadowing issues in your code: userprofile is both defined as a parameter of your template and as the variable you get out of the for comprehension.
#(userprofiles: List[UserProfile],myFriend:models.MyFriend,userprofile:models.UserProfile,useraccount:models.UserAccount)
here ---^
#helper.form(action = routes.Application.createMyFriend) {
<br/><br/><br/>
#for(userprofile <- userprofiles){
and here ---^
Try renaming one of the two and sort out which one you want to refer to in your if.

Dynamically add textareas client-side to a form in lift

I've got a form based on the sample in http://simply.liftweb.net/index-4.2.html#toc-Section-4.2 and I was wondering if there's a way of having a button on the page that would add a textarea each time it's clicked, and then in the lift code get that as an array of strings.
What I'm picturing is something like this:
<form class="lift:OnSubmit?form=post">
Name: <input name="name"><br>
Age: <input name="age" value="0"><br>
<span id="somecomments"></span>
<input type="button" onclick="$('#somecomments').append($('<textarea cols=80 rows=10 name=comments>'))" value="Add Comment"/>
<input type="submit" value="Submit">
</form>
//in scala:
object OnSubmit {
def render = {
var name = ""
var age = 0
var comments = List("")​
def process() {
S.notice("Name: "+name)
S.notice("Age: "+age)
S.notice(comments)
S.redirectTo("/")
}
}​
"name=name" #> SHtml.onSubmit(name = _) &
"name=age" #> SHtml.onSubmit(s => asInt(s).foreach(age = _)) &
"name=comments" #> SHtml.onSubmit(comments = _) &
"type=submit" #> SHtml.onSubmitUnit(process)
}
}
But I get the compile error that the comments field is a String so I can't assign it to a List with "name=comments" #> SHtml.onSubmit(comments = _)
What's the best way to make this code work?
for prepending:
"name=comments" #> SHtml.onSubmit(comments ::= _)
for appending:
"name=comments" #> SHtml.onSubmit(comments :+= _)
Here I describe how you can add any number of fields (I have a textarea and a "related" numeric field.
You add them using jQuery and then Lift gets all the data as a json object.
Dynamically adding fields to a Lift application