Auctions schema and creation
This commit is contained in:
@@ -0,0 +1,45 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import controllers.authentication.AuthenticatedAction
|
||||||
|
import dao.{AuctionsDAO, AuthTokensDAO}
|
||||||
|
import models.Auction
|
||||||
|
import play.api.libs.functional.syntax.toFunctionalBuilderOps
|
||||||
|
import play.api.libs.json.{JsError, JsPath, JsValue, Json, Reads, Writes}
|
||||||
|
import play.api.mvc.{BaseController, ControllerComponents}
|
||||||
|
|
||||||
|
import java.security.SecureRandom
|
||||||
|
import javax.inject.{Inject, Singleton}
|
||||||
|
import scala.concurrent.{ExecutionContext, Future}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class AuctionsController @Inject()(val controllerComponents: ControllerComponents, val auctionsDAO: AuctionsDAO, val authTokensDAO: AuthTokensDAO, implicit val ec: ExecutionContext) extends BaseController {
|
||||||
|
def create = Action.andThen(AuthenticatedAction(authTokensDAO)).async(parse.json) { implicit request =>
|
||||||
|
val auctionCreateDataResult = request.body.validate[AuctionCreateData]
|
||||||
|
auctionCreateDataResult.fold(
|
||||||
|
errors => Future.successful(BadRequest(JsError.toJson(errors))),
|
||||||
|
auctionCreateData => {
|
||||||
|
for {
|
||||||
|
auction <- auctionsDAO.create(auctionCreateData.name, auctionCreateData.startingPrice, request.user)
|
||||||
|
json = Json.toJson(auction)
|
||||||
|
response = Created(json)
|
||||||
|
} yield response
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
case class AuctionCreateData(name: String, startingPrice: BigDecimal)
|
||||||
|
private implicit val auctionCreateDataReads: Reads[AuctionCreateData] = (
|
||||||
|
(JsPath \ "name").read[String] and (JsPath \ "starting_price").read[BigDecimal]
|
||||||
|
)(AuctionCreateData.apply)
|
||||||
|
private implicit val auctionWrites: Writes[Auction] = new Writes[Auction] {
|
||||||
|
override def writes(a: Auction): JsValue = Json.obj(
|
||||||
|
"id" -> a.id,
|
||||||
|
"name" -> a.name,
|
||||||
|
"gid" -> a.gid,
|
||||||
|
"starting_price" -> a.startingPrice,
|
||||||
|
"current_bid" -> a.currentBid,
|
||||||
|
"current_bidder_id" -> a.currentBidderId,
|
||||||
|
"current_bid_at" -> a.currentBidAt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package dao
|
||||||
|
|
||||||
|
import models.Auction
|
||||||
|
import schemas.Auctions
|
||||||
|
import play.api.db.slick.{DatabaseConfigProvider, HasDatabaseConfigProvider}
|
||||||
|
import slick.jdbc.PostgresProfile
|
||||||
|
import slick.jdbc.PostgresProfile.api.*
|
||||||
|
import utils.Random
|
||||||
|
|
||||||
|
import java.time.Instant
|
||||||
|
import javax.inject.Inject
|
||||||
|
import scala.concurrent.{ExecutionContext, Future}
|
||||||
|
|
||||||
|
class AuctionsDAO @Inject()(protected val dbConfigProvider: DatabaseConfigProvider)(implicit val ec: ExecutionContext)
|
||||||
|
extends HasDatabaseConfigProvider[PostgresProfile] {
|
||||||
|
|
||||||
|
def create(name: String, startingPrice: BigDecimal, author: models.User): Future[Auction] = {
|
||||||
|
val auction = Auction(
|
||||||
|
id = None, name = name,
|
||||||
|
gid = Random.randomBase64(24),
|
||||||
|
authorId = author.id.get,
|
||||||
|
startingPrice = startingPrice,
|
||||||
|
currentBid = None, currentBidderId = None, currentBidAt = None,
|
||||||
|
createdAt = Instant.now()
|
||||||
|
)
|
||||||
|
|
||||||
|
create(auction)
|
||||||
|
}
|
||||||
|
|
||||||
|
def create(auction: Auction) : Future[Auction] = {
|
||||||
|
db.run((Auctions returning Auctions) += auction)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,4 +4,9 @@ import java.time.Instant
|
|||||||
|
|
||||||
case class User(id: Option[Int], username: String, gid: String, passwordDigest: Option[String])
|
case class User(id: Option[Int], username: String, gid: String, passwordDigest: Option[String])
|
||||||
|
|
||||||
case class AuthToken(id: Option[Int], userId: Int, token: String, createdAt: Instant, expiresAt: Instant)
|
case class AuthToken(id: Option[Int], userId: Int, token: String, createdAt: Instant, expiresAt: Instant)
|
||||||
|
|
||||||
|
case class Auction(id: Option[Int], name: String, gid: String, authorId: Int,
|
||||||
|
startingPrice: BigDecimal, currentBid: Option[BigDecimal],
|
||||||
|
currentBidderId: Option[Int], currentBidAt: Option[Instant],
|
||||||
|
createdAt: Instant)
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package schemas
|
package schemas
|
||||||
|
|
||||||
import slick.jdbc.PostgresProfile.api._
|
import slick.jdbc.PostgresProfile.api.*
|
||||||
import models._
|
import models.*
|
||||||
import slick.lifted.ProvenShape
|
import slick.lifted.ProvenShape
|
||||||
import slick.model.ForeignKeyAction.Cascade
|
import slick.model.ForeignKeyAction.{Cascade, Restrict}
|
||||||
|
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
@@ -31,4 +31,22 @@ class AuthTokensTable(tag: Tag) extends Table[AuthToken](tag, "auth_tokens") {
|
|||||||
def user = foreignKey("users", userId, Users)(_.id, onDelete = Cascade)
|
def user = foreignKey("users", userId, Users)(_.id, onDelete = Cascade)
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy val AuthTokens = TableQuery[AuthTokensTable]
|
lazy val AuthTokens = TableQuery[AuthTokensTable]
|
||||||
|
|
||||||
|
class AuctionsTable(tag: Tag) extends Table[Auction](tag, "auctions") {
|
||||||
|
def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
|
||||||
|
def name = column[String]("name")
|
||||||
|
def gid = column[String]("gid", O.Unique)
|
||||||
|
def authorId = column[Int]("author_id")
|
||||||
|
def startingPrice = column[BigDecimal]("starting_price")
|
||||||
|
def currentBid = column[Option[BigDecimal]]("current_bid")
|
||||||
|
def currentBidderId = column[Option[Int]]("current_bidder_id")
|
||||||
|
def currentBidAt = column[Option[Instant]]("current_bid_at")
|
||||||
|
def createdAt = column[Instant]("created_at")
|
||||||
|
|
||||||
|
override def * : ProvenShape[Auction] = (id.?, name, gid, authorId, startingPrice, currentBid, currentBidderId, currentBidAt, createdAt).mapTo[Auction]
|
||||||
|
|
||||||
|
def author = foreignKey("users", authorId, Users)(_.id, onDelete = Restrict)
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy val Auctions = TableQuery[AuctionsTable]
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-- !Ups
|
||||||
|
CREATE TABLE auctions
|
||||||
|
(
|
||||||
|
id BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
|
||||||
|
name VARCHAR NOT NULL,
|
||||||
|
gid VARCHAR UNIQUE NOT NULL,
|
||||||
|
author_id BIGINT REFERENCES users (id) NOT NULL,
|
||||||
|
starting_price DECIMAL(20, 3) NOT NULL,
|
||||||
|
current_bid DECIMAL(20, 3),
|
||||||
|
current_bidder_id BIGINT REFERENCES users (id),
|
||||||
|
current_bid_at TIMESTAMP,
|
||||||
|
created_at TIMESTAMP NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- !Downs
|
||||||
|
|
||||||
|
DROP TABLE auctions
|
||||||
@@ -13,3 +13,6 @@ DELETE /logout controllers.authentication.SessionsControlle
|
|||||||
|
|
||||||
# Map static resources from the /public folder to the /assets URL path
|
# Map static resources from the /public folder to the /assets URL path
|
||||||
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
|
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
|
||||||
|
|
||||||
|
+nocsrf
|
||||||
|
POST /auctions controllers.AuctionsController.create()
|
||||||
Reference in New Issue
Block a user