| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- package com.weEat.controllers
- import com.weEat.models.{FoodNode => FoodNodeCollection}
- import com.weEat.models.{RecipeVersion => RecipeVersionCollection}
- import com.weEat.models.FoodNodeView
- import com.weEat.services.MongoDBService
- import com.weEat.shared.models._
- import javax.inject.{Inject,Singleton}
- import play.api.libs.json._
- import play.api.mvc._
- import org.bson.types.ObjectId
- import org.mongodb.scala.model.Filters._
- import scala.concurrent.Future
- import scala.util.{Success,Failure}
- import com.weEat.models.Authorization
- import scalaoauth2.provider.{AuthInfoRequest,OAuth2ProviderActionBuilders}
- import com.weEat.services.OAuth2Service
- @Singleton
- class FoodController @Inject()(
- val controllerComponents: ControllerComponents,
- oauth: OAuth2Service,
- db: MongoDBService
- ) extends BaseController
- with OAuth2ProviderActionBuilders {
- implicit val ec = scala.concurrent.ExecutionContext.global
- import db.withCollection
- def get(id: String) = Action.async
- { implicit request: Request[AnyContent] =>
- withCollection(FoodNodeView) { (collection) =>
- collection.find(equal("_id", new ObjectId(id)))
- .first()
- .toFuture()
- .transform({
- case Success(null) => Success(NotFound(id))
- case Success(x) => Success(Ok(Json.toJson(x)))
- case Failure(x) => throw x
- })
- }.flatten
- }
- def all() = Action.async
- { implicit request: Request[AnyContent] =>
- withCollection(FoodNodeView) { (collection) =>
- collection.find()
- .toFuture()
- .transform({
- case Success(x) => Success(Ok(Json.toJson(x)))
- case Failure(x) => throw x
- })
- }.flatten
- }
- def query(q: String) = Action.async
- { implicit request: Request[AnyContent] =>
- withCollection(FoodNodeView) { (collection) =>
- collection.find(regex("name", q, "i"))
- .toFuture()
- .transform({
- case Success(x) => Success(Ok(Json.toJson(x)))
- case Failure(x) => throw x
- })
- }.flatten
- }
- def getByFdcId(fdcId: Long): Future[Option[USDANodeId]] =
- withCollection(FoodNodeView) { (collection) =>
- collection.find(equal("fdcId", fdcId))
- .first()
- .toFuture()
- .map((foodNode) => Option(foodNode.asInstanceOf[USDANodeId]))
- }.flatten
- // def getImage(foodId: String, idx: Int) = Action.async
- // { implicit request: Request[AnyContent] =>
- // withCollection(FoodImages) {collection =>
- // collection.find(and(equal("food", foodId), equal("index", idx)))
- // .first()
- // .toFuture()
- // .transform({
- // case Success(img) =>
- // Success(Ok.streamed(img.data, img.data.length, img.mime))
- // case Failure(x) => throw x
- // })
- // }.flatten
- // ???
- // }
- // def addImageTo(id: String) = Action.async(parse.byteString)
- // { implicit request: Request[ByteString] =>
- // withCollection(FoodImages) { images =>
- // images.insertOne(FoodImage(None, id, , request.body, request.contentType.get))
- // .head().transformWith({
- // case Success(img) => withCollection(FoodNode) { foods =>
- // foods.findOneAndUpdate(
- // equal("id", id),
- // push("imageIds", img._id.get)
- // ).head().transform({
- // case Success(x) => Success(Ok(x))
- // case Failure(x) =>
- // images.deleteOne(eq("_id", img._id.get))
- // throw x
- // })
- // }
- // case Failure(x) => throw x
- // })
- // }.flatten
- // ???
- // }
- // def deleteImage(foodId: String, imageId: String) = Action.async
- // { implicit request: Request[AnyContent] =>
- // withCollection(FoodNode) { foods =>
- // foods.findOneAndUpdate(
- // equal("id", foodId),
- // pull("imageIds", imageId)
- // ).head().transformWith({
- // case Success(x) => images.deleteOne(eq("_id", img._id.get))
- // .head().transform({
- // case Success(x) => Success(Ok(x))
- // case Failure(x) => throw x
- // })
- // case Failure(x) => throw x
- // })
- // }.flatten
- // ???
- // }
- def add(uid: Option[String]) = AuthorizedAction[Authorization](oauth)
- .async(parse.json)
- { implicit request: AuthInfoRequest[JsValue, Authorization] =>
- try {
- val food = request.body.as[FoodNode].withId(
- new ObjectId,
- uid.flatMap({ (id) =>
- if (request.authInfo.user.hasAdminPermissions) Some(new ObjectId(id))
- else None
- }).getOrElse(request.authInfo.user.userId)
- )
- (food match {
- case recipeNode: RecipeNodeId => _addRecipe(recipeNode)
- case node => _addFood(node)
- }).map((food) => Ok(Json.toJson(food.asInstanceOf[FoodNodeId])))
- }
- catch {
- case _: JsResultException => Future.successful(
- BadRequest(s"Could not parse json into a Food node.")
- )
- }
- }
- private def _addRecipe(node: RecipeNodeId) = {
- val (metaNode, versNode) = RecipeMetaNodeId(node)
- _addFood(metaNode, (_) => _saveVersionIfRecipe(versNode))
- .map((_) => node)
- }
- private def _addFood(
- node: FoodId,
- callback: (FoodId) => Future[FoodId] = Future.successful _
- ) = withCollection(FoodNodeCollection) { (collection) =>
- collection.insertOne(node).map({ (res) => node }).head()
- }.flatten
- .flatMap(callback)
- private def _saveVersionIfRecipe(node: RecipeNodeId): Future[FoodNodeId] =
- withCollection(RecipeVersionCollection) { (collection) =>
- collection.insertOne(node).map({ (res) => node }).head()
- }.flatten
- def update(id: String, uid: Option[String]) =
- AuthorizedAction[Authorization](oauth)
- .async(parse.json)
- { implicit request: AuthInfoRequest[JsValue, Authorization] =>
- try {
- val food = request.body.as[FoodNode].withId(
- new ObjectId(id),
- uid.flatMap({ (uid) =>
- if (request.authInfo.user.hasAdminPermissions) Some(new ObjectId(uid))
- else None
- // tflucke@[2023-10-07] Should this query for the current uid instead?
- }).getOrElse(request.authInfo.user.userId)
- )
- (food match {
- case recipeNode: RecipeNodeId => _updateRecipe(recipeNode)
- case node => _updateFood(node)
- }).map((food) => Ok(Json.toJson(food.asInstanceOf[FoodNodeId])))
- }
- catch {
- case _: JsResultException => Future.successful(
- BadRequest(s"Could not parse json into a Food node.")
- )
- }
- }
- private def _updateRecipe(node: RecipeNodeId) = {
- val (metaNode, versNode) = RecipeMetaNodeId(node)
- _updateFood(metaNode, (_) => _saveVersionIfRecipe(versNode))
- .map((_) => node)
- }
- private def _updateFood(
- node: FoodId,
- callback: (FoodId) => Future[FoodId] = Future.successful _
- ) = withCollection(FoodNodeCollection) { (collection) =>
- collection.replaceOne(and(
- equal("_id", node._id),
- equal("uid", node.uid)
- ), node)
- .head()
- .transform({
- case Success(res) if (res.getModifiedCount > 0) => Success(node)
- case Success(res) => Failure(new NoSuchElementException("User " +
- s"${node.uid} does not have a food node ${node._id}"))
- case Failure(e) => Failure(e)
- })
- }.flatten
- .flatMap(callback)
- }
|