Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NU-1772] Scenario activities BE implementation #6823

Merged
merged 50 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
b421bc7
API specification
mgoworko Sep 9, 2024
20a1c6d
qs
mgoworko Sep 9, 2024
ae8b5b2
Test fixes, activities handling improvements
mgoworko Sep 5, 2024
3e928f9
Restored legacy PDF exporter, legacy API endpoints
mgoworko Sep 6, 2024
be9cb20
Added proper comment handling
mgoworko Sep 8, 2024
e12fc29
API draft, DB table and migration
mgoworko Sep 9, 2024
0fa2984
Fix Scala 2.12 build
mgoworko Sep 9, 2024
9629d4e
Fix Scala 2.12 build
mgoworko Sep 9, 2024
3c84065
Fix Scala 2.12 build
mgoworko Sep 9, 2024
5355ed0
Merge remote-tracking branch 'origin/NU-1772-scenario-activity-api-co…
mgoworko Sep 9, 2024
5391527
qs
mgoworko Sep 9, 2024
02eaa4c
Merge branch 'NU-1772-scenario-activity-api-contract' into NU-1772-sc…
mgoworko Sep 9, 2024
25d642a
qs
mgoworko Sep 10, 2024
e3ed827
qs
mgoworko Sep 10, 2024
1f2c6fb
qs
mgoworko Sep 10, 2024
06eed96
API specification
mgoworko Sep 9, 2024
05c7a58
qs
mgoworko Sep 9, 2024
e101258
qs
mgoworko Sep 9, 2024
3a8aca4
qs
mgoworko Sep 10, 2024
874206e
qs
mgoworko Sep 10, 2024
5c5e25b
Data migration with test
mgoworko Sep 10, 2024
ba7d21f
Merge remote-tracking branch 'origin/NU-1772-scenario-activity-api-co…
mgoworko Sep 10, 2024
ec5963e
qs
mgoworko Sep 10, 2024
9113a0f
fix after merge with API spec
mgoworko Sep 10, 2024
909c3e7
Fixed tests
mgoworko Sep 10, 2024
ac3e8db
API specification
mgoworko Sep 9, 2024
1ed303c
qs
mgoworko Sep 9, 2024
379ecd4
qs
mgoworko Sep 9, 2024
36c721c
qs
mgoworko Sep 10, 2024
735dfab
qs
mgoworko Sep 10, 2024
77a4a78
review fixes
mgoworko Sep 16, 2024
63692b6
Merge remote-tracking branch 'origin/NU-1772-scenario-activity-api-co…
mgoworko Sep 16, 2024
cf05ecb
merge fixes
mgoworko Sep 16, 2024
8c90c68
review fixes
mgoworko Sep 16, 2024
c65eb60
Merge remote-tracking branch 'origin/staging' into NU-1772-scenario-a…
mgoworko Sep 16, 2024
6872380
HTTP service fixes
mgoworko Sep 16, 2024
34b26bc
Scala 2.12 fix
mgoworko Sep 17, 2024
212567a
API swagger and migration fixes
mgoworko Sep 17, 2024
e6d67a6
Fix migration issues
mgoworko Sep 17, 2024
d001c5f
Fix db issues
mgoworko Sep 17, 2024
196a2dd
Test new endpoints
mgoworko Sep 18, 2024
cd3fbc9
Improve and fix migration, add tests
mgoworko Sep 19, 2024
8032ac8
Regenerate swagger
mgoworko Sep 19, 2024
18c34a3
Merge remote-tracking branch 'origin/staging' into NU-1772-scenario-a…
mgoworko Sep 19, 2024
0259c22
merge fixes
mgoworko Sep 19, 2024
818a71a
add custom action migration test
mgoworko Sep 19, 2024
eb1d036
Run now comment
mgoworko Sep 19, 2024
47b84cf
Run now comment
mgoworko Sep 19, 2024
8521700
review changes
mgoworko Sep 20, 2024
750da1e
Merge remote-tracking branch 'origin/staging' into NU-1772-scenario-a…
mgoworko Sep 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package db.migration

import com.typesafe.scalalogging.LazyLogging
import db.migration.V1_055__CreateScenarioActivitiesDefinition.ScenarioActivitiesDefinitions
import pl.touk.nussknacker.ui.db.migration.SlickMigration
import shapeless.syntax.std.tuple._
import slick.jdbc.JdbcProfile
import slick.sql.SqlProfile.ColumnOption.NotNull

