github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/apptemplate/converter.go (about)

     1  package apptemplate
     2  
     3  import (
     4  	"bytes"
     5  	"database/sql"
     6  	"encoding/json"
     7  	"fmt"
     8  	"strings"
     9  
    10  	"k8s.io/client-go/util/jsonpath"
    11  
    12  	"github.com/kyma-incubator/compass/components/director/internal/model"
    13  	"github.com/kyma-incubator/compass/components/director/internal/repo"
    14  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    15  	"github.com/kyma-incubator/compass/components/director/pkg/graphql"
    16  	"github.com/kyma-incubator/compass/components/director/pkg/graphql/graphqlizer"
    17  
    18  	"github.com/pkg/errors"
    19  )
    20  
    21  // AppConverter missing godoc
    22  //
    23  //go:generate mockery --name=AppConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
    24  type AppConverter interface {
    25  	CreateJSONInputGQLToJSON(in *graphql.ApplicationJSONInput) (string, error)
    26  }
    27  
    28  type converter struct {
    29  	appConverter     AppConverter
    30  	webhookConverter WebhookConverter
    31  }
    32  
    33  // NewConverter missing godoc
    34  func NewConverter(appConverter AppConverter, webhookConverter WebhookConverter) *converter {
    35  	return &converter{appConverter: appConverter, webhookConverter: webhookConverter}
    36  }
    37  
    38  // ToGraphQL missing godoc
    39  func (c *converter) ToGraphQL(in *model.ApplicationTemplate) (*graphql.ApplicationTemplate, error) {
    40  	if in == nil {
    41  		return nil, nil
    42  	}
    43  
    44  	if in.ApplicationInputJSON == "" {
    45  		return nil, apperrors.NewInternalError("application input is empty")
    46  	}
    47  
    48  	gqlAppInput, err := c.graphqliseApplicationCreateInput(in.ApplicationInputJSON)
    49  	if err != nil {
    50  		return nil, errors.Wrapf(err, "while graphqlising application create input")
    51  	}
    52  
    53  	webhooks, err := c.webhooksToGraphql(in.Webhooks)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	return &graphql.ApplicationTemplate{
    59  		ID:                   in.ID,
    60  		Name:                 in.Name,
    61  		Description:          in.Description,
    62  		ApplicationNamespace: in.ApplicationNamespace,
    63  		Webhooks:             webhooks,
    64  		ApplicationInput:     gqlAppInput,
    65  		Placeholders:         c.placeholdersToGraphql(in.Placeholders),
    66  		AccessLevel:          graphql.ApplicationTemplateAccessLevel(in.AccessLevel),
    67  	}, nil
    68  }
    69  
    70  // MultipleToGraphQL missing godoc
    71  func (c *converter) MultipleToGraphQL(in []*model.ApplicationTemplate) ([]*graphql.ApplicationTemplate, error) {
    72  	appTemplates := make([]*graphql.ApplicationTemplate, 0, len(in))
    73  	for _, r := range in {
    74  		if r == nil {
    75  			continue
    76  		}
    77  
    78  		appTemplate, err := c.ToGraphQL(r)
    79  		if err != nil {
    80  			return nil, errors.Wrapf(err, "while converting application template")
    81  		}
    82  		appTemplates = append(appTemplates, appTemplate)
    83  	}
    84  
    85  	return appTemplates, nil
    86  }
    87  
    88  // InputFromGraphQL missing godoc
    89  func (c *converter) InputFromGraphQL(in graphql.ApplicationTemplateInput) (model.ApplicationTemplateInput, error) {
    90  	var appCreateInput string
    91  	var err error
    92  	if in.ApplicationInput != nil {
    93  		appCreateInput, err = c.appConverter.CreateJSONInputGQLToJSON(in.ApplicationInput)
    94  		if err != nil {
    95  			return model.ApplicationTemplateInput{}, errors.Wrapf(err, "error occurred while converting GraphQL input to Application Template model with name %s", in.Name)
    96  		}
    97  	}
    98  	webhooks, err := c.webhookConverter.MultipleInputFromGraphQL(in.Webhooks)
    99  	if err != nil {
   100  		return model.ApplicationTemplateInput{}, errors.Wrapf(err, "error occurred while converting webhooks og GraphQL input to Application Template model with name %s", in.Name)
   101  	}
   102  
   103  	var labels map[string]interface{}
   104  	if in.Labels != nil {
   105  		labels = in.Labels
   106  	}
   107  
   108  	return model.ApplicationTemplateInput{
   109  		Name:                 in.Name,
   110  		Description:          in.Description,
   111  		ApplicationNamespace: in.ApplicationNamespace,
   112  		ApplicationInputJSON: appCreateInput,
   113  		Placeholders:         c.placeholdersFromGraphql(in.Placeholders),
   114  		AccessLevel:          model.ApplicationTemplateAccessLevel(in.AccessLevel),
   115  		Labels:               labels,
   116  		Webhooks:             webhooks,
   117  	}, nil
   118  }
   119  
   120  // UpdateInputFromGraphQL missing godoc
   121  func (c *converter) UpdateInputFromGraphQL(in graphql.ApplicationTemplateUpdateInput) (model.ApplicationTemplateUpdateInput, error) {
   122  	var appCreateInput string
   123  	var err error
   124  	if in.ApplicationInput != nil {
   125  		appCreateInput, err = c.appConverter.CreateJSONInputGQLToJSON(in.ApplicationInput)
   126  		if err != nil {
   127  			return model.ApplicationTemplateUpdateInput{}, errors.Wrapf(err, "error occurred while converting GraphQL update input to Application Template model with name %s", in.Name)
   128  		}
   129  	}
   130  
   131  	webhooks, err := c.webhookConverter.MultipleInputFromGraphQL(in.Webhooks)
   132  	if err != nil {
   133  		return model.ApplicationTemplateUpdateInput{}, errors.Wrapf(err, "error occurred while converting webhooks og GraphQL input to Application Template model with name %s", in.Name)
   134  	}
   135  
   136  	return model.ApplicationTemplateUpdateInput{
   137  		Name:                 in.Name,
   138  		Description:          in.Description,
   139  		ApplicationNamespace: in.ApplicationNamespace,
   140  		ApplicationInputJSON: appCreateInput,
   141  		Placeholders:         c.placeholdersFromGraphql(in.Placeholders),
   142  		AccessLevel:          model.ApplicationTemplateAccessLevel(in.AccessLevel),
   143  		Labels:               in.Labels,
   144  		Webhooks:             webhooks,
   145  	}, nil
   146  }
   147  
   148  // ApplicationFromTemplateInputFromGraphQL missing godoc
   149  func (c *converter) ApplicationFromTemplateInputFromGraphQL(appTemplate *model.ApplicationTemplate, in graphql.ApplicationFromTemplateInput) (model.ApplicationFromTemplateInput, error) {
   150  	values := make([]*model.ApplicationTemplateValueInput, 0, len(in.Values))
   151  	if (in.PlaceholdersPayload != nil) && (len(in.Values) == 0) {
   152  		var obj interface{}
   153  		if err := json.Unmarshal([]byte(*in.PlaceholdersPayload), &obj); err != nil {
   154  			return model.ApplicationFromTemplateInput{}, err
   155  		}
   156  
   157  		parser := jsonpath.New("parser")
   158  
   159  		for _, placeholder := range appTemplate.Placeholders {
   160  			if placeholder.JSONPath != nil && len(*placeholder.JSONPath) > 0 {
   161  				if err := parser.Parse(fmt.Sprintf("{%s}", *placeholder.JSONPath)); err != nil {
   162  					return model.ApplicationFromTemplateInput{}, errors.Wrapf(err, "while parsing placeholder JSON path: %s", *placeholder.JSONPath)
   163  				}
   164  
   165  				buf := new(bytes.Buffer)
   166  				if err := parser.Execute(buf, obj); err != nil {
   167  					return model.ApplicationFromTemplateInput{}, errors.Wrapf(err, "while converting GraphQL input to Application From Template model. Value for Placeholder with name %s and path %s, not found in payload %s.", placeholder.Name, *placeholder.JSONPath, *in.PlaceholdersPayload)
   168  				}
   169  
   170  				valueInput := model.ApplicationTemplateValueInput{
   171  					Placeholder: placeholder.Name,
   172  					Value:       buf.String(),
   173  				}
   174  				values = append(values, &valueInput)
   175  			} else {
   176  				return model.ApplicationFromTemplateInput{}, errors.Errorf("error occurred while converting GraphQL input to Application From Template model. Placeholder with name %s, do not have the JSONPath.", placeholder.Name)
   177  			}
   178  		}
   179  	} else {
   180  		for _, value := range in.Values {
   181  			valueInput := model.ApplicationTemplateValueInput{
   182  				Placeholder: value.Placeholder,
   183  				Value:       value.Value,
   184  			}
   185  			values = append(values, &valueInput)
   186  		}
   187  	}
   188  
   189  	var labels map[string]interface{}
   190  	if in.Labels != nil {
   191  		labels = in.Labels
   192  	}
   193  
   194  	return model.ApplicationFromTemplateInput{
   195  		TemplateName: in.TemplateName,
   196  		Values:       values,
   197  		Labels:       labels,
   198  	}, nil
   199  }
   200  
   201  // ToEntity missing godoc
   202  func (c *converter) ToEntity(in *model.ApplicationTemplate) (*Entity, error) {
   203  	if in == nil {
   204  		return nil, nil
   205  	}
   206  
   207  	placeholders, err := c.placeholdersModelToJSON(in.Placeholders)
   208  	if err != nil {
   209  		return nil, errors.Wrap(err, "while converting placeholders from model to JSON")
   210  	}
   211  
   212  	return &Entity{
   213  		ID:                   in.ID,
   214  		Name:                 in.Name,
   215  		Description:          repo.NewNullableString(in.Description),
   216  		ApplicationNamespace: repo.NewNullableString(in.ApplicationNamespace),
   217  		ApplicationInputJSON: in.ApplicationInputJSON,
   218  		PlaceholdersJSON:     placeholders,
   219  		AccessLevel:          string(in.AccessLevel),
   220  	}, nil
   221  }
   222  
   223  // FromEntity missing godoc
   224  func (c *converter) FromEntity(entity *Entity) (*model.ApplicationTemplate, error) {
   225  	if entity == nil {
   226  		return nil, nil
   227  	}
   228  
   229  	placeholders, err := c.placeholdersJSONToModel(entity.PlaceholdersJSON)
   230  	if err != nil {
   231  		return nil, errors.Wrap(err, "while converting placeholders from JSON to model")
   232  	}
   233  
   234  	return &model.ApplicationTemplate{
   235  		ID:                   entity.ID,
   236  		Name:                 entity.Name,
   237  		Description:          repo.StringPtrFromNullableString(entity.Description),
   238  		ApplicationNamespace: repo.StringPtrFromNullableString(entity.ApplicationNamespace),
   239  		ApplicationInputJSON: entity.ApplicationInputJSON,
   240  		Placeholders:         placeholders,
   241  		AccessLevel:          model.ApplicationTemplateAccessLevel(entity.AccessLevel),
   242  	}, nil
   243  }
   244  
   245  func (c *converter) graphqliseApplicationCreateInput(jsonAppInput string) (string, error) {
   246  	var gqlAppCreateInput graphql.ApplicationRegisterInput
   247  	err := json.Unmarshal([]byte(jsonAppInput), &gqlAppCreateInput)
   248  	if err != nil {
   249  		return "", errors.Wrap(err, "while unmarshaling application create input")
   250  	}
   251  
   252  	g := graphqlizer.Graphqlizer{}
   253  	gqlAppInput, err := g.ApplicationRegisterInputToGQL(gqlAppCreateInput)
   254  	if err != nil {
   255  		return "", errors.Wrap(err, "while graphqlising application create input")
   256  	}
   257  	gqlAppInput = strings.ReplaceAll(gqlAppInput, "\t", "")
   258  	gqlAppInput = strings.ReplaceAll(gqlAppInput, "\n", "")
   259  	return gqlAppInput, nil
   260  }
   261  
   262  func (c *converter) placeholdersJSONToModel(in sql.NullString) ([]model.ApplicationTemplatePlaceholder, error) {
   263  	if !in.Valid || in.String == "" {
   264  		return nil, nil
   265  	}
   266  
   267  	var placeholders []model.ApplicationTemplatePlaceholder
   268  	err := json.Unmarshal([]byte(in.String), &placeholders)
   269  	if err != nil {
   270  		return nil, err
   271  	}
   272  
   273  	return placeholders, nil
   274  }
   275  
   276  func (c *converter) placeholdersModelToJSON(in []model.ApplicationTemplatePlaceholder) (sql.NullString, error) {
   277  	result := sql.NullString{}
   278  
   279  	if in == nil {
   280  		return result, nil
   281  	}
   282  
   283  	placeholdersMarshalled, err := json.Marshal(in)
   284  	if err != nil {
   285  		return result, errors.Wrap(err, "while marshalling placeholders")
   286  	}
   287  
   288  	return repo.NewValidNullableString(string(placeholdersMarshalled)), nil
   289  }
   290  
   291  func (c *converter) placeholdersFromGraphql(in []*graphql.PlaceholderDefinitionInput) []model.ApplicationTemplatePlaceholder {
   292  	placeholders := make([]model.ApplicationTemplatePlaceholder, 0, len(in))
   293  	for _, p := range in {
   294  		np := model.ApplicationTemplatePlaceholder{
   295  			Name:        p.Name,
   296  			Description: p.Description,
   297  			JSONPath:    p.JSONPath,
   298  			Optional:    p.Optional,
   299  		}
   300  		placeholders = append(placeholders, np)
   301  	}
   302  	return placeholders
   303  }
   304  
   305  func (c *converter) placeholdersToGraphql(in []model.ApplicationTemplatePlaceholder) []*graphql.PlaceholderDefinition {
   306  	placeholders := make([]*graphql.PlaceholderDefinition, 0, len(in))
   307  	for _, p := range in {
   308  		np := graphql.PlaceholderDefinition{
   309  			Name:        p.Name,
   310  			Description: p.Description,
   311  			JSONPath:    p.JSONPath,
   312  			Optional:    p.Optional,
   313  		}
   314  		placeholders = append(placeholders, &np)
   315  	}
   316  
   317  	return placeholders
   318  }
   319  
   320  func (c *converter) webhooksToGraphql(in []model.Webhook) ([]graphql.Webhook, error) {
   321  	webhookPtrs := make([]*model.Webhook, len(in))
   322  	for i := 0; i < len(in); i++ {
   323  		webhookPtrs[i] = &in[i]
   324  	}
   325  	gqlWebhookPtrs, err := c.webhookConverter.MultipleToGraphQL(webhookPtrs)
   326  	if err != nil {
   327  		return nil, errors.Wrap(err, "while converting webhooks to graphql")
   328  	}
   329  	gqlWebhooks := make([]graphql.Webhook, len(gqlWebhookPtrs))
   330  	for i := 0; i < len(gqlWebhookPtrs); i++ {
   331  		gqlWebhooks[i] = *gqlWebhookPtrs[i]
   332  	}
   333  	return gqlWebhooks, nil
   334  }