Refactor response handling and centralize JSON configuration
Replaced direct fields in `AbstractResponse` with `ResponseResultInfo` for better encapsulation and consistency. Introduced `JsonConf` to provide a shared, reusable `ObjectMapper` configuration. Updated tests and logic to align with the refactored response structure, enhancing maintainability and readability.
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
/.factorypath
|
/.factorypath
|
||||||
/.springBeans
|
/.springBeans
|
||||||
/.idea
|
/.idea
|
||||||
|
*.iml
|
||||||
|
|
||||||
# local files
|
# local files
|
||||||
/info.txt
|
/info.txt
|
||||||
|
|||||||
@@ -2,14 +2,11 @@ package codes.thischwa.cf;
|
|||||||
|
|
||||||
import codes.thischwa.cf.model.AbstractEntity;
|
import codes.thischwa.cf.model.AbstractEntity;
|
||||||
import codes.thischwa.cf.model.AbstractResponse;
|
import codes.thischwa.cf.model.AbstractResponse;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import org.apache.hc.client5.http.classic.methods.HttpDelete;
|
import org.apache.hc.client5.http.classic.methods.HttpDelete;
|
||||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||||
import org.apache.hc.client5.http.classic.methods.HttpPatch;
|
import org.apache.hc.client5.http.classic.methods.HttpPatch;
|
||||||
@@ -39,7 +36,7 @@ abstract class CfBasicHttpClient {
|
|||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
CfBasicHttpClient(String baseUrl, String authEmail, String authKey)
|
CfBasicHttpClient(String baseUrl, String authEmail, String authKey)
|
||||||
throws IllegalArgumentException {
|
throws IllegalArgumentException {
|
||||||
if (authEmail == null || authEmail.isBlank()) {
|
if (authEmail == null || authEmail.isBlank()) {
|
||||||
throw new IllegalArgumentException("Authentication email must not be null or blank!");
|
throw new IllegalArgumentException("Authentication email must not be null or blank!");
|
||||||
}
|
}
|
||||||
@@ -49,110 +46,113 @@ abstract class CfBasicHttpClient {
|
|||||||
this.baseUrl = baseUrl;
|
this.baseUrl = baseUrl;
|
||||||
this.authEmail = authEmail;
|
this.authEmail = authEmail;
|
||||||
this.authKey = authKey;
|
this.authKey = authKey;
|
||||||
this.objectMapper = initObjectMapper();
|
this.objectMapper = JsonConf.initObjectMapper();
|
||||||
}
|
|
||||||
|
|
||||||
private ObjectMapper initObjectMapper() {
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
mapper.registerModule(new JavaTimeModule());
|
|
||||||
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
|
||||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
||||||
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
|
|
||||||
return mapper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CloseableHttpClient createHttpClient() {
|
private CloseableHttpClient createHttpClient() {
|
||||||
return HttpClients.custom()
|
return HttpClients.custom().addRequestInterceptorFirst((request, context, execChain) -> {
|
||||||
.addRequestInterceptorFirst(
|
request.addHeader(HttpHeaders.ACCEPT_CHARSET, "UTF-8");
|
||||||
(request, context, execChain) -> {
|
request.addHeader(HttpHeaders.ACCEPT_ENCODING, "gzip");
|
||||||
request.addHeader(HttpHeaders.ACCEPT_CHARSET, "UTF-8");
|
request.addHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.getMimeType());
|
||||||
request.addHeader(HttpHeaders.ACCEPT_ENCODING, "gzip");
|
request.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
|
||||||
request.addHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.getMimeType());
|
request.addHeader("X-Auth-Email", authEmail);
|
||||||
request.addHeader(
|
request.addHeader("X-Auth-Key", authKey);
|
||||||
HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
|
}).build();
|
||||||
request.addHeader("X-Auth-Email", authEmail);
|
|
||||||
request.addHeader("X-Auth-Key", authKey);
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends AbstractResponse> T executeRequest(
|
private <T extends AbstractResponse> T executeRequest(ClassicHttpRequest request,
|
||||||
ClassicHttpRequest request, Class<T> responseType) throws CloudflareApiException {
|
Class<T> responseType)
|
||||||
|
throws CloudflareApiException {
|
||||||
String logUri = null;
|
String logUri = null;
|
||||||
try (CloseableHttpClient client = createHttpClient()) {
|
try (CloseableHttpClient client = createHttpClient()) {
|
||||||
ResultWrapper result =
|
ResultWrapper result = client.execute(request,
|
||||||
client.execute(
|
(ClassicHttpResponse response) -> new ResultWrapper(response.getCode(),
|
||||||
request,
|
EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8)));
|
||||||
(ClassicHttpResponse response) ->
|
|
||||||
new ResultWrapper(
|
|
||||||
response.getCode(),
|
|
||||||
EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8)));
|
|
||||||
|
|
||||||
logUri = request.getRequestUri();
|
logUri = request.getRequestUri();
|
||||||
if (result.statusCode >= 200 && result.statusCode < 300) {
|
if (result.statusCode >= 200 && result.statusCode < 300) {
|
||||||
return objectMapper.readValue(result.responseBody, responseType);
|
T respObj = objectMapper.readValue(result.responseBody, responseType);
|
||||||
|
if (!respObj.getResponseResultInfo().isSuccess()) {
|
||||||
|
log.error("API error.");
|
||||||
|
respObj.getResponseResultInfo().getErrors().forEach(e -> log.error(" - {}", e));
|
||||||
|
throw new CloudflareApiException("API error.");
|
||||||
|
}
|
||||||
|
return respObj;
|
||||||
} else {
|
} else {
|
||||||
log.error(
|
log.error("{} request failed for URL {}: Status {}", request.getMethod(), request.getUri(),
|
||||||
"{} request failed for URL {}: Status {}",
|
result.statusCode);
|
||||||
request.getMethod(),
|
|
||||||
request.getUri(),
|
|
||||||
result.statusCode);
|
|
||||||
throw new CloudflareApiException(
|
throw new CloudflareApiException(
|
||||||
request.getMethod() + " request failed with status code: " + result.statusCode);
|
request.getMethod() + " request failed with status code: " + result.statusCode);
|
||||||
}
|
}
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
log.error("JSON parsing error for request to {}", logUri, e);
|
log.error("JSON parsing error for request to {}", logUri, e);
|
||||||
throw new CloudflareApiException("Error processing JSON response", e);
|
throw new CloudflareApiException("Error processing JSON response", e);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error during request execution", e);
|
throw new CloudflareApiException("Server error!", e);
|
||||||
throw new CloudflareApiException("Request failed", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sends a GET request to the given endpoint and maps the response. */
|
/**
|
||||||
|
* Sends a GET request to the given endpoint and maps the response.
|
||||||
|
*/
|
||||||
<T extends AbstractResponse> T getRequest(String endpoint, Class<T> responseType)
|
<T extends AbstractResponse> T getRequest(String endpoint, Class<T> responseType)
|
||||||
throws CloudflareApiException {
|
throws CloudflareApiException {
|
||||||
HttpGet request = new HttpGet(buildUrl(endpoint));
|
HttpGet request = new HttpGet(buildUrl(endpoint));
|
||||||
return executeRequest(request, responseType);
|
return executeRequest(request, responseType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sends a DELETE request to the given endpoint and maps the response. */
|
/**
|
||||||
|
* Sends a DELETE request to the given endpoint and maps the response.
|
||||||
|
*/
|
||||||
<T extends AbstractResponse> T deleteRequest(String endpoint) throws CloudflareApiException {
|
<T extends AbstractResponse> T deleteRequest(String endpoint) throws CloudflareApiException {
|
||||||
HttpDelete request = new HttpDelete(buildUrl(endpoint));
|
HttpDelete request = new HttpDelete(buildUrl(endpoint));
|
||||||
return executeRequest(request, (Class<T>) codes.thischwa.cf.model.RecordSingleResponse.class);
|
return executeRequest(request, (Class<T>) codes.thischwa.cf.model.RecordSingleResponse.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sends a POST request with a payload to the given endpoint and maps the response. */
|
/**
|
||||||
<T extends AbstractResponse, R extends AbstractEntity> T postRequest(
|
* Sends a POST request with a payload to the given endpoint and maps the response.
|
||||||
String endpoint, R requestPayload) throws CloudflareApiException {
|
*/
|
||||||
|
<T extends AbstractResponse, R extends AbstractEntity> T postRequest(String endpoint,
|
||||||
|
R requestPayload)
|
||||||
|
throws CloudflareApiException {
|
||||||
HttpPost request = new HttpPost(buildUrl(endpoint));
|
HttpPost request = new HttpPost(buildUrl(endpoint));
|
||||||
setRequestPayload(request, requestPayload);
|
setRequestPayload(request, requestPayload);
|
||||||
return executeRequest(request, (Class<T>) codes.thischwa.cf.model.RecordSingleResponse.class);
|
return executeRequest(request, (Class<T>) codes.thischwa.cf.model.RecordSingleResponse.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sends a PUT request with a payload to the given endpoint and maps the response. */
|
/**
|
||||||
<T extends AbstractResponse, R extends AbstractEntity> T putRequest(
|
* Sends a PUT request with a payload to the given endpoint and maps the response.
|
||||||
String endpoint, R requestPayload, Class<T> responseType) throws CloudflareApiException {
|
*/
|
||||||
|
<T extends AbstractResponse, R extends AbstractEntity> T putRequest(String endpoint,
|
||||||
|
R requestPayload,
|
||||||
|
Class<T> responseType)
|
||||||
|
throws CloudflareApiException {
|
||||||
HttpPut request = new HttpPut(buildUrl(endpoint));
|
HttpPut request = new HttpPut(buildUrl(endpoint));
|
||||||
setRequestPayload(request, requestPayload);
|
setRequestPayload(request, requestPayload);
|
||||||
return executeRequest(request, responseType);
|
return executeRequest(request, responseType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sends a PATCH request with a payload to the given endpoint and maps the response. */
|
/**
|
||||||
<T extends AbstractResponse, R extends AbstractEntity> T patchRequest(
|
* Sends a PATCH request with a payload to the given endpoint and maps the response.
|
||||||
String endpoint, R requestPayload) throws CloudflareApiException {
|
*/
|
||||||
|
<T extends AbstractResponse, R extends AbstractEntity> T patchRequest(String endpoint,
|
||||||
|
R requestPayload)
|
||||||
|
throws CloudflareApiException {
|
||||||
HttpPatch request = new HttpPatch(buildUrl(endpoint));
|
HttpPatch request = new HttpPatch(buildUrl(endpoint));
|
||||||
setRequestPayload(request, requestPayload);
|
setRequestPayload(request, requestPayload);
|
||||||
return executeRequest(request, (Class<T>) codes.thischwa.cf.model.RecordSingleResponse.class);
|
return executeRequest(request, (Class<T>) codes.thischwa.cf.model.RecordSingleResponse.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets the JSON payload for a request. */
|
/**
|
||||||
private <R extends AbstractEntity> void setRequestPayload(
|
* Sets the JSON payload for a request.
|
||||||
BasicClassicHttpRequest request, R requestPayload) throws CloudflareApiException {
|
*/
|
||||||
|
private <R extends AbstractEntity> void setRequestPayload(BasicClassicHttpRequest request,
|
||||||
|
R requestPayload)
|
||||||
|
throws CloudflareApiException {
|
||||||
try {
|
try {
|
||||||
request.setEntity(
|
request.setEntity(new StringEntity(objectMapper.writeValueAsString(requestPayload),
|
||||||
new StringEntity(
|
ContentType.APPLICATION_JSON));
|
||||||
objectMapper.writeValueAsString(requestPayload), ContentType.APPLICATION_JSON));
|
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
throw new CloudflareApiException("Error serializing JSON payload", e);
|
throw new CloudflareApiException("Error serializing JSON payload", e);
|
||||||
}
|
}
|
||||||
@@ -162,5 +162,6 @@ abstract class CfBasicHttpClient {
|
|||||||
return baseUrl + endpoint;
|
return baseUrl + endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
private record ResultWrapper(int statusCode, String responseBody) {}
|
private record ResultWrapper(int statusCode, String responseBody) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import codes.thischwa.cf.model.RecordEntity;
|
|||||||
import codes.thischwa.cf.model.RecordMultipleResponse;
|
import codes.thischwa.cf.model.RecordMultipleResponse;
|
||||||
import codes.thischwa.cf.model.RecordSingleResponse;
|
import codes.thischwa.cf.model.RecordSingleResponse;
|
||||||
import codes.thischwa.cf.model.RecordType;
|
import codes.thischwa.cf.model.RecordType;
|
||||||
|
import codes.thischwa.cf.model.ResponseResultInfo;
|
||||||
import codes.thischwa.cf.model.ZoneEntity;
|
import codes.thischwa.cf.model.ZoneEntity;
|
||||||
import codes.thischwa.cf.model.ZoneMultipleResponse;
|
import codes.thischwa.cf.model.ZoneMultipleResponse;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -307,9 +308,10 @@ public class CfDnsClient extends CfBasicHttpClient {
|
|||||||
|
|
||||||
private void checkResponse(AbstractResponse resp, boolean singleResultExpected)
|
private void checkResponse(AbstractResponse resp, boolean singleResultExpected)
|
||||||
throws CloudflareApiException {
|
throws CloudflareApiException {
|
||||||
if (!resp.isSuccess()) {
|
ResponseResultInfo resultInfo = resp.getResponseResultInfo();
|
||||||
|
if (!resultInfo.isSuccess()) {
|
||||||
String errors =
|
String errors =
|
||||||
resp.getErrors().stream().map(Object::toString).collect(Collectors.joining(", "));
|
resultInfo.getErrors().stream().map(Object::toString).collect(Collectors.joining(", "));
|
||||||
throw new CloudflareApiException("Error in response: " + errors);
|
throw new CloudflareApiException("Error in response: " + errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package codes.thischwa.cf;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JsonConf class provides a utility method for initializing and configuring a shared
|
||||||
|
* {@link ObjectMapper} instance for JSON serialization and deserialization.
|
||||||
|
*/
|
||||||
|
class JsonConf {
|
||||||
|
|
||||||
|
static ObjectMapper initObjectMapper() {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
mapper.registerModule(new JavaTimeModule());
|
||||||
|
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||||
|
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
|
||||||
|
return mapper;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package codes.thischwa.cf.model;
|
package codes.thischwa.cf.model;
|
||||||
|
|
||||||
import java.util.List;
|
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,7 +22,7 @@ import lombok.Data;
|
|||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public abstract class AbstractResponse {
|
public abstract class AbstractResponse {
|
||||||
private boolean success;
|
|
||||||
private List<String> errors;
|
@JsonUnwrapped
|
||||||
private List<String> messages;
|
private ResponseResultInfo responseResultInfo;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package codes.thischwa.cf.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the result of a response with metadata about its success and associated messages or
|
||||||
|
* errors.
|
||||||
|
* <p>This class provides a structure to capture the outcome of an operation, including:
|
||||||
|
* <ul>
|
||||||
|
* <li>Whether the operation was successful.
|
||||||
|
* <li>A list of error messages if the operation failed.
|
||||||
|
* <li>A list of informational or success messages.
|
||||||
|
* </ul>
|
||||||
|
* It can be used to standardize the response format in an application.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ResponseResultInfo {
|
||||||
|
private boolean success;
|
||||||
|
private List<String> errors;
|
||||||
|
private List<String> messages;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package codes.thischwa.cf;
|
||||||
|
|
||||||
|
import codes.thischwa.cf.model.ZoneMultipleResponse;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import java.io.IOException;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class ObjectMapperTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testObjectMapper() throws IOException {
|
||||||
|
ObjectMapper mapper = JsonConf.initObjectMapper();
|
||||||
|
ZoneMultipleResponse resp =
|
||||||
|
mapper.readValue(this.getClass().getResourceAsStream("/zone-list-response.json"),
|
||||||
|
ZoneMultipleResponse.class);
|
||||||
|
assertNotNull(resp.getResponseResultInfo());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"result": null,
|
||||||
|
"success": false,
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"code": 81053,
|
||||||
|
"message": "An A, AAAA, or CNAME record with that host already exists. For more details, refer to \u003chttps://developers.cloudflare.com/dns/manage-dns-records/troubleshooting/records-with-same-name/\u003e."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"messages": []
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration debug="true">
|
<configuration>
|
||||||
|
|
||||||
<appender name="current"
|
<appender name="current"
|
||||||
class="ch.qos.logback.core.ConsoleAppender">
|
class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
{
|
||||||
|
"result": [
|
||||||
|
{
|
||||||
|
"id": "0a83dd6e7f8c46039f2517bbded8115e",
|
||||||
|
"name": "mein-d-ns.de",
|
||||||
|
"status": "active",
|
||||||
|
"paused": false,
|
||||||
|
"type": "full",
|
||||||
|
"development_mode": -230181,
|
||||||
|
"name_servers": [
|
||||||
|
"blair.ns.cloudflare.com",
|
||||||
|
"sergi.ns.cloudflare.com"
|
||||||
|
],
|
||||||
|
"original_name_servers": [
|
||||||
|
"c.ns14.net",
|
||||||
|
"b.ns14.net",
|
||||||
|
"a.ns14.net",
|
||||||
|
"d.ns14.net"
|
||||||
|
],
|
||||||
|
"original_registrar": null,
|
||||||
|
"original_dnshost": null,
|
||||||
|
"modified_on": "2025-01-20T09:06:52.122538Z",
|
||||||
|
"created_on": "2025-01-20T08:56:34.736214Z",
|
||||||
|
"activated_on": "2025-01-20T09:06:52.122538Z",
|
||||||
|
"meta": {
|
||||||
|
"step": 2,
|
||||||
|
"custom_certificate_quota": 0,
|
||||||
|
"page_rule_quota": 3,
|
||||||
|
"phishing_detected": false
|
||||||
|
},
|
||||||
|
"owner": {
|
||||||
|
"id": null,
|
||||||
|
"type": "user",
|
||||||
|
"email": null
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"id": "563335e3d73549dbbc0620f4ce82d527",
|
||||||
|
"name": "myAccount"
|
||||||
|
},
|
||||||
|
"tenant": {
|
||||||
|
"id": null,
|
||||||
|
"name": null
|
||||||
|
},
|
||||||
|
"tenant_unit": {
|
||||||
|
"id": null
|
||||||
|
},
|
||||||
|
"permissions": [
|
||||||
|
"#image:read",
|
||||||
|
"#image:edit",
|
||||||
|
"#worker:edit",
|
||||||
|
"#analytics:read",
|
||||||
|
"#ssl:edit",
|
||||||
|
"#zone_settings:read",
|
||||||
|
"#organization:edit",
|
||||||
|
"#waf:read",
|
||||||
|
"#waf:edit",
|
||||||
|
"#logs:read",
|
||||||
|
"#member:read",
|
||||||
|
"#worker:read",
|
||||||
|
"#blocks:read",
|
||||||
|
"#blocks:edit",
|
||||||
|
"#access:read",
|
||||||
|
"#access:edit",
|
||||||
|
"#billing:read",
|
||||||
|
"#teams:read",
|
||||||
|
"#organization:read",
|
||||||
|
"#logs:edit",
|
||||||
|
"#zaraz:publish",
|
||||||
|
"#zone_settings:edit",
|
||||||
|
"#fbm:read",
|
||||||
|
"#subscription:read",
|
||||||
|
"#lb:read",
|
||||||
|
"#waitingroom:edit",
|
||||||
|
"#ssl:read",
|
||||||
|
"#subscription:edit",
|
||||||
|
"#dns_records:read",
|
||||||
|
"#dns_records:edit",
|
||||||
|
"#api_gateway:read",
|
||||||
|
"#api_gateway:edit",
|
||||||
|
"#cds_compute_account:edit",
|
||||||
|
"#ces_submissions:read",
|
||||||
|
"#fbm:edit",
|
||||||
|
"#healthchecks:edit",
|
||||||
|
"#stream:edit",
|
||||||
|
"#lb:edit",
|
||||||
|
"#healthchecks:read",
|
||||||
|
"#billing:edit",
|
||||||
|
"#member:edit",
|
||||||
|
"#cfone_read",
|
||||||
|
"#cfone_edit",
|
||||||
|
"#integration:read",
|
||||||
|
"#zaraz:edit",
|
||||||
|
"#magic:read",
|
||||||
|
"#magic:edit",
|
||||||
|
"#zaraz:read",
|
||||||
|
"#stream:read",
|
||||||
|
"#integration:install",
|
||||||
|
"#dash_sso:edit",
|
||||||
|
"#zone:read",
|
||||||
|
"#http_applications:read",
|
||||||
|
"#http_applications:edit",
|
||||||
|
"#ces_analytics:read",
|
||||||
|
"#resilience:edit",
|
||||||
|
"#teams:edit",
|
||||||
|
"#r2_bucket_warehouse:read",
|
||||||
|
"#r2_bucket_warehouse:edit",
|
||||||
|
"#query_cache:read",
|
||||||
|
"#query_cache:edit",
|
||||||
|
"#dex:read",
|
||||||
|
"#zone_versioning:read",
|
||||||
|
"#zone_versioning:edit",
|
||||||
|
"#cds:read",
|
||||||
|
"#ces_search:action",
|
||||||
|
"#ces_search:read",
|
||||||
|
"#ces_search:preview",
|
||||||
|
"#ces_search:raw",
|
||||||
|
"#ces_search:trace",
|
||||||
|
"#fbm_acc:edit",
|
||||||
|
"#teams:pii",
|
||||||
|
"#r2_bucket_item:read",
|
||||||
|
"#r2_bucket_item:edit",
|
||||||
|
"#integration:edit",
|
||||||
|
"#resilience:read",
|
||||||
|
"#zone:edit",
|
||||||
|
"#dash_sso:read",
|
||||||
|
"#legal:read",
|
||||||
|
"#ces_integration:edit",
|
||||||
|
"#ces_integration:read",
|
||||||
|
"#cache_purge:edit",
|
||||||
|
"#vectorize:read",
|
||||||
|
"#vectorize:edit",
|
||||||
|
"#auditlogs:read",
|
||||||
|
"#teams:report",
|
||||||
|
"#ces_settings:edit",
|
||||||
|
"#ces_settings:read",
|
||||||
|
"#waitingroom:read",
|
||||||
|
"#web3:read",
|
||||||
|
"#web3:edit",
|
||||||
|
"#dex:edit",
|
||||||
|
"#cds_compute_account:read",
|
||||||
|
"#cds:edit",
|
||||||
|
"#r2_bucket:read",
|
||||||
|
"#r2_bucket:edit",
|
||||||
|
"#ces_phishguard:read",
|
||||||
|
"#page_shield:read",
|
||||||
|
"#page_shield:edit",
|
||||||
|
"#legal:edit",
|
||||||
|
"#app:edit"
|
||||||
|
],
|
||||||
|
"plan": {
|
||||||
|
"id": "0feeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
|
||||||
|
"name": "Free Website",
|
||||||
|
"price": 0,
|
||||||
|
"currency": "USD",
|
||||||
|
"frequency": "",
|
||||||
|
"is_subscribed": false,
|
||||||
|
"can_subscribe": false,
|
||||||
|
"legacy_id": "free",
|
||||||
|
"legacy_discount": false,
|
||||||
|
"externally_managed": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"result_info": {
|
||||||
|
"page": 1,
|
||||||
|
"per_page": 20,
|
||||||
|
"total_pages": 1,
|
||||||
|
"count": 1,
|
||||||
|
"total_count": 1
|
||||||
|
},
|
||||||
|
"success": true,
|
||||||
|
"errors": [],
|
||||||
|
"messages": []
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user