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  }