import java.sql.Timestamp
import java.util.UUID
import scala.concurrent.ExecutionContext.Implicits.global

trait V1_055__CreateScenarioActivitiesDefinition extends SlickMigration with LazyLogging {
lukasz-bigorajski marked this conversation as resolved.
Show resolved Hide resolved

import profile.api._

private val definitions = new ScenarioActivitiesDefinitions(profile)

override def migrateActions: DBIOAction[Any, NoStream, Effect.All] = {
logger.info("Starting migration V1_055__CreateScenarioActivitiesDefinition")
for {
_ <- definitions.scenarioActivitiesTable.schema.create
_ <-
sqlu"""ALTER TABLE "scenario_activities" ADD CONSTRAINT scenario_id_fk FOREIGN KEY ("scenario_id") REFERENCES "processes" ("id") ON DELETE CASCADE;"""
} yield logger.info("Execution finished for migration V1_055__CreateScenarioActivitiesDefinition")
}

}

object V1_055__CreateScenarioActivitiesDefinition {

class ScenarioActivitiesDefinitions(val profile: JdbcProfile) {
import profile.api._

val scenarioActivitiesTable = TableQuery[ScenarioActivityEntity]

class ScenarioActivityEntity(tag: Tag) extends Table[ScenarioActivityEntityData](tag, "scenario_activities") {

def id: Rep[Long] = column[Long]("id", O.PrimaryKey, O.AutoInc)

def activityType: Rep[String] = column[String]("activity_type", NotNull)

def scenarioId: Rep[Long] = column[Long]("scenario_id", NotNull)

def activityId: Rep[UUID] = column[UUID]("activity_id", NotNull, O.Unique)

def userId: Rep[Option[String]] = column[Option[String]]("user_id")

def userName: Rep[String] = column[String]("user_name", NotNull)

def impersonatedByUserId: Rep[Option[String]] = column[Option[String]]("impersonated_by_user_id")

def impersonatedByUserName: Rep[Option[String]] = column[Option[String]]("impersonated_by_user_name")

def lastModifiedByUserName: Rep[Option[String]] = column[Option[String]]("last_modified_by_user_name")

def lastModifiedAt: Rep[Option[Timestamp]] = column[Option[Timestamp]]("last_modified_at")

def createdAt: Rep[Timestamp] = column[Timestamp]("created_at", NotNull)

def scenarioVersion: Rep[Option[Long]] = column[Option[Long]]("scenario_version")

def comment: Rep[Option[String]] = column[Option[String]]("comment")

def attachmentId: Rep[Option[Long]] = column[Option[Long]]("attachment_id")

def performedAt: Rep[Option[Timestamp]] = column[Option[Timestamp]]("performed_at")

def state: Rep[Option[String]] = column[Option[String]]("state")

def errorMessage: Rep[Option[String]] = column[Option[String]]("error_message")

def buildInfo: Rep[Option[String]] = column[Option[String]]("build_info")

def additionalProperties: Rep[String] = column[String]("additional_properties", NotNull)

def activityTypeIndex = index("activity_type_idx", activityType)
def createdAtIndex = index("created_at_idx", activityType)
def scenarioIdIndex = index("scenario_id_idx", activityType)

def tupleWithoutAutoIncId = (
activityType,
scenarioId,
activityId,
userId,
userName,
impersonatedByUserId,
impersonatedByUserName,
lastModifiedByUserName,
lastModifiedAt,
createdAt,
scenarioVersion,
comment,
attachmentId,
performedAt,
state,
errorMessage,
buildInfo,
additionalProperties,
)

override def * =
(id :: tupleWithoutAutoIncId.productElements).tupled <> (
ScenarioActivityEntityData.apply _ tupled, ScenarioActivityEntityData.unapply
)

}

}

final case class ScenarioActivityEntityData(
id: Long,
activityType: String,
scenarioId: Long,
activityId: UUID,
userId: Option[String],
userName: String,
impersonatedByUserId: Option[String],
impersonatedByUserName: Option[String],
lastModifiedByUserName: Option[String],
lastModifiedAt: Option[Timestamp],
createdAt: Timestamp,
scenarioVersion: Option[Long],
comment: Option[String],
attachmentId: Option[Long],
finishedAt: Option[Timestamp],
state: Option[String],
errorMessage: Option[String],
buildInfo: Option[String],
additionalProperties: String,
)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package db.migration

import com.typesafe.scalalogging.LazyLogging
import db.migration.V1_055__CreateScenarioActivitiesDefinition.ScenarioActivitiesDefinitions
import db.migration.V1_056__MigrateActionsAndCommentsToScenarioActivitiesDefinition.Migration
import pl.touk.nussknacker.ui.db.entity.{ScenarioActivityEntityFactory, ScenarioActivityType}
import pl.touk.nussknacker.ui.db.migration.SlickMigration
import slick.jdbc.JdbcProfile
import slick.lifted.{ProvenShape, TableQuery => LTableQuery}
import slick.sql.SqlProfile.ColumnOption.NotNull

import java.sql.Timestamp
import java.util.UUID

trait V1_056__MigrateActionsAndCommentsToScenarioActivitiesDefinition extends SlickMigration with LazyLogging {

import profile.api._

override def migrateActions: DBIOAction[Any, NoStream, Effect.All] = {
new Migration(profile).migrateActions
}

}

object V1_056__MigrateActionsAndCommentsToScenarioActivitiesDefinition extends LazyLogging {

class Migration(val profile: JdbcProfile) extends ScenarioActivityEntityFactory {

import profile.api._

private val scenarioActivitiesDefinitions = new ScenarioActivitiesDefinitions(profile)
private val processActionsDefinitions = new ProcessActionsDefinitions(profile)
private val commentsDefinitions = new CommentsDefinitions(profile)

def migrateActions: DBIOAction[Int, NoStream, Effect.All] = {

val insertQuery =
processActionsDefinitions.table
.joinLeft(commentsDefinitions.table)
.on(_.commentId === _.id)
.map { case (processAction, maybeComment) =>
(
activityType(processAction.actionName), // activityType - converted from action name
processAction.processId, // scenarioId
processAction.id, // activityId
None: Option[String], // userId - always absent in old actions
processAction.user, // userName
processAction.impersonatedByIdentity, // impersonatedByUserId
processAction.impersonatedByUsername, // impersonatedByUserName
processAction.user.?, // lastModifiedByUserName
processAction.createdAt.?, // lastModifiedAt
processAction.createdAt, // createdAt
processAction.processVersionId, // scenarioVersion
maybeComment.map(_.content), // comment
None: Option[Long], // attachmentId
processAction.performedAt, // finishedAt
processAction.state.?, // state
processAction.failureMessage, // errorMessage
None: Option[String], // buildInfo - always absent in old actions
"{}" // additionalProperties - always empty in old actions
)
}

// Slick generates single "insert from select" query and operation is performed solely on db
scenarioActivitiesDefinitions.scenarioActivitiesTable.map(_.tupleWithoutAutoIncId).forceInsertQuery(insertQuery)
}

def activityType(actionNameRep: Rep[String]): Rep[String] = {
val customActionPrefix = s"CUSTOM_ACTION_["
val customActionSuffix = "]"
Case
.If(actionNameRep === "DEPLOY")
.Then(ScenarioActivityType.ScenarioDeployed.entryName)
.If(actionNameRep === "CANCEL")
.Then(ScenarioActivityType.ScenarioCanceled.entryName)
.If(actionNameRep === "ARCHIVE")
.Then(ScenarioActivityType.ScenarioArchived.entryName)
.If(actionNameRep === "UNARCHIVE")
.Then(ScenarioActivityType.ScenarioUnarchived.entryName)
.If(actionNameRep === "PAUSE")
.Then(ScenarioActivityType.ScenarioPaused.entryName)
.If(actionNameRep === "RENAME")
.Then(ScenarioActivityType.ScenarioNameChanged.entryName)
.If(actionNameRep === "run now")
.Then(ScenarioActivityType.PerformedSingleExecution.entryName)
.Else(actionNameRep.reverseString.++(customActionPrefix.reverse).reverseString.++(customActionSuffix))
}

}

class ProcessActionsDefinitions(val profile: JdbcProfile) {
import profile.api._

val table: LTableQuery[ProcessActionEntity] = LTableQuery(new ProcessActionEntity(_))

class ProcessActionEntity(tag: Tag) extends Table[ProcessActionEntityData](tag, "process_actions") {
def id: Rep[UUID] = column[UUID]("id", O.PrimaryKey)

def processId: Rep[Long] = column[Long]("process_id")

def processVersionId: Rep[Option[Long]] = column[Option[Long]]("process_version_id")

def createdAt: Rep[Timestamp] = column[Timestamp]("created_at")

def performedAt: Rep[Option[Timestamp]] = column[Option[Timestamp]]("performed_at")

def user: Rep[String] = column[String]("user")

def impersonatedByIdentity = column[Option[String]]("impersonated_by_identity")

def impersonatedByUsername = column[Option[String]]("impersonated_by_username")

def buildInfo: Rep[Option[String]] = column[Option[String]]("build_info")

def actionName: Rep[String] = column[String]("action_name")

def state: Rep[String] = column[String]("state")

def failureMessage: Rep[Option[String]] = column[Option[String]]("failure_message")

def commentId: Rep[Option[Long]] = column[Option[Long]]("comment_id")

def * : ProvenShape[ProcessActionEntityData] = (
id,
processId,
processVersionId,
user,
impersonatedByIdentity,
impersonatedByUsername,
createdAt,
performedAt,
actionName,
state,
failureMessage,
commentId,
buildInfo
) <> (
ProcessActionEntityData.apply _ tupled, ProcessActionEntityData.unapply
)

}

}

sealed case class ProcessActionEntityData(
id: UUID,
processId: Long,
processVersionId: Option[Long],
user: String,
impersonatedByIdentity: Option[String],
impersonatedByUsername: Option[String],
createdAt: Timestamp,
performedAt: Option[Timestamp],
actionName: String,
state: String,
failureMessage: Option[String],
commentId: Option[Long],
buildInfo: Option[String]
)

class CommentsDefinitions(val profile: JdbcProfile) {
import profile.api._
val table: LTableQuery[CommentEntity] = LTableQuery(new CommentEntity(_))

class CommentEntity(tag: Tag) extends Table[CommentEntityData](tag, "process_comments") {

def id: Rep[Long] = column[Long]("id", O.PrimaryKey)

def processId: Rep[Long] = column[Long]("process_id", NotNull)

def processVersionId: Rep[Long] = column[Long]("process_version_id", NotNull)

def content: Rep[String] = column[String]("content", NotNull)

def createDate: Rep[Timestamp] = column[Timestamp]("create_date", NotNull)

def user: Rep[String] = column[String]("user", NotNull)

def impersonatedByIdentity = column[Option[String]]("impersonated_by_identity")

def impersonatedByUsername = column[Option[String]]("impersonated_by_username")

override def * =
(
id,
processId,
processVersionId,
content,
user,
impersonatedByIdentity,
impersonatedByUsername,
createDate
) <> (
CommentEntityData.apply _ tupled, CommentEntityData.unapply
)

}

}

final case class CommentEntityData(
id: Long,
processId: Long,
processVersionId: Long,
content: String,
user: String,
impersonatedByIdentity: Option[String],
impersonatedByUsername: Option[String],
createDate: Timestamp,
)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package db.migration.hsql

import db.migration.V1_055__CreateScenarioActivitiesDefinition
import slick.jdbc.{HsqldbProfile, JdbcProfile}

class V1_055__CreateScenarioActivities extends V1_055__CreateScenarioActivitiesDefinition {
override protected lazy val profile: JdbcProfile = HsqldbProfile
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package db.migration.hsql

import db.migration.V1_056__MigrateActionsAndCommentsToScenarioActivitiesDefinition
import slick.jdbc.{HsqldbProfile, JdbcProfile}

class V1_056__MigrateActionsAndCommentsToScenarioActivities
extends V1_056__MigrateActionsAndCommentsToScenarioActivitiesDefinition {
override protected lazy val profile: JdbcProfile = HsqldbProfile
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package db.migration.postgres

import db.migration.V1_055__CreateScenarioActivitiesDefinition
import slick.jdbc.{JdbcProfile, PostgresProfile}

class V1_055__CreateScenarioActivities extends V1_055__CreateScenarioActivitiesDefinition {
override protected lazy val profile: JdbcProfile = PostgresProfile
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package db.migration.postgres

import db.migration.V1_056__MigrateActionsAndCommentsToScenarioActivitiesDefinition
import slick.jdbc.{JdbcProfile, PostgresProfile}

class V1_056__MigrateActionsAndCommentsToScenarioActivities
extends V1_056__MigrateActionsAndCommentsToScenarioActivitiesDefinition {
override protected lazy val profile: JdbcProfile = PostgresProfile
}
Loading
Loading