github.com/akamai/AkamaiOPEN-edgegrid-golang/v2@v2.17.0/pkg/papi/propertyversion.go (about)

     1  package papi
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"net/http"
     8  	"strconv"
     9  
    10  	"github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/edgegriderr"
    11  	validation "github.com/go-ozzo/ozzo-validation/v4"
    12  )
    13  
    14  type (
    15  	// PropertyVersions contains operations available on PropertyVersions resource
    16  	// See: https://developer.akamai.com/api/core_features/property_manager/v1.html#propertyversionsgroup
    17  	PropertyVersions interface {
    18  		// GetPropertyVersions fetches available property versions
    19  		// See: https://developer.akamai.com/api/core_features/property_manager/v1.html#getpropertyversions
    20  		GetPropertyVersions(context.Context, GetPropertyVersionsRequest) (*GetPropertyVersionsResponse, error)
    21  
    22  		// GetPropertyVersion fetches specific property version
    23  		// See: https://developer.akamai.com/api/core_features/property_manager/v1.html#getpropertyversion
    24  		GetPropertyVersion(context.Context, GetPropertyVersionRequest) (*GetPropertyVersionsResponse, error)
    25  
    26  		// CreatePropertyVersion creates a new property version
    27  		// See: https://developer.akamai.com/api/core_features/property_manager/v1.html#postpropertyversions
    28  		CreatePropertyVersion(context.Context, CreatePropertyVersionRequest) (*CreatePropertyVersionResponse, error)
    29  
    30  		// GetLatestVersion fetches latest property version
    31  		// See: https://developer.akamai.com/api/core_features/property_manager/v1.html#getlatestversion
    32  		GetLatestVersion(context.Context, GetLatestVersionRequest) (*GetPropertyVersionsResponse, error)
    33  
    34  		// GetAvailableBehaviors fetches a list of behaviors applied to property version
    35  		// See: https://developer.akamai.com/api/core_features/property_manager/v1.html#getavailablebehaviors
    36  		GetAvailableBehaviors(context.Context, GetFeaturesRequest) (*GetFeaturesCriteriaResponse, error)
    37  
    38  		// GetAvailableCriteria fetches a list of criteria applied to property version
    39  		// See: https://developer.akamai.com/api/core_features/property_manager/v1.html#getavailablecriteria
    40  		GetAvailableCriteria(context.Context, GetFeaturesRequest) (*GetFeaturesCriteriaResponse, error)
    41  	}
    42  
    43  	// GetPropertyVersionsRequest contains path and query params used for listing property versions
    44  	GetPropertyVersionsRequest struct {
    45  		PropertyID string
    46  		ContractID string
    47  		GroupID    string
    48  		Limit      int
    49  		Offset     int
    50  	}
    51  
    52  	// GetPropertyVersionsResponse contains GET response returned while fetching property versions or specific version
    53  	GetPropertyVersionsResponse struct {
    54  		PropertyID   string               `json:"propertyId"`
    55  		PropertyName string               `json:"propertyName"`
    56  		AccountID    string               `json:"accountId"`
    57  		ContractID   string               `json:"contractId"`
    58  		GroupID      string               `json:"groupId"`
    59  		AssetID      string               `json:"assetId"`
    60  		Versions     PropertyVersionItems `json:"versions"`
    61  		Version      PropertyVersionGetItem
    62  	}
    63  
    64  	// PropertyVersionItems contains collection of property version details
    65  	PropertyVersionItems struct {
    66  		Items []PropertyVersionGetItem `json:"items"`
    67  	}
    68  
    69  	// PropertyVersionGetItem contains detailed information about specific property version returned in GET
    70  	PropertyVersionGetItem struct {
    71  		Etag             string        `json:"etag"`
    72  		Note             string        `json:"note"`
    73  		ProductID        string        `json:"productId"`
    74  		ProductionStatus VersionStatus `json:"productionStatus"`
    75  		PropertyVersion  int           `json:"propertyVersion"`
    76  		RuleFormat       string        `json:"ruleFormat"`
    77  		StagingStatus    VersionStatus `json:"stagingStatus"`
    78  		UpdatedByUser    string        `json:"updatedByUser"`
    79  		UpdatedDate      string        `json:"updatedDate"`
    80  	}
    81  
    82  	// GetPropertyVersionRequest contains path and query params used for fetching specific property version
    83  	GetPropertyVersionRequest struct {
    84  		PropertyID      string
    85  		PropertyVersion int
    86  		ContractID      string
    87  		GroupID         string
    88  	}
    89  
    90  	// CreatePropertyVersionRequest contains path and query params, as well as request body required to execute POST /versions request
    91  	CreatePropertyVersionRequest struct {
    92  		PropertyID string
    93  		ContractID string
    94  		GroupID    string
    95  		Version    PropertyVersionCreate
    96  	}
    97  
    98  	// PropertyVersionCreate contains request body used in POST /versions request
    99  	PropertyVersionCreate struct {
   100  		CreateFromVersion     int    `json:"createFromVersion"`
   101  		CreateFromVersionEtag string `json:"createFromVersionEtag,omitempty"`
   102  	}
   103  
   104  	// CreatePropertyVersionResponse contains a link returned after creating new property version and version number of this version
   105  	CreatePropertyVersionResponse struct {
   106  		VersionLink     string `json:"versionLink"`
   107  		PropertyVersion int
   108  	}
   109  
   110  	// GetLatestVersionRequest contains path and query params required to fetch latest property version
   111  	GetLatestVersionRequest struct {
   112  		PropertyID  string
   113  		ActivatedOn string
   114  		ContractID  string
   115  		GroupID     string
   116  	}
   117  
   118  	// GetFeaturesRequest contains path and query params required to fetch both available behaviors and available criteria for a property
   119  	GetFeaturesRequest struct {
   120  		PropertyID      string
   121  		PropertyVersion int
   122  		ContractID      string
   123  		GroupID         string
   124  	}
   125  
   126  	// AvailableFeature represents details of a single feature (behavior or criteria available for selected property version
   127  	AvailableFeature struct {
   128  		Name       string `json:"name"`
   129  		SchemaLink string `json:"schemaLink"`
   130  	}
   131  
   132  	// GetFeaturesCriteriaResponse contains response received when fetching both available behaviors and available criteria for a property
   133  	GetFeaturesCriteriaResponse struct {
   134  		ContractID         string                `json:"contractId"`
   135  		GroupID            string                `json:"groupId"`
   136  		ProductID          string                `json:"productId"`
   137  		RuleFormat         string                `json:"ruleFormat"`
   138  		AvailableBehaviors AvailableFeatureItems `json:"availableBehaviors"`
   139  	}
   140  
   141  	// AvailableFeatureItems contains a slice of AvailableFeature items
   142  	AvailableFeatureItems struct {
   143  		Items []AvailableFeature `json:"items"`
   144  	}
   145  
   146  	// VersionStatus represents ProductionVersion and StagingVersion of a Version struct
   147  	VersionStatus string
   148  )
   149  
   150  const (
   151  	// VersionStatusActive const
   152  	VersionStatusActive VersionStatus = "ACTIVE"
   153  	// VersionStatusInactive const
   154  	VersionStatusInactive VersionStatus = "INACTIVE"
   155  	// VersionStatusPending const
   156  	VersionStatusPending VersionStatus = "PENDING"
   157  	// VersionStatusDeactivated const
   158  	VersionStatusDeactivated VersionStatus = "DEACTIVATED"
   159  	// VersionProduction const
   160  	VersionProduction = "PRODUCTION"
   161  	// VersionStaging const
   162  	VersionStaging = "STAGING"
   163  )
   164  
   165  // Validate validates GetPropertyVersionsRequest
   166  func (v GetPropertyVersionsRequest) Validate() error {
   167  	return validation.Errors{
   168  		"PropertyID": validation.Validate(v.PropertyID, validation.Required),
   169  	}.Filter()
   170  }
   171  
   172  // Validate validates GetPropertyVersionRequest
   173  func (v GetPropertyVersionRequest) Validate() error {
   174  	return validation.Errors{
   175  		"PropertyID":      validation.Validate(v.PropertyID, validation.Required),
   176  		"PropertyVersion": validation.Validate(v.PropertyVersion, validation.Required),
   177  	}.Filter()
   178  }
   179  
   180  // Validate validates CreatePropertyVersionRequest
   181  func (v CreatePropertyVersionRequest) Validate() error {
   182  	errs := validation.Errors{
   183  		"PropertyID": validation.Validate(v.PropertyID, validation.Required),
   184  		"Version":    validation.Validate(v.Version),
   185  	}
   186  	return edgegriderr.ParseValidationErrors(errs)
   187  }
   188  
   189  // Validate validates PropertyVersionCreate
   190  func (v PropertyVersionCreate) Validate() error {
   191  	return validation.Errors{
   192  		"CreateFromVersion": validation.Validate(v.CreateFromVersion, validation.Required),
   193  	}.Filter()
   194  }
   195  
   196  // Validate validates GetLatestVersionRequest
   197  func (v GetLatestVersionRequest) Validate() error {
   198  	return validation.Errors{
   199  		"PropertyID":  validation.Validate(v.PropertyID, validation.Required),
   200  		"ActivatedOn": validation.Validate(v.ActivatedOn, validation.In(VersionProduction, VersionStaging)),
   201  	}.Filter()
   202  }
   203  
   204  // Validate validates GetFeaturesRequest
   205  func (v GetFeaturesRequest) Validate() error {
   206  	return validation.Errors{
   207  		"PropertyID":      validation.Validate(v.PropertyID, validation.Required),
   208  		"PropertyVersion": validation.Validate(v.PropertyVersion, validation.Required),
   209  	}.Filter()
   210  }
   211  
   212  var (
   213  	// ErrGetPropertyVersions represents error when fetching property versions fails
   214  	ErrGetPropertyVersions = errors.New("fetching property versions")
   215  	// ErrGetPropertyVersion represents error when fetching property version fails
   216  	ErrGetPropertyVersion = errors.New("fetching property version")
   217  	// ErrGetLatestVersion represents error when fetching latest property version fails
   218  	ErrGetLatestVersion = errors.New("fetching latest property version")
   219  	// ErrCreatePropertyVersion represents error when creating property version fails
   220  	ErrCreatePropertyVersion = errors.New("creating property version")
   221  	// ErrGetAvailableBehaviors represents error when fetching available behaviors fails
   222  	ErrGetAvailableBehaviors = errors.New("fetching available behaviors")
   223  	// ErrGetAvailableCriteria represents error when fetching available criteria fails
   224  	ErrGetAvailableCriteria = errors.New("fetching available criteria")
   225  )
   226  
   227  // GetPropertyVersions returns list of property versions for give propertyID, contractID and groupID
   228  func (p *papi) GetPropertyVersions(ctx context.Context, params GetPropertyVersionsRequest) (*GetPropertyVersionsResponse, error) {
   229  	if err := params.Validate(); err != nil {
   230  		return nil, fmt.Errorf("%s: %w: %s", ErrGetPropertyVersions, ErrStructValidation, err)
   231  	}
   232  
   233  	logger := p.Log(ctx)
   234  	logger.Debug("GetPropertyVersions")
   235  
   236  	getURL := fmt.Sprintf(
   237  		"/papi/v1/properties/%s/versions?contractId=%s&groupId=%s",
   238  		params.PropertyID,
   239  		params.ContractID,
   240  		params.GroupID,
   241  	)
   242  	if params.Limit != 0 {
   243  		getURL += fmt.Sprintf("&limit=%d", params.Limit)
   244  	}
   245  	if params.Offset != 0 {
   246  		getURL += fmt.Sprintf("&offset=%d", params.Offset)
   247  	}
   248  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil)
   249  	if err != nil {
   250  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetPropertyVersions, err)
   251  	}
   252  
   253  	var versions GetPropertyVersionsResponse
   254  	resp, err := p.Exec(req, &versions)
   255  	if err != nil {
   256  		return nil, fmt.Errorf("%w: request failed: %s", ErrGetPropertyVersions, err)
   257  	}
   258  
   259  	if resp.StatusCode != http.StatusOK {
   260  		return nil, fmt.Errorf("%s: %w", ErrGetPropertyVersions, p.Error(resp))
   261  	}
   262  
   263  	return &versions, nil
   264  }
   265  
   266  // GetLatestVersion returns either the latest property version overall, or the latest ACTIVE version on production or staging network
   267  func (p *papi) GetLatestVersion(ctx context.Context, params GetLatestVersionRequest) (*GetPropertyVersionsResponse, error) {
   268  	if err := params.Validate(); err != nil {
   269  		return nil, fmt.Errorf("%s: %w: %s", ErrGetLatestVersion, ErrStructValidation, err)
   270  	}
   271  
   272  	logger := p.Log(ctx)
   273  	logger.Debug("GetLatestVersion")
   274  
   275  	getURL := fmt.Sprintf(
   276  		"/papi/v1/properties/%s/versions/latest?contractId=%s&groupId=%s",
   277  		params.PropertyID,
   278  		params.ContractID,
   279  		params.GroupID,
   280  	)
   281  	if params.ActivatedOn != "" {
   282  		getURL += fmt.Sprintf("&activatedOn=%s", params.ActivatedOn)
   283  	}
   284  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil)
   285  	if err != nil {
   286  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetLatestVersion, err)
   287  	}
   288  
   289  	var version GetPropertyVersionsResponse
   290  	resp, err := p.Exec(req, &version)
   291  	if err != nil {
   292  		return nil, fmt.Errorf("%w: request failed: %s", ErrGetLatestVersion, err)
   293  	}
   294  
   295  	if resp.StatusCode != http.StatusOK {
   296  		return nil, fmt.Errorf("%s: %w", ErrGetLatestVersion, p.Error(resp))
   297  	}
   298  	if len(version.Versions.Items) == 0 {
   299  		return nil, fmt.Errorf("%s: %w: latest version for PropertyID: %s", ErrGetLatestVersion, ErrNotFound, params.PropertyID)
   300  	}
   301  	version.Version = version.Versions.Items[0]
   302  	return &version, nil
   303  }
   304  
   305  // GetPropertyVersion returns property version with provided version number
   306  func (p *papi) GetPropertyVersion(ctx context.Context, params GetPropertyVersionRequest) (*GetPropertyVersionsResponse, error) {
   307  	if err := params.Validate(); err != nil {
   308  		return nil, fmt.Errorf("%s: %w: %s", ErrGetPropertyVersion, ErrStructValidation, err)
   309  	}
   310  
   311  	logger := p.Log(ctx)
   312  	logger.Debug("GetPropertyVersion")
   313  
   314  	getURL := fmt.Sprintf(
   315  		"/papi/v1/properties/%s/versions/%d?contractId=%s&groupId=%s",
   316  		params.PropertyID,
   317  		params.PropertyVersion,
   318  		params.ContractID,
   319  		params.GroupID,
   320  	)
   321  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil)
   322  	if err != nil {
   323  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetPropertyVersion, err)
   324  	}
   325  
   326  	var versions GetPropertyVersionsResponse
   327  	resp, err := p.Exec(req, &versions)
   328  	if err != nil {
   329  		return nil, fmt.Errorf("%w: request failed: %s", ErrGetPropertyVersion, err)
   330  	}
   331  
   332  	if resp.StatusCode != http.StatusOK {
   333  		return nil, fmt.Errorf("%s: %w", ErrGetPropertyVersion, p.Error(resp))
   334  	}
   335  	if len(versions.Versions.Items) == 0 {
   336  		return nil, fmt.Errorf("%s: %w: Version %d for PropertyID: %s", ErrGetPropertyVersion, ErrNotFound, params.PropertyVersion, params.PropertyID)
   337  	}
   338  	versions.Version = versions.Versions.Items[0]
   339  	return &versions, nil
   340  }
   341  
   342  // CreatePropertyVersion creates a new property version and returns location and number for the new version
   343  func (p *papi) CreatePropertyVersion(ctx context.Context, request CreatePropertyVersionRequest) (*CreatePropertyVersionResponse, error) {
   344  	if err := request.Validate(); err != nil {
   345  		return nil, fmt.Errorf("%s: %w:\n%s", ErrCreatePropertyVersion, ErrStructValidation, err)
   346  	}
   347  
   348  	logger := p.Log(ctx)
   349  	logger.Debug("CreatePropertyVersion")
   350  
   351  	getURL := fmt.Sprintf(
   352  		"/papi/v1/properties/%s/versions?contractId=%s&groupId=%s",
   353  		request.PropertyID,
   354  		request.ContractID,
   355  		request.GroupID,
   356  	)
   357  	req, err := http.NewRequestWithContext(ctx, http.MethodPost, getURL, nil)
   358  	if err != nil {
   359  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreatePropertyVersion, err)
   360  	}
   361  
   362  	var version CreatePropertyVersionResponse
   363  	resp, err := p.Exec(req, &version, request.Version)
   364  	if err != nil {
   365  		return nil, fmt.Errorf("%w: request failed: %s", ErrCreatePropertyVersion, err)
   366  	}
   367  
   368  	if resp.StatusCode != http.StatusCreated {
   369  		return nil, fmt.Errorf("%s: %w", ErrCreatePropertyVersion, p.Error(resp))
   370  	}
   371  	propertyVersion, err := ResponseLinkParse(version.VersionLink)
   372  	if err != nil {
   373  		return nil, fmt.Errorf("%s: %w: %s", ErrCreatePropertyVersion, ErrInvalidResponseLink, err)
   374  	}
   375  	versionNumber, err := strconv.Atoi(propertyVersion)
   376  	if err != nil {
   377  		return nil, fmt.Errorf("%s: %w: %s: %s", ErrCreatePropertyVersion, ErrInvalidResponseLink, "version should be a number", propertyVersion)
   378  	}
   379  	version.PropertyVersion = versionNumber
   380  	return &version, nil
   381  }
   382  
   383  // GetAvailableBehaviors lists available behaviors for given property version
   384  func (p *papi) GetAvailableBehaviors(ctx context.Context, params GetFeaturesRequest) (*GetFeaturesCriteriaResponse, error) {
   385  	if err := params.Validate(); err != nil {
   386  		return nil, fmt.Errorf("%s: %w: %s", ErrGetAvailableBehaviors, ErrStructValidation, err)
   387  	}
   388  
   389  	logger := p.Log(ctx)
   390  	logger.Debug("GetAvailableBehaviors")
   391  
   392  	getURL := fmt.Sprintf(
   393  		"/papi/v1/properties/%s/versions/%d/available-behaviors?contractId=%s&groupId=%s",
   394  		params.PropertyID,
   395  		params.PropertyVersion,
   396  		params.ContractID,
   397  		params.GroupID,
   398  	)
   399  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil)
   400  	if err != nil {
   401  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetAvailableBehaviors, err)
   402  	}
   403  
   404  	var versions GetFeaturesCriteriaResponse
   405  	resp, err := p.Exec(req, &versions)
   406  	if err != nil {
   407  		return nil, fmt.Errorf("%w: request failed: %s", ErrGetAvailableBehaviors, err)
   408  	}
   409  
   410  	if resp.StatusCode != http.StatusOK {
   411  		return nil, fmt.Errorf("%s: %w", ErrGetAvailableBehaviors, p.Error(resp))
   412  	}
   413  
   414  	return &versions, nil
   415  }
   416  
   417  // GetAvailableCriteria lists available criteria for given property version
   418  func (p *papi) GetAvailableCriteria(ctx context.Context, params GetFeaturesRequest) (*GetFeaturesCriteriaResponse, error) {
   419  	if err := params.Validate(); err != nil {
   420  		return nil, fmt.Errorf("%s: %w: %s", ErrGetAvailableCriteria, ErrStructValidation, err)
   421  	}
   422  
   423  	logger := p.Log(ctx)
   424  	logger.Debug("GetAvailableCriteria")
   425  
   426  	getURL := fmt.Sprintf(
   427  		"/papi/v1/properties/%s/versions/%d/available-criteria?contractId=%s&groupId=%s",
   428  		params.PropertyID,
   429  		params.PropertyVersion,
   430  		params.ContractID,
   431  		params.GroupID,
   432  	)
   433  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil)
   434  	if err != nil {
   435  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetAvailableCriteria, err)
   436  	}
   437  
   438  	var versions GetFeaturesCriteriaResponse
   439  	resp, err := p.Exec(req, &versions)
   440  	if err != nil {
   441  		return nil, fmt.Errorf("%w: request failed: %s", ErrGetAvailableCriteria, err)
   442  	}
   443  
   444  	if resp.StatusCode != http.StatusOK {
   445  		return nil, fmt.Errorf("%s: %w", ErrGetAvailableCriteria, p.Error(resp))
   446  	}
   447  
   448  	return &versions, nil
   449  }