From eed82d6713292e317739428265cbef4c315d251f Mon Sep 17 00:00:00 2001 From: Ryan Hanks Date: Tue, 19 Mar 2019 08:28:19 -0400 Subject: [PATCH] Add search routes, controller, view, messages, and wiring --- build.sbt | 2 +- .../search/impl/SearchServiceImpl.scala | 1 - web-gateway/app/Loader.scala | 5 +- .../app/controllers/SearchController.scala | 78 +++++++++++ web-gateway/app/views/main.scala.html | 1 + web-gateway/app/views/searchItems.scala.html | 122 ++++++++++++++++++ web-gateway/conf/application.conf | 4 + web-gateway/conf/messages | 12 ++ web-gateway/conf/routes | 2 + 9 files changed, 224 insertions(+), 3 deletions(-) create mode 100644 web-gateway/app/controllers/SearchController.scala create mode 100644 web-gateway/app/views/searchItems.scala.html diff --git a/build.sbt b/build.sbt index 5bfc0bb..b5651e6 100644 --- a/build.sbt +++ b/build.sbt @@ -159,7 +159,7 @@ lazy val userImpl = (project in file("user-impl")) lazy val webGateway = (project in file("web-gateway")) .settings(commonSettings: _*) .enablePlugins(PlayScala, LagomPlay, SbtReactiveAppPlugin) - .dependsOn(biddingApi, itemApi, userApi) + .dependsOn(biddingApi, itemApi, searchApi, userApi) .settings( libraryDependencies ++= Seq( lagomScaladslServer, diff --git a/search-impl/src/main/scala/com/example/auction/search/impl/SearchServiceImpl.scala b/search-impl/src/main/scala/com/example/auction/search/impl/SearchServiceImpl.scala index 8be07ee..0f278b3 100644 --- a/search-impl/src/main/scala/com/example/auction/search/impl/SearchServiceImpl.scala +++ b/search-impl/src/main/scala/com/example/auction/search/impl/SearchServiceImpl.scala @@ -6,7 +6,6 @@ import com.example.elasticsearch.IndexedItem import com.example.elasticsearch.request._ import com.example.elasticsearch.response._ import com.lightbend.lagom.scaladsl.api.ServiceCall -import play.api.libs.json.Json import scala.concurrent.ExecutionContext.Implicits.global diff --git a/web-gateway/app/Loader.scala b/web-gateway/app/Loader.scala index e928b2d..4c97de2 100644 --- a/web-gateway/app/Loader.scala +++ b/web-gateway/app/Loader.scala @@ -2,13 +2,14 @@ package loader import com.example.auction.bidding.api.BiddingService import com.example.auction.item.api.ItemService +import com.example.auction.search.api.SearchService import com.example.auction.user.api.UserService import com.lightbend.lagom.scaladsl.api.{LagomConfigComponent, ServiceAcl, ServiceInfo} import com.lightbend.lagom.scaladsl.client.LagomServiceClientComponents import com.lightbend.lagom.scaladsl.devmode.LagomDevModeComponents import com.lightbend.rp.servicediscovery.lagom.scaladsl.LagomServiceLocatorComponents import com.softwaremill.macwire._ -import controllers.{AssetsComponents, ItemController, Main, ProfileController} +import controllers.{AssetsComponents, ItemController, Main, ProfileController, SearchController} import play.api.ApplicationLoader.Context import play.api.libs.ws.ahc.AhcWSComponents import play.api.{ApplicationLoader, BuiltInComponentsFromContext, Mode} @@ -41,10 +42,12 @@ abstract class WebGateway(context: Context) extends BuiltInComponentsFromContext lazy val userService = serviceClient.implement[UserService] lazy val itemService = serviceClient.implement[ItemService] lazy val biddingService = serviceClient.implement[BiddingService] + lazy val searchService = serviceClient.implement[SearchService] lazy val main = wire[Main] lazy val itemController = wire[ItemController] lazy val profileController = wire[ProfileController] + lazy val searchController = wire[SearchController] } class WebGatewayLoader extends ApplicationLoader { diff --git a/web-gateway/app/controllers/SearchController.scala b/web-gateway/app/controllers/SearchController.scala new file mode 100644 index 0000000..c2a94e3 --- /dev/null +++ b/web-gateway/app/controllers/SearchController.scala @@ -0,0 +1,78 @@ +package controllers + +import com.example.auction.search.api.{SearchRequest, SearchService} +import com.example.auction.user.api.UserService +import com.example.auction.utils.PaginatedSequence +import com.typesafe.config.Config +import play.api.data.Forms.{nonEmptyText, _} +import play.api.data.{Form, Mapping} +import play.api.mvc.{ControllerComponents, _} + +import scala.concurrent.{ExecutionContext, Future} + +class SearchController(config: Config, + searchService: SearchService, + userService: UserService, + controllerComponents: ControllerComponents)(implicit ec: ExecutionContext) + extends AbstractAuctionController(userService, controllerComponents) { + + private val showInlineInstruction: Boolean = config.getBoolean("online-auction.instruction.show") + private val pageSize: Int = config.getInt("items-search.page-size") + + def searchForm(): Action[AnyContent] = Action.async { implicit request => + requireUser(loadNav(_).map { implicit nav => + Ok(views.html.searchItems(showInlineInstruction = showInlineInstruction, + form = SearchItemsForm.form.fill(SearchItemsForm()), + optionalSearchItemPaginatedSequence = None)) + }) + } + + def search(): Action[AnyContent] = Action.async { implicit request => + requireUser(user => + loadNav(user).flatMap { implicit nav => + SearchItemsForm.form.bindFromRequest().fold( + errorForm => { + Future.successful(Ok(views.html.searchItems( + showInlineInstruction = showInlineInstruction, + form = errorForm, + optionalSearchItemPaginatedSequence = None))) + }, + searchItemsForm => { + searchService.search(searchItemsForm.pageNumber, pageSize) + .invoke(SearchRequest( + Some(searchItemsForm.keywords), + Some(searchItemsForm.maximumPrice.intValue()), + Some(searchItemsForm.currency.name))) + .map(searchResponse => { + Ok(views.html.searchItems( + showInlineInstruction = true, + form = SearchItemsForm.form.fill(searchItemsForm), + optionalSearchItemPaginatedSequence = Some(PaginatedSequence( + searchResponse.items, + searchResponse.pageNo, + searchResponse.pageSize, + searchResponse.numResults)))) + }) + }) + }) + } +} + + +case class SearchItemsForm(keywords: String = "", + maximumPrice: BigDecimal = 0.0, + currency: Currency = Currency.USD, + pageNumber: Int = 0) + +object SearchItemsForm { + val currency: Mapping[Currency] = nonEmptyText + .verifying("invalid.currency", c => Currency.isDefined(c)) + .transform[Currency](Currency.valueOf, _.name) + val form = Form(mapping( + "keywords" -> text, + "maximumPrice" -> bigDecimal, + "currency" -> currency, + "pageNumber" -> number(min = 0) + )(SearchItemsForm.apply)(SearchItemsForm.unapply)) +} + diff --git a/web-gateway/app/views/main.scala.html b/web-gateway/app/views/main.scala.html index c141378..2dd09d9 100644 --- a/web-gateway/app/views/main.scala.html +++ b/web-gateway/app/views/main.scala.html @@ -22,6 +22,7 @@