package controllers import actors.auctions.AuctionPublisher import controllers.authentication.AuthenticatedAction import dao.{AuctionsDAO, AuthTokensDAO} import models.AuctionStatus.Ready import models.{Auction, User} import org.apache.pekko.actor.typed.ActorRef import play.api.libs.functional.syntax.toFunctionalBuilderOps import play.api.libs.json.* import play.api.mvc.{BaseController, ControllerComponents} import javax.inject.{Inject, Singleton} import scala.concurrent.{ExecutionContext, Future} @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 { def index = authenticatedAction.async { implicit request => given Writes[Auction] = auctionWrites(request.user) for { auctions <- auctionsDAO.list_available(request.user) json = Json.toJson(auctions) } yield Ok(json) } 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 def auctionWrites(user: User): OWrites[Auction] = (o: Auction) => { Json.toJsObject(o)(using Auction.writes) ++ Json.obj( "actions" -> Json.obj( "bid" -> ( (o.authorId != user.id.get) && (o.currentBidderId match { case None => true // If there's no bidder, we can bid case Some(bidderId) => bidderId != user.id.get }) && (o.status == Ready) ) ) ) } }