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

     1  package apptemplate
     2  
     3  import (
     4  	"context"
     5  	"crypto/sha256"
     6  	"encoding/json"
     7  	"fmt"
     8  	"regexp"
     9  	"strings"
    10  
    11  	"github.com/kyma-incubator/compass/components/director/internal/domain/scenarioassignment"
    12  
    13  	"github.com/kyma-incubator/compass/components/director/internal/domain/tenant"
    14  
    15  	"github.com/kyma-incubator/compass/components/director/pkg/consumer"
    16  
    17  	"github.com/kyma-incubator/compass/components/director/internal/labelfilter"
    18  	"github.com/kyma-incubator/compass/components/director/internal/selfregmanager"
    19  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
    20  
    21  	"github.com/kyma-incubator/compass/components/director/pkg/str"
    22  
    23  	"github.com/kyma-incubator/compass/components/director/pkg/inputvalidation"
    24  
    25  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    26  
    27  	"github.com/kyma-incubator/compass/components/director/internal/model"
    28  	"github.com/kyma-incubator/compass/components/director/pkg/graphql"
    29  	"github.com/kyma-incubator/compass/components/director/pkg/persistence"
    30  
    31  	"github.com/kyma-incubator/compass/components/director/pkg/log"
    32  	"github.com/pkg/errors"
    33  )
    34  
    35  const (
    36  	globalSubaccountIDLabelKey = "global_subaccount_id"
    37  	sapProviderName            = "SAP"
    38  	displayNameLabelKey        = "displayName"
    39  )
    40  
    41  // ApplicationTemplateService missing godoc
    42  //
    43  //go:generate mockery --name=ApplicationTemplateService --output=automock --outpkg=automock --case=underscore --disable-version-string
    44  type ApplicationTemplateService interface {
    45  	Create(ctx context.Context, in model.ApplicationTemplateInput) (string, error)
    46  	CreateWithLabels(ctx context.Context, in model.ApplicationTemplateInput, labels map[string]interface{}) (string, error)
    47  	Get(ctx context.Context, id string) (*model.ApplicationTemplate, error)
    48  	GetByFilters(ctx context.Context, filter []*labelfilter.LabelFilter) (*model.ApplicationTemplate, error)
    49  	GetByNameAndRegion(ctx context.Context, name string, region interface{}) (*model.ApplicationTemplate, error)
    50  	List(ctx context.Context, filter []*labelfilter.LabelFilter, pageSize int, cursor string) (model.ApplicationTemplatePage, error)
    51  	ListByName(ctx context.Context, name string) ([]*model.ApplicationTemplate, error)
    52  	ListByFilters(ctx context.Context, filter []*labelfilter.LabelFilter) ([]*model.ApplicationTemplate, error)
    53  	Update(ctx context.Context, id string, in model.ApplicationTemplateUpdateInput) error
    54  	Delete(ctx context.Context, id string) error
    55  	PrepareApplicationCreateInputJSON(appTemplate *model.ApplicationTemplate, values model.ApplicationFromTemplateInputValues) (string, error)
    56  	ListLabels(ctx context.Context, appTemplateID string) (map[string]*model.Label, error)
    57  	GetLabel(ctx context.Context, appTemplateID string, key string) (*model.Label, error)
    58  }
    59  
    60  // ApplicationTemplateConverter missing godoc
    61  //
    62  //go:generate mockery --name=ApplicationTemplateConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
    63  type ApplicationTemplateConverter interface {
    64  	ToGraphQL(in *model.ApplicationTemplate) (*graphql.ApplicationTemplate, error)
    65  	MultipleToGraphQL(in []*model.ApplicationTemplate) ([]*graphql.ApplicationTemplate, error)
    66  	InputFromGraphQL(in graphql.ApplicationTemplateInput) (model.ApplicationTemplateInput, error)
    67  	UpdateInputFromGraphQL(in graphql.ApplicationTemplateUpdateInput) (model.ApplicationTemplateUpdateInput, error)
    68  	ApplicationFromTemplateInputFromGraphQL(appTemplate *model.ApplicationTemplate, in graphql.ApplicationFromTemplateInput) (model.ApplicationFromTemplateInput, error)
    69  }
    70  
    71  // ApplicationConverter missing godoc
    72  //
    73  //go:generate mockery --name=ApplicationConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
    74  type ApplicationConverter interface {
    75  	ToGraphQL(in *model.Application) *graphql.Application
    76  	CreateRegisterInputJSONToGQL(in string) (graphql.ApplicationRegisterInput, error)
    77  	CreateInputFromGraphQL(ctx context.Context, in graphql.ApplicationRegisterInput) (model.ApplicationRegisterInput, error)
    78  }
    79  
    80  // ApplicationService missing godoc
    81  //
    82  //go:generate mockery --name=ApplicationService --output=automock --outpkg=automock --case=underscore --disable-version-string
    83  type ApplicationService interface {
    84  	Create(ctx context.Context, in model.ApplicationRegisterInput) (string, error)
    85  	CreateFromTemplate(ctx context.Context, in model.ApplicationRegisterInput, appTemplateID *string) (string, error)
    86  	Get(ctx context.Context, id string) (*model.Application, error)
    87  }
    88  
    89  // WebhookService missing godoc
    90  //
    91  //go:generate mockery --name=WebhookService --output=automock --outpkg=automock --case=underscore --disable-version-string
    92  type WebhookService interface {
    93  	ListForApplicationTemplate(ctx context.Context, applicationTemplateID string) ([]*model.Webhook, error)
    94  	EnrichWebhooksWithTenantMappingWebhooks(in []*graphql.WebhookInput) ([]*graphql.WebhookInput, error)
    95  }
    96  
    97  // WebhookConverter missing godoc
    98  //
    99  //go:generate mockery --name=WebhookConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
   100  type WebhookConverter interface {
   101  	MultipleToGraphQL(in []*model.Webhook) ([]*graphql.Webhook, error)
   102  	MultipleInputFromGraphQL(in []*graphql.WebhookInput) ([]*model.WebhookInput, error)
   103  }
   104  
   105  // SelfRegisterManager missing godoc
   106  //
   107  //go:generate mockery --name=SelfRegisterManager --output=automock --outpkg=automock --case=underscore --disable-version-string
   108  type SelfRegisterManager interface {
   109  	IsSelfRegistrationFlow(ctx context.Context, labels map[string]interface{}) (bool, error)
   110  	PrepareForSelfRegistration(ctx context.Context, resourceType resource.Type, labels map[string]interface{}, id string, validate func() error) (map[string]interface{}, error)
   111  	CleanupSelfRegistration(ctx context.Context, selfRegisterLabelValue, region string) error
   112  	GetSelfRegDistinguishingLabelKey() string
   113  }
   114  
   115  // Resolver missing godoc
   116  type Resolver struct {
   117  	transact persistence.Transactioner
   118  
   119  	appSvc                  ApplicationService
   120  	appConverter            ApplicationConverter
   121  	appTemplateSvc          ApplicationTemplateService
   122  	appTemplateConverter    ApplicationTemplateConverter
   123  	webhookSvc              WebhookService
   124  	webhookConverter        WebhookConverter
   125  	selfRegManager          SelfRegisterManager
   126  	uidService              UIDService
   127  	appTemplateProductLabel string
   128  }
   129  
   130  // NewResolver missing godoc
   131  func NewResolver(transact persistence.Transactioner, appSvc ApplicationService, appConverter ApplicationConverter, appTemplateSvc ApplicationTemplateService, appTemplateConverter ApplicationTemplateConverter, webhookService WebhookService, webhookConverter WebhookConverter, selfRegisterManager SelfRegisterManager, uidService UIDService, appTemplateProductLabel string) *Resolver {
   132  	return &Resolver{
   133  		transact:                transact,
   134  		appSvc:                  appSvc,
   135  		appConverter:            appConverter,
   136  		appTemplateSvc:          appTemplateSvc,
   137  		appTemplateConverter:    appTemplateConverter,
   138  		webhookSvc:              webhookService,
   139  		webhookConverter:        webhookConverter,
   140  		selfRegManager:          selfRegisterManager,
   141  		uidService:              uidService,
   142  		appTemplateProductLabel: appTemplateProductLabel,
   143  	}
   144  }
   145  
   146  // ApplicationTemplate missing godoc
   147  func (r *Resolver) ApplicationTemplate(ctx context.Context, id string) (*graphql.ApplicationTemplate, error) {
   148  	tx, err := r.transact.Begin()
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   153  
   154  	ctx = persistence.SaveToContext(ctx, tx)
   155  
   156  	appTemplate, err := r.appTemplateSvc.Get(ctx, id)
   157  	if err != nil {
   158  		if apperrors.IsNotFoundError(err) {
   159  			return nil, tx.Commit()
   160  		}
   161  		return nil, err
   162  	}
   163  
   164  	err = tx.Commit()
   165  	if err != nil {
   166  		return nil, err
   167  	}
   168  
   169  	out, err := r.appTemplateConverter.ToGraphQL(appTemplate)
   170  	if err != nil {
   171  		return nil, errors.Wrapf(err, "while converting application template to graphql")
   172  	}
   173  
   174  	return out, nil
   175  }
   176  
   177  // ApplicationTemplates missing godoc
   178  func (r *Resolver) ApplicationTemplates(ctx context.Context, filter []*graphql.LabelFilter, first *int, after *graphql.PageCursor) (*graphql.ApplicationTemplatePage, error) {
   179  	labelFilter := labelfilter.MultipleFromGraphQL(filter)
   180  	var cursor string
   181  	if after != nil {
   182  		cursor = string(*after)
   183  	}
   184  	if first == nil {
   185  		return nil, apperrors.NewInvalidDataError("missing required parameter 'first'")
   186  	}
   187  
   188  	tx, err := r.transact.Begin()
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   193  
   194  	ctx = persistence.SaveToContext(ctx, tx)
   195  
   196  	appTemplatePage, err := r.appTemplateSvc.List(ctx, labelFilter, *first, cursor)
   197  	if err != nil {
   198  		return nil, err
   199  	}
   200  
   201  	err = tx.Commit()
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  
   206  	gqlAppTemplate, err := r.appTemplateConverter.MultipleToGraphQL(appTemplatePage.Data)
   207  	if err != nil {
   208  		return nil, errors.Wrapf(err, "while converting application templates to graphql")
   209  	}
   210  
   211  	return &graphql.ApplicationTemplatePage{
   212  		Data:       gqlAppTemplate,
   213  		TotalCount: appTemplatePage.TotalCount,
   214  		PageInfo: &graphql.PageInfo{
   215  			StartCursor: graphql.PageCursor(appTemplatePage.PageInfo.StartCursor),
   216  			EndCursor:   graphql.PageCursor(appTemplatePage.PageInfo.EndCursor),
   217  			HasNextPage: appTemplatePage.PageInfo.HasNextPage,
   218  		},
   219  	}, nil
   220  }
   221  
   222  // CreateApplicationTemplate missing godoc
   223  func (r *Resolver) CreateApplicationTemplate(ctx context.Context, in graphql.ApplicationTemplateInput) (*graphql.ApplicationTemplate, error) {
   224  	if err := in.Validate(); err != nil {
   225  		return nil, err
   226  	}
   227  
   228  	if err := validateAppTemplateNameBasedOnProvider(in.Name, in.ApplicationInput); err != nil {
   229  		return nil, err
   230  	}
   231  
   232  	webhooks, err := r.webhookSvc.EnrichWebhooksWithTenantMappingWebhooks(in.Webhooks)
   233  	if err != nil {
   234  		return nil, err
   235  	}
   236  
   237  	if in.Webhooks != nil {
   238  		in.Webhooks = webhooks
   239  	}
   240  	convertedIn, err := r.appTemplateConverter.InputFromGraphQL(in)
   241  
   242  	if err != nil {
   243  		return nil, err
   244  	}
   245  
   246  	if convertedIn.Labels == nil {
   247  		convertedIn.Labels = make(map[string]interface{})
   248  	}
   249  
   250  	selfRegID := r.uidService.Generate()
   251  	convertedIn.ID = &selfRegID
   252  
   253  	consumerInfo, err := consumer.LoadFromContext(ctx)
   254  	if err != nil {
   255  		return nil, errors.Wrapf(err, "while loading consumer")
   256  	}
   257  
   258  	labels := convertedIn.Labels
   259  	if _, err := tenant.LoadFromContext(ctx); err == nil && consumerInfo.Flow.IsCertFlow() {
   260  		isSelfReg, selfRegFlowErr := r.isSelfRegFlow(labels)
   261  		if selfRegFlowErr != nil {
   262  			return nil, selfRegFlowErr
   263  		}
   264  
   265  		if isSelfReg {
   266  			validate := func() error {
   267  				return validateAppTemplateForSelfReg(in.ApplicationInput)
   268  			}
   269  			labels, err = r.selfRegManager.PrepareForSelfRegistration(ctx, resource.ApplicationTemplate, convertedIn.Labels, selfRegID, validate)
   270  			if err != nil {
   271  				return nil, err
   272  			}
   273  		}
   274  
   275  		labels[scenarioassignment.SubaccountIDKey] = consumerInfo.ConsumerID
   276  	}
   277  
   278  	tx, err := r.transact.Begin()
   279  	if err != nil {
   280  		return nil, err
   281  	}
   282  
   283  	defer func() {
   284  		didRollback := r.transact.RollbackUnlessCommitted(ctx, tx)
   285  		if didRollback {
   286  			labelVal := str.CastOrEmpty(convertedIn.Labels[r.selfRegManager.GetSelfRegDistinguishingLabelKey()])
   287  			if labelVal != "" {
   288  				label, ok := labels[selfregmanager.RegionLabel].(string)
   289  				if !ok {
   290  					log.C(ctx).Errorf("An error occurred while casting region label value to string")
   291  				} else {
   292  					r.cleanupAndLogOnError(ctx, selfRegID, label)
   293  				}
   294  			}
   295  		}
   296  	}()
   297  
   298  	ctx = persistence.SaveToContext(ctx, tx)
   299  
   300  	if err := r.checkProviderAppTemplateExistence(ctx, labels); err != nil {
   301  		return nil, err
   302  	}
   303  
   304  	log.C(ctx).Infof("Creating an Application Template with name %s", convertedIn.Name)
   305  	id, err := r.appTemplateSvc.CreateWithLabels(ctx, convertedIn, labels)
   306  	if err != nil {
   307  		return nil, err
   308  	}
   309  	log.C(ctx).Infof("Successfully created an Application Template with name %s and id %s", convertedIn.Name, id)
   310  
   311  	appTemplate, err := r.appTemplateSvc.Get(ctx, id)
   312  	if err != nil {
   313  		return nil, err
   314  	}
   315  
   316  	err = tx.Commit()
   317  	if err != nil {
   318  		return nil, err
   319  	}
   320  
   321  	gqlAppTemplate, err := r.appTemplateConverter.ToGraphQL(appTemplate)
   322  	if err != nil {
   323  		return nil, errors.Wrapf(err, "while converting Application Template with id %s to GraphQL", id)
   324  	}
   325  
   326  	return gqlAppTemplate, nil
   327  }
   328  
   329  // Labels retrieve all labels for application template
   330  func (r *Resolver) Labels(ctx context.Context, obj *graphql.ApplicationTemplate, key *string) (graphql.Labels, error) {
   331  	if obj == nil {
   332  		return nil, apperrors.NewInternalError("Application Template cannot be empty")
   333  	}
   334  
   335  	tx, err := r.transact.Begin()
   336  	if err != nil {
   337  		return nil, err
   338  	}
   339  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   340  
   341  	ctx = persistence.SaveToContext(ctx, tx)
   342  
   343  	itemMap, err := r.appTemplateSvc.ListLabels(ctx, obj.ID)
   344  	if err != nil {
   345  		if strings.Contains(err.Error(), "doesn't exist") {
   346  			return nil, tx.Commit()
   347  		}
   348  		return nil, err
   349  	}
   350  
   351  	err = tx.Commit()
   352  	if err != nil {
   353  		return nil, err
   354  	}
   355  
   356  	resultLabels := make(map[string]interface{})
   357  
   358  	for _, label := range itemMap {
   359  		if key == nil || label.Key == *key {
   360  			resultLabels[label.Key] = label.Value
   361  		}
   362  	}
   363  
   364  	var gqlLabels graphql.Labels = resultLabels
   365  	return gqlLabels, nil
   366  }
   367  
   368  // RegisterApplicationFromTemplate registers an Application using Application Template
   369  func (r *Resolver) RegisterApplicationFromTemplate(ctx context.Context, in graphql.ApplicationFromTemplateInput) (*graphql.Application, error) {
   370  	consumerInfo, err := consumer.LoadFromContext(ctx)
   371  	if err != nil {
   372  		return nil, errors.Wrapf(err, "while fetching consumer info from context")
   373  	}
   374  
   375  	tx, err := r.transact.Begin()
   376  	if err != nil {
   377  		return nil, err
   378  	}
   379  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   380  
   381  	ctx = persistence.SaveToContext(ctx, tx)
   382  
   383  	log.C(ctx).Debugf("Extracting Application Template with name %q and consumer id REDACTED_%x from GraphQL input", in.TemplateName, sha256.Sum256([]byte(consumerInfo.ConsumerID)))
   384  	appTemplate, err := r.retrieveAppTemplate(ctx, in.TemplateName, consumerInfo.ConsumerID, in.ID)
   385  	if err != nil {
   386  		return nil, err
   387  	}
   388  
   389  	log.C(ctx).Infof("Registering an Application from Application Template with name %s", in.TemplateName)
   390  	convertedIn, err := r.appTemplateConverter.ApplicationFromTemplateInputFromGraphQL(appTemplate, in)
   391  	if err != nil {
   392  		return nil, err
   393  	}
   394  
   395  	log.C(ctx).Debugf("Preparing ApplicationCreateInput JSON from Application Template with name %s", in.TemplateName)
   396  	appCreateInputJSON, err := r.appTemplateSvc.PrepareApplicationCreateInputJSON(appTemplate, convertedIn.Values)
   397  	if err != nil {
   398  		return nil, errors.Wrapf(err, "while preparing ApplicationCreateInput JSON from Application Template with name %s", in.TemplateName)
   399  	}
   400  
   401  	log.C(ctx).Debugf("Converting ApplicationCreateInput JSON to GraphQL ApplicationRegistrationInput from Application Template with name %s", in.TemplateName)
   402  	appCreateInputGQL, err := r.appConverter.CreateRegisterInputJSONToGQL(appCreateInputJSON)
   403  	if err != nil {
   404  		return nil, errors.Wrapf(err, "while converting ApplicationCreateInput JSON to GraphQL ApplicationRegistrationInput from Application Template with name %s", in.TemplateName)
   405  	}
   406  
   407  	log.C(ctx).Infof("Validating GraphQL ApplicationRegistrationInput from Application Template with name %s", convertedIn.TemplateName)
   408  	if err := inputvalidation.Validate(appCreateInputGQL); err != nil {
   409  		return nil, errors.Wrapf(err, "while validating application input from Application Template with name %s", convertedIn.TemplateName)
   410  	}
   411  
   412  	appCreateInputModel, err := r.appConverter.CreateInputFromGraphQL(ctx, appCreateInputGQL)
   413  	if err != nil {
   414  		return nil, errors.Wrap(err, "while converting ApplicationFromTemplate input")
   415  	}
   416  
   417  	if appCreateInputModel.Labels == nil {
   418  		appCreateInputModel.Labels = make(map[string]interface{})
   419  	}
   420  	appCreateInputModel.Labels["managed"] = "false"
   421  
   422  	if convertedIn.Labels != nil {
   423  		for k, v := range in.Labels {
   424  			appCreateInputModel.Labels[k] = v
   425  		}
   426  	}
   427  
   428  	applicationName, err := extractApplicationNameFromTemplateInput(appCreateInputJSON)
   429  	if err != nil {
   430  		return nil, err
   431  	}
   432  	log.C(ctx).Infof("Creating an Application with name %s from Application Template with name %s", applicationName, in.TemplateName)
   433  	id, err := r.appSvc.CreateFromTemplate(ctx, appCreateInputModel, &appTemplate.ID)
   434  	if err != nil {
   435  		return nil, errors.Wrapf(err, "while creating an Application with name %s from Application Template with name %s", applicationName, in.TemplateName)
   436  	}
   437  	log.C(ctx).Infof("Application with name %s and id %s successfully created from Application Template with name %s", applicationName, id, in.TemplateName)
   438  
   439  	app, err := r.appSvc.Get(ctx, id)
   440  	if err != nil {
   441  		return nil, err
   442  	}
   443  
   444  	err = tx.Commit()
   445  	if err != nil {
   446  		return nil, err
   447  	}
   448  
   449  	gqlApp := r.appConverter.ToGraphQL(app)
   450  	return gqlApp, nil
   451  }
   452  
   453  // UpdateApplicationTemplate missing godoc
   454  func (r *Resolver) UpdateApplicationTemplate(ctx context.Context, id string, in graphql.ApplicationTemplateUpdateInput) (*graphql.ApplicationTemplate, error) {
   455  	tx, err := r.transact.Begin()
   456  	if err != nil {
   457  		return nil, err
   458  	}
   459  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   460  
   461  	ctx = persistence.SaveToContext(ctx, tx)
   462  
   463  	if err := in.Validate(); err != nil {
   464  		return nil, err
   465  	}
   466  
   467  	if err := validateAppTemplateNameBasedOnProvider(in.Name, in.ApplicationInput); err != nil {
   468  		return nil, err
   469  	}
   470  
   471  	webhooks, err := r.webhookSvc.EnrichWebhooksWithTenantMappingWebhooks(in.Webhooks)
   472  	if err != nil {
   473  		return nil, err
   474  	}
   475  
   476  	if in.Webhooks != nil {
   477  		in.Webhooks = webhooks
   478  	}
   479  
   480  	convertedIn, err := r.appTemplateConverter.UpdateInputFromGraphQL(in)
   481  	if err != nil {
   482  		return nil, err
   483  	}
   484  
   485  	labels, err := r.appTemplateSvc.ListLabels(ctx, id)
   486  	if err != nil {
   487  		return nil, err
   488  	}
   489  
   490  	resultLabels := make(map[string]interface{}, len(labels))
   491  	for _, label := range labels {
   492  		resultLabels[label.Key] = label.Value
   493  	}
   494  
   495  	isSelfRegFlow, err := r.selfRegManager.IsSelfRegistrationFlow(ctx, resultLabels)
   496  	if err != nil {
   497  		return nil, err
   498  	}
   499  	if isSelfRegFlow {
   500  		if err := validateAppTemplateForSelfReg(in.ApplicationInput); err != nil {
   501  			return nil, err
   502  		}
   503  	}
   504  
   505  	log.C(ctx).Infof("Updating an Application Template with id %q", id)
   506  	err = r.appTemplateSvc.Update(ctx, id, convertedIn)
   507  	if err != nil {
   508  		return nil, err
   509  	}
   510  
   511  	appTemplate, err := r.appTemplateSvc.Get(ctx, id)
   512  	if err != nil {
   513  		return nil, err
   514  	}
   515  
   516  	err = tx.Commit()
   517  	if err != nil {
   518  		return nil, err
   519  	}
   520  
   521  	gqlAppTemplate, err := r.appTemplateConverter.ToGraphQL(appTemplate)
   522  	if err != nil {
   523  		return nil, errors.Wrapf(err, "while converting application template to graphql")
   524  	}
   525  
   526  	return gqlAppTemplate, nil
   527  }
   528  
   529  // DeleteApplicationTemplate missing godoc
   530  func (r *Resolver) DeleteApplicationTemplate(ctx context.Context, id string) (*graphql.ApplicationTemplate, error) {
   531  	tx, err := r.transact.Begin()
   532  	if err != nil {
   533  		return nil, err
   534  	}
   535  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   536  
   537  	ctx = persistence.SaveToContext(ctx, tx)
   538  
   539  	appTemplate, err := r.appTemplateSvc.Get(ctx, id)
   540  	if err != nil {
   541  		return nil, err
   542  	}
   543  
   544  	_, err = r.appTemplateSvc.GetLabel(ctx, id, r.selfRegManager.GetSelfRegDistinguishingLabelKey())
   545  	if err != nil {
   546  		if !apperrors.IsNotFoundError(err) {
   547  			return nil, errors.Wrapf(err, "while getting self register label")
   548  		}
   549  	} else {
   550  		regionLabel, err := r.appTemplateSvc.GetLabel(ctx, id, selfregmanager.RegionLabel)
   551  		if err != nil {
   552  			return nil, errors.Wrapf(err, "while getting region label")
   553  		}
   554  
   555  		// Committing transaction as the cleanup sends request to external service
   556  		if err = tx.Commit(); err != nil {
   557  			return nil, err
   558  		}
   559  
   560  		regionValue, ok := regionLabel.Value.(string)
   561  		if !ok {
   562  			return nil, errors.Wrap(err, "while casting region label value to string")
   563  		}
   564  
   565  		log.C(ctx).Infof("Executing clean-up for self-registered app template with id %q", id)
   566  		if err := r.selfRegManager.CleanupSelfRegistration(ctx, id, regionValue); err != nil {
   567  			return nil, errors.Wrap(err, "An error occurred during cleanup of self-registered app template: ")
   568  		}
   569  
   570  		tx, err = r.transact.Begin()
   571  		if err != nil {
   572  			return nil, err
   573  		}
   574  		ctx = persistence.SaveToContext(ctx, tx)
   575  	}
   576  
   577  	log.C(ctx).Infof("Deleting an Application Template with id %q", id)
   578  	err = r.appTemplateSvc.Delete(ctx, id)
   579  	if err != nil {
   580  		return nil, err
   581  	}
   582  
   583  	err = tx.Commit()
   584  	if err != nil {
   585  		return nil, err
   586  	}
   587  
   588  	deletedAppTemplate, err := r.appTemplateConverter.ToGraphQL(appTemplate)
   589  	if err != nil {
   590  		return nil, errors.Wrapf(err, "while converting application template to graphql")
   591  	}
   592  
   593  	return deletedAppTemplate, nil
   594  }
   595  
   596  // Webhooks missing godoc
   597  func (r *Resolver) Webhooks(ctx context.Context, obj *graphql.ApplicationTemplate) ([]*graphql.Webhook, error) {
   598  	tx, err := r.transact.Begin()
   599  	if err != nil {
   600  		return nil, err
   601  	}
   602  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   603  
   604  	ctx = persistence.SaveToContext(ctx, tx)
   605  
   606  	webhooks, err := r.webhookSvc.ListForApplicationTemplate(ctx, obj.ID)
   607  	if err != nil {
   608  		return nil, err
   609  	}
   610  
   611  	if err := tx.Commit(); err != nil {
   612  		return nil, err
   613  	}
   614  
   615  	return r.webhookConverter.MultipleToGraphQL(webhooks)
   616  }
   617  
   618  func extractApplicationNameFromTemplateInput(applicationInputJSON string) (string, error) {
   619  	b := []byte(applicationInputJSON)
   620  	data := make(map[string]interface{})
   621  
   622  	err := json.Unmarshal(b, &data)
   623  	if err != nil {
   624  		return "", errors.Wrap(err, "while unmarshalling application input JSON")
   625  	}
   626  
   627  	return data["name"].(string), nil
   628  }
   629  
   630  func (r *Resolver) cleanupAndLogOnError(ctx context.Context, id, region string) {
   631  	if err := r.selfRegManager.CleanupSelfRegistration(ctx, id, region); err != nil {
   632  		log.C(ctx).Errorf("An error occurred during cleanup of self-registered app template: %v", err)
   633  	}
   634  }
   635  
   636  func (r *Resolver) retrieveAppTemplate(ctx context.Context,
   637  	appTemplateName, consumerID string, appTemplateID *string) (*model.ApplicationTemplate, error) {
   638  	filters := []*labelfilter.LabelFilter{
   639  		labelfilter.NewForKeyWithQuery(globalSubaccountIDLabelKey, fmt.Sprintf("\"%s\"", consumerID)),
   640  	}
   641  	appTemplates, err := r.appTemplateSvc.ListByFilters(ctx, filters)
   642  	if err != nil {
   643  		return nil, err
   644  	}
   645  
   646  	for _, appTemplate := range appTemplates {
   647  		if (appTemplateID == nil && appTemplate.Name == appTemplateName) ||
   648  			(appTemplateID != nil && *appTemplateID == appTemplate.ID) {
   649  			return appTemplate, nil
   650  		}
   651  	}
   652  
   653  	appTemplates, err = r.appTemplateSvc.ListByName(ctx, appTemplateName)
   654  	if err != nil {
   655  		return nil, err
   656  	}
   657  	templates := make([]*model.ApplicationTemplate, 0, len(appTemplates))
   658  	for _, appTemplate := range appTemplates {
   659  		_, err := r.appTemplateSvc.GetLabel(ctx, appTemplate.ID, globalSubaccountIDLabelKey)
   660  		if err != nil && !apperrors.IsNotFoundError(err) {
   661  			return nil, errors.Wrapf(err, "while getting %q label", globalSubaccountIDLabelKey)
   662  		}
   663  		if err != nil && apperrors.IsNotFoundError(err) {
   664  			templates = append(templates, appTemplate)
   665  		}
   666  	}
   667  
   668  	if appTemplateID != nil {
   669  		log.C(ctx).Infof("searching for application template with ID: %s", *appTemplateID)
   670  		for _, appTemplate := range appTemplates {
   671  			if appTemplate.ID == *appTemplateID {
   672  				log.C(ctx).Infof("found application template with ID: %s", *appTemplateID)
   673  				return appTemplate, nil
   674  			}
   675  		}
   676  		return nil, errors.Errorf("application template with id %s and consumer id %q not found", *appTemplateID, consumerID)
   677  	}
   678  	if len(templates) < 1 {
   679  		return nil, errors.Errorf("application template with name %q and consumer id %q not found", appTemplateName, consumerID)
   680  	}
   681  	if len(templates) > 1 {
   682  		return nil, errors.Errorf("unexpected number of application templates. found %d", len(appTemplates))
   683  	}
   684  	return templates[0], nil
   685  }
   686  
   687  func validateAppTemplateForSelfReg(applicationInput *graphql.ApplicationJSONInput) error {
   688  	appNameExists := applicationInput.Name != ""
   689  	var appDisplayNameLabelExists bool
   690  
   691  	if displayName, ok := applicationInput.Labels[displayNameLabelKey]; ok {
   692  		displayNameValue, ok := displayName.(string)
   693  		if !ok {
   694  			return fmt.Errorf("%q label value must be string", displayNameLabelKey)
   695  		}
   696  		appDisplayNameLabelExists = displayNameValue != ""
   697  	}
   698  
   699  	if !appNameExists || !appDisplayNameLabelExists {
   700  		return errors.Errorf("applicationInputJSON name property or applicationInputJSON displayName label is missing. They must be present in order to proceed.")
   701  	}
   702  
   703  	return nil
   704  }
   705  
   706  func validateAppTemplateNameBasedOnProvider(name string, appInput *graphql.ApplicationJSONInput) error {
   707  	if appInput == nil || appInput.ProviderName == nil || str.PtrStrToStr(appInput.ProviderName) != sapProviderName {
   708  		return nil
   709  	}
   710  
   711  	// Matches the following pattern - "SAP <product name>"
   712  	r := regexp.MustCompile(`(^SAP\s)([A-Za-z0-9()_\- ]*)`)
   713  	matches := r.FindStringSubmatch(name)
   714  	if len(matches) == 0 {
   715  		return errors.Errorf("application template name %q does not comply with the following naming convention: %q", name, "SAP <product name>")
   716  	}
   717  
   718  	return nil
   719  }
   720  
   721  func (r *Resolver) checkProviderAppTemplateExistence(ctx context.Context, labels map[string]interface{}) error {
   722  	selfRegisterDistinguishLabelKey := r.selfRegManager.GetSelfRegDistinguishingLabelKey()
   723  	regionLabelKey := selfregmanager.RegionLabel
   724  	region, regionExists := labels[regionLabelKey]
   725  
   726  	distinguishLabelKeys := []string{selfRegisterDistinguishLabelKey, r.appTemplateProductLabel}
   727  	appTemplateDistinguishLabels := make(map[string]interface{}, len(distinguishLabelKeys))
   728  
   729  	for _, key := range distinguishLabelKeys {
   730  		if value, exists := labels[key]; exists {
   731  			appTemplateDistinguishLabels[key] = value
   732  		}
   733  	}
   734  
   735  	for labelKey, labelValue := range appTemplateDistinguishLabels {
   736  		msg := fmt.Sprintf("%q: %q", labelKey, labelValue)
   737  
   738  		filters := []*labelfilter.LabelFilter{
   739  			labelfilter.NewForKeyWithQuery(labelKey, fmt.Sprintf("\"%s\"", labelValue)),
   740  		}
   741  
   742  		if regionExists {
   743  			if _, ok := region.(string); !ok {
   744  				return errors.Errorf("%s label should be string", regionLabelKey)
   745  			}
   746  			filters = append(filters, labelfilter.NewForKeyWithQuery(regionLabelKey, fmt.Sprintf("\"%s\"", region)))
   747  			msg += fmt.Sprintf(" and %q: %q", regionLabelKey, region)
   748  		}
   749  
   750  		log.C(ctx).Infof("Getting application template for labels %s", msg)
   751  		appTemplate, err := r.appTemplateSvc.GetByFilters(ctx, filters)
   752  		if err != nil && !apperrors.IsNotFoundError(err) {
   753  			return errors.Wrap(err, fmt.Sprintf("Failed to get application template for labels %s", msg))
   754  		}
   755  
   756  		if appTemplate != nil {
   757  			errMsg := fmt.Sprintf("Cannot have more than one application template with labels %s", msg)
   758  			log.C(ctx).Error(errMsg)
   759  			return errors.New(errMsg)
   760  		}
   761  	}
   762  	return nil
   763  }
   764  
   765  func (r *Resolver) isSelfRegFlow(labels map[string]interface{}) (bool, error) {
   766  	selfRegLabelKey := r.selfRegManager.GetSelfRegDistinguishingLabelKey()
   767  	_, distinguishLabelExists := labels[selfRegLabelKey]
   768  	_, productLabelExists := labels[r.appTemplateProductLabel]
   769  	if !distinguishLabelExists && !productLabelExists {
   770  		return false, errors.Errorf("missing %q or %q label", selfRegLabelKey, r.appTemplateProductLabel)
   771  	}
   772  
   773  	if distinguishLabelExists && productLabelExists {
   774  		return false, errors.Errorf("should provide either %q or %q label - providing both at the same time is not allowed", selfRegLabelKey, r.appTemplateProductLabel)
   775  	}
   776  
   777  	if distinguishLabelExists {
   778  		return true, nil
   779  	}
   780  
   781  	return false, nil
   782  }