app/controllers/PostrunActionController.scala (128 lines of code) (raw):
package controllers
import akka.actor.ActorRef
import javax.inject.{Inject, Named, Singleton}
import akka.http.scaladsl.Http
import auth.{BearerTokenAuth, Security}
import exceptions.AlreadyExistsException
import helpers.PostrunSorter
import models._
import play.api.Configuration
import play.api.cache.SyncCacheApi
import play.api.db.slick.DatabaseConfigProvider
import play.api.libs.json.{JsValue, Json}
import play.api.mvc.{ControllerComponents, Request}
import slick.jdbc.PostgresProfile
import slick.lifted.TableQuery
import slick.jdbc.PostgresProfile.api._
import play.api.libs.json._
import services.PostrunActionScanner
import scala.concurrent.Future
import scala.util.{Failure, Success, Try}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.io.Source
@Singleton
class PostrunActionController @Inject() (override val controllerComponents:ControllerComponents,
override val bearerTokenAuth:BearerTokenAuth,
override implicit val config: Configuration, dbConfigProvider: DatabaseConfigProvider,
cacheImpl:SyncCacheApi,
@Named("postrun-action-scanner") postrunActionScanner:ActorRef)
extends GenericDatabaseObjectController[PostrunAction] with PostrunActionSerializer with PostrunDependencySerializer with Security {
implicit val cache:SyncCacheApi = cacheImpl
val dbConfig = dbConfigProvider.get[PostgresProfile]
override def selectid(requestedId: Int): Future[Try[Seq[PostrunAction]]] = dbConfig.db.run(
TableQuery[PostrunActionRow].filter(_.id === requestedId).result.asTry
)
override def selectall(startAt: Int, limit: Int): Future[Try[(Int, Seq[PostrunAction])]] = dbConfig.db.run(
TableQuery[PostrunActionRow].length.result.zip(
TableQuery[PostrunActionRow].drop(startAt).take(limit).result
)
).map(Success(_)).recover(Failure(_))
override def jstranslate(result: PostrunAction): Json.JsValueWrapper = result
override def jstranslate(result: Seq[PostrunAction]): Json.JsValueWrapper = result //PostrunActionSerializer is implicitly called to do this
override def deleteid(requestedId: Int) = dbConfig.db.run(
TableQuery[PostrunActionRow].filter(_.id === requestedId).delete.asTry
)
override def validate(request: Request[JsValue]) = request.body.validate[PostrunAction]
override def insert(entry: PostrunAction, uid:String) = dbConfig.db.run(
(TableQuery[PostrunActionRow] returning TableQuery[PostrunActionRow].map(_.id) += entry).asTry)
override def dbupdate(itemId:Int, entry:PostrunAction) = {
val newRecord = entry.id match {
case Some(id)=>entry
case None=>entry.copy(id=Some(itemId))
}
dbConfig.db.run(
TableQuery[PostrunActionRow].filter(_.id===itemId).update(newRecord).asTry
)
}
def insertAssociation(postrunId: Int, projectTypeId: Int) = dbConfig.db.run(
(TableQuery[PostrunAssociationRow] returning TableQuery[PostrunAssociationRow].map(_.id) += (projectTypeId, postrunId)).asTry
)
def removeAssociation(postrunId: Int, projectTypeId: Int) =dbConfig.db.run(
TableQuery[PostrunAssociationRow].filter(_.postrunEntry===postrunId).filter(_.projectType===projectTypeId).delete.asTry
)
def associate(postrunId: Int, projectTypeId: Int) = IsAuthenticatedAsync {uid=> { request =>
insertAssociation(postrunId, projectTypeId).map({
case Success(newRowId) => Ok(Json.obj("status" -> "ok", "detail" -> s"added association with id $newRowId"))
case Failure(error) => handleConflictErrors(error, "postrun association", isInsert=true)
})
}}
def unassociate(postrunId: Int, projectTypeId: Int) = IsAuthenticatedAsync {uid=>{request=>
removeAssociation(postrunId, projectTypeId) map {
case Success(affectedRows)=>Ok(Json.obj("status"->"ok", "detail"->"removed association"))
case Failure(error)=>handleConflictErrors(error, "postrun association", isInsert=true)
}
}}
def insertDependency(entry: PostrunDependency) = dbConfig.db.run(
(TableQuery[PostrunDependencyRow] returning TableQuery[PostrunDependencyRow].map(_.id) += entry).asTry
)
def deleteDependency(entry: PostrunDependency) = dbConfig.db.run(
TableQuery[PostrunDependencyRow].filter(_.sourceAction === entry.sourceAction).filter(_.dependsOn === entry.dependsOn).delete.asTry
)
def selectDependencies(postrunId:Int) = dbConfig.db.run(
TableQuery[PostrunDependencyRow].filter(_.sourceAction===postrunId).result.asTry
)
def listDependencies(postrunId: Int) = IsAdminAsync {uid=>{request=>
selectDependencies(postrunId).map({
case Success(dependencyList)=>Ok(Json.obj("status"->"ok", "result"->dependencyList))
case Failure(error)=>
logger.error(s"Could not list postrun dependencies for $postrunId: ", error)
InternalServerError(Json.obj("status"->"error", "detail"->error.toString))
})
}}
def addDependency(sourceId:Int, dependsOn:Int) = IsAdminAsync {uid=>{request=>
insertDependency(PostrunDependency(None,sourceId,dependsOn)).map({
case Success(newRowId) => Ok(Json.obj("status" -> "ok", "detail" -> s"added dependency with id $newRowId"))
case Failure(error) => handleConflictErrors(error,"postrun dependency", isInsert=true)
})
}}
def removeDependency(sourceId:Int, dependsOn:Int) = IsAdminAsync {uid=>{request=>
deleteDependency(PostrunDependency(None,sourceId,dependsOn)).map({
case Success(newRowId) => Ok(Json.obj("status" -> "ok", "detail" -> s"deleted dependency"))
case Failure(error) => handleConflictErrors(error,"postrun dependency", isInsert=false)
})
}}
def startScan = IsAdmin {uid=> request=>
postrunActionScanner ! PostrunActionScanner.Rescan
Ok(Json.obj("status"->"ok","detail"->"scan started"))
}
def testPostrunSort(projectTypeId:Int) = IsAuthenticatedAsync { uid=> request=>
implicit val db = dbConfig.db
val postrunAssociationJoinQuery = TableQuery[PostrunAssociationRow] joinLeft TableQuery[PostrunActionRow] on (_.postrunEntry===_.id)
val sortedPostrunList = for {
associationResults <- dbConfig.db.run(postrunAssociationJoinQuery.filter(_._1.projectType===projectTypeId).result)
postrunDependencies <- PostrunDependencyGraph.loadAllById
results <- Future(PostrunSorter.doSort(associationResults.map(_._2).collect({case Some(entry)=>entry}).toList, postrunDependencies))
} yield (associationResults, postrunDependencies, results)
sortedPostrunList.map(results=>{
Ok(Json.obj("status"->"ok",
"associated_postruns"->results._1.map(joined_row=>(joined_row._1._1, joined_row._1._2, joined_row._2.map(_.runnable))),
"dependency_input"->results._2,
"final_results"->results._3.map(_.runnable)
))
}).recover({
case err:Throwable=>
logger.error(s"Could not test the postrun sorting: ${err.getMessage}", err)
InternalServerError(Json.obj("status"->"error","description"->err.getMessage,"trace"->err.getStackTrace.map(_.toString)))
})
}
}