From d79239a89c795035ea8d8a971aa9953d9e9a8e48 Mon Sep 17 00:00:00 2001 From: Pacien TRAN-GIRARD Date: Mon, 9 Feb 2015 00:14:18 +0100 Subject: Implement item pages and bids --- app/controllers/Sale.scala | 81 +++++++++++++++++++- app/views/pages/sales/itemPage.scala.html | 120 ++++++++++++++++++++++++++++++ conf/routes | 51 +++++++------ 3 files changed, 223 insertions(+), 29 deletions(-) create mode 100644 app/views/pages/sales/itemPage.scala.html diff --git a/app/controllers/Sale.scala b/app/controllers/Sale.scala index e6244c3..d6dab2d 100644 --- a/app/controllers/Sale.scala +++ b/app/controllers/Sale.scala @@ -1,5 +1,6 @@ package controllers +import org.omg.CosNaming._BindingIteratorImplBase import play.api._ import play.api.data._ import play.api.data.Forms._ @@ -20,6 +21,8 @@ case class SaleData(endDate: java.sql.Date, longDescription: String, initialPrice: BigDecimal) +case class BidData(offer: BigDecimal) + object Sale extends Controller { def sales = Auth { implicit request => @@ -82,11 +85,83 @@ object Sale extends Controller { } } + val bidForm = Form( + mapping( + "offer" -> bigDecimal(precision = 8, scale = 2) + )(BidData.apply)(BidData.unapply) + ) - def item(itemUuid: String) = TODO + def item(itemUuid: String) = Auth { implicit request => + DB.withSession { implicit session => + val item = Some(Tables.Items.filter(_.uuid === itemUuid).first) + + if (item.isEmpty) { + Redirect(routes.Sale.sales()) + .flashing("error" -> "Item not found") + } else { + val seller = Tables.Users.filter(_.uuid === item.get.userUuid).first + val bids = Tables.Bids.filter(_.itemUuid === item.get.uuid).sortBy(_.bidDate.desc) + val bidders = Tables.Users + val bidsWithBidders = (bids join bidders on (_.userUuid === _.uuid)).run + Ok(views.html.pages.sales.itemPage(item.get, seller, bidsWithBidders, bidForm)) + } + } + } - def bids(itemUuid: String) = TODO + def bidSubmit(itemUuid: String) = Auth { implicit request => + if (request.account.isEmpty) { + Redirect(routes.Authentication.login()) + .flashing("error" -> "Authentication required") + } else { + DB.withSession { implicit session => + val item = Some(Tables.Items.filter(_.uuid === itemUuid).first) + val currentTimestamp = new java.sql.Timestamp((new java.util.Date).getTime) + + if (item.isEmpty) { + Redirect(routes.Sale.sales()) + .flashing("error" -> "Item not found") + } else if (item.get.endDate before currentTimestamp) { + Redirect(routes.Sale.item(itemUuid)) + .flashing("error" -> "This sale has already ended") + } else { + + bidForm.bindFromRequest.fold( + formsWithErrors => { + Redirect(routes.Sale.item(itemUuid)) + .flashing("error" -> "Invalid bid") + }, + validForm => { + + val bids = Tables.Bids.filter(_.itemUuid === itemUuid).sortBy(_.bidDate.desc).run + val offersEnough = validForm.offer > item.get.initialPrice && (bids.isEmpty || validForm.offer > bids.head.offer) + + val userEquity = Views.Accounts.filter(_.userUuid === request.account.get.userUuid).map(_.equity).first.get + val enoughFunds = validForm.offer < userEquity + + if (!enoughFunds) { + Redirect(routes.Sale.item(itemUuid)) + .flashing("error" -> "You are too poor!") + } else if (!offersEnough) { + Redirect(routes.Sale.item(itemUuid)) + .flashing("error" -> "Please offer more.") + } else { + Tables.Bids += new Tables.Bid( + itemUuid = itemUuid, + userUuid = request.account.get.userUuid.get, + bidDate = currentTimestamp, + offer = validForm.offer + ) + + Redirect(routes.Sale.item(itemUuid)) + .flashing("success" -> "Thanks!") + } + } + ) + + } - def bidSubmit(itemUuid: String) = TODO + } + } + } } diff --git a/app/views/pages/sales/itemPage.scala.html b/app/views/pages/sales/itemPage.scala.html new file mode 100644 index 0000000..adfd5da --- /dev/null +++ b/app/views/pages/sales/itemPage.scala.html @@ -0,0 +1,120 @@ +@(item: Tables.Item, seller: Tables.User, bids: Seq[(Tables.Bid, Tables.User)], bidForm: Form[BidData])(implicit request: AuthRequest[AnyContent], flash: Flash, token: play.filters.csrf.CSRF.Token) + +@templates.ebe("Item page")(request.account) { + +

Item summary: @item.itemName

+ +
+
+
+ + + + + + + + + + + + + + + + + + +
Item summary
Item name@item.itemName
Short description@item.shortDesc
+
+ +
+ + + + + + + + + + + + + +
Detailed description
@item.longDesc
+
+
+ +
+
+ + + + + + + + + + + + + + + + + +
Bid
Current price + @if(bids.nonEmpty) { + @bids.head._1.offer + } else { + @item.initialPrice + } € +
+ @helper.form(action = routes.Sale.bidSubmit(item.uuid), 'class -> "pure-form") { + + @helper.CSRF.formField + +
+
+ @views.html.fragments.forms.inputField(bidForm("offer"), "number", "Offer") +
+ +
+ +
+
+ } +
+
+ +
+ + + + + + + + + @if(bids.isEmpty) { + + + + } + + @for(bid <- bids) { + + + + + } + +
Bid history
No bid
@bid._2.username@bid._1.offer
+
+
+
+ + +} diff --git a/conf/routes b/conf/routes index 903480d..21a5b46 100644 --- a/conf/routes +++ b/conf/routes @@ -4,51 +4,50 @@ # Home page -GET / controllers.Application.index -GET /terms controllers.Application.terms -GET /privacy controllers.Application.privacy +GET / controllers.Application.index +GET /terms controllers.Application.terms +GET /privacy controllers.Application.privacy # User account -GET /login controllers.Authentication.login -POST /login controllers.Authentication.loginSubmit +GET /login controllers.Authentication.login +POST /login controllers.Authentication.loginSubmit -GET /logout controllers.Authentication.logout +GET /logout controllers.Authentication.logout -GET /signup controllers.Profile.signup -POST /signup controllers.Profile.signupSubmit +GET /signup controllers.Profile.signup +POST /signup controllers.Profile.signupSubmit -GET /account controllers.Profile.editProfile -POST /account controllers.Profile.editProfile +GET /account controllers.Profile.editProfile +POST /account controllers.Profile.editProfile -GET /profile/:uuid controllers.Profile.viewProfile(uuid) +GET /profile/:uuid controllers.Profile.viewProfile(uuid) # Internal wallet and transactions (Pépal) -GET /summary controllers.Account.summary +GET /summary controllers.Account.summary -GET /deposit controllers.Account.deposit -POST /deposit controllers.Account.deposit +GET /deposit controllers.Account.deposit +POST /deposit controllers.Account.deposit -GET /withdraw controllers.Account.withdraw -POST /withdraw controllers.Account.withdraw +GET /withdraw controllers.Account.withdraw +POST /withdraw controllers.Account.withdraw -GET /transfer controllers.Account.transfer -POST /transfer controllers.Account.transfer +GET /transfer controllers.Account.transfer +POST /transfer controllers.Account.transfer # Items and sales (eBé) -GET /sales controllers.Sale.sales +GET /sales controllers.Sale.sales -GET /item/:uuid controllers.Sale.item(uuid) +GET /item/:uuid controllers.Sale.item(uuid) -GET /item/:uuid/bids controllers.Sale.bids(uuid) -POST /item/:uuid/bids controllers.Sale.bids(uuid) +POST /item/:uuid/bid controllers.Sale.bidSubmit(uuid) -GET /sell controllers.Sale.sell +GET /sell controllers.Sale.sell #GET /sell/:uuid controllers.Sale.sell(uuid) -POST /sell controllers.Sale.sellSubmit +POST /sell controllers.Sale.sellSubmit #POST /sell/:uuid controllers.Sale.sell # Cheat console -POST /console controllers.Console.console +POST /console controllers.Console.console # Map static resources from the /public folder to the /assets URL path -GET /assets/*file controllers.Assets.at(path="/public", file) +GET /assets/*file controllers.Assets.at(path="/public", file) -- cgit v1.2.3