From a022850963552096dab032fb57c16d3b1d3ac51a Mon Sep 17 00:00:00 2001 From: Pacien TRAN-GIRARD Date: Sun, 8 Feb 2015 15:47:07 +0100 Subject: Add sign up form and AutoInc on tables uuid --- app/controllers/Account.scala | 19 +++ app/controllers/Application.scala | 9 +- app/controllers/Console.scala | 7 +- app/controllers/Profile.scala | 141 ++++++++++++++++++++++ app/models/Tables.scala | 22 ++-- app/views/fragments/accountInfos.scala.html | 2 +- app/views/fragments/forms/inputField.scala.html | 1 + app/views/fragments/forms/inputLabel.scala.html | 3 + app/views/fragments/forms/labeledField.scala.html | 4 + app/views/pages/signupForm.scala.html | 43 +++++++ conf/routes | 11 +- 11 files changed, 230 insertions(+), 32 deletions(-) create mode 100644 app/controllers/Account.scala create mode 100644 app/controllers/Profile.scala create mode 100644 app/views/fragments/forms/inputLabel.scala.html create mode 100644 app/views/fragments/forms/labeledField.scala.html create mode 100644 app/views/pages/signupForm.scala.html diff --git a/app/controllers/Account.scala b/app/controllers/Account.scala new file mode 100644 index 0000000..ff1d44d --- /dev/null +++ b/app/controllers/Account.scala @@ -0,0 +1,19 @@ +package controllers + +import play.api._ +import play.api.data._ +import play.api.data.Forms._ +import play.api.mvc._ + +import play.api.db.slick._ +import play.api.db.slick.Config.driver.simple._ +import play.api.Play.current + +import scala.concurrent.Future + +import models._ + + +object Account { + +} diff --git a/app/controllers/Application.scala b/app/controllers/Application.scala index 93bba51..deb96d8 100644 --- a/app/controllers/Application.scala +++ b/app/controllers/Application.scala @@ -13,20 +13,13 @@ import scala.concurrent.Future import models._ + object Application extends Controller { def index = Auth { implicit request => Ok(views.html.pages.ebeHomepage()) } - def ebe = Auth { implicit request => - Ok(views.html.pages.ebeHomepage()) - } - - def pepal = Auth { implicit request => - Ok(views.html.pages.pepalHomepage()) - } - def terms = Auth { implicit request => Ok(views.html.pages.terms()) } diff --git a/app/controllers/Console.scala b/app/controllers/Console.scala index 58a2478..5c576b5 100644 --- a/app/controllers/Console.scala +++ b/app/controllers/Console.scala @@ -1,7 +1,5 @@ package controllers -import java.sql.Timestamp - import play.api._ import play.api.data._ import play.api.data.Forms._ @@ -42,11 +40,10 @@ object Console extends Controller { if (grant > 0) { Tables.Transactions += Tables.Transaction( - uuid = java.util.UUID.randomUUID.toString, userUuid = request.account.get.userUuid.get, - transactionDate = new Timestamp(new java.util.Date().getTime), + transactionDate = new java.sql.Timestamp(new java.util.Date().getTime), amount = grant, - label = commandData.command + label = "GRANT " + commandData.command ) Redirect(routes.Application.index()).flashing("success" -> commandData.command) diff --git a/app/controllers/Profile.scala b/app/controllers/Profile.scala new file mode 100644 index 0000000..a41b3e9 --- /dev/null +++ b/app/controllers/Profile.scala @@ -0,0 +1,141 @@ +package controllers + +import play.api._ +import play.api.data._ +import play.api.data.Forms._ +import play.api.mvc._ + +import play.api.db.slick._ +import play.api.db.slick.Config.driver.simple._ +import play.api.Play.current + +import scala.concurrent.Future + +import models._ + + +case class SignupData(username: String, + email: String, + password: String, + passwordCheck: String, + firstName: String, + lastName: String, + country: String, + postalCode: String, + address: String, + phone: String, + birthdate: java.sql.Date) + +case class ProfileData(email: String, + password: String, + passwordCheck: String, + country: String, + postalCode: String, + address: String, + phone: String) + + +object Profile extends Controller { + + val signupForm = Form( + mapping( + "username" -> nonEmptyText(minLength = 3, maxLength = 20), + "email" -> email, + "password" -> nonEmptyText(minLength = 5, maxLength = 255), + "passwordCheck" -> nonEmptyText(minLength = 5, maxLength = 255), + "firstName" -> nonEmptyText(minLength = 1, maxLength = 255), + "lastName" -> nonEmptyText(minLength = 1, maxLength = 255), + "country" -> nonEmptyText(minLength = 2, maxLength = 2), + "postalCode" -> nonEmptyText(minLength = 4, maxLength = 20), + "address" -> nonEmptyText(minLength = 5, maxLength = 255), + "phone" -> nonEmptyText(minLength = 5, maxLength = 20), + "birthdate" -> sqlDate + )(SignupData.apply)(SignupData.unapply) + .verifying("Password mismatch", fields => fields match { + case profileData => checkPasswordCoherence(profileData.password, profileData.passwordCheck) + }) + .verifying("Username already registered", fields => fields match { + case profileData => !checkUsernameUse(profileData.username) + }) + .verifying("Email address already in use", fields => fields match { + case profileData => !checkEmailUse(profileData.email) + }) + ) + + val profileForm = Form( + mapping( + "email" -> email, + "password" -> text(maxLength = 255), + "passwordCheck" -> text(maxLength = 255), + "country" -> nonEmptyText(minLength = 2, maxLength = 2), + "postalCode" -> nonEmptyText(minLength = 4, maxLength = 20), + "address" -> nonEmptyText(minLength = 5, maxLength = 255), + "phone" -> nonEmptyText(minLength = 5, maxLength = 20) + )(ProfileData.apply)(ProfileData.unapply) + .verifying("Password mismatch", fields => fields match { + case profileData => checkPasswordCoherence(profileData.password, profileData.passwordCheck) + }) + .verifying("Email address already in use", fields => fields match { + case profileData => !checkEmailUse(profileData.email) + }) + ) + + + def checkPasswordCoherence(p1: String, p2: String) = { + p1 == p2 + } + + def checkUsernameUse(username: String) = DB.withSession { implicit session => + Tables.Users.filter(_.username === username).length.run > 0 + } + + def checkEmailUse(email: String) = DB.withSession { implicit session => + Tables.Users.filter(_.email === email).length.run > 0 + } + + + def signup = Auth { implicit request => + if (request.account.nonEmpty) { + Redirect(routes.Application.index()) + } else { + Ok(views.html.pages.signupForm(signupForm)) + } + } + + def signupSubmit = Auth { implicit request => + if (request.account.nonEmpty) { + Redirect(routes.Application.index()) + } else { + DB.withSession { implicit session => + signupForm.bindFromRequest.fold( + formWithErrors => { + BadRequest(views.html.pages.signupForm(formWithErrors)) + }, + validForm => { + + val users = Tables.Users returning Tables.Users.map(_.uuid) + val uuid = users += Tables.User( + username = validForm.username, + email = validForm.email, + userPassword = validForm.password, + creationDate = new java.sql.Timestamp(new java.util.Date().getTime), + firstName = validForm.firstName, + lastName = validForm.lastName, + countryCode = validForm.country, + postalCode = validForm.postalCode, + address = validForm.address, + phone = validForm.phone, + birthdate = new java.sql.Timestamp(validForm.birthdate.getTime) + ) + + Redirect(routes.Application.index()) + .withSession(Security.username -> uuid) + .flashing("success" -> "You are now registered. Welcome! You may now spend your money.") + + } + ) + } + } + } + +} diff --git a/app/models/Tables.scala b/app/models/Tables.scala index ff1f267..24e0aeb 100644 --- a/app/models/Tables.scala +++ b/app/models/Tables.scala @@ -22,7 +22,7 @@ trait Tables { * @param userUuid Database column user_uuid DBType(varchar), Length(36,true) * @param bidDate Database column bid_date DBType(timestamptz) * @param offer Database column offer DBType(numeric) */ - case class Bid(uuid: String, itemUuid: String, userUuid: String, bidDate: java.sql.Timestamp, offer: scala.math.BigDecimal) + case class Bid(uuid: String = null, itemUuid: String, userUuid: String, bidDate: java.sql.Timestamp, offer: scala.math.BigDecimal) /** GetResult implicit for fetching Bid objects using plain SQL queries */ implicit def GetResultBid(implicit e0: GR[String], e1: GR[java.sql.Timestamp], e2: GR[scala.math.BigDecimal]): GR[Bid] = GR{ prs => import prs._ @@ -35,7 +35,7 @@ trait Tables { def ? = (uuid.?, itemUuid.?, userUuid.?, bidDate.?, offer.?).shaped.<>({r=>import r._; _1.map(_=> Bid.tupled((_1.get, _2.get, _3.get, _4.get, _5.get)))}, (_:Any) => throw new Exception("Inserting into ? projection not supported.")) /** Database column uuid DBType(varchar), PrimaryKey, Length(36,true) */ - val uuid: Column[String] = column[String]("uuid", O.PrimaryKey, O.Length(36,varying=true)) + val uuid: Column[String] = column[String]("uuid", O.PrimaryKey, O.Length(36,varying=true), O.AutoInc) /** Database column item_uuid DBType(varchar), Length(36,true) */ val itemUuid: Column[String] = column[String]("item_uuid", O.Length(36,varying=true)) /** Database column user_uuid DBType(varchar), Length(36,true) */ @@ -59,7 +59,7 @@ trait Tables { * @param endDate Database column end_date DBType(timestamptz) * @param fee Database column fee DBType(numeric) * @param rate Database column rate DBType(numeric) */ - case class Charge(uuid: String, startDate: java.sql.Timestamp, endDate: java.sql.Timestamp, fee: scala.math.BigDecimal, rate: scala.math.BigDecimal) + case class Charge(uuid: String = null, startDate: java.sql.Timestamp, endDate: java.sql.Timestamp, fee: scala.math.BigDecimal, rate: scala.math.BigDecimal) /** GetResult implicit for fetching Charge objects using plain SQL queries */ implicit def GetResultCharge(implicit e0: GR[String], e1: GR[java.sql.Timestamp], e2: GR[scala.math.BigDecimal]): GR[Charge] = GR{ prs => import prs._ @@ -72,7 +72,7 @@ trait Tables { def ? = (uuid.?, startDate.?, endDate.?, fee.?, rate.?).shaped.<>({r=>import r._; _1.map(_=> Charge.tupled((_1.get, _2.get, _3.get, _4.get, _5.get)))}, (_:Any) => throw new Exception("Inserting into ? projection not supported.")) /** Database column uuid DBType(varchar), PrimaryKey, Length(36,true) */ - val uuid: Column[String] = column[String]("uuid", O.PrimaryKey, O.Length(36,varying=true)) + val uuid: Column[String] = column[String]("uuid", O.PrimaryKey, O.Length(36,varying=true), O.AutoInc) /** Database column start_date DBType(timestamptz) */ val startDate: Column[java.sql.Timestamp] = column[java.sql.Timestamp]("start_date") /** Database column end_date DBType(timestamptz) */ @@ -94,7 +94,7 @@ trait Tables { * @param shortDesc Database column short_desc DBType(varchar), Length(30,true) * @param longDesc Database column long_desc DBType(text), Length(2147483647,true) * @param initialPrice Database column initial_price DBType(numeric) */ - case class Item(uuid: String, userUuid: String, startDate: java.sql.Timestamp, endDate: java.sql.Timestamp, itemName: String, shortDesc: String, longDesc: String, initialPrice: scala.math.BigDecimal) + case class Item(uuid: String = null, userUuid: String, startDate: java.sql.Timestamp, endDate: java.sql.Timestamp, itemName: String, shortDesc: String, longDesc: String, initialPrice: scala.math.BigDecimal) /** GetResult implicit for fetching Item objects using plain SQL queries */ implicit def GetResultItem(implicit e0: GR[String], e1: GR[java.sql.Timestamp], e2: GR[scala.math.BigDecimal]): GR[Item] = GR{ prs => import prs._ @@ -107,7 +107,7 @@ trait Tables { def ? = (uuid.?, userUuid.?, startDate.?, endDate.?, itemName.?, shortDesc.?, longDesc.?, initialPrice.?).shaped.<>({r=>import r._; _1.map(_=> Item.tupled((_1.get, _2.get, _3.get, _4.get, _5.get, _6.get, _7.get, _8.get)))}, (_:Any) => throw new Exception("Inserting into ? projection not supported.")) /** Database column uuid DBType(varchar), PrimaryKey, Length(36,true) */ - val uuid: Column[String] = column[String]("uuid", O.PrimaryKey, O.Length(36,varying=true)) + val uuid: Column[String] = column[String]("uuid", O.PrimaryKey, O.Length(36,varying=true), O.AutoInc) /** Database column user_uuid DBType(varchar), Length(36,true) */ val userUuid: Column[String] = column[String]("user_uuid", O.Length(36,varying=true)) /** Database column start_date DBType(timestamptz) */ @@ -135,7 +135,7 @@ trait Tables { * @param transactionDate Database column transaction_date DBType(timestamptz) * @param amount Database column amount DBType(numeric) * @param label Database column label DBType(varchar), Length(255,true) */ - case class Transaction(uuid: String, userUuid: String, transactionDate: java.sql.Timestamp, amount: scala.math.BigDecimal, label: String) + case class Transaction(uuid: String = null, userUuid: String, transactionDate: java.sql.Timestamp, amount: scala.math.BigDecimal, label: String) /** GetResult implicit for fetching Transaction objects using plain SQL queries */ implicit def GetResultTransaction(implicit e0: GR[String], e1: GR[java.sql.Timestamp], e2: GR[scala.math.BigDecimal]): GR[Transaction] = GR{ prs => import prs._ @@ -148,7 +148,7 @@ trait Tables { def ? = (uuid.?, userUuid.?, transactionDate.?, amount.?, label.?).shaped.<>({r=>import r._; _1.map(_=> Transaction.tupled((_1.get, _2.get, _3.get, _4.get, _5.get)))}, (_:Any) => throw new Exception("Inserting into ? projection not supported.")) /** Database column uuid DBType(varchar), PrimaryKey, Length(36,true) */ - val uuid: Column[String] = column[String]("uuid", O.PrimaryKey, O.Length(36,varying=true)) + val uuid: Column[String] = column[String]("uuid", O.PrimaryKey, O.Length(36,varying=true), O.AutoInc) /** Database column user_uuid DBType(varchar), Length(36,true) */ val userUuid: Column[String] = column[String]("user_uuid", O.Length(36,varying=true)) /** Database column transaction_date DBType(timestamptz) */ @@ -177,7 +177,7 @@ trait Tables { * @param address Database column address DBType(varchar), Length(255,true) * @param phone Database column phone DBType(varchar), Length(20,true) * @param birthdate Database column birthdate DBType(timestamptz) */ - case class User(uuid: String, username: String, email: String, userPassword: String, creationDate: java.sql.Timestamp, firstName: String, lastName: String, countryCode: String, postalCode: String, address: String, phone: String, birthdate: java.sql.Timestamp) + case class User(uuid: String = null, username: String, email: String, userPassword: String, creationDate: java.sql.Timestamp, firstName: String, lastName: String, countryCode: String, postalCode: String, address: String, phone: String, birthdate: java.sql.Timestamp) /** GetResult implicit for fetching User objects using plain SQL queries */ implicit def GetResultUser(implicit e0: GR[String], e1: GR[java.sql.Timestamp]): GR[User] = GR{ prs => import prs._ @@ -190,7 +190,7 @@ trait Tables { def ? = (uuid.?, username.?, email.?, userPassword.?, creationDate.?, firstName.?, lastName.?, countryCode.?, postalCode.?, address.?, phone.?, birthdate.?).shaped.<>({r=>import r._; _1.map(_=> User.tupled((_1.get, _2.get, _3.get, _4.get, _5.get, _6.get, _7.get, _8.get, _9.get, _10.get, _11.get, _12.get)))}, (_:Any) => throw new Exception("Inserting into ? projection not supported.")) /** Database column uuid DBType(varchar), PrimaryKey, Length(36,true) */ - val uuid: Column[String] = column[String]("uuid", O.PrimaryKey, O.Length(36,varying=true)) + val uuid: Column[String] = column[String]("uuid", O.PrimaryKey, O.Length(36,varying=true), O.AutoInc) /** Database column username DBType(varchar), Length(20,true) */ val username: Column[String] = column[String]("username", O.Length(20,varying=true)) /** Database column email DBType(varchar), Length(255,true) */ @@ -219,4 +219,4 @@ trait Tables { } /** Collection-like TableQuery object for table Users */ lazy val Users = new TableQuery(tag => new Users(tag)) -} \ No newline at end of file +} diff --git a/app/views/fragments/accountInfos.scala.html b/app/views/fragments/accountInfos.scala.html index 6bf8655..887e485 100644 --- a/app/views/fragments/accountInfos.scala.html +++ b/app/views/fragments/accountInfos.scala.html @@ -19,7 +19,7 @@ } case None => { - + Sign up diff --git a/app/views/fragments/forms/inputField.scala.html b/app/views/fragments/forms/inputField.scala.html index 7de0e3b..41b6656 100644 --- a/app/views/fragments/forms/inputField.scala.html +++ b/app/views/fragments/forms/inputField.scala.html @@ -7,4 +7,5 @@ placeholder="@label" name="@field.name" id="@field.name" value="@field.value" +required > diff --git a/app/views/fragments/forms/inputLabel.scala.html b/app/views/fragments/forms/inputLabel.scala.html new file mode 100644 index 0000000..d03a23b --- /dev/null +++ b/app/views/fragments/forms/inputLabel.scala.html @@ -0,0 +1,3 @@ +@(field: Field, label: String) + + diff --git a/app/views/fragments/forms/labeledField.scala.html b/app/views/fragments/forms/labeledField.scala.html new file mode 100644 index 0000000..6a2c697 --- /dev/null +++ b/app/views/fragments/forms/labeledField.scala.html @@ -0,0 +1,4 @@ +@(field: Field, inputType: String, label: String) + +@views.html.fragments.forms.inputLabel(field, label) +@views.html.fragments.forms.inputField(field, inputType, label) diff --git a/app/views/pages/signupForm.scala.html b/app/views/pages/signupForm.scala.html new file mode 100644 index 0000000..b026167 --- /dev/null +++ b/app/views/pages/signupForm.scala.html @@ -0,0 +1,43 @@ +@(signupForm: Form[SignupData])(implicit flash: Flash, token: play.filters.csrf.CSRF.Token) + +@templates.ebe("Sign up")() { + +
+
+ +

Sign up

+ + @views.html.fragments.forms.globalErrors(signupForm) + + @helper.form(action = routes.Profile.signupSubmit(), 'class -> "pure-form pure-form-stacked") { + + @helper.CSRF.formField + +
+ @views.html.fragments.forms.labeledField(signupForm("username"), "text", "Username") + @views.html.fragments.forms.labeledField(signupForm("password"), "password", "Password") + @views.html.fragments.forms.labeledField(signupForm("passwordCheck"), "password", "Password check") +
+ +
+ @views.html.fragments.forms.labeledField(signupForm("firstName"), "text", "First name") + @views.html.fragments.forms.labeledField(signupForm("lastName"), "text", "Last name") + @views.html.fragments.forms.labeledField(signupForm("birthdate"), "date", "Birthdate") +
+ +
+ @views.html.fragments.forms.labeledField(signupForm("email"), "email", "E-mail address") + @views.html.fragments.forms.labeledField(signupForm("phone"), "tel", "Phone number") + @views.html.fragments.forms.labeledField(signupForm("address"), "text", "Address") + @views.html.fragments.forms.labeledField(signupForm("postalCode"), "text", "Postal code") + @views.html.fragments.forms.labeledField(signupForm("country"), "text", "Country code") +
+ + + + } + +
+
+ +} diff --git a/conf/routes b/conf/routes index e8a880e..732fa3f 100644 --- a/conf/routes +++ b/conf/routes @@ -2,9 +2,6 @@ # This file defines all application routes (Higher priority routes first) # ~~~~ -# Dev -GET /ebe controllers.Application.ebe -GET /pepal controllers.Application.pepal # Home page GET / controllers.Application.index @@ -16,10 +13,10 @@ GET /login controllers.Authentication.login POST /login controllers.Authentication.loginSubmit GET /logout controllers.Authentication.logout -# -#GET /signup controllers.Application.index -#POST /signup controllers.Application.index -# + +GET /signup controllers.Profile.signup +POST /signup controllers.Profile.signupSubmit + #GET /profile controllers.Application.index #POST /profile controllers.Application.index # -- cgit v1.2.3