package controllers import actors.auctions.AuctionPublisher import controllers.authentication.AuthenticatedAction import dao.{AuctionsDAO, AuthTokensDAO} import org.apache.pekko.actor.typed.ActorRef import play.api.libs.json.* import play.api.mvc.{BaseController, ControllerComponents} import javax.inject.{Inject, Singleton} import scala.concurrent.{ExecutionContext, Future} import models.Auction import caching.{CheckFresh, DigestEtagable, Etagable} import java.io.DataOutputStream @Singleton class AuctionsController @Inject()(val controllerComponents: ControllerComponents, val auctionsDAO: AuctionsDAO, val authTokensDAO: AuthTokensDAO, authenticatedAction: AuthenticatedAction, val auctionPublisher: ActorRef[AuctionPublisher.Command]) (implicit val ec: ExecutionContext) extends BaseController with CheckFresh { def index = authenticatedAction.async { request => for { auctions <- auctionsDAO.list_available(request.user) json = Json.toJson(auctions) } yield Ok(json) } def show(id: Long) = authenticatedAction.async { implicit request => auctionsDAO.showAvailable(request.user, id).map { auctionOpt => auctionOpt.fold(NotFound) { auction => checkFresh(auction) { Ok(Json.toJson(auction)).withHeaders("etag" -> auction.etag) } } } } def create = authenticatedAction.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) _ = auctionPublisher ! AuctionPublisher.Publish(auction, request.user) } yield Created(json) } ) } private case class AuctionCreateData(name: String, startingPrice: BigDecimal) private given Reads[AuctionCreateData] = Json.reads[AuctionCreateData] private given DigestEtagable[Auction] with { override protected def writeDigestData(a: Auction, s: DataOutputStream): Unit = { s.writeLong(a.id.getOrElse(0)) s.writeLong(a.authorId) s.writeUTF(a.gid) s.writeUTF(a.name) s.writeLong(a.createdAt.getEpochSecond) s.writeLong(a.currentBidderId.getOrElse(0)) a.currentBid.foreach(b => s.writeLong((b * 1000).toLong)) a.currentBidAt.foreach(ba => s.writeLong(ba.getEpochSecond)) } } }