Skip to content
Open
62 changes: 60 additions & 2 deletions api/handle_datamodel.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/checkmarble/marble-backend/dto"
"github.com/checkmarble/marble-backend/models"
"github.com/checkmarble/marble-backend/pubapi"
"github.com/checkmarble/marble-backend/pure_utils"
"github.com/checkmarble/marble-backend/usecases"
"github.com/checkmarble/marble-backend/utils"
)
Expand Down Expand Up @@ -52,8 +53,22 @@ func handleCreateTable(uc usecases.Usecases) func(c *gin.Context) {
return
}

var ftmEntity *models.FollowTheMoneyEntity
if input.FTMEntity != nil {
entity := models.FollowTheMoneyEntityFrom(*input.FTMEntity)
if entity == models.FollowTheMoneyEntityUnknown {
presentError(
ctx,
c,
errors.Wrapf(models.BadParameterError, "invalid FTM entity: %s", *input.FTMEntity),
)
return
}
ftmEntity = &entity
}

usecase := usecasesWithCreds(ctx, uc).NewDataModelUseCase()
tableID, err := usecase.CreateDataModelTable(ctx, organizationID, input.Name, input.Description)
tableID, err := usecase.CreateDataModelTable(ctx, organizationID, input.Name, input.Description, ftmEntity)
if presentError(ctx, c, err) {
return
}
Expand All @@ -73,8 +88,23 @@ func handleUpdateDataModelTable(uc usecases.Usecases) func(c *gin.Context) {
}
tableID := c.Param("tableID")

var ftmEntity pure_utils.Null[models.FollowTheMoneyEntity]
if input.FTMEntity.Set {
if input.FTMEntity.Valid {
entity := models.FollowTheMoneyEntityFrom(input.FTMEntity.Value())
if entity == models.FollowTheMoneyEntityUnknown {
presentError(ctx, c, errors.Wrapf(models.BadParameterError,
"invalid FTM entity: %s", input.FTMEntity.Value()))
return
}
ftmEntity = pure_utils.NullFrom(entity)
} else {
ftmEntity = pure_utils.NullFromPtr[models.FollowTheMoneyEntity](nil)
}
}

usecase := usecasesWithCreds(ctx, uc).NewDataModelUseCase()
err := usecase.UpdateDataModelTable(ctx, tableID, input.Description)
err := usecase.UpdateDataModelTable(ctx, tableID, input.Description, ftmEntity)
if presentError(ctx, c, err) {
return
}
Expand All @@ -91,6 +121,17 @@ func handleCreateField(uc usecases.Usecases) func(c *gin.Context) {
return
}

var ftmProperty *models.FollowTheMoneyProperty
if input.FTMProperty != nil {
property := models.FollowTheMoneyPropertyFrom(*input.FTMProperty)
if property == models.FollowTheMoneyPropertyUnknown {
presentError(ctx, c, errors.Wrapf(models.BadParameterError,
"invalid FTM property: %s", *input.FTMProperty))
return
}
ftmProperty = &property
}

