diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v3/contenttype/FieldResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v3/contenttype/FieldResource.java
index d2e6477d056e..e3cce2423c14 100644
--- a/dotCMS/src/main/java/com/dotcms/rest/api/v3/contenttype/FieldResource.java
+++ b/dotCMS/src/main/java/com/dotcms/rest/api/v3/contenttype/FieldResource.java
@@ -8,13 +8,20 @@
import com.dotcms.rest.ResponseEntityView;
import com.dotcms.rest.WebResource;
import com.dotcms.rest.annotation.NoCache;
+import com.dotcms.util.filtering.Specification;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.exception.DotSecurityException;
+import com.dotmarketing.util.Logger;
import com.liferay.portal.model.User;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.glassfish.jersey.server.JSONP;
import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
@@ -22,11 +29,13 @@
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -36,6 +45,7 @@
*/
@Path("/v3/contenttype/{typeIdOrVarName}/fields")
public class FieldResource {
+
private final WebResource webResource;
private final ContentTypeFieldLayoutAPI contentTypeFieldLayoutAPI;
@@ -233,4 +243,122 @@ public Response deleteFields(
)
)).build();
}
+
+ /**
+ * Returns the list of fields in a Content Type that meet the specified criteria. For instance,
+ * if you need to retrieve all fields marked as 'required', 'unique'`, and 'system indexed',
+ * you can call the endpoint like this:
+ *
+ * {@code
+ * {{serverURL}}/api/v3/contenttype/AAA/fields/allfields?filter=REQUIRED&filter=SYSTEM_INDEXED&filter=UNIQUE
+ * }
+ *
+ * Just add the same `filter` parameter for each criterion you want to apply.
+ *
+ * @param request The current instance of the {@link HttpServletRequest}.
+ * @param response The current instance of the {@link HttpServletResponse}.
+ * @param typeIdOrVarName The Identifier or Velocity Variable Name of a given
+ * {@link ContentType}.
+ * @param criteria A set of {@link FilteringCriteria} objects that will be used to filter
+ * the fields.
+ *
+ * @return A {@link FieldResponseView} object that contains the list of {@link Field} objects
+ * that meet the specified criteria.
+ *
+ * @throws DotDataException An error occurred when interacting with the database.
+ * @throws DotSecurityException The specified User does not have the necessary permissions to
+ * execute this operation.
+ */
+ @GET
+ @Path("/allfields")
+ @JSONP
+ @NoCache
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces({MediaType.APPLICATION_JSON, "application/javascript"})
+ @Operation(
+ operationId = "allfields",
+ summary = "Returns filtered Content Type fields",
+ description = "Returns the list of fields in a Content Type that meet the specified criteria.",
+ tags = {"Content Type Field"},
+ requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
+ content = @Content(
+ examples = {
+ @ExampleObject(
+ name = "filter",
+ value = "REQUIRED,SYSTEM_INDEXED,UNIQUE,SHOW_IN_LIST,USER_SEARCHABLE",
+ summary = "Filter fields by one or more of the specified criteria"
+ )
+ }
+ )
+ ),
+ responses = {
+ @ApiResponse(responseCode = "200", description = "Content type retrieved successfully",
+ content = @Content(mediaType = "application/json",
+ examples = {
+ @ExampleObject(
+ description = "Returning a list of one Field matching the filtering criteria.",
+ value = "{\n" +
+ " \"entity\": [\n" +
+ " {\n" +
+ " \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableTextField\",\n" +
+ " \"contentTypeId\": \"3b70f386cf65117a675f284eea928415\",\n" +
+ " \"dataType\": \"TEXT\",\n" +
+ " \"dbColumn\": \"text2\",\n" +
+ " \"defaultValue\": null,\n" +
+ " \"fixed\": false,\n" +
+ " \"forceIncludeInApi\": false,\n" +
+ " \"hint\": null,\n" +
+ " \"iDate\": 1732992811000,\n" +
+ " \"id\": \"e39533a92ee05d8c083f7e6a1a5ee5e5\",\n" +
+ " \"indexed\": true,\n" +
+ " \"listed\": false,\n" +
+ " \"modDate\": 1732992838000,\n" +
+ " \"name\": \"Description\",\n" +
+ " \"owner\": null,\n" +
+ " \"readOnly\": false,\n" +
+ " \"regexCheck\": null,\n" +
+ " \"relationType\": null,\n" +
+ " \"required\": true,\n" +
+ " \"searchable\": false,\n" +
+ " \"sortOrder\": 3,\n" +
+ " \"unique\": true,\n" +
+ " \"values\": null,\n" +
+ " \"variable\": \"description\"\n" +
+ " }\n" +
+ " ],\n" +
+ " \"errors\": [],\n" +
+ " \"i18nMessagesMap\": {},\n" +
+ " \"messages\": [],\n" +
+ " \"pagination\": null,\n" +
+ " \"permissions\": []\n" +
+ "}"
+ )
+ }
+ )
+ ),
+ @ApiResponse(responseCode = "400", description = "Bad Request, when using invalid filter names"),
+ @ApiResponse(responseCode = "401", description = "Invalid User"),
+ @ApiResponse(responseCode = "404", description = "Content Type was not found"),
+ @ApiResponse(responseCode = "500", description = "Internal Server Error")
+ }
+ )
+ public FieldResponseView allFieldsBy(@Context final HttpServletRequest request,
+ @Context final HttpServletResponse response,
+ @PathParam("typeIdOrVarName") final String typeIdOrVarName,
+ @QueryParam("filter") final Set criteria) throws DotDataException, DotSecurityException {
+ final InitDataObject initDataObject = new WebResource.InitBuilder(this.webResource)
+ .requestAndResponse(request, response)
+ .requiredBackendUser(true)
+ .rejectWhenNoUser(true)
+ .init();
+ final User user = initDataObject.getUser();
+ Logger.debug(this, () -> String.format("Returning filtered fields from Content Type '%s' " +
+ "using the criteria: %s", typeIdOrVarName, criteria));
+ final ContentType contentType = APILocator.getContentTypeAPI(user).find(typeIdOrVarName);
+ final Specification fieldSpecification = FilteringCriteria.specificationsFrom(criteria);
+ final List filteredFields = contentType.fields().stream().filter(fieldSpecification::isSatisfiedBy)
+ .collect(Collectors.toList());
+ return new FieldResponseView(filteredFields);
+ }
+
}
diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v3/contenttype/FieldResponseView.java b/dotCMS/src/main/java/com/dotcms/rest/api/v3/contenttype/FieldResponseView.java
new file mode 100644
index 000000000000..924db74c1b2f
--- /dev/null
+++ b/dotCMS/src/main/java/com/dotcms/rest/api/v3/contenttype/FieldResponseView.java
@@ -0,0 +1,21 @@
+package com.dotcms.rest.api.v3.contenttype;
+
+import com.dotcms.contenttype.model.field.Field;
+import com.dotcms.rest.ResponseEntityView;
+
+import java.util.List;
+
+/**
+ * This class represents a Response View for objects of type {@link Field}. It's very useful for
+ * returning a list of fields, or a filtered sub-set if necessary.
+ *
+ * @author Jose Castro
+ * @since Nov 29th, 2024
+ */
+public class FieldResponseView extends ResponseEntityView> {
+
+ public FieldResponseView(final List entity) {
+ super(entity);
+ }
+
+}
diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v3/contenttype/FilteringCriteria.java b/dotCMS/src/main/java/com/dotcms/rest/api/v3/contenttype/FilteringCriteria.java
new file mode 100644
index 000000000000..2010d0e15d31
--- /dev/null
+++ b/dotCMS/src/main/java/com/dotcms/rest/api/v3/contenttype/FilteringCriteria.java
@@ -0,0 +1,66 @@
+package com.dotcms.rest.api.v3.contenttype;
+
+import com.dotcms.contenttype.model.field.Field;
+import com.dotcms.util.filtering.Specification;
+import com.dotcms.util.filtering.contenttype.field.CombinedSpecification;
+import com.dotcms.util.filtering.contenttype.field.RequiredSpecification;
+import com.dotcms.util.filtering.contenttype.field.ShowInListSpecification;
+import com.dotcms.util.filtering.contenttype.field.SystemIndexedSpecification;
+import com.dotcms.util.filtering.contenttype.field.UniqueSpecification;
+import com.dotcms.util.filtering.contenttype.field.UserSearchableSpecification;
+
+import java.util.Set;
+
+/**
+ * Enum that represents the different criteria that can be used to filter fields in a Content Type.
+ * This allows you to get a specific list of {@link Field}s from a Content Type that meet your
+ * specified criteria via @{link Specification} classes. In here, you can define as many
+ * Specifications as you need.
+ * The initial specifications represent the default attributes that you can enable for a given
+ * field, such as:
+ *
+ * - Required.
+ * - User Searchable.
+ * - System Indexed.
+ * - Show in List.
+ * - Unique.
+ *
+ *
+ * @author Jose Castro
+ * @since Nov 30th, 2024
+ */
+public enum FilteringCriteria {
+
+ REQUIRED(new RequiredSpecification()),
+ USER_SEARCHABLE(new UserSearchableSpecification()),
+ SYSTEM_INDEXED(new SystemIndexedSpecification()),
+ SHOW_IN_LIST(new ShowInListSpecification()),
+ UNIQUE(new UniqueSpecification());
+
+ final Specification specification;
+
+ FilteringCriteria(final Specification specification) {
+ this.specification = specification;
+ }
+
+ public Specification specification() {
+ return this.specification;
+ }
+
+ /**
+ * Takes the list of criteria that will be used to query for specific fields in a Content Type
+ * and generates the appropriate Specification object to be used in the filtering.
+ *
+ * @param criteria A Set of FilteringCriteria objects that will be used to filter the fields.
+ *
+ * @return The {@link Specification} object that will be used to filter the fields.
+ */
+ public static Specification specificationsFrom(final Set criteria) {
+ Specification mainSpec = new CombinedSpecification();
+ for (final FilteringCriteria criterion : criteria) {
+ mainSpec = mainSpec.and(criterion.specification());
+ }
+ return mainSpec;
+ }
+
+}
diff --git a/dotCMS/src/main/java/com/dotcms/rest/config/DotRestApplication.java b/dotCMS/src/main/java/com/dotcms/rest/config/DotRestApplication.java
index 1c155bc5823b..51f0cc796c68 100644
--- a/dotCMS/src/main/java/com/dotcms/rest/config/DotRestApplication.java
+++ b/dotCMS/src/main/java/com/dotcms/rest/config/DotRestApplication.java
@@ -43,6 +43,7 @@
@Tag(name = "Workflow"),
@Tag(name = "Page"),
@Tag(name = "Content Type"),
+ @Tag(name = "Content Type Field"),
@Tag(name = "Content Delivery"),
@Tag(name = "Bundle"),
@Tag(name = "Navigation"),
diff --git a/dotCMS/src/main/java/com/dotcms/util/filtering/Specification.java b/dotCMS/src/main/java/com/dotcms/util/filtering/Specification.java
new file mode 100644
index 000000000000..348524674fa3
--- /dev/null
+++ b/dotCMS/src/main/java/com/dotcms/util/filtering/Specification.java
@@ -0,0 +1,61 @@
+package com.dotcms.util.filtering;
+
+import java.io.Serializable;
+
+/**
+ * This class represents the base Specification interface for filtering objects that meet given
+ * satisfaction criteria using the Specification Pattern, which is a behavioral pattern
+ * often used to encapsulate filtering logic.
+ * By implementing this interface, you can create your own custom Specification class to filter
+ * objects based on given criteria.
+ *
+ * @param The type of the object to be filtered.
+ *
+ * @author Jose Castro
+ * @since Nov 29th, 2024
+ */
+public interface Specification extends Serializable {
+
+ /**
+ * Determines whether the provided object meets the satisfaction criteria for your Specification
+ * or not.
+ *
+ * @param item The object to be evaluated.
+ *
+ * @return If the object meets your criteria, returns {@code true}.
+ */
+ boolean isSatisfiedBy(final T item);
+
+ /**
+ * Allows you to chain multiple Specifications together using the logical AND operator.
+ *
+ * @param other The other Specification to be chained.
+ *
+ * @return If all chained Specifications are satisfied, returns {@code true}.
+ */
+ default Specification and(final Specification other) {
+ return item -> Specification.this.isSatisfiedBy(item) && other.isSatisfiedBy(item);
+ }
+
+ /**
+ * Allows you to chain multiple Specifications together using the logical OR operator.
+ *
+ * @param other The other Specification to be chained.
+ *
+ * @return If any of the chained Specifications are satisfied, returns {@code true}.
+ */
+ default Specification or(final Specification other) {
+ return item -> this.isSatisfiedBy(item) || other.isSatisfiedBy(item);
+ }
+
+ /**
+ * Allows you to chain multiple Specifications together using the logical NOT operator. This is
+ * particularly useful for excluding objects from your result set.
+ *
+ * @return If the Specification is not satisfied, returns {@code true}.
+ */
+ default Specification not() {
+ return item -> !this.isSatisfiedBy(item);
+ }
+
+}
diff --git a/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/CombinedSpecification.java b/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/CombinedSpecification.java
new file mode 100644
index 000000000000..388547acbdfe
--- /dev/null
+++ b/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/CombinedSpecification.java
@@ -0,0 +1,22 @@
+package com.dotcms.util.filtering.contenttype.field;
+
+import com.dotcms.contenttype.model.field.Field;
+import com.dotcms.util.filtering.Specification;
+
+/**
+ * This simple Specification serves as a base/placeholder for developers to combine multiple
+ * {@link Specification} objects. This is very useful when the given list of Specifications is
+ * dynamic.
+ *
+ * @author Jose Castro
+ * @since Nov 29th, 2024
+ */
+public class CombinedSpecification implements Specification {
+
+ @Override
+ public boolean isSatisfiedBy(final Field field) {
+ // This base Specification returns 'true' by default
+ return true;
+ }
+
+}
diff --git a/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/RequiredSpecification.java b/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/RequiredSpecification.java
new file mode 100644
index 000000000000..aef7a30f35cc
--- /dev/null
+++ b/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/RequiredSpecification.java
@@ -0,0 +1,19 @@
+package com.dotcms.util.filtering.contenttype.field;
+
+import com.dotcms.contenttype.model.field.Field;
+import com.dotcms.util.filtering.Specification;
+
+/**
+ * This Specification is responsible for verifying if a Field is flagged as {@code Required}.
+ *
+ * @author Jose Castro
+ * @since Nov 29th, 2024
+ */
+public class RequiredSpecification implements Specification {
+
+ @Override
+ public boolean isSatisfiedBy(final Field field) {
+ return field.required();
+ }
+
+}
diff --git a/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/ShowInListSpecification.java b/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/ShowInListSpecification.java
new file mode 100644
index 000000000000..6c51684b03a3
--- /dev/null
+++ b/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/ShowInListSpecification.java
@@ -0,0 +1,19 @@
+package com.dotcms.util.filtering.contenttype.field;
+
+import com.dotcms.contenttype.model.field.Field;
+import com.dotcms.util.filtering.Specification;
+
+/**
+ * This Specification is responsible for verifying if a Field is flagged as {@code Show in List}.
+ *
+ * @author Jose Castro
+ * @since Nov 29th, 2024
+ */
+public class ShowInListSpecification implements Specification {
+
+ @Override
+ public boolean isSatisfiedBy(final Field field) {
+ return field.listed();
+ }
+
+}
diff --git a/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/SystemIndexedSpecification.java b/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/SystemIndexedSpecification.java
new file mode 100644
index 000000000000..4aa8e59f151d
--- /dev/null
+++ b/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/SystemIndexedSpecification.java
@@ -0,0 +1,19 @@
+package com.dotcms.util.filtering.contenttype.field;
+
+import com.dotcms.contenttype.model.field.Field;
+import com.dotcms.util.filtering.Specification;
+
+/**
+ * This Specification is responsible for verifying if a Field is flagged as {@code System Indexed}.
+ *
+ * @author Jose Castro
+ * @since Nov 29th, 2024
+ */
+public class SystemIndexedSpecification implements Specification {
+
+ @Override
+ public boolean isSatisfiedBy(final Field field) {
+ return field.indexed();
+ }
+
+}
diff --git a/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/UniqueSpecification.java b/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/UniqueSpecification.java
new file mode 100644
index 000000000000..64675649a0c2
--- /dev/null
+++ b/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/UniqueSpecification.java
@@ -0,0 +1,19 @@
+package com.dotcms.util.filtering.contenttype.field;
+
+import com.dotcms.contenttype.model.field.Field;
+import com.dotcms.util.filtering.Specification;
+
+/**
+ * This Specification is responsible for verifying if a Field is flagged as {@code Unique}.
+ *
+ * @author Jose Castro
+ * @since Nov 29th, 2024
+ */
+public class UniqueSpecification implements Specification {
+
+ @Override
+ public boolean isSatisfiedBy(final Field field) {
+ return field.unique();
+ }
+
+}
diff --git a/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/UserSearchableSpecification.java b/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/UserSearchableSpecification.java
new file mode 100644
index 000000000000..2a28ea000592
--- /dev/null
+++ b/dotCMS/src/main/java/com/dotcms/util/filtering/contenttype/field/UserSearchableSpecification.java
@@ -0,0 +1,20 @@
+package com.dotcms.util.filtering.contenttype.field;
+
+import com.dotcms.contenttype.model.field.Field;
+import com.dotcms.util.filtering.Specification;
+
+/**
+ * This Specification is responsible for verifying if a Field is flagged as
+ * {@code User Searchable}.
+ *
+ * @author Jose Castro
+ * @since Nov 29th, 2024
+ */
+public class UserSearchableSpecification implements Specification {
+
+ @Override
+ public boolean isSatisfiedBy(final Field field) {
+ return field.searchable();
+ }
+
+}
diff --git a/dotcms-postman/src/main/resources/postman/ContentTypeResourceTests.json b/dotcms-postman/src/main/resources/postman/ContentTypeResourceTests.json
index 999a261cdaa7..9bb863b3aeea 100644
--- a/dotcms-postman/src/main/resources/postman/ContentTypeResourceTests.json
+++ b/dotcms-postman/src/main/resources/postman/ContentTypeResourceTests.json
@@ -1,9 +1,10 @@
{
"info": {
- "_postman_id": "c2e4152e-4233-43ae-8e7c-c2e682ade9f8",
+ "_postman_id": "9f75619d-685f-4bdb-b16d-4baa2f6d62d6",
"name": "ContentType Resource",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
- "_exporter_id": "31066048"
+ "_exporter_id": "5403727",
+ "_collection_link": "https://cloudy-robot-285072.postman.co/workspace/JCastro-Workspace~5bfa586e-54db-429b-b7d5-c4ff997e3a0d/collection/5403727-9f75619d-685f-4bdb-b16d-4baa2f6d62d6?action=share&source=collection_link&creator=5403727"
},
"item": [
{
@@ -379,6 +380,546 @@
{
"name": "Test CRUD Fields",
"item": [
+ {
+ "name": "Filtering Fields",
+ "item": [
+ {
+ "name": "Generate Test Data",
+ "item": [
+ {
+ "name": "Create Test Content Type",
+ "event": [
+ {
+ "listen": "prerequest",
+ "script": {
+ "exec": [
+ "pm.collectionVariables.set(\"typeNameWithMetadata\", \"test-type-\" + \"{{$randomInt}}\");"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ },
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "pm.test(\"Test Content Type was created successfully\", function () {",
+ " const jsonData = pm.response.json();",
+ " const entity = jsonData.entity[0];",
+ " pm.expect(jsonData.errors.length).to.eql(0);",
+ " pm.collectionVariables.set(\"contentTypeId\", entity.id);",
+ "});",
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"defaultType\": false,\n \"icon\": null,\n \"fixed\": false,\n \"system\": false,\n \"clazz\": \"com.dotcms.contenttype.model.type.ImmutableSimpleContentType\",\n \"description\": \"\",\n \"host\": \"48190c8c-42c4-46af-8d1a-0cd5db894797\",\n \"name\": \"My Test CT\",\n \"metadata\": {\n \"edit_mode\": true\n },\n \"systemActionMappings\": {\n \"NEW\": \"\"\n },\n \"workflow\": [\n \"d61a59e1-a49c-46f2-a929-db2b4bfa88b2\"\n ]\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{serverURL}}/api/v1/contenttype",
+ "host": [
+ "{{serverURL}}"
+ ],
+ "path": [
+ "api",
+ "v1",
+ "contenttype"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Add Fields to Content Type",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "pm.test(\"Test Content Type Fields were created successfully\", function () {",
+ " const jsonData = pm.response.json();",
+ " pm.expect(jsonData.errors.length).to.eql(0);",
+ "});",
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "PUT",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"layout\": [\n {\n \"divider\": {\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableRowField\",\n \"contentTypeId\": \"{{contentTypeId}}\",\n \"dataType\": \"SYSTEM\",\n \"fieldContentTypeProperties\": [],\n \"fieldType\": \"Row\",\n \"fieldTypeLabel\": \"Row\",\n \"fieldVariables\": [],\n \"fixed\": false,\n \"forceIncludeInApi\": false,\n \"iDate\": 1705078587000,\n \"indexed\": false,\n \"listed\": false,\n \"modDate\": 1705078587000,\n \"name\": \"Row Field\",\n \"readOnly\": false,\n \"required\": false,\n \"searchable\": false,\n \"sortOrder\": -1,\n \"unique\": false\n },\n \"columns\": [\n {\n \"columnDivider\": {\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableColumnField\",\n \"dataType\": \"SYSTEM\",\n \"fieldContentTypeProperties\": [],\n \"fieldType\": \"Column\",\n \"fieldTypeLabel\": \"Column\",\n \"fieldVariables\": [],\n \"fixed\": false,\n \"forceIncludeInApi\": false,\n \"iDate\": 1705078587000,\n \"indexed\": false,\n \"listed\": false,\n \"modDate\": 1705078587000,\n \"name\": \"Column Field\",\n \"readOnly\": false,\n \"required\": false,\n \"searchable\": false,\n \"sortOrder\": -1,\n \"unique\": false\n },\n \"fields\": [\n {\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableTextField\",\n \"name\": \"Title\",\n \"dataType\": \"TEXT\",\n \"regexCheck\": \"\",\n \"defaultValue\": \"\",\n \"hint\": \"\",\n \"required\": true,\n \"searchable\": true,\n \"listed\": true,\n \"unique\": false,\n \"id\": null\n },\n {\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableTextField\",\n \"name\": \"Description\",\n \"dataType\": \"TEXT\",\n \"regexCheck\": \"\",\n \"defaultValue\": \"\",\n \"hint\": \"\",\n \"required\": false,\n \"searchable\": true,\n \"listed\": false,\n \"unique\": false,\n \"id\": null\n }\n ]\n }\n ]\n }\n ]\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{serverURL}}/api/v3/contenttype/{{contentTypeId}}/fields/move",
+ "host": [
+ "{{serverURL}}"
+ ],
+ "path": [
+ "api",
+ "v3",
+ "contenttype",
+ "{{contentTypeId}}",
+ "fields",
+ "move"
+ ]
+ }
+ },
+ "response": []
+ }
+ ],
+ "event": [
+ {
+ "listen": "prerequest",
+ "script": {
+ "type": "text/javascript",
+ "packages": {},
+ "exec": [
+ ""
+ ]
+ }
+ },
+ {
+ "listen": "test",
+ "script": {
+ "type": "text/javascript",
+ "packages": {},
+ "exec": [
+ "pm.test(\"HTTP Status code must be successful\", function () {",
+ " pm.response.to.have.status(200);",
+ "});",
+ ""
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "name": "Success",
+ "item": [
+ {
+ "name": "Filter By Required Fields",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "pm.test(\"Data was returned successfully\", function () {",
+ " const jsonData = pm.response.json();",
+ " pm.expect(jsonData.errors.length).to.eql(0);",
+ "});",
+ "",
+ "pm.test(\"There must be only one 'Required' field\", function () {",
+ " const entity = pm.response.json().entity;",
+ " pm.expect(entity.length).to.equal(1, \"Just one field must be marked as 'Required'\");",
+ "});",
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{serverURL}}/api/v3/contenttype/{{contentTypeId}}/fields/allfields?filter=REQUIRED",
+ "host": [
+ "{{serverURL}}"
+ ],
+ "path": [
+ "api",
+ "v3",
+ "contenttype",
+ "{{contentTypeId}}",
+ "fields",
+ "allfields"
+ ],
+ "query": [
+ {
+ "key": "filter",
+ "value": "REQUIRED"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Filter By Indexed Fields",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "pm.test(\"Data was returned successfully\", function () {",
+ " const jsonData = pm.response.json();",
+ " pm.expect(jsonData.errors.length).to.eql(0);",
+ "});",
+ "",
+ "pm.test(\"There must be two 'System Indexed' fields\", function () {",
+ " const entity = pm.response.json().entity;",
+ " pm.expect(entity.length).to.equal(2, \"Two fields must be marked as 'System Indexed'\");",
+ "});",
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{serverURL}}/api/v3/contenttype/{{contentTypeId}}/fields/allfields?filter=SYSTEM_INDEXED",
+ "host": [
+ "{{serverURL}}"
+ ],
+ "path": [
+ "api",
+ "v3",
+ "contenttype",
+ "{{contentTypeId}}",
+ "fields",
+ "allfields"
+ ],
+ "query": [
+ {
+ "key": "filter",
+ "value": "SYSTEM_INDEXED"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Filter By Several Criteria",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "pm.test(\"Data was returned successfully\", function () {",
+ " const jsonData = pm.response.json();",
+ " pm.expect(jsonData.errors.length).to.eql(0);",
+ "});",
+ "",
+ "pm.test(\"There must be only one 'Required', 'User Searchable', and 'Show in List' field\", function () {",
+ " const entity = pm.response.json().entity;",
+ " pm.expect(entity.length).to.equal(1, \"Just one field must be marked as 'Required', 'User Searchable', and 'Show in List' field\");",
+ "});",
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{serverURL}}/api/v3/contenttype/{{contentTypeId}}/fields/allfields?filter=REQUIRED&filter=USER_SEARCHABLE&filter=SHOW_IN_LIST",
+ "host": [
+ "{{serverURL}}"
+ ],
+ "path": [
+ "api",
+ "v3",
+ "contenttype",
+ "{{contentTypeId}}",
+ "fields",
+ "allfields"
+ ],
+ "query": [
+ {
+ "key": "filter",
+ "value": "REQUIRED"
+ },
+ {
+ "key": "filter",
+ "value": "USER_SEARCHABLE"
+ },
+ {
+ "key": "filter",
+ "value": "SHOW_IN_LIST"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Filter By Non-met Criteria",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "pm.test(\"Data was returned successfully\", function () {",
+ " const jsonData = pm.response.json();",
+ " pm.expect(jsonData.errors.length).to.eql(0);",
+ "});",
+ "",
+ "pm.test(\"No field must match 'Required', 'User Searchable', 'Show in List' and 'Unique'\", function () {",
+ " const entity = pm.response.json().entity;",
+ " pm.expect(entity.length).to.equal(0, \"No field must match the four specified filters\");",
+ "});",
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{serverURL}}/api/v3/contenttype/{{contentTypeId}}/fields/allfields?filter=REQUIRED&filter=USER_SEARCHABLE&filter=SHOW_IN_LIST&filter=UNIQUE",
+ "host": [
+ "{{serverURL}}"
+ ],
+ "path": [
+ "api",
+ "v3",
+ "contenttype",
+ "{{contentTypeId}}",
+ "fields",
+ "allfields"
+ ],
+ "query": [
+ {
+ "key": "filter",
+ "value": "REQUIRED"
+ },
+ {
+ "key": "filter",
+ "value": "USER_SEARCHABLE"
+ },
+ {
+ "key": "filter",
+ "value": "SHOW_IN_LIST"
+ },
+ {
+ "key": "filter",
+ "value": "UNIQUE"
+ }
+ ]
+ }
+ },
+ "response": []
+ }
+ ],
+ "event": [
+ {
+ "listen": "prerequest",
+ "script": {
+ "type": "text/javascript",
+ "packages": {},
+ "exec": [
+ ""
+ ]
+ }
+ },
+ {
+ "listen": "test",
+ "script": {
+ "type": "text/javascript",
+ "packages": {},
+ "exec": [
+ "pm.test(\"HTTP Status code must be successful\", function () {",
+ " pm.response.to.have.status(200);",
+ "});",
+ ""
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "name": "Failure",
+ "item": [
+ {
+ "name": "Log User out",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{serverURL}}/dotAdmin/logout",
+ "host": [
+ "{{serverURL}}"
+ ],
+ "path": [
+ "dotAdmin",
+ "logout"
+ ]
+ },
+ "description": "This request just makes sure that the next request does NOT have an authenticated User."
+ },
+ "response": []
+ },
+ {
+ "name": "No Authentication",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "pm.test(\"HTTP Status code must be 'Unauthorized'\", function () {",
+ " pm.response.to.have.status(401);",
+ "});",
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "auth": {
+ "type": "noauth"
+ },
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{serverURL}}/api/v3/contenttype/{{contentTypeId}}/fields/allfields?filter=REQUIRED",
+ "host": [
+ "{{serverURL}}"
+ ],
+ "path": [
+ "api",
+ "v3",
+ "contenttype",
+ "{{contentTypeId}}",
+ "fields",
+ "allfields"
+ ],
+ "query": [
+ {
+ "key": "filter",
+ "value": "REQUIRED"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Using Invalid Filter",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "pm.test(\"HTTP Status code must be 'Bad Request'\", function () {",
+ " pm.response.to.have.status(400);",
+ "});",
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{serverURL}}/api/v3/contenttype/{{contentTypeId}}/fields/allfields?filter=INVALID_FILTER",
+ "host": [
+ "{{serverURL}}"
+ ],
+ "path": [
+ "api",
+ "v3",
+ "contenttype",
+ "{{contentTypeId}}",
+ "fields",
+ "allfields"
+ ],
+ "query": [
+ {
+ "key": "filter",
+ "value": "INVALID_FILTER"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Using Invalid Content Type",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "pm.test(\"HTTP Status code must be 'Not Found'\", function () {",
+ " pm.response.to.have.status(404);",
+ "});",
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{serverURL}}/api/v3/contenttype/INVALID_CONTENT_TYPE/fields/allfields?filter=REQUIRED",
+ "host": [
+ "{{serverURL}}"
+ ],
+ "path": [
+ "api",
+ "v3",
+ "contenttype",
+ "INVALID_CONTENT_TYPE",
+ "fields",
+ "allfields"
+ ],
+ "query": [
+ {
+ "key": "filter",
+ "value": "REQUIRED"
+ }
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ }
+ ]
+ },
{
"name": "Create ContentType",
"event": [
@@ -13486,95 +14027,5 @@
]
}
}
- ],
- "variable": [
- {
- "key": "testDetailPagePageId1",
- "value": ""
- },
- {
- "key": "testDetailPagePageURL1",
- "value": ""
- },
- {
- "key": "testDetailPagePageId2",
- "value": ""
- },
- {
- "key": "testDetailPagePageURL2",
- "value": ""
- },
- {
- "key": "testDetailPagePageInode1",
- "value": ""
- },
- {
- "key": "testDetailPagePageInode2",
- "value": ""
- },
- {
- "key": "contentTypeID",
- "value": ""
- },
- {
- "key": "contentTypeVAR",
- "value": ""
- },
- {
- "key": "contentTypeFieldID",
- "value": ""
- },
- {
- "key": "pageDetailSiteId",
- "value": ""
- },
- {
- "key": "pageDetailSiteName",
- "value": ""
- },
- {
- "key": "contentTypeId",
- "value": ""
- },
- {
- "key": "pageDetailPageId1",
- "value": ""
- },
- {
- "key": "pageDetailPageInode1",
- "value": ""
- },
- {
- "key": "pageDetailPageURL1",
- "value": ""
- },
- {
- "key": "pageDetailPageId2",
- "value": ""
- },
- {
- "key": "pageDetailPageInode2",
- "value": ""
- },
- {
- "key": "pageDetailPageURL2",
- "value": ""
- },
- {
- "key": "contentTypeVariable",
- "value": ""
- },
- {
- "key": "contentTypeField1Id",
- "value": ""
- },
- {
- "key": "contentTypeField1Variable",
- "value": ""
- },
- {
- "key": "skipPreResquest",
- "value": ""
- }
]
}
\ No newline at end of file