Skip to content

Commit

Permalink
qs
Browse files Browse the repository at this point in the history
  • Loading branch information
mgoworko committed Feb 26, 2025
1 parent 4467f58 commit 629f6ca
Show file tree
Hide file tree
Showing 20 changed files with 376 additions and 267 deletions.
14 changes: 14 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -1890,6 +1890,18 @@ lazy val listenerApi = (project in file("designer/listener-api"))
)
.dependsOn(extensionsApi)

lazy val customHttpServiceApi = (project in file("designer/custom-http-service-api"))
.settings(commonSettings)
.settings(
name := "nussknacker-custom-http-service-api",
libraryDependencies ++= {
Seq(
"com.typesafe.akka" %% "akka-http" % akkaHttpV,
)
}
)
.dependsOn(extensionsApi, security)

lazy val configLoaderApi = (project in file("designer/config-loader-api"))
.settings(commonSettings)
.settings(
Expand Down Expand Up @@ -2060,6 +2072,7 @@ lazy val designer = (project in file("designer/server"))
componentsApi,
restmodel,
listenerApi,
customHttpServiceApi,
configLoaderApi,
defaultHelpers % Test,
testUtils % Test,
Expand Down Expand Up @@ -2191,6 +2204,7 @@ lazy val modules = List[ProjectReference](
httpUtils,
restmodel,
listenerApi,
customHttpServiceApi,
configLoaderApi,
deploymentManagerApi,
designer,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package pl.touk.nussknacker.ui.customhttpservice

import akka.http.scaladsl.server.Directives.reject
import akka.http.scaladsl.server.Route
import pl.touk.nussknacker.ui.security.api.LoggedUser

trait CustomHttpServiceProvider {
def provideRouteWithUser(implicit user: LoggedUser): Route
def provideRouteWithoutUser(): Route
}

object CustomHttpServiceProvider {

def noop: CustomHttpServiceProvider = new CustomHttpServiceProvider {
override def provideRouteWithUser(implicit user: LoggedUser): Route = reject
override def provideRouteWithoutUser(): Route = reject
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package pl.touk.nussknacker.ui.customhttpservice

import com.typesafe.config.Config
import pl.touk.nussknacker.ui.customhttpservice.services.NussknackerServicesForCustomHttpService

import scala.concurrent.ExecutionContext

trait CustomHttpServiceProviderFactory {

def create(
config: Config,
executionContext: ExecutionContext,
services: NussknackerServicesForCustomHttpService
): CustomHttpServiceProvider

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package pl.touk.nussknacker.ui.customhttpservice.services

final case class NussknackerServicesForCustomHttpService(
scenarioService: ScenarioService,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package pl.touk.nussknacker.ui.customhttpservice.services

import pl.touk.nussknacker.engine.api.component.ProcessingMode
import pl.touk.nussknacker.engine.api.deployment.{ProcessAction, ProcessState}
import pl.touk.nussknacker.engine.api.process._
import pl.touk.nussknacker.engine.deployment.EngineSetupName
import pl.touk.nussknacker.ui.customhttpservice.services.ScenarioService._
import pl.touk.nussknacker.ui.security.api.LoggedUser

import java.time.Instant
import scala.concurrent.Future

trait ScenarioService {

def getLatestProcessesWithDetails(query: ScenarioQuery)(
implicit user: LoggedUser
): Future[List[ScenarioWithDetails]]

def getLatestVersionForProcesses(query: ScenarioQuery, excludedUserNames: Set[String])(
implicit user: LoggedUser
): Future[Map[ProcessId, ScenarioVersionMetadata]]

}

object ScenarioService {

final case class ScenarioWithDetails(
name: ProcessName,
processVersionId: VersionId,
isLatestVersion: Boolean,
description: Option[String],
isArchived: Boolean,
isFragment: Boolean,
processingType: ProcessingType,
processCategory: String,
processingMode: ProcessingMode,
engineSetupName: EngineSetupName,
modifiedAt: Instant,
modifiedBy: String,
createdAt: Instant,
createdBy: String,
labels: List[String],
// Actions are deprecated
lastDeployedAction: Option[ProcessAction],
lastStateAction: Option[ProcessAction],
lastAction: Option[ProcessAction],
//
modelVersion: Option[Int],
state: Option[ProcessState],
)

final case class ScenarioQuery(
isFragment: Option[Boolean] = None,
isArchived: Option[Boolean] = None,
isDeployed: Option[Boolean] = None,
categories: Option[Seq[String]] = None,
processingTypes: Option[Seq[String]] = None,
names: Option[Seq[ProcessName]] = None,
)

final case class ScenarioVersionMetadata(
versionId: VersionId,
createdAt: Instant,
createdByUser: String,
)

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,10 @@ import scala.concurrent.{ExecutionContext, Future}

class ProcessesResources(
protected val processService: ProcessService,
processesWithDetailsProvider: ProcessesWithDetailsProvider,
scenarioStateProvider: ScenarioStateProvider,
processToolbarService: ScenarioToolbarService,
val processAuthorizer: AuthorizeProcess,
processChangeListener: ProcessChangeListener,
processChangeListener: ProcessChangeListener
)(implicit val ec: ExecutionContext, mat: Materializer)
extends Directives
with FailFastCirceSupport
Expand Down Expand Up @@ -78,26 +77,26 @@ class ProcessesResources(
}
}
} ~ path("processes") {
(get & parameterMap & processesQuery) { (queryParams, query) =>
complete {
processesWithDetailsProvider.getLatestProcessesWithDetails(
queryParams,
query,
GetScenarioWithDetailsOptions.withoutAdditionalFields.withFetchState,
)
get {
processesQuery { query =>
complete {
processService.getLatestProcessesWithDetails(
query,
GetScenarioWithDetailsOptions.withoutAdditionalFields.withFetchState
)
}
}
}
} ~ path("processesDetails") {
(get & parameterMap & processesQuery & skipValidateAndResolveParameter & skipNodeResultsParameter) {
(queryParams, query, skipValidateAndResolve, skipNodeResults) =>
(get & processesQuery & skipValidateAndResolveParameter & skipNodeResultsParameter) {
(query, skipValidateAndResolve, skipNodeResults) =>
complete {
processesWithDetailsProvider.getLatestProcessesWithDetails(
queryParams,
processService.getLatestProcessesWithDetails(
query,
GetScenarioWithDetailsOptions(
FetchScenarioGraph(validationFlagsToMode(skipValidateAndResolve, skipNodeResults)),
fetchState = false
),
)
)
}
}
Expand Down Expand Up @@ -152,14 +151,13 @@ class ProcessesResources(
}
}
}
} ~ (get & parameterMap & skipValidateAndResolveParameter & skipNodeResultsParameter) {
} ~ (get & skipValidateAndResolveParameter & skipNodeResultsParameter) {
// FIXME: The `skipValidateAndResolve` flag has a non-trivial side effect.
// Besides skipping validation (that is the intended and obvious result) it causes the `dictKeyWithLabel` expressions to miss the label field.
// It happens, because in the current implementation we need the full compilation and type resolving in order to obtain the dict expression label.
(queryParams, skipValidateAndResolve, skipNodeResults) =>
(skipValidateAndResolve, skipNodeResults) =>
complete {
processesWithDetailsProvider.getLatestProcessWithDetails(
queryParams,
processService.getLatestProcessWithDetails(
processId,
GetScenarioWithDetailsOptions(
FetchScenarioGraph(validationFlagsToMode(skipValidateAndResolve, skipNodeResults)),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package pl.touk.nussknacker.ui.customhttpservice

import pl.touk.nussknacker.engine.api.process.ProcessId
import pl.touk.nussknacker.restmodel.scenariodetails.ScenarioWithDetails
import pl.touk.nussknacker.ui.customhttpservice.services.ScenarioService
import pl.touk.nussknacker.ui.process.ProcessService.GetScenarioWithDetailsOptions
import pl.touk.nussknacker.ui.process.repository.FetchingProcessRepository.ScenarioVersionMetadata
import pl.touk.nussknacker.ui.process.{ProcessService, ScenarioQuery}
import pl.touk.nussknacker.ui.security.api.LoggedUser

import scala.concurrent.{ExecutionContext, Future}
import scala.language.implicitConversions

class ScenarioServiceImpl(
processService: ProcessService
)(implicit executionContext: ExecutionContext)
extends ScenarioService {

override def getLatestProcessesWithDetails(
query: ScenarioService.ScenarioQuery
)(implicit user: LoggedUser): Future[List[ScenarioService.ScenarioWithDetails]] =
processService
.getLatestProcessesWithDetails(
toDomain(query),
GetScenarioWithDetailsOptions.withoutAdditionalFields.withFetchState
)
.map(_.map(toApi))

override def getLatestVersionForProcesses(
query: ScenarioService.ScenarioQuery,
excludedUserNames: Set[String]
)(implicit user: LoggedUser): Future[Map[ProcessId, ScenarioService.ScenarioVersionMetadata]] =
processService
.getLatestVersionForProcesses(toDomain(query), excludedUserNames)
.map(_.map { case (processId, metadata) => (processId, toApi(metadata)) })

private def toDomain(query: ScenarioService.ScenarioQuery): ScenarioQuery =
ScenarioQuery(
isFragment = query.isFragment,
isArchived = query.isArchived,
isDeployed = query.isDeployed,
categories = query.categories,
processingTypes = query.processingTypes,
names = query.names,
)

private def toApi(metadata: ScenarioVersionMetadata): ScenarioService.ScenarioVersionMetadata =
ScenarioService.ScenarioVersionMetadata(
versionId = metadata.versionId,
createdAt = metadata.createdAt,
createdByUser = metadata.createdByUser,
)

private implicit def toApi(metadata: ScenarioWithDetails): ScenarioService.ScenarioWithDetails =
ScenarioService.ScenarioWithDetails(
name = metadata.name,
processVersionId = metadata.processVersionId,
isLatestVersion = metadata.isLatestVersion,
description = metadata.description,
isArchived = metadata.isArchived,
isFragment = metadata.isFragment,
processingType = metadata.processingType,
processCategory = metadata.processCategory,
processingMode = metadata.processingMode,
engineSetupName = metadata.engineSetupName,
modifiedAt = metadata.modifiedAt,
modifiedBy = metadata.modifiedBy,
createdAt = metadata.createdAt,
createdBy = metadata.createdBy,
labels = metadata.labels,
lastDeployedAction = metadata.lastDeployedAction,
lastStateAction = metadata.lastStateAction,
lastAction = metadata.lastAction,
modelVersion = metadata.modelVersion,
state = metadata.state,
)

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import pl.touk.nussknacker.ui.process.label.ScenarioLabel
import pl.touk.nussknacker.ui.process.marshall.CanonicalProcessConverter
import pl.touk.nussknacker.ui.process.processingtype.ScenarioParametersService
import pl.touk.nussknacker.ui.process.processingtype.provider.ProcessingTypeDataProvider
import pl.touk.nussknacker.ui.process.repository.FetchingProcessRepository.ScenarioVersionMetadata
import pl.touk.nussknacker.ui.process.repository.ProcessDBQueryRepository.{
ProcessNotFoundError,
ProcessVersionNotFoundError
Expand Down Expand Up @@ -139,6 +140,10 @@ trait ProcessService {
implicit user: LoggedUser
): Future[List[ScenarioWithDetails]]

def getLatestVersionForProcesses(query: ScenarioQuery, excludedUserNames: Set[String])(
implicit user: LoggedUser
): Future[Map[ProcessId, ScenarioVersionMetadata]]

def getLatestRawProcessesWithDetails[PS: ScenarioShapeFetchStrategy](query: ScenarioQuery)(
implicit user: LoggedUser
): Future[List[ScenarioWithDetailsEntity[PS]]]
Expand Down Expand Up @@ -250,6 +255,12 @@ class DBProcessService(
)
}

override def getLatestVersionForProcesses(query: ScenarioQuery, excludedUserNames: Set[String])(
implicit user: LoggedUser
): Future[Map[ProcessId, ScenarioVersionMetadata]] = {
fetchingProcessRepository.fetchLatestVersionForProcesses(query, excludedUserNames)
}

private abstract class FetchScenarioFun[F[_]] {
def apply[PS: ScenarioShapeFetchStrategy]: Future[F[ScenarioWithDetailsEntity[PS]]]
}
Expand Down
Loading

0 comments on commit 629f6ca

Please sign in to comment.