github.com/akamai/AkamaiOPEN-edgegrid-golang/v2@v2.17.0/pkg/papi/rule.go (about) 1 package papi 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net/http" 8 "regexp" 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 // PropertyRules contains operations available on PropertyRule resource 16 // See: https://developer.akamai.com/api/core_features/property_manager/v1.html#propertyversionrulesgroup 17 PropertyRules interface { 18 // GetRuleTree lists all available CP codes 19 // See: https://developer.akamai.com/api/core_features/property_manager/v1.html#getpropertyversionrules 20 GetRuleTree(context.Context, GetRuleTreeRequest) (*GetRuleTreeResponse, error) 21 22 // UpdateRuleTree lists all available CP codes 23 // See: https://developer.akamai.com/api/core_features/property_manager/v1.html#putpropertyversionrules 24 UpdateRuleTree(context.Context, UpdateRulesRequest) (*UpdateRulesResponse, error) 25 } 26 27 // GetRuleTreeRequest contains path and query params necessary to perform GET /rules request 28 GetRuleTreeRequest struct { 29 PropertyID string 30 PropertyVersion int 31 ContractID string 32 GroupID string 33 ValidateMode string 34 ValidateRules bool 35 RuleFormat string 36 } 37 38 // GetRuleTreeResponse contains data returned by performing GET /rules request 39 GetRuleTreeResponse struct { 40 Response 41 PropertyID string `json:"propertyId"` 42 PropertyVersion int `json:"propertyVersion"` 43 Etag string `json:"etag"` 44 RuleFormat string `json:"ruleFormat"` 45 Rules Rules `json:"rules"` 46 Comments string `json:"comments,omitempty"` 47 } 48 49 // Rules contains Rule object 50 Rules struct { 51 AdvancedOverride string `json:"advancedOverride,omitempty"` 52 Behaviors []RuleBehavior `json:"behaviors,omitempty"` 53 Children []Rules `json:"children,omitempty"` 54 Comments string `json:"comments,omitempty"` 55 Criteria []RuleBehavior `json:"criteria,omitempty"` 56 CriteriaLocked bool `json:"criteriaLocked,omitempty"` 57 CustomOverride *RuleCustomOverride `json:"customOverride,omitempty"` 58 Name string `json:"name"` 59 Options RuleOptions `json:"options,omitempty"` 60 UUID string `json:"uuid,omitempty"` 61 TemplateUuid string `json:"templateUuid,omitempty"` 62 TemplateLink string `json:"templateLink,omitempty"` 63 Variables []RuleVariable `json:"variables,omitempty"` 64 CriteriaMustSatisfy RuleCriteriaMustSatisfy `json:"criteriaMustSatisfy,omitempty"` 65 } 66 67 // RuleBehavior contains data for both rule behaviors and rule criteria 68 RuleBehavior struct { 69 Locked bool `json:"locked,omitempty"` 70 Name string `json:"name"` 71 Options RuleOptionsMap `json:"options"` 72 UUID string `json:"uuid,omitempty"` 73 TemplateUuid string `json:"templateUuid,omitempty"` 74 } 75 76 // RuleCustomOverride represents customOverride field from Rule resource 77 RuleCustomOverride struct { 78 Name string `json:"name"` 79 OverrideID string `json:"overrideId"` 80 } 81 82 // RuleOptions represents options field from Rule resource 83 RuleOptions struct { 84 IsSecure bool `json:"is_secure,omitempty"` 85 } 86 87 // RuleVariable represents and entry in variables field from Rule resource 88 RuleVariable struct { 89 Description string `json:"description,omitempty"` 90 Hidden bool `json:"hidden"` 91 Name string `json:"name"` 92 Sensitive bool `json:"sensitive"` 93 Value string `json:"value,omitempty"` 94 } 95 96 // UpdateRulesRequest contains path and query params, as well as request body necessary to perform PUT /rules request 97 UpdateRulesRequest struct { 98 PropertyID string 99 PropertyVersion int 100 ContractID string 101 DryRun bool 102 GroupID string 103 ValidateMode string 104 ValidateRules bool 105 Rules RulesUpdate 106 } 107 108 // RulesUpdate is a wrapper for the request body of PUT /rules request 109 RulesUpdate struct { 110 Comments string `json:"comments,omitempty"` 111 Rules Rules `json:"rules"` 112 } 113 114 // UpdateRulesResponse contains data returned by performing PUT /rules request 115 UpdateRulesResponse struct { 116 AccountID string `json:"accountId"` 117 ContractID string `json:"contractId"` 118 Comments string `json:"comments,omitempty"` 119 GroupID string `json:"groupId"` 120 PropertyID string `json:"propertyId"` 121 PropertyVersion int `json:"propertyVersion"` 122 Etag string `json:"etag"` 123 RuleFormat string `json:"ruleFormat"` 124 Rules Rules `json:"rules"` 125 Errors []RuleError `json:"errors"` 126 } 127 128 // RuleError represents and entry in error field from PUT /rules response body 129 RuleError struct { 130 Type string `json:"type"` 131 Title string `json:"title"` 132 Detail string `json:"detail"` 133 Instance string `json:"instance"` 134 BehaviorName string `json:"behaviorName"` 135 } 136 137 // RuleOptionsMap is a type wrapping map[string]interface{} used for adding rule options 138 RuleOptionsMap map[string]interface{} 139 140 // RuleCriteriaMustSatisfy represents criteriaMustSatisfy field values 141 RuleCriteriaMustSatisfy string 142 ) 143 144 const ( 145 // RuleValidateModeFast const 146 RuleValidateModeFast = "fast" 147 // RuleValidateModeFull const 148 RuleValidateModeFull = "full" 149 150 // RuleCriteriaMustSatisfyAll const 151 RuleCriteriaMustSatisfyAll RuleCriteriaMustSatisfy = "all" 152 //RuleCriteriaMustSatisfyAny const 153 RuleCriteriaMustSatisfyAny RuleCriteriaMustSatisfy = "any" 154 ) 155 156 var validRuleFormat = regexp.MustCompile("^(latest|v\\d{4}-\\d{2}-\\d{2})$") 157 158 // Validate validates GetRuleTreeRequest struct 159 func (r GetRuleTreeRequest) Validate() error { 160 return validation.Errors{ 161 "PropertyID": validation.Validate(r.PropertyID, validation.Required), 162 "PropertyVersion": validation.Validate(r.PropertyVersion, validation.Required), 163 "ValidateMode": validation.Validate(r.ValidateMode, validation.In(RuleValidateModeFast, RuleValidateModeFull)), 164 "RuleFormat": validation.Validate(r.RuleFormat, validation.Match(validRuleFormat)), 165 }.Filter() 166 } 167 168 // Validate validates UpdateRulesRequest struct 169 func (r UpdateRulesRequest) Validate() error { 170 errs := validation.Errors{ 171 "PropertyID": validation.Validate(r.PropertyID, validation.Required), 172 "PropertyVersion": validation.Validate(r.PropertyVersion, validation.Required), 173 "ValidateMode": validation.Validate(r.ValidateMode, validation.In(RuleValidateModeFast, RuleValidateModeFull)), 174 "Rules": validation.Validate(r.Rules), 175 } 176 return edgegriderr.ParseValidationErrors(errs) 177 } 178 179 // Validate validates RulesUpdate struct 180 func (r RulesUpdate) Validate() error { 181 return validation.Errors{ 182 "Rules": validation.Validate(r.Rules), 183 "Comments": validation.Validate(r.Comments), 184 }.Filter() 185 } 186 187 // Validate validates Rules struct 188 func (r Rules) Validate() error { 189 return validation.Errors{ 190 "Behaviors": validation.Validate(r.Behaviors), 191 "Name": validation.Validate(r.Name, validation.Required), 192 "CustomOverride": validation.Validate(r.CustomOverride), 193 "Criteria": validation.Validate(r.Criteria), 194 "Children": validation.Validate(r.Children), 195 "Variables": validation.Validate(r.Variables), 196 "Comments": validation.Validate(r.Comments), 197 }.Filter() 198 } 199 200 // Validate validates RuleBehavior struct 201 func (b RuleBehavior) Validate() error { 202 return validation.Errors{ 203 "Name": validation.Validate(b.Name), 204 "Options": validation.Validate(b.Options), 205 }.Filter() 206 } 207 208 // Validate validates RuleCustomOverride struct 209 func (co RuleCustomOverride) Validate() error { 210 return validation.Errors{ 211 "Name": validation.Validate(co.Name, validation.Required), 212 "OverrideID": validation.Validate(co.OverrideID, validation.Required), 213 }.Filter() 214 } 215 216 // Validate validates RuleVariable struct 217 func (v RuleVariable) Validate() error { 218 return validation.Errors{ 219 "Name": validation.Validate(v.Name, validation.Required), 220 }.Filter() 221 } 222 223 var ( 224 // ErrGetRuleTree represents error when fetching rule tree fails 225 ErrGetRuleTree = errors.New("fetching rule tree") 226 // ErrUpdateRuleTree represents error when updating rule tree fails 227 ErrUpdateRuleTree = errors.New("updating rule tree") 228 ) 229 230 func (p *papi) GetRuleTree(ctx context.Context, params GetRuleTreeRequest) (*GetRuleTreeResponse, error) { 231 if err := params.Validate(); err != nil { 232 return nil, fmt.Errorf("%s: %w: %s", ErrGetRuleTree, ErrStructValidation, err) 233 } 234 235 logger := p.Log(ctx) 236 logger.Debug("GetRuleTree") 237 238 getURL := fmt.Sprintf( 239 "/papi/v1/properties/%s/versions/%d/rules?contractId=%s&groupId=%s", 240 params.PropertyID, 241 params.PropertyVersion, 242 params.ContractID, 243 params.GroupID, 244 ) 245 if params.ValidateMode != "" { 246 getURL += fmt.Sprintf("&validateMode=%s", params.ValidateMode) 247 } 248 if !params.ValidateRules { 249 getURL += fmt.Sprintf("&validateRules=%t", params.ValidateRules) 250 } 251 req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) 252 if err != nil { 253 return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetRuleTree, err) 254 } 255 256 if params.RuleFormat != "" { 257 req.Header.Set("Accept", fmt.Sprintf("application/vnd.akamai.papirules.%s+json", params.RuleFormat)) 258 } 259 260 var rules GetRuleTreeResponse 261 resp, err := p.Exec(req, &rules) 262 if err != nil { 263 return nil, fmt.Errorf("%w: request failed: %s", ErrGetRuleTree, err) 264 } 265 266 if resp.StatusCode != http.StatusOK { 267 return nil, fmt.Errorf("%s: %w", ErrGetRuleTree, p.Error(resp)) 268 } 269 270 return &rules, nil 271 } 272 273 func (p *papi) UpdateRuleTree(ctx context.Context, request UpdateRulesRequest) (*UpdateRulesResponse, error) { 274 if err := request.Validate(); err != nil { 275 return nil, fmt.Errorf("%s: %w:\n%s", ErrUpdateRuleTree, ErrStructValidation, err) 276 } 277 278 logger := p.Log(ctx) 279 logger.Debug("UpdateRuleTree") 280 281 putURL := fmt.Sprintf( 282 "/papi/v1/properties/%s/versions/%d/rules?contractId=%s&groupId=%s", 283 request.PropertyID, 284 request.PropertyVersion, 285 request.ContractID, 286 request.GroupID, 287 ) 288 if request.ValidateMode != "" { 289 putURL += fmt.Sprintf("&validateMode=%s", request.ValidateMode) 290 } 291 if !request.ValidateRules { 292 putURL += fmt.Sprintf("&validateRules=%t", request.ValidateRules) 293 } 294 if request.DryRun { 295 putURL += fmt.Sprintf("&dryRun=%t", request.DryRun) 296 } 297 req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, nil) 298 if err != nil { 299 return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateRuleTree, err) 300 } 301 302 var versions UpdateRulesResponse 303 resp, err := p.Exec(req, &versions, request.Rules) 304 if err != nil { 305 return nil, fmt.Errorf("%w: request failed: %s", ErrUpdateRuleTree, err) 306 } 307 if resp.StatusCode != http.StatusOK { 308 return nil, fmt.Errorf("%s: %w", ErrUpdateRuleTree, p.Error(resp)) 309 } 310 311 return &versions, nil 312 }