github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/label/service.go (about) 1 package label 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 8 "github.com/kyma-incubator/compass/components/director/internal/model" 9 "github.com/kyma-incubator/compass/components/director/pkg/apperrors" 10 "github.com/kyma-incubator/compass/components/director/pkg/jsonschema" 11 "github.com/kyma-incubator/compass/components/director/pkg/log" 12 "github.com/pkg/errors" 13 ) 14 15 // LabelRepository missing godoc 16 // 17 //go:generate mockery --name=LabelRepository --output=automock --outpkg=automock --case=underscore --disable-version-string 18 type LabelRepository interface { 19 Create(ctx context.Context, tenant string, label *model.Label) error 20 Upsert(ctx context.Context, tenant string, label *model.Label) error 21 UpsertGlobal(ctx context.Context, label *model.Label) error 22 UpdateWithVersion(ctx context.Context, tenant string, label *model.Label) error 23 GetByKey(ctx context.Context, tenant string, objectType model.LabelableObject, objectID, key string) (*model.Label, error) 24 } 25 26 // LabelDefinitionRepository missing godoc 27 // 28 //go:generate mockery --name=LabelDefinitionRepository --output=automock --outpkg=automock --case=underscore --disable-version-string 29 type LabelDefinitionRepository interface { 30 Create(ctx context.Context, def model.LabelDefinition) error 31 Exists(ctx context.Context, tenant string, key string) (bool, error) 32 GetByKey(ctx context.Context, tenant string, key string) (*model.LabelDefinition, error) 33 } 34 35 // UIDService missing godoc 36 // 37 //go:generate mockery --name=UIDService --output=automock --outpkg=automock --case=underscore --disable-version-string 38 type UIDService interface { 39 Generate() string 40 } 41 42 type labelService struct { 43 labelRepo LabelRepository 44 labelDefinitionRepo LabelDefinitionRepository 45 uidService UIDService 46 } 47 48 // NewLabelService missing godoc 49 func NewLabelService(labelRepo LabelRepository, labelDefinitionRepo LabelDefinitionRepository, uidService UIDService) *labelService { 50 return &labelService{labelRepo: labelRepo, labelDefinitionRepo: labelDefinitionRepo, uidService: uidService} 51 } 52 53 // UpsertMultipleLabels upserts multiple labels for a given tenant and object 54 func (s *labelService) UpsertMultipleLabels(ctx context.Context, tenant string, objectType model.LabelableObject, objectID string, labels map[string]interface{}) error { 55 for key, val := range labels { 56 err := s.UpsertLabel(ctx, tenant, &model.LabelInput{ 57 Key: key, 58 Value: val, 59 ObjectID: objectID, 60 ObjectType: objectType, 61 }) 62 if err != nil { 63 return errors.Wrap(err, "while upserting multiple Labels") 64 } 65 } 66 67 return nil 68 } 69 70 // CreateLabel missing godoc 71 func (s *labelService) CreateLabel(ctx context.Context, tenant, id string, labelInput *model.LabelInput) error { 72 if err := s.validateLabel(ctx, tenant, labelInput); err != nil { 73 return err 74 } 75 label := labelInput.ToLabel(id, tenant) 76 77 if err := s.labelRepo.Create(ctx, tenant, label); err != nil { 78 return errors.Wrapf(err, "while creating Label with id %s for %s with id %s", label.ID, label.ObjectType, label.ObjectID) 79 } 80 log.C(ctx).Debugf("Successfully created Label with id %s for %s with id %s", label.ID, label.ObjectType, label.ObjectID) 81 82 return nil 83 } 84 85 // UpsertLabel missing godoc 86 func (s *labelService) UpsertLabel(ctx context.Context, tenant string, labelInput *model.LabelInput) error { 87 if err := s.validateLabel(ctx, tenant, labelInput); err != nil { 88 return err 89 } 90 91 label := labelInput.ToLabel(s.uidService.Generate(), tenant) 92 93 if err := s.labelRepo.Upsert(ctx, tenant, label); err != nil { 94 return errors.Wrapf(err, "while creating Label with id %s for %s with id %s", label.ID, label.ObjectType, label.ObjectID) 95 } 96 log.C(ctx).Debugf("Successfully created Label with id %s for %s with id %s", label.ID, label.ObjectType, label.ObjectID) 97 98 return nil 99 } 100 101 // UpsertLabelGlobal missing godoc 102 func (s *labelService) UpsertLabelGlobal(ctx context.Context, labelInput *model.LabelInput) error { 103 if err := s.validateLabel(ctx, "", labelInput); err != nil { 104 return err 105 } 106 107 label := labelInput.ToLabel(s.uidService.Generate(), "") 108 109 if err := s.labelRepo.UpsertGlobal(ctx, label); err != nil { 110 return errors.Wrapf(err, "while upserting Label with id %q for %q with id %q", label.ID, label.ObjectType, label.ObjectID) 111 } 112 log.C(ctx).Debugf("Successfully upserted Label with id %q for %q with id %q", label.ID, label.ObjectType, label.ObjectID) 113 114 return nil 115 } 116 117 // UpdateLabel missing godoc 118 func (s *labelService) UpdateLabel(ctx context.Context, tenant, id string, labelInput *model.LabelInput) error { 119 if err := s.validateLabel(ctx, tenant, labelInput); err != nil { 120 return err 121 } 122 label := labelInput.ToLabel(id, tenant) 123 124 if err := s.labelRepo.UpdateWithVersion(ctx, tenant, label); err != nil { 125 return errors.Wrapf(err, "while updating Label with id %s for %s with id %s", label.ID, label.ObjectType, label.ObjectID) 126 } 127 log.C(ctx).Debugf("Successfully updated Label with id %s for %s with id %s", label.ID, label.ObjectType, label.ObjectID) 128 129 return nil 130 } 131 132 // GetLabel missing godoc 133 func (s *labelService) GetLabel(ctx context.Context, tenant string, labelInput *model.LabelInput) (*model.Label, error) { 134 label, err := s.labelRepo.GetByKey(ctx, tenant, labelInput.ObjectType, labelInput.ObjectID, labelInput.Key) 135 if err != nil { 136 return nil, errors.Wrapf(err, "while getting Label with key %s for %s with id %s", labelInput.Key, labelInput.ObjectType, labelInput.ObjectID) 137 } 138 return label, nil 139 } 140 141 // GetByKey returns label for a given tenant, object and key 142 func (s *labelService) GetByKey(ctx context.Context, tenant string, objectType model.LabelableObject, objectID, key string) (*model.Label, error) { 143 return s.labelRepo.GetByKey(ctx, tenant, objectType, objectID, key) 144 } 145 146 func (s *labelService) validateLabel(ctx context.Context, tenant string, labelInput *model.LabelInput) error { 147 // we should validate only scenario labels 148 if labelInput.Key != model.ScenariosKey { 149 return nil 150 } 151 152 labelDef, err := s.labelDefinitionRepo.GetByKey(ctx, tenant, labelInput.Key) 153 if err != nil { 154 return errors.Wrapf(err, "while getting LabelDefinition for key '%s'", labelInput.Key) 155 } 156 157 if err := s.validateLabelInputValue(labelInput, labelDef); err != nil { 158 return errors.Wrapf(err, "while validating Label value for '%s'", labelInput.Key) 159 } 160 return nil 161 } 162 163 func (s *labelService) validateLabelInputValue(labelInput *model.LabelInput, labelDef *model.LabelDefinition) error { 164 if labelDef == nil || labelDef.Schema == nil { 165 // nothing to validate 166 return nil 167 } 168 169 validator, err := jsonschema.NewValidatorFromRawSchema(*labelDef.Schema) 170 if err != nil { 171 return errors.Wrapf(err, "while creating JSON Schema validator for schema %+v", *labelDef.Schema) 172 } 173 174 jsonSchema, err := json.Marshal(*labelDef.Schema) 175 if err != nil { 176 return apperrors.InternalErrorFrom(err, "while marshalling json schema") 177 } 178 179 result, err := validator.ValidateRaw(labelInput.Value) 180 if err != nil { 181 return apperrors.InternalErrorFrom(err, "while validating value=%+v against JSON Schema=%s", labelInput.Value, string(jsonSchema)) 182 } 183 if !result.Valid { 184 return apperrors.NewInvalidDataError(fmt.Sprintf("input value=%+v, key=%s, is not valid against JSON Schema=%s,result=%s", labelInput.Value, labelInput.Key, jsonSchema, result.Error.Error())) 185 } 186 187 return nil 188 }