From d210818e6b0b2da956b9fe107b3607b176502128 Mon Sep 17 00:00:00 2001 From: Sam Lucidi Date: Thu, 28 Sep 2023 16:04:30 -0400 Subject: [PATCH] Apply Questionnaire seeds Adds logic to seed Questionnaires. Fixes a bug that would have caused an unnecessary query when an item to be seeded is found by UUID and not being renamed. Signed-off-by: Sam Lucidi --- go.mod | 2 +- go.sum | 4 +- seed/jobfunction.go | 2 +- seed/questionnaire.go | 132 ++++++++++++++++++++++++++++++++++++++++++ seed/ruleset.go | 2 +- seed/seed.go | 7 +++ seed/tag.go | 2 +- seed/target.go | 2 +- 8 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 seed/questionnaire.go diff --git a/go.mod b/go.mod index 6b0803e38..de8b5f734 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/uuid v1.3.0 github.com/jortel/go-utils v0.1.1 - github.com/konveyor/tackle2-seed v0.0.0-20230731150314-953199a73e93 + github.com/konveyor/tackle2-seed v0.0.0-20230928184719-4a383c5aa887 github.com/mattn/go-sqlite3 v1.14.17 github.com/onsi/gomega v1.27.6 github.com/prometheus/client_golang v1.15.0 diff --git a/go.sum b/go.sum index 89150508f..30856dc6a 100644 --- a/go.sum +++ b/go.sum @@ -139,8 +139,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/konveyor/tackle2-seed v0.0.0-20230731150314-953199a73e93 h1:uMJnrcH2+luiLf1l7skj5kBJSEffbhyl41uvXA+JKUQ= -github.com/konveyor/tackle2-seed v0.0.0-20230731150314-953199a73e93/go.mod h1:4yas66RZJudLqkehmiFeQZ6NDgXk+XutksjoKFx8JzY= +github.com/konveyor/tackle2-seed v0.0.0-20230928184719-4a383c5aa887 h1:LF8F78Oz/S7K0LakDWrjMaoeBMs5tYj2ntcf73u+gt0= +github.com/konveyor/tackle2-seed v0.0.0-20230928184719-4a383c5aa887/go.mod h1:wt9Zb1l1PAd+XxW03KTp8z4dth3DkCDsRrcdZSWTyjA= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= diff --git a/seed/jobfunction.go b/seed/jobfunction.go index e3f61b6be..6bd2cb98d 100644 --- a/seed/jobfunction.go +++ b/seed/jobfunction.go @@ -53,7 +53,7 @@ func (r *JobFunction) Apply(db *gorm.DB) (err error) { return } } - } else { + } else if !found { jobFunction, found, fErr = r.find(db, "name = ?", jf.Name) if fErr != nil { err = fErr diff --git a/seed/questionnaire.go b/seed/questionnaire.go new file mode 100644 index 000000000..fa1c943ba --- /dev/null +++ b/seed/questionnaire.go @@ -0,0 +1,132 @@ +package seed + +import ( + "encoding/json" + "errors" + "fmt" + liberr "github.com/jortel/go-utils/error" + "github.com/konveyor/tackle2-hub/model" + libseed "github.com/konveyor/tackle2-seed/pkg" + "gorm.io/gorm" +) + +// +// Questionnaire applies Questionnaire seeds. +type Questionnaire struct { + questionnaires []libseed.Questionnaire +} + +// +// With collects all the Questionnaire seeds. +func (r *Questionnaire) With(seed libseed.Seed) (err error) { + items, err := seed.DecodeItems() + if err != nil { + return + } + for _, item := range items { + r.questionnaires = append(r.questionnaires, item.(libseed.Questionnaire)) + } + return +} + +// +// Apply seeds the database with Questionnaires. +func (r *Questionnaire) Apply(db *gorm.DB) (err error) { + log.Info("Applying Questionnaires", "count", len(r.questionnaires)) + for i := range r.questionnaires { + q := r.questionnaires[i] + questionnaire, found, fErr := r.find(db, "uuid = ?", q.UUID) + if fErr != nil { + err = fErr + return + } + // model exists and is being renamed + if found && questionnaire.Name != q.Name { + // ensure that the target name is clear + collision, collides, fErr := r.find(db, "name = ? and id != ?", q.Name, questionnaire.ID) + if fErr != nil { + err = fErr + return + } + if collides { + err = r.rename(db, collision) + if err != nil { + return + } + } + } else if !found { + questionnaire, found, fErr = r.find(db, "name = ?", q.Name) + if fErr != nil { + err = fErr + return + } + if found && questionnaire.CreateUser != "" { + err = r.rename(db, questionnaire) + if err != nil { + return + } + found = false + } + if !found { + // only set the required flag on first seed so that + // we don't e.g. turn it back on when reseeding to + // fix a typo in the questionnaire or etc. + questionnaire = &model.Questionnaire{} + questionnaire.Required = q.Required + } + } + + questionnaire.Name = q.Name + questionnaire.UUID = &q.UUID + questionnaire.Description = q.Description + questionnaire.Sections, _ = json.Marshal(q.Sections) + questionnaire.RiskMessages, _ = json.Marshal(q.RiskMessages) + questionnaire.Thresholds, _ = json.Marshal(q.Thresholds) + result := db.Save(&questionnaire) + if result.Error != nil { + err = liberr.Wrap(result.Error) + return + } + } + return +} + +// +// Convenience method to find a Questionnaire. +func (r *Questionnaire) find(db *gorm.DB, conditions ...interface{}) (q *model.Questionnaire, found bool, err error) { + q = &model.Questionnaire{} + result := db.First(q, conditions...) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return + } + err = liberr.Wrap(result.Error) + return + } + found = true + return +} + +// +// Rename a Questionnaire by adding a suffix. +func (r *Questionnaire) rename(db *gorm.DB, q *model.Questionnaire) (err error) { + suffix := 0 + for { + suffix++ + newName := fmt.Sprintf("%s (%d)", q.Name, suffix) + _, found, fErr := r.find(db, "name = ?", newName) + if fErr != nil { + err = fErr + return + } + if !found { + q.Name = newName + result := db.Save(q) + if result.Error != nil { + err = liberr.Wrap(result.Error) + return + } + return + } + } +} diff --git a/seed/ruleset.go b/seed/ruleset.go index 4376960c2..ab8afb7b3 100644 --- a/seed/ruleset.go +++ b/seed/ruleset.go @@ -62,7 +62,7 @@ func (r *RuleSet) Apply(db *gorm.DB) (err error) { return } } - } else { + } else if !found { ruleSet, found, fErr = r.find(db, "name = ?", rs.Name) if fErr != nil { err = fErr diff --git a/seed/seed.go b/seed/seed.go index b600b9477..94bfab2f3 100644 --- a/seed/seed.go +++ b/seed/seed.go @@ -18,6 +18,7 @@ type Hub struct { JobFunction RuleSet Target + Questionnaire } // @@ -32,6 +33,8 @@ func (r *Hub) With(seed libseed.Seed) (err error) { err = r.RuleSet.With(seed) case libseed.KindTarget: err = r.Target.With(seed) + case libseed.KindQuestionnaire: + err = r.Questionnaire.With(seed) default: err = liberr.New("unknown kind", "kind", seed.Kind, "file", seed.Filename()) } @@ -57,6 +60,10 @@ func (r *Hub) Apply(db *gorm.DB) (err error) { if err != nil { return } + err = r.Questionnaire.Apply(db) + if err != nil { + return + } return } diff --git a/seed/tag.go b/seed/tag.go index 206596295..bc84674e0 100644 --- a/seed/tag.go +++ b/seed/tag.go @@ -53,7 +53,7 @@ func (r *TagCategory) Apply(db *gorm.DB) (err error) { return } } - } else { + } else if !found { category, found, fErr = r.find(db, "name = ?", tc.Name) if fErr != nil { err = fErr diff --git a/seed/target.go b/seed/target.go index 5651a9f24..4e9361d63 100644 --- a/seed/target.go +++ b/seed/target.go @@ -56,7 +56,7 @@ func (r *Target) Apply(db *gorm.DB) (err error) { return } } - } else { + } else if !found { target, found, fErr = r.find(db, "name = ?", t.Name) if fErr != nil { err = fErr