tableID := c.Param("tableID")
field := models.CreateFieldInput{
TableId: tableID,
Expand All @@ -100,6 +141,7 @@ func handleCreateField(uc usecases.Usecases) func(c *gin.Context) {
Nullable: input.Nullable,
IsEnum: input.IsEnum,
IsUnique: input.IsUnique,
FTMProperty: ftmProperty,
}

usecase := usecasesWithCreds(ctx, uc).NewDataModelUseCase()
Expand All @@ -123,12 +165,28 @@ func handleUpdateDataModelField(uc usecases.Usecases) func(c *gin.Context) {
}
fieldID := c.Param("fieldID")

var ftmProperty pure_utils.Null[models.FollowTheMoneyProperty]
if input.FTMProperty.Set {
if input.FTMProperty.Valid {
property := models.FollowTheMoneyPropertyFrom(input.FTMProperty.Value())
if property == models.FollowTheMoneyPropertyUnknown {
presentError(ctx, c, errors.Wrapf(models.BadParameterError,
"invalid FTM property: %s", input.FTMProperty.Value()))
return
}
ftmProperty = pure_utils.NullFrom(property)
} else {
ftmProperty = pure_utils.NullFromPtr[models.FollowTheMoneyProperty](nil)
}
}

usecase := usecasesWithCreds(ctx, uc).NewDataModelUseCase()
err := usecase.UpdateDataModelField(ctx, fieldID, models.UpdateFieldInput{
Description: input.Description,
IsEnum: input.IsEnum,
IsUnique: input.IsUnique,
IsNullable: input.IsNullable,
FTMProperty: ftmProperty,
})
if presentError(ctx, c, err) {
return
Expand Down
118 changes: 118 additions & 0 deletions api/handle_screening_monitoring.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package api

import (
"net/http"

"github.com/checkmarble/marble-backend/dto"
"github.com/checkmarble/marble-backend/models"
"github.com/checkmarble/marble-backend/pure_utils"
"github.com/checkmarble/marble-backend/usecases"
"github.com/checkmarble/marble-backend/utils"
"github.com/cockroachdb/errors"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)

func handleGetScreeningMonitoringConfig(uc usecases.Usecases) func(c *gin.Context) {
return func(c *gin.Context) {
ctx := c.Request.Context()
configId, err := uuid.Parse(c.Param("config_id"))
if err != nil {
presentError(ctx, c, errors.Wrap(models.BadParameterError, err.Error()))
return
}

uc := usecasesWithCreds(ctx, uc).NewScreeningMonitoringUsecase()
screeningMonitoringConfig, err := uc.GetScreeningMonitoringConfig(ctx, configId)
if presentError(ctx, c, err) {
return
}

c.JSON(http.StatusOK, dto.AdaptScreeningMonitoringConfigDto(screeningMonitoringConfig))
}
}

func handleListScreeningMonitoringConfigs(uc usecases.Usecases) func(c *gin.Context) {
return func(c *gin.Context) {
ctx := c.Request.Context()
organizationId, err := utils.OrganizationIdFromRequest(c.Request)
if presentError(ctx, c, err) {
return
}

uc := usecasesWithCreds(ctx, uc).NewScreeningMonitoringUsecase()
screeningMonitoringConfigs, err := uc.GetScreeningMonitoringConfigsByOrgId(ctx, organizationId)
if presentError(ctx, c, err) {
return
}

c.JSON(http.StatusOK, pure_utils.Map(screeningMonitoringConfigs, dto.AdaptScreeningMonitoringConfigDto))
}
}

func handleCreateScreeningMonitoringConfig(uc usecases.Usecases) func(c *gin.Context) {
return func(c *gin.Context) {
ctx := c.Request.Context()
organizationId, err := utils.OrganizationIdFromRequest(c.Request)
if presentError(ctx, c, err) {
return
}

var input dto.CreateScreeningMonitoringConfigDto
if err := c.ShouldBindJSON(&input); err != nil {
presentError(ctx, c, errors.Wrap(models.BadParameterError, err.Error()))
return
}

if err := input.Validate(); err != nil {
presentError(ctx, c, errors.Wrap(models.BadParameterError, err.Error()))
return
}

createScreeningMonitoringConfigInput :=
dto.AdaptCreateScreeningMonitoringConfigDtoToModel(input)
createScreeningMonitoringConfigInput.OrgId = organizationId

uc := usecasesWithCreds(ctx, uc).NewScreeningMonitoringUsecase()
screeningMonitoringConfig, err := uc.CreateScreeningMonitoringConfig(ctx, createScreeningMonitoringConfigInput)
if presentError(ctx, c, err) {
return
}

c.JSON(http.StatusCreated, dto.AdaptScreeningMonitoringConfigDto(screeningMonitoringConfig))
}
}

func handleUpdateScreeningMonitoringConfig(uc usecases.Usecases) func(c *gin.Context) {
return func(c *gin.Context) {
ctx := c.Request.Context()

configId, err := uuid.Parse(c.Param("config_id"))
if err != nil {
presentError(ctx, c, errors.Wrap(models.BadParameterError, err.Error()))
return
}

var input dto.UpdateScreeningMonitoringConfigDto
if err := c.ShouldBindJSON(&input); err != nil {
presentError(ctx, c, errors.Wrap(models.BadParameterError, err.Error()))
return
}
if err := input.Validate(); err != nil {
presentError(ctx, c, errors.Wrap(models.BadParameterError, err.Error()))
return
}

uc := usecasesWithCreds(ctx, uc).NewScreeningMonitoringUsecase()
screeningMonitoringConfig, err := uc.UpdateScreeningMonitoringConfig(
ctx,
configId,
dto.AdaptUpdateScreeningMonitoringConfigDtoToModel(input),
)
if presentError(ctx, c, err) {
return
}

c.JSON(http.StatusOK, dto.AdaptScreeningMonitoringConfigDto(screeningMonitoringConfig))
}
}
7 changes: 7 additions & 0 deletions api/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,13 @@ func addRoutes(r *gin.Engine, conf Configuration, uc usecases.Usecases, auth uti
router.PATCH("/screenings/matches/:id", tom, handleUpdateScreeningMatchStatus(uc))
router.POST("/screenings/matches/:id/enrich", tom, handleEnrichScreeningMatch(uc))

router.GET("/screening-monitoring/configs", tom, handleListScreeningMonitoringConfigs(uc))
router.POST("/screening-monitoring/configs", tom, handleCreateScreeningMonitoringConfig(uc))
router.GET("/screening-monitoring/configs/:config_id", tom, handleGetScreeningMonitoringConfig(uc))
router.PATCH("/screening-monitoring/configs/:config_id", tom,
handleUpdateScreeningMonitoringConfig(uc),
)

router.GET("/scenario-publications", tom, handleListScenarioPublications(uc))
router.POST("/scenario-publications", tom, handleCreateScenarioPublication(uc))
router.GET("/scenario-publications/preparation", tom,
Expand Down
30 changes: 17 additions & 13 deletions dto/data_model_dto.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,14 @@ func AdaptDataModelDto(dataModel models.DataModel) DataModel {
}

type CreateTableInput struct {
Name string `json:"name"`
Description string `json:"description"`
Name string `json:"name"`
Description string `json:"description"`
FTMEntity *string `json:"ftm_entity"`
}

type UpdateTableInput struct {
Description string `json:"description"`
Description string `json:"description"`
FTMEntity pure_utils.Null[string] `json:"ftm_entity"`
}

type CreateLinkInput struct {
Expand All @@ -135,19 +137,21 @@ type CreateLinkInput struct {
}

type UpdateFieldInput struct {
Description *string `json:"description"`
IsEnum *bool `json:"is_enum"`
IsUnique *bool `json:"is_unique"`
IsNullable *bool `json:"is_nullable"`
Description *string `json:"description"`
IsEnum *bool `json:"is_enum"`
IsUnique *bool `json:"is_unique"`
IsNullable *bool `json:"is_nullable"`
FTMProperty pure_utils.Null[string] `json:"ftm_property"`
}

type CreateFieldInput struct {
Name string `json:"name"`
Description string `json:"description"`
Type string `json:"type"`
Nullable bool `json:"nullable"`
IsEnum bool `json:"is_enum"`
IsUnique bool `json:"is_unique"`
Name string `json:"name"`
Description string `json:"description"`
Type string `json:"type"`
Nullable bool `json:"nullable"`
IsEnum bool `json:"is_enum"`
IsUnique bool `json:"is_unique"`
FTMProperty *string `json:"ftm_property"`
}

type DataModelObject struct {
Expand Down
104 changes: 104 additions & 0 deletions dto/screening_monitoring_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package dto

import (
"time"

"github.com/checkmarble/marble-backend/models"
"github.com/cockroachdb/errors"
)

type ScreeningMonitoringConfigDto struct {
Id string `json:"id"`
Name string `json:"name"`
Description *string `json:"description"`
Datasets []string `json:"datasets"`
MatchThreshold int `json:"match_threshold"`
MatchLimit int `json:"match_limit"`
Enabled bool `json:"enabled"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}

func AdaptScreeningMonitoringConfigDto(config models.ScreeningMonitoringConfig) ScreeningMonitoringConfigDto {
return ScreeningMonitoringConfigDto{
Id: config.Id.String(),
Name: config.Name,
Description: config.Description,
Datasets: config.Datasets,
MatchThreshold: config.MatchThreshold,
MatchLimit: config.MatchLimit,
Enabled: config.Enabled,
CreatedAt: config.CreatedAt,
UpdatedAt: config.UpdatedAt,
}
}

type CreateScreeningMonitoringConfigDto struct {
Name string `json:"name" binding:"required"`
Description *string `json:"description"`
Datasets []string `json:"datasets" binding:"required"`
MatchThreshold int `json:"match_threshold" binding:"required"`
MatchLimit int `json:"match_limit" binding:"required"`
}

func (dto CreateScreeningMonitoringConfigDto) Validate() error {
if len(dto.Datasets) == 0 {
return errors.New("datasets are required for screening monitoring config")
}

if dto.MatchThreshold < 0 || dto.MatchThreshold > 100 {
return errors.New("match threshold must be between 0 and 100")
}

if dto.MatchLimit < 1 {
return errors.New("match limit must be greater than or equal to 0")
}

return nil
}

func AdaptCreateScreeningMonitoringConfigDtoToModel(dto CreateScreeningMonitoringConfigDto) models.CreateScreeningMonitoringConfig {
return models.CreateScreeningMonitoringConfig{
Name: dto.Name,
Description: dto.Description,
Datasets: dto.Datasets,
MatchThreshold: dto.MatchThreshold,
MatchLimit: dto.MatchLimit,
}
}

type UpdateScreeningMonitoringConfigDto struct {
Name *string `json:"name"`
Description *string `json:"description"`
Datasets *[]string `json:"datasets"`
MatchThreshold *int `json:"match_threshold"`
MatchLimit *int `json:"match_limit"`
Enabled *bool `json:"enabled"`
}

func (dto UpdateScreeningMonitoringConfigDto) Validate() error {
if dto.MatchThreshold != nil && (*dto.MatchThreshold < 0 || *dto.MatchThreshold > 100) {
return errors.New("match threshold must be between 0 and 100")
}

if dto.MatchLimit != nil && *dto.MatchLimit < 0 {
return errors.New("match limit must be greater than or equal to 0")
}

if dto.Datasets != nil && len(*dto.Datasets) == 0 {
return errors.New("datasets cannot be empty")
}

return nil
}

func AdaptUpdateScreeningMonitoringConfigDtoToModel(dto UpdateScreeningMonitoringConfigDto) models.UpdateScreeningMonitoringConfig {
return models.UpdateScreeningMonitoringConfig{
Name: dto.Name,
Description: dto.Description,
Datasets: dto.Datasets,
MatchThreshold: dto.MatchThreshold,
MatchLimit: dto.MatchLimit,
Enabled: dto.Enabled,
}
}
Loading
Loading