diff --git a/cmd/delete-all.go b/cmd/delete-all.go index d3a0aaf..f7d72ff 100644 --- a/cmd/delete-all.go +++ b/cmd/delete-all.go @@ -7,9 +7,11 @@ import ( "github.com/elasticpath/epcc-cli/external/apihelper" "github.com/elasticpath/epcc-cli/external/httpclient" "github.com/elasticpath/epcc-cli/external/id" + "github.com/elasticpath/epcc-cli/external/json" "github.com/elasticpath/epcc-cli/external/resources" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "io" "net/url" "reflect" "regexp" @@ -176,6 +178,7 @@ func getParentIds(ctx context.Context, resource resources.Resource) ([][]id.Idab } var flowsUrlRegex = regexp.MustCompile("^/v2/flows/([^/]+)$") +var cartsUrlRegex = regexp.MustCompile("^/v2/carts/([^/]+)$") func delPage(ctx context.Context, urlInfo *resources.CrudEntityInfo, ids [][]id.IdableAttributes) { // Create a wait group to run DELETE in parallel @@ -206,6 +209,102 @@ func delPage(ctx context.Context, urlInfo *resources.CrudEntityInfo, ids [][]id. if resp.Body != nil { defer resp.Body.Close() } + if resp.StatusCode == 400 && cartsUrlRegex.MatchString(resourceURL) { + log.Warnf("Could not delete %s, likely associations, trying to clean up", resourceURL) + + resp2, err := httpclient.DoRequest(ctx, "GET", resourceURL, "", nil) + + if err != nil { + return + } + + if resp2 != nil { + if resp2.Body != nil { + defer resp2.Body.Close() + } + } + + if resp2.StatusCode != 200 { + log.Warnf("Couldn't retrieve cart %d", resp2.StatusCode) + return + } + + bytes, err := io.ReadAll(resp2.Body) + + if err != nil { + log.Warnf("Couldn't read cart body for %s: %v", resourceURL, err) + return + } + + custIds, err := json.RunJQOnStringWithArray(".data.relationships.customers.data[].id", string(bytes)) + + if err == nil { + for _, id := range custIds { + jsonBody := fmt.Sprintf(`{ "data": [{ "id":"%s", "type": "customer"}]}`, id) + resp3, err := httpclient.DoRequest(ctx, "DELETE", fmt.Sprintf("%s/relationships/customers", resourceURL), "", strings.NewReader(jsonBody)) + + if err != nil { + log.Warnf("Couldn't delete customer cart association %s: %v", id, err) + continue + } + + if resp3 == nil { + continue + } + + if resp3.Body != nil { + defer resp3.Body.Close() + } + } + } else { + + // JQ might give us an error if there are no customers (perhaps because there are accounts). + log.Tracef("Couldn't parse customers, %v", err) + } + + acctIds, err := json.RunJQOnStringWithArray(".data.relationships.accounts.data[].id", string(bytes)) + + if err == nil { + for _, id := range acctIds { + jsonBody := fmt.Sprintf(`{ "data": [{ "id":"%s", "type": "account"}]}`, id) + resp3, err := httpclient.DoRequest(ctx, "DELETE", fmt.Sprintf("%s/relationships/accounts", resourceURL), "", strings.NewReader(jsonBody)) + + if err != nil { + log.Warnf("Couldn't delete account cart association %s: %v", id, err) + continue + } + + if resp3 == nil { + continue + } + + if resp3.Body != nil { + defer resp3.Body.Close() + } + } + } else { + + // JQ might give us an error if there are no customers (perhaps because there are accounts). + log.Tracef("Couldn't parse customers, %v", err) + } + + resp3, err := httpclient.DoRequest(ctx, "DELETE", resourceURL, "", nil) + if err != nil { + return + } + + if resp3 == nil { + return + } + + if resp3.Body != nil { + defer resp3.Body.Close() + } + + if resp3.StatusCode == 400 { + log.Infof("Even after cleaning up associations, still couldn't clean up the cart") + } + } if resp.StatusCode == 405 && flowsUrlRegex.MatchString(resourceURL) { log.Warnf("Could not delete %s, likely core flow, trying to rename and then try again", resourceURL) diff --git a/external/resources/uritemplates.go b/external/resources/uritemplates.go index 9a6b763..fa766e5 100644 --- a/external/resources/uritemplates.go +++ b/external/resources/uritemplates.go @@ -63,7 +63,15 @@ func GenerateUrlViaIdableAttributes(urlInfo *CrudEntityInfo, args []id.IdableAtt } - return template.Expand(values) + uri, err := template.Expand(values) + + if err != nil { + return "", err + } + + decodedUrlBytes, err := url.PathUnescape(uri) + + return decodedUrlBytes, err } diff --git a/external/resources/yaml/resources.yaml b/external/resources/yaml/resources.yaml index 6cda623..a64a5e4 100644 --- a/external/resources/yaml/resources.yaml +++ b/external/resources/yaml/resources.yaml @@ -240,6 +240,7 @@ carts: type: STRING name: type: STRING + autofill: FUNC:Noun description: type: STRING cart-items: diff --git a/external/runbooks/run-all-runbooks.sh b/external/runbooks/run-all-runbooks.sh index 89195f5..25cc8d1 100755 --- a/external/runbooks/run-all-runbooks.sh +++ b/external/runbooks/run-all-runbooks.sh @@ -3,12 +3,7 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) # We just need to hack this for now, due to API limitations -epcc get cart cust1_and_2 --output-jq .data.relationships.customers.data[].id | sed -E 's/"//g' | xargs -d "\n" -n 1 epcc delete customer-cart-association cust1_and_2 data[0].type customer data[0].id -epcc get cart cust4_and_5 --output-jq .data.relationships.customers.data[].id | sed -E 's/"//g' | xargs -d "\n" -n 1 epcc delete customer-cart-association cust4_and_5 data[0].type customer data[0].id -sleep 1 -epcc get cart cust1_and_2 --output-jq .data.relationships.customers.data[].id | sed -E 's/"//g' | xargs -d "\n" -n 1 epcc delete customer-cart-association cust1_and_2 data[0].type customer data[0].id -epcc get cart cust4_and_5 --output-jq .data.relationships.customers.data[].id | sed -E 's/"//g' | xargs -d "\n" -n 1 epcc delete customer-cart-association cust4_and_5 data[0].type customer data[0].id - +epcc delete cart no_cust_cart set -e set -x