All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pl.touk.nussknacker.ui.process.newactivity.ActivityService.scala Maven / Gradle / Ivy

There is a newer version: 1.18.1
Show newest version
package pl.touk.nussknacker.ui.process.newactivity

import cats.data.EitherT
import pl.touk.nussknacker.engine.api.Comment
import pl.touk.nussknacker.engine.api.deployment._
import pl.touk.nussknacker.engine.api.process.{ProcessId, VersionId}
import pl.touk.nussknacker.ui.api.DeploymentCommentSettings
import pl.touk.nussknacker.ui.process.newactivity.ActivityService._
import pl.touk.nussknacker.ui.process.newdeployment.DeploymentService.RunDeploymentError
import pl.touk.nussknacker.ui.process.newdeployment.{DeploymentService, RunDeploymentCommand}
import pl.touk.nussknacker.ui.process.repository.activities.ScenarioActivityRepository
import pl.touk.nussknacker.ui.process.repository.{DBIOActionRunner, DeploymentComment}
import pl.touk.nussknacker.ui.security.api.LoggedUser
import pl.touk.nussknacker.ui.util.LoggedUserUtils.Ops

import java.time.Clock
import scala.concurrent.{ExecutionContext, Future}

// TODO: This service in the future should handle all activities that modify anything in application.
//       These activities should be stored in the dedicated table (not in comments table)
class ActivityService(
    deploymentCommentSettings: Option[DeploymentCommentSettings],
    scenarioActivityRepository: ScenarioActivityRepository,
    deploymentService: DeploymentService,
    dbioRunner: DBIOActionRunner,
    clock: Clock,
)(implicit ec: ExecutionContext) {

  def processCommand[Command, ErrorType](command: Command, comment: Option[Comment])(
      implicit toActivityCommandConverter: ToActivityCommandConverter[Command, ErrorType]
  ): Future[Either[ActivityError[ErrorType], Unit]] = {
    toActivityCommandConverter.convert(command) match {
      case RunDeploymentActivityCommand(command) =>
        (for {
          validatedCommentOpt <- validateDeploymentCommentWhenPassed(comment)
          keys                <- runDeployment(command)
          _ <- saveActivityWhenFinished[RunDeploymentError](
            validatedCommentOpt,
            keys.scenarioId,
            keys.scenarioGraphVersionId,
            command.user
          )
        } yield ()).value
    }
  }

  private def validateDeploymentCommentWhenPassed(
      comment: Option[Comment]
  ): EitherT[Future, ActivityError[RunDeploymentError], Option[Comment]] = EitherT.fromEither {
    DeploymentComment
      .createDeploymentComment(comment, deploymentCommentSettings)
      .toEither
      .left
      .map[ActivityError[RunDeploymentError]](err => CommentValidationError(err.message))
  }

  private def runDeployment(command: RunDeploymentCommand) =
    EitherT(deploymentService.runDeployment(command))
      .leftMap[ActivityError[RunDeploymentError]](UnderlyingServiceError(_))

  private def saveActivityWhenFinished[ErrorType](
      commentOpt: Option[Comment],
      scenarioId: ProcessId,
      scenarioGraphVersionId: VersionId,
      loggedUser: LoggedUser
  ): EitherT[Future, ActivityError[ErrorType], Unit] = {
    val now = clock.instant()
    EitherT.right[ActivityError[ErrorType]](
      dbioRunner
        .run(
          scenarioActivityRepository.addActivity(
            ScenarioActivity.ScenarioDeployed(
              scenarioId = ScenarioId(scenarioId.value),
              scenarioActivityId = ScenarioActivityId.random,
              user = loggedUser.scenarioUser,
              date = now,
              scenarioVersionId = Some(ScenarioVersionId.from(scenarioGraphVersionId)),
              comment = ScenarioComment.from(commentOpt, UserName(loggedUser.username), now),
              result = DeploymentResult.Success(clock.instant()),
            )
          )
        )
        .map(_ => ())
    )
  }

}

object ActivityService {

  sealed trait ActivityCommand[Command, ErrorType] {
    def underlyingCommand: Command
  }

  trait ToActivityCommandConverter[Command, ErrorType] {
    def convert(command: Command): ActivityCommand[Command, ErrorType]
  }

  implicit val fromRunDeploymentCommand: ToActivityCommandConverter[RunDeploymentCommand, RunDeploymentError] =
    (command: RunDeploymentCommand) => RunDeploymentActivityCommand(command)

  private final case class RunDeploymentActivityCommand(underlyingCommand: RunDeploymentCommand)
      extends ActivityCommand[RunDeploymentCommand, RunDeploymentError] {}

  trait ActivityError[+UnderlyingServiceErrorType]

  final case class UnderlyingServiceError[UnderlyingServiceErrorType](error: UnderlyingServiceErrorType)
      extends ActivityError[UnderlyingServiceErrorType]

  final case class CommentValidationError(message: String) extends ActivityError[Nothing]

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy