From 9a9569ec9ba2cb0eabb444244ff9eef536f2077e Mon Sep 17 00:00:00 2001 From: Sam Lucidi Date: Mon, 18 Dec 2023 15:52:12 -0500 Subject: [PATCH] Fix risk/confidence to only count required Qs Signed-off-by: Sam Lucidi --- api/application.go | 31 ++++++++++++++++++---------- api/archetype.go | 17 ++++++++++++---- assessment/application.go | 40 ++++++++++++++++++++++++++++--------- assessment/archetype.go | 17 +++++++++++++--- assessment/questionnaire.go | 6 ++++++ 5 files changed, 84 insertions(+), 27 deletions(-) diff --git a/api/application.go b/api/application.go index 615cbd8a6..5de64271c 100644 --- a/api/application.go +++ b/api/application.go @@ -2,14 +2,15 @@ package api import ( "encoding/json" + "net/http" + "sort" + "strings" + "github.com/gin-gonic/gin" "github.com/konveyor/tackle2-hub/assessment" "github.com/konveyor/tackle2-hub/metrics" "github.com/konveyor/tackle2-hub/model" "gorm.io/gorm/clause" - "net/http" - "sort" - "strings" ) // @@ -502,7 +503,12 @@ func (h ApplicationHandler) TagList(ctx *gin.Context) { _ = ctx.Error(err) return } - resolver := assessment.NewApplicationResolver(app, tagsResolver, membership, nil) + questionnaire, err := assessment.NewQuestionnaireResolver(h.DB(ctx)) + if err != nil { + _ = ctx.Error(err) + return + } + resolver := assessment.NewApplicationResolver(app, tagsResolver, membership, questionnaire) if includeArchetype { archetypeTags, err := resolver.ArchetypeTags() if err != nil { @@ -1137,6 +1143,7 @@ func (r *Application) With(m *model.Application, tags []model.ApplicationTag) { }) r.Effort = m.Analyses[len(m.Analyses)-1].Effort } + r.Risk = assessment.RiskUnknown } // @@ -1172,13 +1179,15 @@ func (r *Application) WithResolver(resolver *assessment.ApplicationResolver) (er if err != nil { return } - r.Confidence, err = resolver.Confidence() - if err != nil { - return - } - r.Risk, err = resolver.Risk() - if err != nil { - return + if r.Assessed { + r.Confidence, err = resolver.Confidence() + if err != nil { + return + } + r.Risk, err = resolver.Risk() + if err != nil { + return + } } return } diff --git a/api/archetype.go b/api/archetype.go index 7ea3eaa46..c1c6dea91 100644 --- a/api/archetype.go +++ b/api/archetype.go @@ -1,12 +1,13 @@ package api import ( + "net/http" + "github.com/gin-gonic/gin" "github.com/konveyor/tackle2-hub/assessment" "github.com/konveyor/tackle2-hub/metrics" "github.com/konveyor/tackle2-hub/model" "gorm.io/gorm/clause" - "net/http" ) // @@ -152,7 +153,12 @@ func (h ArchetypeHandler) Create(ctx *gin.Context) { } membership := assessment.NewMembershipResolver(h.DB(ctx)) - resolver := assessment.NewArchetypeResolver(m, nil, membership, nil) + questionnaires, err := assessment.NewQuestionnaireResolver(h.DB(ctx)) + if err != nil { + _ = ctx.Error(err) + return + } + resolver := assessment.NewArchetypeResolver(m, nil, membership, questionnaires) r.With(m) err = r.WithResolver(resolver) if err != nil { @@ -384,15 +390,18 @@ func (r *Archetype) With(m *model.Archetype) { ref.With(m.Review.ID, "") r.Review = ref } + r.Risk = assessment.RiskUnknown } // // WithResolver uses an ArchetypeResolver to update the resource with // values derived from the archetype's assessments. func (r *Archetype) WithResolver(resolver *assessment.ArchetypeResolver) (err error) { - r.Risk = resolver.Risk() - r.Confidence = resolver.Confidence() r.Assessed = resolver.Assessed() + if r.Assessed { + r.Risk = resolver.Risk() + r.Confidence = resolver.Confidence() + } apps, err := resolver.Applications() for i := range apps { ref := Ref{} diff --git a/assessment/application.go b/assessment/application.go index 57446c1a0..3600ea475 100644 --- a/assessment/application.go +++ b/assessment/application.go @@ -95,12 +95,23 @@ func (r *ApplicationResolver) ArchetypeTags() (tags []model.Tag, err error) { return } +// +// RequiredAssessments returns the slice of assessments that are for required questionnaires. +func (r *ApplicationResolver) RequiredAssessments() (required []Assessment) { + for _, a := range r.application.Assessments { + if r.questionnaireResolver.Required(a.QuestionnaireID) { + required = append(required, a) + } + } + return +} + // // AssessmentTags returns the list of tags that the application should inherit from the answers given // to its assessments. func (r *ApplicationResolver) AssessmentTags() (tags []model.Tag) { seenTags := make(map[uint]bool) - for _, assessment := range r.application.Assessments { + for _, assessment := range r.RequiredAssessments() { aTags := r.tagResolver.Assessment(assessment) for _, t := range aTags { if _, found := seenTags[t.ID]; !found { @@ -116,8 +127,9 @@ func (r *ApplicationResolver) AssessmentTags() (tags []model.Tag) { // Risk returns the overall risk level for the application based on its or its archetypes' assessments. func (r *ApplicationResolver) Risk() (risk string, err error) { var assessments []Assessment - if len(r.application.Assessments) > 0 { - assessments = r.application.Assessments + requiredAssessments := r.RequiredAssessments() + if len(requiredAssessments) > 0 { + assessments = requiredAssessments } else { archetypes, aErr := r.Archetypes() if aErr != nil { @@ -125,7 +137,11 @@ func (r *ApplicationResolver) Risk() (risk string, err error) { return } for _, a := range archetypes { - assessments = append(assessments, a.Assessments...) + for _, assessment := range a.Assessments { + if r.questionnaireResolver.Required(assessment.QuestionnaireID) { + assessments = append(assessments, assessment) + } + } } } risk = Risk(assessments) @@ -136,8 +152,9 @@ func (r *ApplicationResolver) Risk() (risk string, err error) { // Confidence returns the application's overall assessment confidence score. func (r *ApplicationResolver) Confidence() (confidence int, err error) { var assessments []Assessment - if len(r.application.Assessments) > 0 { - assessments = r.application.Assessments + requiredAssessments := r.RequiredAssessments() + if len(requiredAssessments) > 0 { + assessments = requiredAssessments } else { archetypes, aErr := r.Archetypes() if aErr != nil { @@ -145,7 +162,11 @@ func (r *ApplicationResolver) Confidence() (confidence int, err error) { return } for _, a := range archetypes { - assessments = append(assessments, a.Assessments...) + for _, assessment := range a.Assessments { + if r.questionnaireResolver.Required(assessment.QuestionnaireID) { + assessments = append(assessments, assessment) + } + } } } confidence = Confidence(assessments) @@ -157,8 +178,9 @@ func (r *ApplicationResolver) Confidence() (confidence int, err error) { func (r *ApplicationResolver) Assessed() (assessed bool, err error) { // if the application has any of its own assessments, only consider them for // determining whether it has been assessed. - if len(r.application.Assessments) > 0 { - assessed = r.questionnaireResolver.Assessed(r.application.Assessments) + assessments := r.RequiredAssessments() + if len(assessments) > 0 { + assessed = r.questionnaireResolver.Assessed(assessments) return } // otherwise the application is assessed if all of its archetypes are fully assessed. diff --git a/assessment/archetype.go b/assessment/archetype.go index 2450c1c56..6ad51f245 100644 --- a/assessment/archetype.go +++ b/assessment/archetype.go @@ -65,17 +65,28 @@ func (r *ArchetypeResolver) AssessmentTags() (tags []model.Tag) { return } +// +// RequiredAssessments returns the slice of assessments that are for required questionnaires. +func (r *ArchetypeResolver) RequiredAssessments() (required []Assessment) { + for _, a := range r.archetype.Assessments { + if r.questionnaire.Required(a.QuestionnaireID) { + required = append(required, a) + } + } + return +} + // // Risk returns the overall risk level for the archetypes' assessments. func (r *ArchetypeResolver) Risk() (risk string) { - risk = Risk(r.archetype.Assessments) + risk = Risk(r.RequiredAssessments()) return } // // Confidence returns the archetype's overall assessment confidence score. func (r *ArchetypeResolver) Confidence() (confidence int) { - confidence = Confidence(r.archetype.Assessments) + confidence = Confidence(r.RequiredAssessments()) return } @@ -85,7 +96,7 @@ func (r *ArchetypeResolver) Assessed() (assessed bool) { if r.questionnaire == nil { return } - assessed = r.questionnaire.Assessed(r.archetype.Assessments) + assessed = r.questionnaire.Assessed(r.RequiredAssessments()) return } diff --git a/assessment/questionnaire.go b/assessment/questionnaire.go index 0e21bacd2..d615d0262 100644 --- a/assessment/questionnaire.go +++ b/assessment/questionnaire.go @@ -41,6 +41,12 @@ func (r *QuestionnaireResolver) cacheQuestionnaires() (err error) { return } +// +// Required returns whether a questionnaire is required. +func (r *QuestionnaireResolver) Required(id uint) (required bool) { + return r.requiredQuestionnaires.Contains(id) +} + // // Assessed returns whether a slice contains a completed assessment for each of the required // questionnaires.