app/controllers/UserDataController.scala (157 lines of code) (raw):
package controllers
import com.gu.facia.client.models.Trail
import model.editions.CardType
import model.editions.client.EditionsClientCard
import org.scanamo._
import org.scanamo.syntax._
import model.{FeatureSwitch, FeatureSwitches, UserData}
import org.scanamo.generic.auto.genericDerivedFormat
import org.scanamo.query.UniqueKey
import play.api.libs.json.{
JsError,
JsResult,
JsSuccess,
JsValue,
Json,
JsonValidationError,
Reads
}
import services.FrontsApi
import software.amazon.awssdk.services.dynamodb.DynamoDbClient
import scala.concurrent.ExecutionContext
import org.scanamo.generic.semiauto._
import scala.util.{Failure, Success, Try}
class UserDataController(
frontsApi: FrontsApi,
dynamoClient: DynamoDbClient,
val deps: BaseFaciaControllerComponents
)(implicit ec: ExecutionContext)
extends BaseFaciaController(deps) {
implicit val jsValue: DynamoFormat[JsValue] =
DynamoFormat.xmap[JsValue, String](
x =>
Try(Json.parse(x)) match {
case Success(y) => Right(y)
case Failure(t) => Left(TypeCoercionError(t))
},
x => (Json.stringify(x))
)
implicit val trail: DynamoFormat[Trail] = deriveDynamoFormat[Trail]
implicit val cardType: DynamoFormat[CardType] = deriveDynamoFormat[CardType]
implicit val editionsCard: DynamoFormat[EditionsClientCard] =
deriveDynamoFormat[EditionsClientCard]
implicit val userData: DynamoFormat[UserData] = deriveDynamoFormat[UserData]
private lazy val userDataTable =
Table[UserData](config.faciatool.userDataTable)
private def updateClipboardContentByFieldName[T](
maybeJson: Option[JsValue],
userEmail: String,
fieldName: String
)(implicit dynamoFormat: DynamoFormat[T], jsonFormat: Reads[T]) = {
maybeJson.map(_.validate[T]) match {
case Some(JsSuccess(model, _)) =>
Scanamo(dynamoClient).exec(
userDataTable.update(
UniqueKey("email" === userEmail),
set(fieldName, model)
)
)
Ok
case Some(JsError(errors)) =>
BadRequest(errors.toString())
case None => BadRequest
}
}
def putClipboardContent() = APIAuthAction { request =>
updateClipboardContentByFieldName[List[Trail]](
request.body.asJson,
request.user.email,
"clipboardArticles"
)
}
def putEditionsClipboardContent() = APIAuthAction { request =>
updateClipboardContentByFieldName[List[EditionsClientCard]](
request.body.asJson,
request.user.email,
"editionsClipboardArticles"
)
}
def putFeastClipboardContent() = APIAuthAction { request =>
updateClipboardContentByFieldName[List[EditionsClientCard]](
request.body.asJson,
request.user.email,
"feastEditionsClipboardCards"
)
}
def putFrontIds() = APIAuthAction { request =>
val maybeFrontIds: Option[List[String]] =
request.body.asJson.flatMap(_.asOpt[List[String]])
maybeFrontIds match {
case Some(frontIds) =>
Scanamo(dynamoClient).exec(
userDataTable.update(
"email" === request.user.email,
set("frontIds", frontIds)
)
)
Ok
case _ => BadRequest
}
}
def putFrontIdsByPriority() = APIAuthAction { request =>
val maybeFrontIdsByPriority: Option[Map[String, List[String]]] =
request.body.asJson.flatMap(_.asOpt[Map[String, List[String]]])
maybeFrontIdsByPriority match {
case Some(frontIdsByPriority) =>
Scanamo(dynamoClient).exec(
userDataTable.update(
"email" === request.user.email,
set("frontIdsByPriority", frontIdsByPriority)
)
)
Ok
case _ => BadRequest
}
}
def putFavouriteFrontIdsByPriority() = APIAuthAction { request =>
val maybeFavouriteFrontIdsByPriority: Option[Map[String, List[String]]] =
request.body.asJson.flatMap(_.asOpt[Map[String, List[String]]])
maybeFavouriteFrontIdsByPriority match {
case Some(favouriteFrontIdsByPriority) =>
Scanamo(dynamoClient).exec(
userDataTable.update(
"email" === request.user.email,
set("favouriteFrontIdsByPriority", favouriteFrontIdsByPriority)
)
)
Ok
case _ => BadRequest
}
}
def putFeatureSwitch() = APIAuthAction { request =>
val maybeFeatureSwitch: Option[FeatureSwitch] =
request.body.asJson.flatMap(_.asOpt[FeatureSwitch])
val maybeUserData: Option[UserData] = Scanamo(dynamoClient)
.exec(userDataTable.get("email" === request.user.email))
.flatMap(_.toOption)
(maybeUserData, maybeFeatureSwitch) match {
case (Some(userData), Some(featureSwitch)) =>
if (FeatureSwitches.all.map(_.key).contains(featureSwitch.key)) {
val updatedSwitches = FeatureSwitches.updateFeatureSwitchesForUser(
userData.featureSwitches,
featureSwitch
)
Scanamo(dynamoClient).exec(
userDataTable.update(
"email" === request.user.email,
set("featureSwitches", updatedSwitches)
)
)
Ok
} else {
BadRequest(s"Feature with key ${featureSwitch.key} not found")
}
case _ => BadRequest
}
}
}