From f60c7cad560f706653525f162bb8fd7fc350d098 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Mon, 13 Apr 2026 15:57:50 -0600 Subject: [PATCH 01/38] Content types APIs v2 --- src/main/api/studio-api.yaml | 267 +++++++++--------- .../scripts/api/ContentServices.groovy | 5 - .../scripts/api/ContentTypeServices.groovy | 60 ---- .../content/SpringContentTypeServices.groovy | 49 ---- .../api/1/content/get-content-type.get.groovy | 55 ---- .../1/content/get-content-types.get.groovy | 58 ---- 6 files changed, 134 insertions(+), 360 deletions(-) delete mode 100644 src/main/webapp/default-site/scripts/api/ContentTypeServices.groovy delete mode 100644 src/main/webapp/default-site/scripts/api/impl/content/SpringContentTypeServices.groovy delete mode 100644 src/main/webapp/default-site/scripts/rest/api/1/content/get-content-type.get.groovy delete mode 100644 src/main/webapp/default-site/scripts/rest/api/1/content/get-content-types.get.groovy diff --git a/src/main/api/studio-api.yaml b/src/main/api/studio-api.yaml index ec85208c2b..f39f82805e 100644 --- a/src/main/api/studio-api.yaml +++ b/src/main/api/studio-api.yaml @@ -2360,95 +2360,6 @@ paths: '500': $ref: '#/components/responses/InternalServerError' - /api/1/services/api/1/content/get-content-type.json: - get: - tags: - - content - summary: Get content type configuration. - description: "Required role: N/A" - operationId: getContentType - parameters: - - name: site_id - in: query - description: Project/Site ID to use - required: true - schema: - type: string - - name: type - in: query - schema: - type: string - description: Content type - required: true - example: /page/category-landing - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/ContentType' - example: - name: "/page/category-landing" - label: "Category Landing" - form: "/page/category-landing" - formPath: "simple" - type: "page" - contentAsFolder: true - useRoundedFolder: false - modelInstancePath: "NOT-USED-BY-SIMPLE-FORM-ENGINE" - allowedRoles: [ ] - lastUpdated: "2023-11-10T18:00:05.882948Z" - copyDependencyPattern: [ ] - imageThumbnail: "page-category-landing.png" - noThumbnail: false - pathIncludes: [ "^/site/website/(?!articles/)(.*)" ] - pathExcludes: [ ] - nodeRef: "null" - quickCreate: false - quickCreatePath: "" - deleteDependencyPattern: [ ] - previewable: true - '400': - $ref: '#/components/responses/api1BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - - /api/1/services/api/1/content/get-content-types.json: - get: - tags: - - content - summary: Get content types allowed for given path. - description: "Required role: N/A" - operationId: getContentTypes - parameters: - - name: site - in: query - description: Project/Site ID to use - required: true - schema: - type: string - - name: path - in: query - schema: - type: string - description: Path to get content types for - required: true - example: /site/website/ - responses: - '200': - description: OK - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ContentType' - '400': - $ref: '#/components/responses/api1BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - /api/1/services/api/1/content/get-item-orders.json: get: tags: @@ -3988,6 +3899,94 @@ paths: '500': $ref: '#/components/responses/InternalServerError' + /api/2/configuration/content-type/{siteId}/allowed_types: + get: + tags: + - contentTypes + summary: Get allowed content types for a given site at a given path + description: 'Required permission "content_read"' + operationId: getAllowedContentTypes + parameters: + - name: siteId + in: path + description: site ID + required: true + schema: + type: string + - name: path + in: query + required: true + schema: + type: string + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + response: + $ref: '#/components/schemas/ApiResponse' + allowedTypes: + type: array + items: + type: string + example: + - "page/article" + - "page/news" + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + + /api/2/configuration/content_type/{siteId}: + get: + tags: + - contentTypes + summary: Get content type configuration file for a given content type + description: 'Required permission "content_read"' + operationId: getContentTypeConfiguration + parameters: + - name: siteId + in: path + description: site ID + required: true + schema: + type: string + - name: contentTypeId + in: query + schema: + type: string + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + response: + $ref: '#/components/schemas/ApiResponse' + contentType: + $ref: '#/components/schemas/ContentType' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + /api/2/configuration/content-type/form_controller: get: tags: @@ -10515,77 +10514,79 @@ components: ContentType: type: object + description: Represents a content type in the system. properties: - name: + id: type: string - description: The site content name + description: Unique identifier for the content type. label: type: string - description: The content type display name - form: - type: string - description: The content type form - formPath: - type: string - description: The content type form path + description: Human-readable label for the content type. type: type: string - description: The type, e.g. page, component, etc - contentAsFolder: - type: boolean - description: "Indicates whether to create content in a folder wrapper e.g. pageUrl: 101 means 101\\/index.xml instead of 101.xml" - useRoundedFolder: - type: boolean - description: Indicates whether use rounded folder to arrange content - modelInstancePath: - type: string - description: The path to the model instance file (WCM) + description: The type of content. + enum: [PAGE, COMPONENT, UNKNOWN] allowedRoles: type: array + description: Set of roles allowed to access this content type. items: - type: string - description: The list of roles allowed - lastUpdated: - type: string - description: The date the content type was last updated - copyDependencyPattern: + type: object + description: Role allowed to access the content type. + properties: + name: + type: string + description: Name of the role. + deleteDependencies: type: array + description: List of dependencies to delete with this content type. items: - type: string - description: The list of copy association patterns + type: object + description: Dependency to delete with the content type. + properties: + pattern: + type: string + description: Pattern for the dependency to delete. + removeEmptyFolder: + type: boolean + description: Whether to remove the folder if it becomes empty after deletion. + copyDependencies: + type: array + description: List of dependencies to copy with this content type. + items: + type: object + description: Dependency to copy with the content type. + properties: + pattern: + type: string + description: Pattern for the dependency to copy. + target: + type: string + description: Target path for the copied dependency. + previewable: + type: boolean + description: Whether the content type is previewable. imageThumbnail: type: string - description: The thumbnail image file to be displayed + description: Path or URL to the thumbnail image. noThumbnail: type: boolean - description: Indicates whether content type has a thumbnail + description: Whether the content type has no thumbnail. pathIncludes: type: array items: type: string - description: The the list of included paths + description: List of path patterns to include. pathExcludes: type: array items: type: string - description: The the list of excluded paths - nodeRef: - type: string - description: The configuration noderef this content type is associated with + description: List of path patterns to exclude. quickCreate: type: boolean - description: Indicates whether the content type is available from the quick create button + description: Whether quick create is enabled for this content type. quickCreatePath: type: string - description: The destination path pattern of content type - deleteDependencyPattern: - type: array - items: - type: string - description: The list of delete association patterns that this content type is dependent on for deleting indexes in webproject - previewable: - type: boolean - description: Indicates whether the content type is previewable + description: Path to use for quick create. ContentItemV1: type: object diff --git a/src/main/webapp/default-site/scripts/api/ContentServices.groovy b/src/main/webapp/default-site/scripts/api/ContentServices.groovy index ff6c276506..d5e0b85323 100644 --- a/src/main/webapp/default-site/scripts/api/ContentServices.groovy +++ b/src/main/webapp/default-site/scripts/api/ContentServices.groovy @@ -66,11 +66,6 @@ class ContentServices { return contentServicesImpl.getContentVersionAtPath(site, path, version) } - static getContentType(context, site, type) { - def contentTypeServicesImpl = ServiceFactory.getContentTypeServices(context); - return contentTypeServicesImpl.getContentType(site, type) - } - static reorderItems(context, site, path, before, after) { def contentServicesImpl = ServiceFactory.getContentServices(context); return contentServicesImpl.reorderItems(site, path, before, after); diff --git a/src/main/webapp/default-site/scripts/api/ContentTypeServices.groovy b/src/main/webapp/default-site/scripts/api/ContentTypeServices.groovy deleted file mode 100644 index 2efffde3e3..0000000000 --- a/src/main/webapp/default-site/scripts/api/ContentTypeServices.groovy +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package scripts.api -/** - * content type services - */ -class ContentTypeServices { - - /** - * create the context object - * @param applicationContext - studio application's contect (spring container etc) - * @param request - web request if in web request context - */ - static createContext(applicationContext, request) { - return ServiceFactory.createContext(applicationContext, request) - } - - /** - * get all content types for a given site - * @param site - the project ID - * @param searchable - include non-searchable types (true/false) - */ - static getContentTypes(context, site, searchable) { - def contentTypeServiceImpl = ServiceFactory.getContentTypeServices(context) - return contentTypeServiceImpl.getContentTypes(site, searchable) - } - - /** - * get allowed content types for a given path - * @param site - the project ID - * @param path - the path - */ - static getAllowedContentTypesForPath(context, site, path) { - def contentTypeServiceImpl = ServiceFactory.getContentTypeServices(context) - return contentTypeServiceImpl.getAllowedContentTypesForPath(site, path) - } - - /** - * Get a content type definition - * @param site - the Project ID - * @param type - the content type - */ - def getContentType(site, type) { - - } -} diff --git a/src/main/webapp/default-site/scripts/api/impl/content/SpringContentTypeServices.groovy b/src/main/webapp/default-site/scripts/api/impl/content/SpringContentTypeServices.groovy deleted file mode 100644 index 85dc3e4581..0000000000 --- a/src/main/webapp/default-site/scripts/api/impl/content/SpringContentTypeServices.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @author Dejan Brkic - */ -package scripts.api.impl.content; - -/** - * content type services - */ -class SpringContentTypeServices { - - static CONTENT_TYPE_SERVICES_BEAN = "cstudioContentTypeService" - - def context = null - - def SpringContentTypeServices(context) { - this.context = context - } - - def getContentTypes(site, searchable) { - def springBackedService = this.context.applicationContext.get(CONTENT_TYPE_SERVICES_BEAN) - return springBackedService.getAllContentTypes(site, searchable) - } - - def getContentType(site, type) { - def springBackedService = this.context.applicationContext.get(CONTENT_TYPE_SERVICES_BEAN) - return springBackedService.getContentType(site, type) - } - - def getAllowedContentTypesForPath(site, path) { - def springBackedService = this.context.applicationContext.get(CONTENT_TYPE_SERVICES_BEAN) - return springBackedService.getAllowedContentTypesForPath(site, path); - } -} diff --git a/src/main/webapp/default-site/scripts/rest/api/1/content/get-content-type.get.groovy b/src/main/webapp/default-site/scripts/rest/api/1/content/get-content-type.get.groovy deleted file mode 100644 index 5376294cdb..0000000000 --- a/src/main/webapp/default-site/scripts/rest/api/1/content/get-content-type.get.groovy +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @author Dejan Brkic - */ - -import org.apache.commons.lang3.StringUtils -import scripts.api.ContentServices - -def result = [:] -def site = params.site_id -def type = params.type - -/** Validate Parameters */ -def invalidParams = false -def paramsList = [] - -// site_id -try { - if (StringUtils.isEmpty(site)) { - site = params.site - if (StringUtils.isEmpty(site)) { - invalidParams = true - paramsList.add("site_id") - } - } -} catch (Exception e) { - invalidParams = true - paramsList.add("site_id") -} - -if (invalidParams) { - response.setStatus(400) - result.message = "Invalid parameter(s): " + paramsList -} else { - def context = ContentServices.createContext(applicationContext, request) - - result = ContentServices.getContentType(context, site, type) - -} -return result diff --git a/src/main/webapp/default-site/scripts/rest/api/1/content/get-content-types.get.groovy b/src/main/webapp/default-site/scripts/rest/api/1/content/get-content-types.get.groovy deleted file mode 100644 index b970ee355b..0000000000 --- a/src/main/webapp/default-site/scripts/rest/api/1/content/get-content-types.get.groovy +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @author Dejan Brkic - */ - -import org.apache.commons.lang3.StringUtils -import scripts.api.ContentTypeServices - -def result = [:] -def site = params.site -def path = params.path - -/** Validate Parameters */ -def invalidParams = false -def paramsList = [] - -// site_id -try { - if (StringUtils.isEmpty(site)) { - site = params.site - if (StringUtils.isEmpty(site)) { - invalidParams = true - paramsList.add("site_id") - } - } -} catch (Exception e) { - invalidParams = true - paramsList.add("site_id") -} - -if (invalidParams) { - response.setStatus(400) - result.message = "Invalid parameter(s): " + paramsList -} else { - def context = ContentTypeServices.createContext(applicationContext, request) - if (path != null) { - result = ContentTypeServices.getAllowedContentTypesForPath(context, site, path) - } else { - result = ContentTypeServices.getContentTypes(context, site, true) - } - -} -return result From e5c550c949a36d3e889bb0784a25901167bf1134 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Thu, 16 Apr 2026 12:55:19 -0600 Subject: [PATCH 02/38] Fix tests --- .../java/org/craftercms/studio/api/v2/utils/StudioUtils.java | 1 + .../site/ContentTypeControllerUpgradeOperationTest.java | 4 ++-- .../content-type/{ => 5.0/5.0.0}/custom/expected.groovy | 0 .../upgrade/content-type/{ => 5.0/5.0.0}/custom/input.groovy | 0 4 files changed, 3 insertions(+), 2 deletions(-) rename src/test/resources/crafter/studio/upgrade/content-type/{ => 5.0/5.0.0}/custom/expected.groovy (100%) rename src/test/resources/crafter/studio/upgrade/content-type/{ => 5.0/5.0.0}/custom/input.groovy (100%) diff --git a/src/main/java/org/craftercms/studio/api/v2/utils/StudioUtils.java b/src/main/java/org/craftercms/studio/api/v2/utils/StudioUtils.java index d78171b682..0c43f19310 100644 --- a/src/main/java/org/craftercms/studio/api/v2/utils/StudioUtils.java +++ b/src/main/java/org/craftercms/studio/api/v2/utils/StudioUtils.java @@ -116,6 +116,7 @@ public static Path getStudioTemporaryFilesRoot() { * @throws IOException if an error occurs while creating the file */ public static Path createTempFile(String name) throws IOException { + Files.createDirectories(getStudioTemporaryFilesRoot()); return Files.createTempFile(getStudioTemporaryFilesRoot(), UUID.randomUUID().toString(), "." + FilenameUtils.getExtension(name)); } diff --git a/src/test/java/org/craftercms/studio/impl/v2/upgrade/operations/site/ContentTypeControllerUpgradeOperationTest.java b/src/test/java/org/craftercms/studio/impl/v2/upgrade/operations/site/ContentTypeControllerUpgradeOperationTest.java index f4303cbbb2..f84b3db709 100644 --- a/src/test/java/org/craftercms/studio/impl/v2/upgrade/operations/site/ContentTypeControllerUpgradeOperationTest.java +++ b/src/test/java/org/craftercms/studio/impl/v2/upgrade/operations/site/ContentTypeControllerUpgradeOperationTest.java @@ -64,10 +64,10 @@ public void testDefaultScript() throws IOException, UpgradeException { @Test public void testCustomScript() throws UpgradeException, IOException, URISyntaxException { - ClassPathResource inputResource = new ClassPathResource("crafter/studio/upgrade/content-type/custom/input.groovy"); + ClassPathResource inputResource = new ClassPathResource("crafter/studio/upgrade/content-type/5.0/5.0.0/custom/input.groovy"); Path inputScriptFile = createTempFile("controller.groovy", inputResource.getInputStream()); operation.updateFile(mock(StudioUpgradeContext.class), inputScriptFile); - ClassPathResource expectedResource = new ClassPathResource("crafter/studio/upgrade/content-type/custom/expected.groovy"); + ClassPathResource expectedResource = new ClassPathResource("crafter/studio/upgrade/content-type/5.0/5.0.0/custom/expected.groovy"); Assert.assertEquals("Output file does not match ", -1, Files.mismatch(inputScriptFile, Paths.get(expectedResource.getURL().toURI()))); } diff --git a/src/test/resources/crafter/studio/upgrade/content-type/custom/expected.groovy b/src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0/custom/expected.groovy similarity index 100% rename from src/test/resources/crafter/studio/upgrade/content-type/custom/expected.groovy rename to src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0/custom/expected.groovy diff --git a/src/test/resources/crafter/studio/upgrade/content-type/custom/input.groovy b/src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0/custom/input.groovy similarity index 100% rename from src/test/resources/crafter/studio/upgrade/content-type/custom/input.groovy rename to src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0/custom/input.groovy From 36d1d1e87f30a38f29c83e003cb0e3d13e38e5aa Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Wed, 15 Apr 2026 13:36:54 -0600 Subject: [PATCH 03/38] API tweaks --- src/main/api/studio-api.yaml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/api/studio-api.yaml b/src/main/api/studio-api.yaml index f39f82805e..f2791da4c9 100644 --- a/src/main/api/studio-api.yaml +++ b/src/main/api/studio-api.yaml @@ -3899,7 +3899,7 @@ paths: '500': $ref: '#/components/responses/InternalServerError' - /api/2/configuration/content-type/{siteId}/allowed_types: + /api/2/configuration/content-types/{siteId}/allowed_types: get: tags: - contentTypes @@ -3946,11 +3946,11 @@ paths: '500': $ref: '#/components/responses/InternalServerError' - /api/2/configuration/content_type/{siteId}: + /api/2/configuration/content_types/{siteId}: get: tags: - contentTypes - summary: Get content type configuration file for a given content type + summary: Get content type configuration file for a given content type. It gets all content types if no contentTypeId is provided description: 'Required permission "content_read"' operationId: getContentTypeConfiguration parameters: @@ -3974,8 +3974,10 @@ paths: properties: response: $ref: '#/components/schemas/ApiResponse' - contentType: - $ref: '#/components/schemas/ContentType' + contentTypes: + type: array + items: + $ref: '#/components/schemas/ContentType' '400': $ref: '#/components/responses/BadRequest' '401': From 82ec6db371f54c838d4a0c864d19785e869b00f6 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Tue, 21 Apr 2026 11:41:41 -0600 Subject: [PATCH 04/38] Merge config.xml into form-definition.xml --- .../service/content/ContentTypeService.java | 21 + .../rest/v2/ConfigurationController.java | 115 +-- .../rest/v2/ContentTypeController.java | 120 +++ .../rest/v2/RequestMappingConstants.java | 14 + .../controller/rest/v2/ResultConstants.java | 6 + .../content/ContentTypeServiceImpl.java | 17 + .../internal/ContentServiceInternalImpl.java | 1 - .../ContentTypeServiceInternalImpl.java | 23 +- .../ContentTypeConfigMergeUpgrader.java | 87 ++ .../AbstractXsltFileUpgradeOperation.java | 15 +- .../site/BatchXsltFileUpgradeOperation.java | 52 +- .../studio/model/contentType/ContentType.java | 45 + .../model/contentType/CopyDependency.java | 28 + .../model/contentType/DeleteDependency.java | 27 + .../contentType/DeleteContentTypeRequest.java | 61 ++ .../extension/rendering-overlay-context.xml | 3 + .../crafter/studio/studio-upgrade-context.xml | 4 + .../content-type-merge-v5.0.0.2.xslt | 54 ++ .../crafter/studio/upgrade/pipelines.yaml | 7 + .../scripts/api/ServiceFactory.groovy | 11 +- .../content-types/page/article/config.xml | 28 +- .../ContentTypeConfigMergeUpgraderTest.java | 121 +++ .../content-type/5.0/5.0.0.2/config.xml | 50 + .../content-type/5.0/5.0.0.2/expected.xml | 902 ++++++++++++++++++ .../5.0/5.0.0.2/form-definition.xml | 879 +++++++++++++++++ 25 files changed, 2545 insertions(+), 146 deletions(-) create mode 100644 src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java create mode 100644 src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/contentType/ContentTypeConfigMergeUpgrader.java create mode 100644 src/main/java/org/craftercms/studio/model/contentType/ContentType.java create mode 100644 src/main/java/org/craftercms/studio/model/contentType/CopyDependency.java create mode 100644 src/main/java/org/craftercms/studio/model/contentType/DeleteDependency.java create mode 100644 src/main/java/org/craftercms/studio/model/rest/contentType/DeleteContentTypeRequest.java create mode 100644 src/main/resources/crafter/studio/upgrade/5.0.x/content-type/content-type-merge-v5.0.0.2.xslt create mode 100644 src/test/java/org/craftercms/studio/impl/v2/upgrade/operations/contentType/ContentTypeConfigMergeUpgraderTest.java create mode 100644 src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0.2/config.xml create mode 100644 src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0.2/expected.xml create mode 100644 src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0.2/form-definition.xml diff --git a/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java b/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java index 1edfee9494..3b32aeb701 100644 --- a/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java +++ b/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java @@ -17,9 +17,12 @@ import org.apache.commons.lang3.tuple.ImmutablePair; import org.craftercms.studio.api.v1.exception.ServiceLayerException; +import org.craftercms.studio.api.v1.exception.SiteNotFoundException; import org.craftercms.studio.api.v1.exception.security.AuthenticationException; import org.craftercms.studio.api.v1.exception.security.UserNotFoundException; +import org.craftercms.studio.api.v1.to.ContentTypeConfigTO; import org.craftercms.studio.api.v2.dal.QuickCreateItem; +import org.craftercms.studio.model.contentType.ContentType; import org.craftercms.studio.model.contentType.ContentTypeUsage; import org.springframework.core.io.Resource; @@ -109,4 +112,22 @@ void deleteContentType(String siteId, String contentType, boolean deleteDependen * @return List of quick creatable content types */ List getQuickCreatableContentTypes(String siteId) throws ServiceLayerException; + + /** + * Get the content type configuration for a given content type id + * + * @param siteId the id of the site + * @param contentTypeId the id of the content type + * @return the content type configuration + */ + ContentType getContentType(String siteId, String contentTypeId) throws SiteNotFoundException; + + /** + * Get a collection of the ids of the content types allowed for the given site and path + * + * @param siteId the id of the site + * @param path the path of the content item to be created + * @return a collection of the ids of the content types allowed for the given site and path + */ + Collection getAllowedContentTypes(String siteId, String path); } diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/ConfigurationController.java b/src/main/java/org/craftercms/studio/controller/rest/v2/ConfigurationController.java index c443de8dcb..b466f009a4 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/ConfigurationController.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/ConfigurationController.java @@ -16,10 +16,7 @@ package org.craftercms.studio.controller.rest.v2; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import jakarta.validation.Valid; import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.tuple.ImmutablePair; import org.craftercms.commons.validation.annotations.param.EsapiValidatedParam; import org.craftercms.commons.validation.annotations.param.ValidConfigurationPath; import org.craftercms.commons.validation.annotations.param.ValidSiteId; @@ -28,9 +25,7 @@ import org.craftercms.studio.api.v1.exception.security.UserNotFoundException; import org.craftercms.studio.api.v2.annotation.LogExecutionTime; import org.craftercms.studio.api.v2.service.config.ConfigurationService; -import org.craftercms.studio.api.v2.service.content.ContentTypeService; import org.craftercms.studio.api.v2.utils.StudioConfiguration; -import org.craftercms.studio.api.v2.utils.StudioUtils; import org.craftercms.studio.model.config.TranslationConfiguration; import org.craftercms.studio.model.rest.ConfigurationHistory; import org.craftercms.studio.model.rest.Result; @@ -38,9 +33,6 @@ import org.craftercms.studio.model.rest.WriteConfigurationRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.core.io.Resource; -import org.springframework.http.HttpHeaders; -import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -51,30 +43,28 @@ import static org.apache.commons.lang3.Strings.CS; import static org.craftercms.commons.validation.annotations.param.EsapiValidationType.ALPHANUMERIC; import static org.craftercms.studio.api.v2.utils.StudioConfiguration.CONFIGURATION_GLOBAL_SYSTEM_SITE; -import static org.craftercms.studio.controller.rest.v2.ResultConstants.*; -import static org.craftercms.studio.model.rest.ApiResponse.DELETED; +import static org.craftercms.studio.controller.rest.v2.RequestMappingConstants.*; +import static org.craftercms.studio.controller.rest.v2.ResultConstants.RESULT_KEY_CONFIG; +import static org.craftercms.studio.controller.rest.v2.ResultConstants.RESULT_KEY_HISTORY; import static org.craftercms.studio.model.rest.ApiResponse.OK; @Validated @RestController -@RequestMapping("/api/2/configuration") +@RequestMapping(API_2 + CONFIGURATION) public class ConfigurationController { private final ConfigurationService configurationService; private final StudioConfiguration studioConfiguration; - private final ContentTypeService contentTypeService; @SuppressWarnings("unused") private static final Logger logger = LoggerFactory.getLogger(ConfigurationController.class); - @ConstructorProperties({"configurationService", "studioConfiguration", "contentTypeService"}) - public ConfigurationController(ConfigurationService configurationService, StudioConfiguration studioConfiguration, - ContentTypeService contentTypeService) { + @ConstructorProperties({"configurationService", "studioConfiguration"}) + public ConfigurationController(ConfigurationService configurationService, StudioConfiguration studioConfiguration) { this.configurationService = configurationService; this.studioConfiguration = studioConfiguration; - this.contentTypeService = contentTypeService; } - @GetMapping("clear_cache") + @GetMapping(CLEAR_CACHE) public Result clearCache(@ValidSiteId @RequestParam String siteId) { configurationService.invalidateConfiguration(siteId); var result = new Result(); @@ -82,7 +72,7 @@ public Result clearCache(@ValidSiteId @RequestParam String siteId) { return result; } - @GetMapping("/get_configuration") + @GetMapping(GET_CONFIGURATION) @LogExecutionTime public ResultOne getConfiguration(@ValidSiteId @RequestParam(name = "siteId", required = true) String siteId, @EsapiValidatedParam(type = ALPHANUMERIC) @RequestParam(name = "module", required = true) String module, @@ -102,7 +92,7 @@ public ResultOne getConfiguration(@ValidSiteId @RequestParam(name = "sit return result; } - @PostMapping("/write_configuration") + @PostMapping(WRITE_CONFIGURATION) public Result writeConfiguration(@Validated @RequestBody WriteConfigurationRequest wcRequest) throws ServiceLayerException, UserNotFoundException, AuthenticationException { InputStream is = IOUtils.toInputStream(wcRequest.getContent(), UTF_8); @@ -118,7 +108,7 @@ public Result writeConfiguration(@Validated @RequestBody WriteConfigurationReque return result; } - @GetMapping("/get_configuration_history") + @GetMapping(GET_CONFIGURATION_HISTORY) public ResultOne getConfigurationHistory(@ValidSiteId @RequestParam(name = "siteId", required = true) String siteId, @EsapiValidatedParam(type = ALPHANUMERIC) @RequestParam(name = "module", required = true) String module, @ValidConfigurationPath @RequestParam(name = "path", required = true) String path, @@ -132,7 +122,7 @@ public ResultOne getConfigurationHistory(@ValidSiteId @Req return result; } - @GetMapping("translation") + @GetMapping(TRANSLATION) public ResultOne getTranslationConfiguration(@ValidSiteId @RequestParam String siteId) throws ServiceLayerException { ResultOne result = new ResultOne<>(); result.setEntity(RESULT_KEY_CONFIG, configurationService.getTranslationConfiguration(siteId)); @@ -140,87 +130,4 @@ public ResultOne getTranslationConfiguration(@ValidSit return result; } - @GetMapping("content-type/usage") - public ResultOne getContentTypeUsage(@ValidSiteId @RequestParam String siteId, - @ValidConfigurationPath @RequestParam String contentType) - throws Exception { - var result = new ResultOne<>(); - result.setResponse(OK); - result.setEntity(RESULT_KEY_USAGE, contentTypeService.getContentTypeUsage(siteId, contentType)); - - return result; - } - - @GetMapping("content-type/form_controller") - public ResponseEntity getContentTypeFormController(@ValidSiteId @RequestParam String siteId, - @ValidConfigurationPath @RequestParam String contentTypeId) throws ServiceLayerException { - ImmutablePair resource = contentTypeService.getContentTypeFormController(siteId, contentTypeId); - return getResourceResponse(resource.getKey(), resource.getValue()); - } - - @GetMapping("content-type/preview_image") - public ResponseEntity getContentTypePreviewImage(@ValidSiteId @RequestParam String siteId, - @ValidConfigurationPath @RequestParam String contentTypeId) - throws ServiceLayerException { - ImmutablePair resource = contentTypeService.getContentTypePreviewImage(siteId, contentTypeId); - return getResourceResponse(resource.getKey(), resource.getValue()); - } - - private ResponseEntity getResourceResponse(String name, Resource resource) { - String mimeType = StudioUtils.getMimeType(name); - - return ResponseEntity - .ok() - .header(HttpHeaders.CONTENT_TYPE, mimeType) - .body(resource); - } - - @PostMapping("content-type/delete") - public Result deleteContentType(@RequestBody @Valid DeleteContentTypeRequest request) - throws ServiceLayerException, AuthenticationException, UserNotFoundException { - contentTypeService.deleteContentType(request.getSiteId(), request.getContentType(), - request.isDeleteDependencies()); - var result = new Result(); - result.setResponse(DELETED); - - return result; - } - - @JsonIgnoreProperties - public static class DeleteContentTypeRequest { - - @ValidSiteId - protected String siteId; - - @ValidConfigurationPath - protected String contentType; - - protected boolean deleteDependencies; - - public String getSiteId() { - return siteId; - } - - public void setSiteId(String siteId) { - this.siteId = siteId; - } - - public String getContentType() { - return contentType; - } - - public void setContentType(String contentType) { - this.contentType = contentType; - } - - public boolean isDeleteDependencies() { - return deleteDependencies; - } - - public void setDeleteDependencies(boolean deleteDependencies) { - this.deleteDependencies = deleteDependencies; - } - - } - } diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java b/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java new file mode 100644 index 0000000000..9d6e2b07cb --- /dev/null +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.controller.rest.v2; + +import jakarta.validation.Valid; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.craftercms.commons.validation.annotations.param.ValidConfigurationPath; +import org.craftercms.commons.validation.annotations.param.ValidExistingContentPath; +import org.craftercms.commons.validation.annotations.param.ValidSiteId; +import org.craftercms.studio.api.v1.exception.ServiceLayerException; +import org.craftercms.studio.api.v1.exception.SiteNotFoundException; +import org.craftercms.studio.api.v1.exception.security.AuthenticationException; +import org.craftercms.studio.api.v1.exception.security.UserNotFoundException; +import org.craftercms.studio.api.v2.service.content.ContentTypeService; +import org.craftercms.studio.api.v2.utils.StudioUtils; +import org.craftercms.studio.model.contentType.ContentType; +import org.craftercms.studio.model.rest.Result; +import org.craftercms.studio.model.rest.ResultList; +import org.craftercms.studio.model.rest.ResultOne; +import org.craftercms.studio.model.rest.contentType.DeleteContentTypeRequest; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.beans.ConstructorProperties; + +import static org.craftercms.studio.controller.rest.v2.RequestMappingConstants.*; +import static org.craftercms.studio.controller.rest.v2.ResultConstants.*; +import static org.craftercms.studio.model.rest.ApiResponse.DELETED; +import static org.craftercms.studio.model.rest.ApiResponse.OK; + +@Validated +@RestController +@RequestMapping(API_2 + CONFIGURATION + CONTENT_TYPE) +public class ContentTypeController { + private final ContentTypeService contentTypeService; + + @ConstructorProperties("contentTypeService") + public ContentTypeController(ContentTypeService contentTypeService) { + this.contentTypeService = contentTypeService; + } + + @GetMapping(USAGE) + public ResultOne getContentTypeUsage(@ValidSiteId @RequestParam String siteId, + @ValidConfigurationPath @RequestParam String contentType) + throws Exception { + var result = new ResultOne<>(); + result.setResponse(OK); + result.setEntity(RESULT_KEY_USAGE, contentTypeService.getContentTypeUsage(siteId, contentType)); + + return result; + } + + @GetMapping(FORM_CONTROLLER) + public ResponseEntity getContentTypeFormController(@ValidSiteId @RequestParam String siteId, + @ValidConfigurationPath @RequestParam String contentTypeId) throws ServiceLayerException { + ImmutablePair resource = contentTypeService.getContentTypeFormController(siteId, contentTypeId); + return getResourceResponse(resource.getKey(), resource.getValue()); + } + + @GetMapping(PREVIEW_IMAGE) + public ResponseEntity getContentTypePreviewImage(@ValidSiteId @RequestParam String siteId, + @ValidConfigurationPath @RequestParam String contentTypeId) + throws ServiceLayerException { + ImmutablePair resource = contentTypeService.getContentTypePreviewImage(siteId, contentTypeId); + return getResourceResponse(resource.getKey(), resource.getValue()); + } + + @GetMapping(SITE_ID) + public ResultOne getContentType(@ValidSiteId @PathVariable String siteId, + @ValidConfigurationPath @RequestParam String contentTypeId) throws SiteNotFoundException { + var result = new ResultOne(); + result.setResponse(OK); + result.setEntity(RESULT_KEY_CONTENT_TYPE, contentTypeService.getContentType(siteId, contentTypeId)); + return result; + } + + @GetMapping(SITE_ID + ALLOWED_TYPES) + public ResultList getAllowedContentTypes(@ValidSiteId @PathVariable String siteId, @ValidExistingContentPath @RequestParam String path) { + ResultList result = new ResultList<>(); + result.setResponse(OK); + result.setEntities(RESULT_KEY_ALLOWED_TYPES, contentTypeService.getAllowedContentTypes(siteId, path)); + return result; + } + + @PostMapping(DELETE) + public Result deleteContentType(@RequestBody @Valid DeleteContentTypeRequest request) + throws ServiceLayerException, AuthenticationException, UserNotFoundException { + contentTypeService.deleteContentType(request.getSiteId(), request.getContentType(), + request.isDeleteDependencies()); + var result = new Result(); + result.setResponse(DELETED); + return result; + } + + private ResponseEntity getResourceResponse(String name, Resource resource) { + String mimeType = StudioUtils.getMimeType(name); + + return ResponseEntity + .ok() + .header(HttpHeaders.CONTENT_TYPE, mimeType) + .body(resource); + } +} diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java b/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java index 7d9c34d073..9180d38219 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java @@ -164,6 +164,20 @@ public final class RequestMappingConstants { */ public static final String MONITOR = "/monitor"; + /** + * Configuration Controller + */ + public static final String CONFIGURATION = "/configuration"; + public static final String CLEAR_CACHE = "/clear_cache"; + public static final String GET_CONFIGURATION = "/get_configuration"; + public static final String WRITE_CONFIGURATION = "/write_configuration"; + public static final String GET_CONFIGURATION_HISTORY = "/get_configuration_history"; + public static final String TRANSLATION = "/translation"; + public static final String CONTENT_TYPE = "/content-type"; + public static final String USAGE = "/usage"; + public static final String PREVIEW_IMAGE = "/preview_image"; + public static final String FORM_CONTROLLER = "/form_controller"; + public static final String ALLOWED_TYPES = "/allowed_types"; private RequestMappingConstants() { } diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/ResultConstants.java b/src/main/java/org/craftercms/studio/controller/rest/v2/ResultConstants.java index 2040faafa4..502cb7b0d7 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/ResultConstants.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/ResultConstants.java @@ -117,6 +117,12 @@ public final class ResultConstants { */ public static final String RESULT_KEY_MONITORS = "monitors"; + /** + * Content types controller + */ + public static final String RESULT_KEY_CONTENT_TYPE = "contentType"; + public static final String RESULT_KEY_ALLOWED_TYPES = "allowedTypes"; + /** * Exception Handler */ diff --git a/src/main/java/org/craftercms/studio/impl/v2/service/content/ContentTypeServiceImpl.java b/src/main/java/org/craftercms/studio/impl/v2/service/content/ContentTypeServiceImpl.java index 108c015ece..9bbd3ec07e 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/service/content/ContentTypeServiceImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v2/service/content/ContentTypeServiceImpl.java @@ -19,12 +19,15 @@ import org.craftercms.commons.security.permissions.DefaultPermission; import org.craftercms.commons.security.permissions.annotations.HasPermission; import org.craftercms.studio.api.v1.exception.ServiceLayerException; +import org.craftercms.studio.api.v1.exception.SiteNotFoundException; import org.craftercms.studio.api.v1.exception.security.AuthenticationException; import org.craftercms.studio.api.v1.exception.security.UserNotFoundException; +import org.craftercms.studio.api.v2.annotation.ContentPath; import org.craftercms.studio.api.v2.annotation.RequireSiteReady; import org.craftercms.studio.api.v2.annotation.SiteId; import org.craftercms.studio.api.v2.dal.QuickCreateItem; import org.craftercms.studio.api.v2.service.content.ContentTypeService; +import org.craftercms.studio.model.contentType.ContentType; import org.craftercms.studio.model.contentType.ContentTypeUsage; import org.springframework.core.io.Resource; @@ -116,6 +119,20 @@ public List getQuickCreatableContentTypes(@SiteId String siteId return contentTypeServiceInternal.getQuickCreatableContentTypes(siteId); } + @Override + @RequireSiteReady + @HasPermission(type = DefaultPermission.class, action = PERMISSION_CONTENT_READ) + public ContentType getContentType(@SiteId String siteId, String contentTypeId) throws SiteNotFoundException { + return contentTypeServiceInternal.getContentType(siteId, contentTypeId); + } + + @Override + @RequireSiteReady + @HasPermission(type = DefaultPermission.class, action = PERMISSION_CONTENT_READ) + public Collection getAllowedContentTypes(@SiteId String siteId, @ContentPath String path) { + return contentTypeServiceInternal.getAllowedContentTypes(siteId, path); + } + @Override @HasPermission(type = DefaultPermission.class, action = PERMISSION_READ_CONFIGURATION) public String getContentTypeControllerPath(String contentTypeId) { diff --git a/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentServiceInternalImpl.java b/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentServiceInternalImpl.java index 3490cb9cce..0096aafad8 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentServiceInternalImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentServiceInternalImpl.java @@ -94,7 +94,6 @@ import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.Node; -import org.eclipse.jgit.api.errors.GitAPIException; import org.jspecify.annotations.NonNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImpl.java b/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImpl.java index bbfb95e46e..83fa2a1d00 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImpl.java @@ -26,6 +26,7 @@ import org.craftercms.studio.api.v1.exception.SiteNotFoundException; import org.craftercms.studio.api.v1.exception.security.AuthenticationException; import org.craftercms.studio.api.v1.exception.security.UserNotFoundException; +import org.craftercms.studio.api.v1.service.configuration.ServicesConfig; import org.craftercms.studio.api.v1.service.content.ContentTypeService; import org.craftercms.studio.api.v1.service.security.SecurityService; import org.craftercms.studio.api.v1.to.ContentTypeConfigTO; @@ -39,6 +40,7 @@ import org.craftercms.studio.api.v2.service.publish.PublishService; import org.craftercms.studio.api.v2.utils.GitRepositoryHelper; import org.craftercms.studio.impl.v2.utils.security.SecurityUtils; +import org.craftercms.studio.model.contentType.ContentType; import org.craftercms.studio.model.contentType.ContentTypeUsage; import org.dom4j.Document; import org.dom4j.Node; @@ -63,6 +65,7 @@ import static java.lang.String.format; import static java.nio.file.Files.walkFileTree; +import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; import static org.apache.commons.io.FilenameUtils.normalize; @@ -92,13 +95,15 @@ public class ContentTypeServiceInternalImpl implements org.craftercms.studio.api protected final String previewImageXPath; protected final String defaultPreviewImagePath; protected final String formControllerFilePath; + protected final ServicesConfig servicesConfig; private final GitRepositoryHelper gitRepositoryHelper; @ConstructorProperties({"contentTypeService", "securityService", "configurationService", "itemDao", "contentTypeBasePathPattern", "contentTypeDefinitionFilename", "contentTypeConfigFilename", "contentTypesRootPath", "templateXPath", "controllerPattern", "controllerFormat", "previewImageXPath", "defaultPreviewImagePath", - "formControllerFilePath", "gitRepositoryHelper"}) + "formControllerFilePath", "gitRepositoryHelper", + "servicesConfig"}) public ContentTypeServiceInternalImpl(ContentTypeService contentTypeService, SecurityService securityService, ConfigurationService configurationService, ItemDAO itemDao, String contentTypeBasePathPattern, String contentTypeDefinitionFilename, String contentTypeConfigFilename, @@ -106,7 +111,8 @@ public ContentTypeServiceInternalImpl(ContentTypeService contentTypeService, Sec String controllerPattern, String controllerFormat, String previewImageXPath, String defaultPreviewImagePath, String formControllerFilePath, - GitRepositoryHelper gitRepositoryHelper) { + GitRepositoryHelper gitRepositoryHelper, + ServicesConfig servicesConfig) { this.contentTypeService = contentTypeService; this.securityService = securityService; this.configurationService = configurationService; @@ -122,6 +128,7 @@ public ContentTypeServiceInternalImpl(ContentTypeService contentTypeService, Sec this.defaultPreviewImagePath = defaultPreviewImagePath; this.formControllerFilePath = formControllerFilePath; this.gitRepositoryHelper = gitRepositoryHelper; + this.servicesConfig = servicesConfig; } public void setContentService(ContentService contentService) { @@ -152,6 +159,18 @@ public List getQuickCreatableContentTypes(String siteId) throws .collect(toList()); } + @Override + public ContentType getContentType(String siteId, String contentTypeId) throws SiteNotFoundException { + // TODO: implement + return null; + } + + @Override + public Collection getAllowedContentTypes(String siteId, String path) { + // TODO: implement + return emptyList(); + } + @Override public ContentTypeUsage getContentTypeUsage(String siteId, String contentType) throws ServiceLayerException { diff --git a/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/contentType/ContentTypeConfigMergeUpgrader.java b/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/contentType/ContentTypeConfigMergeUpgrader.java new file mode 100644 index 0000000000..2a4644de7a --- /dev/null +++ b/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/contentType/ContentTypeConfigMergeUpgrader.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.impl.v2.upgrade.operations.contentType; + +import org.apache.commons.collections4.ListUtils; +import org.apache.commons.configuration2.HierarchicalConfiguration; +import org.craftercms.commons.upgrade.exception.UpgradeException; +import org.craftercms.studio.api.v2.utils.StudioConfiguration; +import org.craftercms.studio.impl.v2.upgrade.StudioUpgradeContext; +import org.craftercms.studio.impl.v2.upgrade.operations.site.BatchXsltFileUpgradeOperation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.beans.ConstructorProperties; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; + +import static org.craftercms.studio.api.v2.utils.StudioConfiguration.CONFIGURATION_SITE_CONTENT_TYPES_CONFIG_FILE_NAME; + +/** + * Upgrader to merge config.xml into form-definition.xml files for content types. + */ +public class ContentTypeConfigMergeUpgrader extends BatchXsltFileUpgradeOperation { + private static final Logger logger = LoggerFactory.getLogger(ContentTypeConfigMergeUpgrader.class); + + protected static final String CONFIG_FILE_PARAM = "configFileName"; + private String configFileName; + + @ConstructorProperties("studioConfiguration") + public ContentTypeConfigMergeUpgrader(StudioConfiguration studioConfiguration) { + super(studioConfiguration); + } + + @Override + protected void doInit(final HierarchicalConfiguration config) { + super.doInit(config); + configFileName = studioConfiguration.getProperty(CONFIGURATION_SITE_CONTENT_TYPES_CONFIG_FILE_NAME); + } + + @Override + public void doExecute(StudioUpgradeContext context) throws UpgradeException { + super.doExecute(context); + Path repositoryRoot = context.getRepositoryPath(); + for (String deletedFile : ListUtils.emptyIfNull(deletedFiles)) { + logger.info("Deleting config file after merging: {}", deletedFile); + try { + Files.deleteIfExists(repositoryRoot.resolve(deletedFile)); + } catch (IOException e) { + throw new UpgradeException("Error deleting config file after merging: " + deletedFile, e); + } + } + } + + @Override + protected void executeTemplate(StudioUpgradeContext context, String formDefinitionPath, OutputStream os) throws UpgradeException { + logger.info("Executing config merge template for form definition: {}", formDefinitionPath); + super.executeTemplate(context, formDefinitionPath, os); + + Path configFilePath = Path.of(formDefinitionPath).resolveSibling(configFileName); + trackDeletedFiles(configFilePath.toString()); + } + + @Override + protected Map getTemplateParameters(StudioUpgradeContext context, String formDefinitionPath) { + Map params = new HashMap<>(super.getTemplateParameters(context, formDefinitionPath)); + params.put(CONFIG_FILE_PARAM, Path.of(formDefinitionPath).resolveSibling(configFileName)); + return params; + } +} diff --git a/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/AbstractXsltFileUpgradeOperation.java b/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/AbstractXsltFileUpgradeOperation.java index db74f7629f..a028494735 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/AbstractXsltFileUpgradeOperation.java +++ b/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/AbstractXsltFileUpgradeOperation.java @@ -82,7 +82,7 @@ protected void executeTemplate(StudioUpgradeContext context, String path, Output try (InputStream templateIs = template.getInputStream(); InputStream sourceIs = Files.newInputStream(file)) { logger.info("Apply the XSLT template '{}' to file '{}' in site '{}'", template, path, site); - Map params = Map.of(PARAM_KEY_SITE, site, PARAM_KEY_VERSION, nextVersion); + Map params = getTemplateParameters(context, path); XsltUtils.executeTemplate(templateIs, params, getURIResolver(context), sourceIs, os); trackChangedFiles(path); } catch (Exception e) { @@ -93,6 +93,18 @@ protected void executeTemplate(StudioUpgradeContext context, String path, Output } } + /** + * Gets the parameters to be passed to the XSLT template. By default, it includes the site name and the next version, + * but it can be overridden by subclasses to provide additional parameters if needed. + * + * @param context the upgrade context, which can be used to get additional information for the parameters if needed + * @param path the path of the file being upgraded + * @return a map of parameter names and values to be passed to the XSLT template + */ + protected Map getTemplateParameters(StudioUpgradeContext context, String path) { + return Map.of(PARAM_KEY_SITE, context.getTarget(), PARAM_KEY_VERSION, nextVersion); + } + protected URIResolver getURIResolver(StudioUpgradeContext context) { return (href, base) -> { try { @@ -101,7 +113,6 @@ protected URIResolver getURIResolver(StudioUpgradeContext context) { logger.info("Failed to create a resolver for referencing documents inside XSLT forms", e); return null; } - }; } } diff --git a/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/BatchXsltFileUpgradeOperation.java b/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/BatchXsltFileUpgradeOperation.java index d818d05a25..1ca4bdb63a 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/BatchXsltFileUpgradeOperation.java +++ b/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/BatchXsltFileUpgradeOperation.java @@ -16,6 +16,13 @@ package org.craftercms.studio.impl.v2.upgrade.operations.site; +import org.apache.commons.configuration2.HierarchicalConfiguration; +import org.craftercms.commons.upgrade.exception.UpgradeException; +import org.craftercms.studio.api.v2.utils.StudioConfiguration; +import org.craftercms.studio.impl.v2.upgrade.StudioUpgradeContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; @@ -23,15 +30,6 @@ import java.nio.file.StandardCopyOption; import java.util.stream.Stream; -import org.apache.commons.configuration2.HierarchicalConfiguration; -import org.craftercms.commons.upgrade.exception.UpgradeException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.craftercms.studio.api.v2.utils.StudioConfiguration; -import org.craftercms.studio.impl.v2.upgrade.StudioUpgradeContext; - -import javax.sql.DataSource; - import static org.craftercms.studio.api.v2.utils.StudioUtils.getStudioTemporaryFilesRoot; /** @@ -54,7 +52,7 @@ public class BatchXsltFileUpgradeOperation extends AbstractXsltFileUpgradeOperat protected String regex; - public BatchXsltFileUpgradeOperation(StudioConfiguration studioConfiguration, DataSource dataSource) { + public BatchXsltFileUpgradeOperation(StudioConfiguration studioConfiguration) { super(studioConfiguration); } @@ -64,24 +62,33 @@ protected void doInit(final HierarchicalConfiguration config) { regex = config.getString(CONFIG_KEY_REGEX); } + /** + * Finds all files in the repository that match the regex. + * + * @param repository the repository path + * @return a stream of paths that match the regex + * @throws IOException if an error occurs while searching for files + */ + public Stream getPaths(Path repository) throws IOException { + return Files.find(repository, Integer.MAX_VALUE, + (path, attrs) -> repository.relativize(path).toString().matches(regex)); + } + @Override public void doExecute(final StudioUpgradeContext context) throws UpgradeException { var site = context.getTarget(); logger.debug("Find files that match the regex '{}' in site '{}'", regex, site); Path repository = context.getRepositoryPath(); - try (Stream paths = Files.find(repository, Integer.MAX_VALUE, - (path, attrs) -> repository.relativize(path).toString().matches(regex))) { + try (Stream paths = getPaths(repository)) { paths.forEach(path -> { logger.debug("Execute the XSLT template against site '{}' path '{}'", site, path); try { - Path temp = Files.createTempFile(getStudioTemporaryFilesRoot(), "upgrade-manager", "xslt"); + Path temp = Files.createTempFile(getStudioTemporaryFilesRoot(), "upgrade-manager", ".xslt"); try { OutputStream os = Files.newOutputStream(temp); executeTemplate(context, repository.relativize(path).toString(), os); os.close(); - if (Files.size(temp) > 0) { - Files.move(temp, path, StandardCopyOption.REPLACE_EXISTING); - } + replaceFile(path, temp); } finally { Files.deleteIfExists(temp); } @@ -94,4 +101,17 @@ public void doExecute(final StudioUpgradeContext context) throws UpgradeExceptio } } + /** + * Replaces the original file with the transformed file if the transformed file is not empty. + * + * @param path the original file path + * @param temp the transformed file path + * @throws IOException if an error occurs while replacing the file + */ + protected void replaceFile(Path path, Path temp) throws IOException { + if (Files.size(temp) > 0) { + Files.move(temp, path, StandardCopyOption.REPLACE_EXISTING); + } + } + } diff --git a/src/main/java/org/craftercms/studio/model/contentType/ContentType.java b/src/main/java/org/craftercms/studio/model/contentType/ContentType.java new file mode 100644 index 0000000000..eb170209c5 --- /dev/null +++ b/src/main/java/org/craftercms/studio/model/contentType/ContentType.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.model.contentType; + +import org.craftercms.studio.api.v2.dal.security.NormalizedRole; + +import java.util.List; +import java.util.Set; + +/** + * Represents a content type in the system. + */ +public class ContentType { + protected String id; + protected String label; + protected Type type; + protected Set allowedRoles; + protected List deleteDependencies; + protected List copyDependencies; + protected boolean previewable; + protected String imageThumbnail; + protected boolean noThumbnail; + protected List pathIncludes; + protected List pathExcludes; + protected boolean quickCreate; + protected String quickCreatePath; + + public enum Type { + PAGE, COMPONENT, UNKNOWN + } +} diff --git a/src/main/java/org/craftercms/studio/model/contentType/CopyDependency.java b/src/main/java/org/craftercms/studio/model/contentType/CopyDependency.java new file mode 100644 index 0000000000..893635e0c4 --- /dev/null +++ b/src/main/java/org/craftercms/studio/model/contentType/CopyDependency.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.model.contentType; + +/** + * Represents a copy dependency for a content type. + * + * @param pattern the pattern to match the dependencies to be copied + * @param target the target location where the dependencies should be copied to + */ +public record CopyDependency(String pattern, + String target) { + +} diff --git a/src/main/java/org/craftercms/studio/model/contentType/DeleteDependency.java b/src/main/java/org/craftercms/studio/model/contentType/DeleteDependency.java new file mode 100644 index 0000000000..cb7b66fd6f --- /dev/null +++ b/src/main/java/org/craftercms/studio/model/contentType/DeleteDependency.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.model.contentType; + +/** + * Represents a delete dependency for a content type. + * + * @param pattern the pattern to match the dependencies to be deleted + * @param removeEmptyFolder a flag indicating whether to remove empty folders after deletion + */ +public record DeleteDependency(String pattern, + boolean removeEmptyFolder) { +} diff --git a/src/main/java/org/craftercms/studio/model/rest/contentType/DeleteContentTypeRequest.java b/src/main/java/org/craftercms/studio/model/rest/contentType/DeleteContentTypeRequest.java new file mode 100644 index 0000000000..49feef16e0 --- /dev/null +++ b/src/main/java/org/craftercms/studio/model/rest/contentType/DeleteContentTypeRequest.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.model.rest.contentType; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.craftercms.commons.validation.annotations.param.ValidConfigurationPath; +import org.craftercms.commons.validation.annotations.param.ValidSiteId; + +/** + * Request for deleting a content-type. + */ +@JsonIgnoreProperties +public class DeleteContentTypeRequest { + + @ValidSiteId + protected String siteId; + + @ValidConfigurationPath + protected String contentType; + + protected boolean deleteDependencies; + + public String getSiteId() { + return siteId; + } + + public void setSiteId(String siteId) { + this.siteId = siteId; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public boolean isDeleteDependencies() { + return deleteDependencies; + } + + public void setDeleteDependencies(boolean deleteDependencies) { + this.deleteDependencies = deleteDependencies; + } + +} diff --git a/src/main/resources/crafter/studio/extension/rendering-overlay-context.xml b/src/main/resources/crafter/studio/extension/rendering-overlay-context.xml index ab3343cc3f..b71ff09eed 100644 --- a/src/main/resources/crafter/studio/extension/rendering-overlay-context.xml +++ b/src/main/resources/crafter/studio/extension/rendering-overlay-context.xml @@ -139,6 +139,9 @@ + + + diff --git a/src/main/resources/crafter/studio/studio-upgrade-context.xml b/src/main/resources/crafter/studio/studio-upgrade-context.xml index 54ea367b67..5caf1c2648 100644 --- a/src/main/resources/crafter/studio/studio-upgrade-context.xml +++ b/src/main/resources/crafter/studio/studio-upgrade-context.xml @@ -207,4 +207,8 @@ + + + diff --git a/src/main/resources/crafter/studio/upgrade/5.0.x/content-type/content-type-merge-v5.0.0.2.xslt b/src/main/resources/crafter/studio/upgrade/5.0.x/content-type/content-type-merge-v5.0.0.2.xslt new file mode 100644 index 0000000000..6be7a314ee --- /dev/null +++ b/src/main/resources/crafter/studio/upgrade/5.0.x/content-type/content-type-merge-v5.0.0.2.xslt @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/crafter/studio/upgrade/pipelines.yaml b/src/main/resources/crafter/studio/upgrade/pipelines.yaml index 0164c34900..5fa588ad08 100644 --- a/src/main/resources/crafter/studio/upgrade/pipelines.yaml +++ b/src/main/resources/crafter/studio/upgrade/pipelines.yaml @@ -763,6 +763,13 @@ pipelines: - pattern: "\\._toQuery\\(\\)" replacement: '.toQuery()' commitDetails: Upgrade to OpenSearch 3 in site scripts + - currentVersion: 5.0.0.1 + nextVersion: 5.0.0.2 + operations: + - type: contentTypeConfigMergeUpgrader + regex: config/studio/content-types/.+/form-definition\.xml + template: crafter/studio/upgrade/5.0.x/content-type/content-type-merge-v5.0.0.2.xslt + commitDetails: Merge content type config.xml into form-definition.xml and remove config.xml files # Pipeline to upgrade blueprints blueprint: diff --git a/src/main/webapp/default-site/scripts/api/ServiceFactory.groovy b/src/main/webapp/default-site/scripts/api/ServiceFactory.groovy index 266ff280a3..140f5d711f 100644 --- a/src/main/webapp/default-site/scripts/api/ServiceFactory.groovy +++ b/src/main/webapp/default-site/scripts/api/ServiceFactory.groovy @@ -16,13 +16,13 @@ package scripts.api -import scripts.libs.Cookies import scripts.api.impl.content.SpringContentServices -import scripts.api.impl.content.SpringContentTypeServices import scripts.api.impl.content.SpringPageNavigationOrderServices +import scripts.api.impl.dependency.SpringDependencyServices import scripts.api.impl.security.SpringSecurityServices import scripts.api.impl.site.SpringSiteServices import scripts.api.impl.user.SpringUserServices +import scripts.libs.Cookies /** * Class is a factory used by the API wrappers to find their implementation @@ -53,13 +53,6 @@ class ServiceFactory { return new SpringContentServices(context) } - /** - * return the implementation for content type services - */ - static getContentTypeServices(context) { - return new SpringContentTypeServices(context) - } - /** * return the implementation for security services * diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/article/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/article/config.xml index 86ae812b09..8231e385e9 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/article/config.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/article/config.xml @@ -15,20 +15,24 @@ --> - -
/page/article
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - true - true - true - /site/website/articles/{year}/{month} - false - page-article.png - + -> already in form-definition - title +
/page/article
-> content-type + simple -> not used + NOT-USED-BY-SIMPLE-FORM-ENGINE -> not used + xml -> not used + true -> not used + true -> MIGRATE + true -> already in form-definition + /site/website/articles/{year}/{month} -> already in form-definition + false -> not used + page-article.png -> already in form-definition + -> MIGRATE ^/site/website/articles/.* + Also MIGRATE: + delete-dependencies + copy-dependencies + allowed-roles
diff --git a/src/test/java/org/craftercms/studio/impl/v2/upgrade/operations/contentType/ContentTypeConfigMergeUpgraderTest.java b/src/test/java/org/craftercms/studio/impl/v2/upgrade/operations/contentType/ContentTypeConfigMergeUpgraderTest.java new file mode 100644 index 0000000000..4859b8727b --- /dev/null +++ b/src/test/java/org/craftercms/studio/impl/v2/upgrade/operations/contentType/ContentTypeConfigMergeUpgraderTest.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.impl.v2.upgrade.operations.contentType; + +import org.apache.commons.collections4.IterableUtils; +import org.apache.commons.configuration2.HierarchicalConfiguration; +import org.apache.commons.io.IOUtils; +import org.craftercms.studio.api.v2.utils.StudioConfiguration; +import org.craftercms.studio.api.v2.utils.StudioUtils; +import org.craftercms.studio.impl.v2.upgrade.StudioUpgradeContext; +import org.craftercms.studio.impl.v2.upgrade.operations.site.AbstractXsltFileUpgradeOperation; +import org.craftercms.studio.impl.v2.upgrade.operations.site.BatchXsltFileUpgradeOperation; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xmlunit.builder.DiffBuilder; +import org.xmlunit.diff.Diff; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.stream.Stream; + +import static org.craftercms.studio.api.v2.utils.StudioConfiguration.CONFIGURATION_SITE_CONTENT_TYPES_CONFIG_FILE_NAME; +import static org.craftercms.studio.api.v2.utils.StudioUtils.getStudioTemporaryFilesRoot; +import static org.mockito.Mockito.*; +import static org.testng.Assert.assertEquals; + +@RunWith(MockitoJUnitRunner.class) +public class ContentTypeConfigMergeUpgraderTest { + private static final Logger logger = LoggerFactory.getLogger(ContentTypeConfigMergeUpgraderTest.class); + + @Mock + private StudioConfiguration studioConfiguration; + @Spy + @InjectMocks + private ContentTypeConfigMergeUpgrader upgrader; + + @Before + public void setUp() throws Exception { + var config = mock(HierarchicalConfiguration.class); + when(config.getString(BatchXsltFileUpgradeOperation.CONFIG_KEY_REGEX)).thenReturn("config/studio/content-types/.+/form-definition\\.xml"); + when(config.getString(AbstractXsltFileUpgradeOperation.CONFIG_KEY_TEMPLATE)).thenReturn("crafter/studio/upgrade/5.0.x/content-type/content-type-merge-v5.0.0.2.xslt"); + when(studioConfiguration.getProperty(CONFIGURATION_SITE_CONTENT_TYPES_CONFIG_FILE_NAME)).thenReturn("config.xml"); + upgrader.init("1", "2", config); + } + + @Test + public void testUpgrade() throws Exception { + String basePath = "src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0.2/"; + File originalFormFile = new File(basePath + "form-definition.xml"); + File originalConfigFile = new File(basePath + "config.xml"); + Path configFilePath = StudioUtils.getStudioTemporaryFilesRoot().resolve("config.xml"); + Path formFilePath = StudioUtils.createTempFile("form-definition.xml"); + formFilePath.toFile().deleteOnExit(); + configFilePath.toFile().deleteOnExit(); + Files.copy(originalFormFile.toPath(), formFilePath, StandardCopyOption.REPLACE_EXISTING); + + Files.copy(originalConfigFile.toPath(), configFilePath, StandardCopyOption.REPLACE_EXISTING); + + File resultFile = formFilePath.toFile(); + File expectedFile = new File(basePath + "expected.xml"); + + StudioUpgradeContext context = mock(StudioUpgradeContext.class); + when(context.getTarget()).thenReturn("test-site"); + when(context.getRepositoryPath()).thenReturn(Path.of(getStudioTemporaryFilesRoot().toString())); + when(context.getFile(getStudioTemporaryFilesRoot().relativize(formFilePath).toString())).thenReturn(formFilePath); + + (doReturn(Stream.of(formFilePath)).when(upgrader)).getPaths(any()); + + upgrader.doExecute(context); + + // Assert + try (InputStream expectedIn = new FileInputStream(expectedFile); + InputStream actualIn = new FileInputStream(resultFile)) { + String expectedXml = IOUtils.toString(expectedIn, StandardCharsets.UTF_8); + String actualXml = IOUtils.toString(actualIn, StandardCharsets.UTF_8); + + // Compare the result + Diff diff = DiffBuilder + .compare(expectedXml) + .withTest(actualXml) + .ignoreWhitespace() + .ignoreComments() + .checkForSimilar() + .build(); + + if (diff.hasDifferences()) { + logger.debug(actualXml); + } + + // there should not be any differences + assertEquals(IterableUtils.size(diff.getDifferences()), 0, + "The result XML should be equal to the expected XML"); + } + } +} diff --git a/src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0.2/config.xml b/src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0.2/config.xml new file mode 100644 index 0000000000..713d23629f --- /dev/null +++ b/src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0.2/config.xml @@ -0,0 +1,50 @@ + + + + +
/page/article
+ simple + NOT-USED-BY-SIMPLE-FORM-ENGINE + xml + true + true + true + /site/website/articles/{year}/{month} + false + page-article.png + + + ^/site/website/articles/.* + + + + + ^/site/website/articles/.* + true + + + + + ^/site/website/articles/.* + /site/website/articles2 + + + + author + admin + +
diff --git a/src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0.2/expected.xml b/src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0.2/expected.xml new file mode 100644 index 0000000000..56ef1aeccc --- /dev/null +++ b/src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0.2/expected.xml @@ -0,0 +1,902 @@ + + +
+ Article + + page + /page/article + page-article.png + true + /site/website/articles/{year}/{month} + + + display-template + + /templates/web/pages/article.ftl + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Page Properties + + true + + + file-name + file-name + + Page URL + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + + boolean + + + + + checkbox + disabled + + Disable Page + + + + + + readonly + + boolean + + + + + required + + boolean + + + + + input + title_t + core + Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + + boolean + + + pattern + + string + + + + + node-selector + header_o + core + Header + Default header is inherited from Section Defaults. Specify a new header to overwrite it. + + + + + minSize + 0 + int + + + maxSize + 1 + int + + + itemManager + components-header + datasource:item + + + readonly + + boolean + + + disableFlattening + false + boolean + + + useSingleValueFilename + + boolean + + + contentTypes + /component/header + contentTypes + + + tags + + string + + + + + allowDuplicates + + boolean + + + + + node-selector + left_rail_o + + Left Rail + Default left-rail is inherited from Section Defaults. Specify a new left-rail to overwrite it. + + + + + minSize + 0 + int + + + maxSize + 1 + int + + + itemManager + components-left-rail + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + contentTypes + /component/left-rail + contentTypes + + + tags + + string + + + + + allowDuplicates + + boolean + + + + +
+
+ Metadata + + true + + + checkbox-group + categories_o + + Categories + + + + + + datasource + categories + datasource:item + + + selectAll + true + boolean + + + readonly + + boolean + + + listDirection + [{"value":"horizontal","label":"Horizonal","selected":true},{"value":"vertical","label":"Vertical","selected":false}] + dropdown + + + + + minSize + + int + + + + + checkbox-group + segments_o + + Segments + + + + + + datasource + segments + datasource:item + + + selectAll + true + boolean + + + readonly + + boolean + + + + + minSize + + int + + + + + checkbox + featured_b + + Featured + + + + + + readonly + + boolean + + + + + required + + boolean + + + + +
+
+ Content + + true + + + input + subject_t + subject + Subject + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + + boolean + + + pattern + + string + + + + + input + author_s + subject + Author + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + + boolean + + + pattern + + string + + + + + date-time + date_dt + + Date + + + + + + showDate + true + boolean + + + showTime + + boolean + + + showClear + true + boolean + + + showNowLink + true + boolean + + + populate + true + boolean + + + allowPastDate + true + boolean + + + populateDateExp + now + string + + + useCustomTimezone + false + boolean + + + readonly + + boolean + + + readonlyEdit + false + boolean + + + + + required + + boolean + + + + date_dt_tz + + + + textarea + summary_t + + Summary + + + + + + cols + 50 + int + + + rows + 5 + int + + + maxlength + 100000 + int + + + allowResize + true + boolean + + + readonly + + boolean + + + + + required + + boolean + + + + + image-picker + image_s + + Image + + + + + + width + { "exact":"", "min":"", "max":"" } + range + + + height + { "exact":"", "min":"", "max":"" } + range + + + thumbnailWidth + + int + + + thumbnailHeight + + int + + + imageManager + upload_images,existing_images + datasource:image + + + readonly + + boolean + + + + + required + + boolean + + + + + repeat + sections_o + article + Sections + + 1 + * + + + minOccurs + 1 + string + + + maxOccurs + * + string + + + + + rte + section_html + article + Section + + + + + + height + + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + upload_images,existing_images + datasource:image + + + videoManager + + datasource:video + + + + + required + + boolean + + + + + + +
+
+ + + shared-content + components-header + Components Header + item + + + repoPath + /site/components/headers + undefined + + + browsePath + + undefined + + + type + + undefined + + + enableCreateNew + true + boolean + + + enableBrowseExisting + true + boolean + + + enableSearchExisting + true + boolean + + + + + img-desktop-upload + upload_images + Upload Images + image + + + repoPath + /static-assets/item/images/{yyyy}/{mm}/{dd}/ + undefined + + + + + img-repository-upload + existing_images + Existing Images + image + + + repoPath + /static-assets/images + undefined + + + + + simpleTaxonomy + categories + Categories + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] + undefined + + + componentPath + /site/taxonomy/categories.xml + undefined + + + + + simpleTaxonomy + segments + Segments + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] + undefined + + + componentPath + /site/taxonomy/segments.xml + undefined + + + + + shared-content + components-left-rail + Components Left Rail + item + + + repoPath + /site/components/left-rails/ + undefined + + + browsePath + + undefined + + + type + + undefined + + + enableCreateNew + true + boolean + + + enableBrowseExisting + true + boolean + + + enableSearchExisting + true + boolean + + + + + true + false + + + ^/site/website/articles/.* + + + + + ^/site/website/articles/.* + true + + + + + ^/site/website/articles/.* + /site/website/articles2 + + + + author + admin + +
diff --git a/src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0.2/form-definition.xml b/src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0.2/form-definition.xml new file mode 100644 index 0000000000..706cfddc8a --- /dev/null +++ b/src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0.2/form-definition.xml @@ -0,0 +1,879 @@ + + +
+ Article + + page + /page/article + page-article.png + true + /site/website/articles/{year}/{month} + + + display-template + + /templates/web/pages/article.ftl + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Page Properties + + true + + + file-name + file-name + + Page URL + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + + boolean + + + + + checkbox + disabled + + Disable Page + + + + + + readonly + + boolean + + + + + required + + boolean + + + + + input + title_t + core + Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + + boolean + + + pattern + + string + + + + + node-selector + header_o + core + Header + Default header is inherited from Section Defaults. Specify a new header to overwrite it. + + + + + minSize + 0 + int + + + maxSize + 1 + int + + + itemManager + components-header + datasource:item + + + readonly + + boolean + + + disableFlattening + false + boolean + + + useSingleValueFilename + + boolean + + + contentTypes + /component/header + contentTypes + + + tags + + string + + + + + allowDuplicates + + boolean + + + + + node-selector + left_rail_o + + Left Rail + Default left-rail is inherited from Section Defaults. Specify a new left-rail to overwrite it. + + + + + minSize + 0 + int + + + maxSize + 1 + int + + + itemManager + components-left-rail + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + contentTypes + /component/left-rail + contentTypes + + + tags + + string + + + + + allowDuplicates + + boolean + + + + +
+
+ Metadata + + true + + + checkbox-group + categories_o + + Categories + + + + + + datasource + categories + datasource:item + + + selectAll + true + boolean + + + readonly + + boolean + + + listDirection + [{"value":"horizontal","label":"Horizonal","selected":true},{"value":"vertical","label":"Vertical","selected":false}] + dropdown + + + + + minSize + + int + + + + + checkbox-group + segments_o + + Segments + + + + + + datasource + segments + datasource:item + + + selectAll + true + boolean + + + readonly + + boolean + + + + + minSize + + int + + + + + checkbox + featured_b + + Featured + + + + + + readonly + + boolean + + + + + required + + boolean + + + + +
+
+ Content + + true + + + input + subject_t + subject + Subject + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + + boolean + + + pattern + + string + + + + + input + author_s + subject + Author + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + + boolean + + + pattern + + string + + + + + date-time + date_dt + + Date + + + + + + showDate + true + boolean + + + showTime + + boolean + + + showClear + true + boolean + + + showNowLink + true + boolean + + + populate + true + boolean + + + allowPastDate + true + boolean + + + populateDateExp + now + string + + + useCustomTimezone + false + boolean + + + readonly + + boolean + + + readonlyEdit + false + boolean + + + + + required + + boolean + + + + date_dt_tz + + + + textarea + summary_t + + Summary + + + + + + cols + 50 + int + + + rows + 5 + int + + + maxlength + 100000 + int + + + allowResize + true + boolean + + + readonly + + boolean + + + + + required + + boolean + + + + + image-picker + image_s + + Image + + + + + + width + { "exact":"", "min":"", "max":"" } + range + + + height + { "exact":"", "min":"", "max":"" } + range + + + thumbnailWidth + + int + + + thumbnailHeight + + int + + + imageManager + upload_images,existing_images + datasource:image + + + readonly + + boolean + + + + + required + + boolean + + + + + repeat + sections_o + article + Sections + + 1 + * + + + minOccurs + 1 + string + + + maxOccurs + * + string + + + + + rte + section_html + article + Section + + + + + + height + + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + upload_images,existing_images + datasource:image + + + videoManager + + datasource:video + + + + + required + + boolean + + + + + + +
+
+ + + shared-content + components-header + Components Header + item + + + repoPath + /site/components/headers + undefined + + + browsePath + + undefined + + + type + + undefined + + + enableCreateNew + true + boolean + + + enableBrowseExisting + true + boolean + + + enableSearchExisting + true + boolean + + + + + img-desktop-upload + upload_images + Upload Images + image + + + repoPath + /static-assets/item/images/{yyyy}/{mm}/{dd}/ + undefined + + + + + img-repository-upload + existing_images + Existing Images + image + + + repoPath + /static-assets/images + undefined + + + + + simpleTaxonomy + categories + Categories + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] + undefined + + + componentPath + /site/taxonomy/categories.xml + undefined + + + + + simpleTaxonomy + segments + Segments + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] + undefined + + + componentPath + /site/taxonomy/segments.xml + undefined + + + + + shared-content + components-left-rail + Components Left Rail + item + + + repoPath + /site/components/left-rails/ + undefined + + + browsePath + + undefined + + + type + + undefined + + + enableCreateNew + true + boolean + + + enableBrowseExisting + true + boolean + + + enableSearchExisting + true + boolean + + + + +
From efeed138468feb4b006766219f39763c742ce7ed Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Tue, 21 Apr 2026 13:42:43 -0600 Subject: [PATCH 05/38] Upgrade blueprints content types --- .../component/articles-widget/config.xml | 34 - .../articles-widget/form-definition.xml | 556 +++--- .../component/contact-widget/config.xml | 34 - .../contact-widget/form-definition.xml | 808 ++++---- .../component/feature/config.xml | 34 - .../component/feature/form-definition.xml | 641 +++--- .../content-types/component/header/config.xml | 34 - .../component/header/form-definition.xml | 792 ++++---- .../component/left-rail/config.xml | 34 - .../component/left-rail/form-definition.xml | 398 ++-- .../component/level-descriptor/config.xml | 34 - .../level-descriptor/form-definition.xml | 424 ++-- .../component/social-media-widget/config.xml | 18 - .../social-media-widget/form-definition.xml | 1041 +++++----- .../content-types/page/article/config.xml | 38 - .../page/article/form-definition.xml | 1730 +++++++++-------- .../page/category-landing/config.xml | 34 - .../page/category-landing/form-definition.xml | 1062 +++++----- .../studio/content-types/page/home/config.xml | 34 - .../page/home/form-definition.xml | 1484 +++++++------- .../page/search-results/config.xml | 34 - .../page/search-results/form-definition.xml | 774 ++++---- .../studio/content-types/taxonomy/config.xml | 34 - .../taxonomy/form-definition.xml | 412 ++-- .../config/studio/studio_version.xml | 2 +- .../component/company/config.xml | 34 - .../component/company/form-definition.xml | 839 ++++---- .../component/level-descriptor/config.xml | 34 - .../level-descriptor/form-definition.xml | 136 +- .../component/product/config.xml | 34 - .../component/product/form-definition.xml | 1013 +++++----- .../content-types/page/catalog/config.xml | 34 - .../page/catalog/form-definition.xml | 382 ++-- .../studio/content-types/taxonomy/config.xml | 34 - .../taxonomy/form-definition.xml | 412 ++-- .../config/studio/studio_version.xml | 2 +- .../component/level-descriptor/config.xml | 29 - .../level-descriptor/form-definition.xml | 133 +- .../content-types/page/entry/config.xml | 29 - .../page/entry/form-definition.xml | 545 +++--- .../config/studio/studio_version.xml | 2 +- .../content-types/component/author/config.xml | 34 - .../component/author/form-definition.xml | 667 +++---- .../component/level-descriptor/config.xml | 34 - .../level-descriptor/form-definition.xml | 136 +- .../content-types/component/post/config.xml | 34 - .../component/post/form-definition.xml | 1069 +++++----- .../page/item-explorer/config.xml | 34 - .../page/item-explorer/form-definition.xml | 498 ++--- .../studio/content-types/taxonomy/config.xml | 34 - .../taxonomy/form-definition.xml | 412 ++-- .../config/studio/studio_version.xml | 2 +- 52 files changed, 8251 insertions(+), 8915 deletions(-) delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/articles-widget/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/contact-widget/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/feature/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/header/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/left-rail/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/level-descriptor/config.xml delete mode 100755 src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/social-media-widget/config.xml mode change 100755 => 100644 src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/social-media-widget/form-definition.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/article/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/category-landing/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/home/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/search-results/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/taxonomy/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/company/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/level-descriptor/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/product/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/page/catalog/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/taxonomy/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/component/level-descriptor/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/page/entry/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/author/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/level-descriptor/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/post/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/page/item-explorer/config.xml delete mode 100644 src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/taxonomy/config.xml diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/articles-widget/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/articles-widget/config.xml deleted file mode 100644 index 4f78e08624..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/articles-widget/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/component/articles-widget
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - false - component-articles-widget.png - - - ^/site/components/articles-widget/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/articles-widget/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/articles-widget/form-definition.xml index a2f6e746e2..2b8f4b9a72 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/articles-widget/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/articles-widget/form-definition.xml @@ -1,3 +1,4 @@ + -
- Articles Widget - - component - /component/articles-widget - component-articles-widget.png - false - - - - display-template - - /templates/web/components/articles-widget.ftl - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Component - Articles Widget Properties - - true - - - file-name - file-name - - Component ID - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - - - - - input - internal-name - articles - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - - - required - - boolean - - - - - checkbox - disabled - articles - Disable Component - - - - - - readonly - - boolean - - - - - required - - boolean - - - - - node-selector - scripts_o - - Controllers - The controller script(s) that will be executed before the component is rendered - - - - - minSize - 1 - int - - - maxSize - - int - - - itemManager - scripts - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - - - allowDuplicates - - boolean - - - - - input - title_t - articles - Title - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - numeric-input - max_articles_i - articles - Max Articles - - - - - - size - 3 - int - - - maxlength - 3 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - -
-
- - - shared-content - scripts - Scripts - item - - - repoPath - /scripts/components - undefined - - - browsePath - - undefined - - - type - - undefined - - - - + Articles Widget + + component + /component/articles-widget + component-articles-widget.png + false + + + + display-template + + /templates/web/components/articles-widget.ftl + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Component - Articles Widget Properties + + true + + + file-name + file-name + + Component ID + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + input + internal-name + articles + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + + + required + true + boolean + + + + + checkbox + disabled + articles + Disable Component + + + + + + readonly + + boolean + + + + + required + + boolean + + + + + node-selector + scripts_o + + Controllers + The controller script(s) that will be executed before the component is rendered + + + + + minSize + 1 + int + + + maxSize + + int + + + itemManager + scripts + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + + + allowDuplicates + + boolean + + + + + input + title_t + articles + Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + numeric-input + max_articles_i + articles + Max Articles + + + + + + size + 3 + int + + + maxlength + 3 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + +
+
+ + + shared-content + scripts + Scripts + item + + + repoPath + /scripts/components + undefined + + + browsePath + + undefined + + + type + + undefined + + + + + false + false + + + ^/site/components/articles-widget/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/contact-widget/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/contact-widget/config.xml deleted file mode 100644 index 1222a096ac..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/contact-widget/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/component/contact-widget
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - false - component-contact-widget.png - - - ^/site/components/contacts/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/contact-widget/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/contact-widget/form-definition.xml index f2ae4c2f05..cc72b4de76 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/contact-widget/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/contact-widget/form-definition.xml @@ -1,3 +1,4 @@ + -
- Contact Widget - - component - /component/contact-widget - component-contact-widget.png - false - - - - display-template - - /templates/web/components/contact-widget.ftl - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Component - Contact Widget Properties - - true - - - file-name - file-name - - Component ID - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - - - required - - boolean - - - - - checkbox - disabled - - Disable Component - - - - - - readonly - - boolean - - - - - required - - boolean - - - - -
-
- Content - - true - - - input - title_t - - Title - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - rte - text_html - - Text - - - - - - height - - int - - - forceRootBlockPTag - true - boolean - - - forcePTags - true - boolean - - - forceBRTags - false - boolean - - - supportedChannels - - supportedChannels - - - rteConfiguration - generic - string - - - imageManager - uploadImages,existingImages - datasource:image - - - videoManager - - datasource:video - - - - - required - - boolean - - - - - input - email_s - - Email - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - input - phone_s - - Phone - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - rte - address_html - - Address - - - - - - height - - int - - - forceRootBlockPTag - true - boolean - - - forcePTags - true - boolean - - - forceBRTags - false - boolean - - - supportedChannels - - supportedChannels - - - rteConfiguration - generic - string - - - imageManager - uploadImages,existingImages - datasource:image - - - videoManager - - datasource:video - - - - - required - - boolean - - - - -
-
- - - img-desktop-upload - uploadImages - Upload Images - image - - - repoPath - /static-assets/images - content-path-input - - - - - img-repository-upload - existingImages - Existing Images - image - - - repoPath - /static-assets/images - content-path-input - - - useSearch - false - boolean - - - - + Contact Widget + + component + /component/contact-widget + component-contact-widget.png + false + + + + display-template + + /templates/web/components/contact-widget.ftl + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Component - Contact Widget Properties + + true + + + file-name + file-name + + Component ID + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + + + required + true + boolean + + + + + checkbox + disabled + + Disable Component + + + + + + readonly + + boolean + + + + + required + + boolean + + + + +
+
+ Content + + true + + + input + title_t + + Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + rte + text_html + + Text + + + + + + height + + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + uploadImages,existingImages + datasource:image + + + videoManager + + datasource:video + + + + + required + true + boolean + + + + + input + email_s + + Email + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + input + phone_s + + Phone + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + rte + address_html + + Address + + + + + + height + + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + uploadImages,existingImages + datasource:image + + + videoManager + + datasource:video + + + + + required + true + boolean + + + + +
+
+ + + img-desktop-upload + uploadImages + Upload Images + image + + + repoPath + /static-assets/images + content-path-input + + + + + img-repository-upload + existingImages + Existing Images + image + + + repoPath + /static-assets/images + content-path-input + + + useSearch + false + boolean + + + + + false + false + + + ^/site/components/contacts/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/feature/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/feature/config.xml deleted file mode 100644 index 06d4c828ae..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/feature/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/component/feature
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - false - component-feature.png - - - ^/site/components/features/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/feature/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/feature/form-definition.xml index 65a4e86c00..a2ce7c0475 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/feature/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/feature/form-definition.xml @@ -1,3 +1,4 @@ + -
- Feature - - component - /component/feature - component-feature.png - false - - - - display-template - - /templates/web/components/feature.ftl - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Component - Feature Properties - - true - - - auto-filename - file-name - - Component ID - - - - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - - - checkbox - disabled - - Disable Component - - false - - - - readonly - - boolean - - - - - required - - boolean - - - - -
-
- Content - - true - - - dropdown - icon_s - icon_s - Icon - - fa-closed-captioning far - - - - datasource - feature_icons - datasource:item - - - emptyvalue - - boolean - - - readonly - - boolean - - - - - required - - boolean - - - - - input - title_t - - Title - - Feature Title - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - rte - body_html - - Body - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. - - - - height - - int - - - forceRootBlockPTag - true - boolean - - - forcePTags - true - boolean - - - forceBRTags - false - boolean - - - supportedChannels - - supportedChannels - - - rteConfiguration - generic - string - - - imageManager - uploadImages,existingImages - datasource:image - - - videoManager - - datasource:video - - - width - - int - - - autoGrow - false - boolean - - - fileManager - - datasource:item - - - - - required - - boolean - - - - -
-
- - - simpleTaxonomy - feature_icons - Feature Icons - item - - - dataType - [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] - undefined - - - componentPath - /site/taxonomy/feature-icons.xml - undefined - - - - - img-desktop-upload - uploadImages - Upload Images - image - - - repoPath - /static-assets/images - content-path-input - - - - - img-repository-upload - existingImages - Existing Images - image - - - repoPath - /static-assets/images - content-path-input - - - useSearch - false - boolean - - - - + Feature + + component + /component/feature + component-feature.png + false + + + + display-template + + /templates/web/components/feature.ftl + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Component - Feature Properties + + true + + + auto-filename + file-name + + Component ID + + + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + + + checkbox + disabled + + Disable Component + + false + + + + readonly + + boolean + + + + + required + + boolean + + + + +
+
+ Content + + true + + + dropdown + icon_s + icon_s + Icon + + fa-closed-captioning far + + + + datasource + feature_icons + datasource:item + + + emptyvalue + + boolean + + + readonly + + boolean + + + + + required + true + boolean + + + + + input + title_t + + Title + + Feature Title + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + rte + body_html + + Body + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + + + + height + + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + uploadImages,existingImages + datasource:image + + + videoManager + + datasource:video + + + width + + int + + + autoGrow + false + boolean + + + fileManager + + datasource:item + + + + + required + true + boolean + + + + +
+
+ + + simpleTaxonomy + feature_icons + Feature Icons + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] + undefined + + + componentPath + /site/taxonomy/feature-icons.xml + undefined + + + + + img-desktop-upload + uploadImages + Upload Images + image + + + repoPath + /static-assets/images + content-path-input + + + + + img-repository-upload + existingImages + Existing Images + image + + + repoPath + /static-assets/images + content-path-input + + + useSearch + false + boolean + + + + + false + false + + + ^/site/components/features/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/header/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/header/config.xml deleted file mode 100644 index 32aba74823..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/header/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/component/header
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - false - component-header.png - - - ^/site/components/headers/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/header/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/header/form-definition.xml index 639fe2b8a4..3d0b4c8c36 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/header/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/header/form-definition.xml @@ -1,3 +1,4 @@ + -
- Header - - component - /component/header - component-header.png - false - - - - display-template - - /templates/web/components/header.ftl - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Component - Header Properties - - true - - - file-name - file-name - - Component ID - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - - - required - - boolean - - - - - checkbox - disabled - - Disable Component - - - - - - readonly - - boolean - - - - - required - - boolean - - - - -
-
- Business Name and Logo - - true - - - image-picker - logo_s - header - Logo - - - - - - width - { "exact":"", "min":"", "max":"" + Header + + component + /component/header + component-header.png + false + + + + display-template + + /templates/web/components/header.ftl + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Component - Header Properties + + true + + + file-name + file-name + + Component ID + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + + + required + true + boolean + + + + + checkbox + disabled + + Disable Component + + + + + + readonly + + boolean + + + + + required + + boolean + + + + +
+
+ Business Name and Logo + + true + + + image-picker + logo_s + header + Logo + + + + + + width + { "exact":"", "min":"", "max":"" } - range - - - height - { "exact":"", "min":"", "max":"" + range + + + height + { "exact":"", "min":"", "max":"" } - range - - - thumbnailWidth - - int - - - thumbnailHeight - - int - - - imageManager - existingimages,uploadimage,existing_images,upload_image - datasource:image - - - readonly - - boolean - - - - - required - - boolean - - - - - input - logo_text_t - hero - Logo Alt Text - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - input - business_name_s - header - Business Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - -
-
- Social Media Links - - true - - - node-selector - socialMediaWidget_o - - Social Media Widget - - - - - - minSize - - int - - - maxSize - 1 - int - - - itemManager - socialMedia - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - useMVS - - boolean - - - - - allowDuplicates - - boolean - - - - -
-
- - - img-repository-upload - existing_images - Existing Images - image - - - repoPath - /static-assets/images - undefined - - - - - img-desktop-upload - upload_image - Upload Images - image - - - repoPath - /static-assets/item/images/{yyyy}/{mm}/{dd}/ - undefined - - - - - components - socialMedia - Social Media - item - - - allowShared - true - boolean - - - allowEmbedded - true - boolean - - - enableBrowse - true - boolean - - - enableSearch - false - boolean - - - baseRepositoryPath - /site/components - string - - - baseBrowsePath - /site/components - string - - - contentTypes - /component/social-media-widget - contentTypes - - - tags - - string - - - - + range +
+ + thumbnailWidth + + int + + + thumbnailHeight + + int + + + imageManager + existing_images,upload_image + datasource:image + + + readonly + + boolean + +
+ + + required + false + boolean + + +
+ + input + logo_text_t + hero + Logo Alt Text + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + false + boolean + + + pattern + + string + + + + + input + business_name_s + header + Business Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + +
+
+
+ Social Media Links + + true + + + node-selector + socialMediaWidget_o + + Social Media Widget + + + + + + minSize + + int + + + maxSize + 1 + int + + + itemManager + socialMedia + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + useMVS + + boolean + + + + + allowDuplicates + + boolean + + + + +
+
+ + + img-repository-upload + existing_images + Existing Images + image + + + repoPath + /static-assets/images + undefined + + + + + img-desktop-upload + upload_image + Upload Images + image + + + repoPath + /static-assets/item/images/{yyyy}/{mm}/{dd}/ + undefined + + + + + components + socialMedia + Social Media + item + + + allowShared + true + boolean + + + allowEmbedded + true + boolean + + + enableBrowse + true + boolean + + + enableSearch + false + boolean + + + baseRepositoryPath + /site/components + string + + + baseBrowsePath + /site/components + string + + + contentTypes + /component/social-media-widget + contentTypes + + + tags + + string + + + + + false + false + + + ^/site/components/headers/.* + +
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/left-rail/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/left-rail/config.xml deleted file mode 100644 index 26e2b88680..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/left-rail/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/component/left-rail
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - false - component-left-rail.png - - - ^/site/components/left-rails/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/left-rail/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/left-rail/form-definition.xml index 7dc6385aba..5f5c0827aa 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/left-rail/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/left-rail/form-definition.xml @@ -1,3 +1,4 @@ + -
- Left Rail - - component - /component/left-rail - component-left-rail.png - false - - - - display-template - - /templates/web/components/left-rail.ftl - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Component - Left Rail Properties - - true - - - file-name - file-name - left-rail - Component ID - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - - - - - input - internal-name - left-rail - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - - - required - - boolean - - - - - checkbox - disabled - left-rail - Disable Component - - - - - - readonly - - boolean - - - - - required - - boolean - - - - -
-
- Widgets - - true - - - node-selector - widgets_o - left-rail - Widgets - - - - - - minSize - 0 - int - - - maxSize - - int - - - itemManager - components - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - - - allowDuplicates - - boolean - - - - -
-
- - - shared-content - components - Components - item - - - repoPath - /site/components - undefined - - - browsePath - - undefined - - - type - - undefined - - - - + Left Rail + + component + /component/left-rail + component-left-rail.png + false + + + + display-template + + /templates/web/components/left-rail.ftl + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Component - Left Rail Properties + + true + + + file-name + file-name + left-rail + Component ID + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + input + internal-name + left-rail + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + + + required + true + boolean + + + + + checkbox + disabled + left-rail + Disable Component + + + + + + readonly + + boolean + + + + + required + + boolean + + + + +
+
+ Widgets + + true + + + node-selector + widgets_o + left-rail + Widgets + + + + + + minSize + 0 + int + + + maxSize + + int + + + itemManager + components + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + + + allowDuplicates + + boolean + + + + +
+
+ + + shared-content + components + Components + item + + + repoPath + /site/components + undefined + + + browsePath + + undefined + + + type + + undefined + + + + + false + false + + + ^/site/components/left-rails/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/level-descriptor/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/level-descriptor/config.xml deleted file mode 100644 index 25272dc5a7..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/level-descriptor/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/component/level-descriptor
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - false - section-defaults.png - - - ^/site/website/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/level-descriptor/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/level-descriptor/form-definition.xml index 1d3a984097..fe35e8833d 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/level-descriptor/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/level-descriptor/form-definition.xml @@ -1,3 +1,4 @@ + -
- Section Defaults - Section Defaults provides inherited values to all children and sibling content items. To learn more about content inheritance see craftercms.com/docs topic "Content Inheritance" - component - /component/level-descriptor - section-defaults.png - false - - - - display-template - - - template - - - no-template-required - - true - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Section Defaults Properties - - true - - - file-name - file-name - - File Name - - crafter-level-descriptor.level - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - true - boolean - - - - - - - node-selector - header_o - - Header - - - - - - minSize - 0 - int - - - maxSize - 1 - int - - - itemManager - components-header - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - - - allowDuplicates - - boolean - - - - - node-selector - left_rail_o - - Left Rail - - - - - - minSize - 0 - int - - - maxSize - 1 - int - - - itemManager - components-left-rail - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - - - allowDuplicates - - boolean - - - - -
-
- - - shared-content - components-header - Components Header - item - - - repoPath - /site/components/headers/ - undefined - - - browsePath - - undefined - - - type - - undefined - - - - - shared-content - components-left-rail - Components Left Rail - item - - - repoPath - /site/components/left-rails/ - undefined - - - browsePath - - undefined - - - type - - undefined - - - - + Section Defaults + Section Defaults provides inherited values to all children and sibling content items. To learn more about content inheritance see craftercms.com/docs topic "Content Inheritance" + component + /component/level-descriptor + section-defaults.png + false + + + + display-template + + + template + + + no-template-required + + true + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Section Defaults Properties + + true + + + file-name + file-name + + File Name + + crafter-level-descriptor.level + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + true + boolean + + + + + + node-selector + header_o + + Header + + + + + + minSize + 0 + int + + + maxSize + 1 + int + + + itemManager + components-header + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + + + allowDuplicates + + boolean + + + + + node-selector + left_rail_o + + Left Rail + + + + + + minSize + 0 + int + + + maxSize + 1 + int + + + itemManager + components-left-rail + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + + + allowDuplicates + + boolean + + + + +
+
+ + + shared-content + components-header + Components Header + item + + + repoPath + /site/components/headers/ + undefined + + + browsePath + + undefined + + + type + + undefined + + + + + shared-content + components-left-rail + Components Left Rail + item + + + repoPath + /site/components/left-rails/ + undefined + + + browsePath + + undefined + + + type + + undefined + + + + + false + false + + + ^/site/website/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/social-media-widget/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/social-media-widget/config.xml deleted file mode 100755 index 43057711c3..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/social-media-widget/config.xml +++ /dev/null @@ -1,18 +0,0 @@ - - -
/component/social-media-widget
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - true - - - - ^/site/components/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/social-media-widget/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/social-media-widget/form-definition.xml old mode 100755 new mode 100644 index 9cce9e6ce1..e82873ddcf --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/social-media-widget/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/component/social-media-widget/form-definition.xml @@ -1,525 +1,532 @@ +
- Social Media Widget - - component - /component/social-media-widget - - false - - - - display-template - - /templates/web/components/social-media-widget.ftl - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Social Media Widget Properties - - true - - - auto-filename - file-name - - Component ID - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - - - required - - boolean - - - - - input - header_s - - Header - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - escapeContent - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - repeat - accounts_o - - Accounts - - 1 - * - - - minOccurs - 0 - string - - - maxOccurs - * - string - - - - - dropdown - network_s - - Network - - - - - - datasource - networks - datasource:item - - - emptyvalue - - boolean - - - readonly - - boolean - - - - - required - - boolean - - - - - input - title_s - - Title - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - escapeContent - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - input - url_s - - URL - - # - The full URL for your profile in the given social network - - - size - 150 - int - - - maxlength - 300 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - escapeContent - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - image-picker - icon_s - - Icon - Leave empty to use the default icon. If no icon is provided, the system will use the + Social Media Widget + + component + /component/social-media-widget + + false + + + + display-template + + /templates/web/components/social-media-widget.ftl + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Social Media Widget Properties + + true + + + auto-filename + file-name + + Component ID + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + + + required + true + boolean + + + + + input + header_s + + Header + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + escapeContent + false + boolean + + + + + required + + boolean + + + pattern + + string + + + + + repeat + accounts_o + + Accounts + + 1 + * + + + minOccurs + 0 + string + + + maxOccurs + * + string + + + + + dropdown + network_s + + Network + + + + + + datasource + networks + datasource:item + + + emptyvalue + + boolean + + + readonly + + boolean + + + + + required + true + boolean + + + + + input + title_s + + Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + escapeContent + false + boolean + + + + + required + + boolean + + + pattern + + string + + + + + input + url_s + + URL + + # + The full URL for your profile in the given social network + + + size + 150 + int + + + maxlength + 300 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + escapeContent + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + image-picker + icon_s + + Icon + Leave empty to use the default icon. If no icon is provided, the system will use the built-in. - - - - - width - { "exact":"", "min":"", "max":"" + + + + + width + { "exact":"", "min":"", "max":"" } - range - - - height - { "exact":"", "min":"", "max":"" + range + + + height + { "exact":"", "min":"", "max":"" } - range - - - thumbnailWidth - - int - - - thumbnailHeight - - int - - - imageManager - imageUpload,imageFromRepository - datasource:image - - - readonly - - boolean - - - - - required - - boolean - - - - - - -
-
- Advanced Options - - false - - - numeric-input - iconsWidth_i - - Icons Width (in pixels) - - 24 - - - - size - 50 - int - - - maxValue - - float - - - minValue - - float - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - numeric-input - iconsHeight_i - - Icons Height (in pixels) - - 24 - - - - size - 50 - int - - - maxValue - - float - - - minValue - - float - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - checkbox - showItemsInline_b - - Show Items Inline - - true - - - - readonly - - boolean - - - - - required - - boolean - - - - -
-
- - - img-repository-upload - imageFromRepository - Image From Repository - image - - - repoPath - /static-assets/images - content-path-input - - - useSearch - false - boolean - - - - - img-desktop-upload - imageUpload - Image Upload - image - - - repoPath - /static-assets/images/{objectId} - content-path-input - - - - - simpleTaxonomy - networks - Networks - item - - - dataType - [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"Data Type","selected":false}] - dropdown - - - componentPath - /site/taxonomy/social-media-networks.xml - string - - - - + range + + + thumbnailWidth + + int + + + thumbnailHeight + + int + + + imageManager + imageUpload,imageFromRepository + datasource:image + + + readonly + + boolean + + + + + required + + boolean + + +
+
+
+
+
+
+ Advanced Options + + false + + + numeric-input + iconsWidth_i + + Icons Width (in pixels) + + 24 + + + + size + 50 + int + + + maxValue + + float + + + minValue + + float + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + + boolean + + + pattern + + string + + + + + numeric-input + iconsHeight_i + + Icons Height (in pixels) + + 24 + + + + size + 50 + int + + + maxValue + + float + + + minValue + + float + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + + boolean + + + pattern + + string + + + + + checkbox + showItemsInline_b + + Show Items Inline + + true + + + + readonly + + boolean + + + + + required + + boolean + + + + +
+
+ + + img-repository-upload + imageFromRepository + Image From Repository + image + + + repoPath + /static-assets/images + content-path-input + + + useSearch + false + boolean + + + + + img-desktop-upload + imageUpload + Image Upload + image + + + repoPath + /static-assets/images/{objectId} + content-path-input + + + + + simpleTaxonomy + networks + Networks + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"Data Type","selected":false}] + dropdown + + + componentPath + /site/taxonomy/social-media-networks.xml + string + + + + + false + true + + + ^/site/components/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/article/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/article/config.xml deleted file mode 100644 index 8231e385e9..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/article/config.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - -> already in form-definition - title -
/page/article
-> content-type - simple -> not used - NOT-USED-BY-SIMPLE-FORM-ENGINE -> not used - xml -> not used - true -> not used - true -> MIGRATE - true -> already in form-definition - /site/website/articles/{year}/{month} -> already in form-definition - false -> not used - page-article.png -> already in form-definition - -> MIGRATE - - ^/site/website/articles/.* - - - Also MIGRATE: - delete-dependencies - copy-dependencies - allowed-roles -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/article/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/article/form-definition.xml index bd4a56bad0..297abd2b94 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/article/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/article/form-definition.xml @@ -1,3 +1,4 @@ + -
- Article - - page - /page/article - page-article.png - true - /site/website/articles/{year}/{month} - - - display-template - - /templates/web/pages/article.ftl - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Page Properties - - true - - - file-name - file-name - - Page URL - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - - - checkbox - disabled - - Disable Page - - - - - - readonly - - boolean - - - - - required - - boolean - - - - - input - title_t - core - Title - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - node-selector - header_o - core - Header - Default header is inherited from Section Defaults. Specify a new header to overwrite it. - - - - - minSize - 0 - int - - - maxSize - 1 - int - - - itemManager - components-header - datasource:item - - - readonly - - boolean - - - disableFlattening - false - boolean - - - useSingleValueFilename - - boolean - - - contentTypes - /component/header - contentTypes - - - tags - - string - - - - - allowDuplicates - - boolean - - - - - node-selector - left_rail_o - - Left Rail - Default left-rail is inherited from Section Defaults. Specify a new left-rail to overwrite it. - - - - - minSize - 0 - int - - - maxSize - 1 - int - - - itemManager - components-left-rail - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - contentTypes - /component/left-rail - contentTypes - - - tags - - string - - - - - allowDuplicates - - boolean - - - - -
-
- Metadata - - true - - - checkbox-group - categories_o - - Categories - - - - - - datasource - categories - datasource:item - - - selectAll - true - boolean - - - readonly - - boolean - - - listDirection - [{"value":"horizontal","label":"Horizonal","selected":true},{"value":"vertical","label":"Vertical","selected":false}] - dropdown - - - - - minSize - - int - - - - - checkbox-group - segments_o - - Segments - - - - - - datasource - segments - datasource:item - - - selectAll - true - boolean - - - readonly - - boolean - - - - - minSize - - int - - - - - checkbox - featured_b - - Featured - - - - - - readonly - - boolean - - - - - required - - boolean - - - - -
-
- Content - - true - - - input - subject_t - subject - Subject - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - input - author_s - subject - Author - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - date-time - date_dt - - Date - - - - - - showDate - true - boolean - - - showTime - - boolean - - - showClear - true - boolean - - - showNowLink - true - boolean - - - populate - true - boolean - - - allowPastDate - true - boolean - - - populateDateExp - now - string - - - useCustomTimezone - false - boolean - - - readonly - - boolean - - - readonlyEdit - false - boolean - - - - - required - - boolean - - - - date_dt_tz - - - - textarea - summary_t - - Summary - - - - - - cols - 50 - int - - - rows - 5 - int - - - maxlength - 100000 - int - - - allowResize - true - boolean - - - readonly - - boolean - - - - - required - - boolean - - - - - image-picker - image_s - - Image - - - - - - width - { "exact":"", "min":"", "max":"" } - range - - - height - { "exact":"", "min":"", "max":"" } - range - - - thumbnailWidth - - int - - - thumbnailHeight - - int - - - imageManager - upload_images,existing_images - datasource:image - - - readonly - - boolean - - - - - required - - boolean - - - - - repeat - sections_o - article - Sections - - 1 - * - - - minOccurs - 1 - string - - - maxOccurs - * - string - - - - - rte - section_html - article - Section - - - - - - height - - int - - - forceRootBlockPTag - true - boolean - - - forcePTags - true - boolean - - - forceBRTags - false - boolean - - - supportedChannels - - supportedChannels - - - rteConfiguration - generic - string - - - imageManager - upload_images,existing_images - datasource:image - - - videoManager - - datasource:video - - - - - required - - boolean - - - - - - -
-
- - - shared-content - components-header - Components Header - item - - - repoPath - /site/components/headers - undefined - - - browsePath - - undefined - - - type - - undefined - - - enableCreateNew - true - boolean - - - enableBrowseExisting - true - boolean - - - enableSearchExisting - true - boolean - - - - - img-desktop-upload - upload_images - Upload Images - image - - - repoPath - /static-assets/item/images/{yyyy}/{mm}/{dd}/ - undefined - - - - - img-repository-upload - existing_images - Existing Images - image - - - repoPath - /static-assets/images - undefined - - - - - simpleTaxonomy - categories - Categories - item - - - dataType - [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] - undefined - - - componentPath - /site/taxonomy/categories.xml - undefined - - - - - simpleTaxonomy - segments - Segments - item - - - dataType - [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] - undefined - - - componentPath - /site/taxonomy/segments.xml - undefined - - - - - shared-content - components-left-rail - Components Left Rail - item - - - repoPath - /site/components/left-rails/ - undefined - - - browsePath - - undefined - - - type - - undefined - - - enableCreateNew - true - boolean - - - enableBrowseExisting - true - boolean - - - enableSearchExisting - true - boolean - - - - + Article + + page + /page/article + page-article.png + true + /site/website/articles/{year}/{month} + + + display-template + + /templates/web/pages/article.ftl + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Page Properties + + true + + + file-name + file-name + + Page URL + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + + + checkbox + disabled + + Disable Page + + + + + + readonly + + boolean + + + + + required + + boolean + + + + + input + title_t + core + Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + + boolean + + + pattern + + string + + + + + node-selector + header_o + core + Header + Default header is inherited from Section Defaults. Specify a new header to overwrite it. + + + + + minSize + 0 + int + + + maxSize + 1 + int + + + itemManager + components-header + datasource:item + + + readonly + + boolean + + + disableFlattening + false + boolean + + + useSingleValueFilename + + boolean + + + contentTypes + /component/header + contentTypes + + + tags + + string + + + + + allowDuplicates + + boolean + + + + + node-selector + left_rail_o + + Left Rail + Default left-rail is inherited from Section Defaults. Specify a new left-rail to overwrite it. + + + + + minSize + 0 + int + + + maxSize + 1 + int + + + itemManager + components-left-rail + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + contentTypes + /component/left-rail + contentTypes + + + tags + + string + + + + + allowDuplicates + + boolean + + + + +
+
+ Metadata + + true + + + checkbox-group + categories_o + + Categories + + + + + + datasource + categories + datasource:item + + + selectAll + true + boolean + + + readonly + + boolean + + + listDirection + [{"value":"horizontal","label":"Horizonal","selected":true},{"value":"vertical","label":"Vertical","selected":false}] + dropdown + + + + + minSize + 1 + int + + + + + checkbox-group + segments_o + + Segments + + + + + + datasource + segments + datasource:item + + + selectAll + true + boolean + + + readonly + + boolean + + + + + minSize + 1 + int + + + + + checkbox + featured_b + + Featured + + + + + + readonly + + boolean + + + + + required + + boolean + + + + +
+
+ Content + + true + + + input + subject_t + subject + Subject + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + input + author_s + subject + Author + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + date-time + date_dt + + Date + + + + + + showDate + true + boolean + + + showTime + + boolean + + + showClear + true + boolean + + + showNowLink + true + boolean + + + populate + true + boolean + + + allowPastDate + true + boolean + + + populateDateExp + now + string + + + useCustomTimezone + false + boolean + + + readonly + + boolean + + + readonlyEdit + false + boolean + + + + + required + true + boolean + + + + date_dt_tz + + + + textarea + summary_t + + Summary + + + + + + cols + 50 + int + + + rows + 5 + int + + + maxlength + 100000 + int + + + allowResize + true + boolean + + + readonly + + boolean + + + + + required + true + boolean + + + + + image-picker + image_s + + Image + + + + + + width + { "exact":"", "min":"", "max":"" } + range + + + height + { "exact":"", "min":"", "max":"" } + range + + + thumbnailWidth + + int + + + thumbnailHeight + + int + + + imageManager + upload_images,existing_images + datasource:image + + + readonly + + boolean + + + + + required + + boolean + + + + + repeat + sections_o + article + Sections + + 1 + * + + + minOccurs + 1 + string + + + maxOccurs + * + string + + + + + rte + section_html + article + Section + + + + + + height + + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + upload_images,existing_images + datasource:image + + + videoManager + + datasource:video + + + + + required + true + boolean + + + + + + +
+
+ + + shared-content + components-header + Components Header + item + + + repoPath + /site/components/headers + undefined + + + browsePath + + undefined + + + type + + undefined + + + enableCreateNew + true + boolean + + + enableBrowseExisting + true + boolean + + + enableSearchExisting + true + boolean + + + + + img-desktop-upload + upload_images + Upload Images + image + + + repoPath + /static-assets/item/images/{yyyy}/{mm}/{dd}/ + undefined + + + + + img-repository-upload + existing_images + Existing Images + image + + + repoPath + /static-assets/images + undefined + + + + + simpleTaxonomy + categories + Categories + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] + undefined + + + componentPath + /site/taxonomy/categories.xml + undefined + + + + + simpleTaxonomy + segments + Segments + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] + undefined + + + componentPath + /site/taxonomy/segments.xml + undefined + + + + + shared-content + components-left-rail + Components Left Rail + item + + + repoPath + /site/components/left-rails/ + undefined + + + browsePath + + undefined + + + type + + undefined + + + enableCreateNew + true + boolean + + + enableBrowseExisting + true + boolean + + + enableSearchExisting + true + boolean + + + + + true + false + + + ^/site/website/articles/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/category-landing/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/category-landing/config.xml deleted file mode 100644 index 876738af4e..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/category-landing/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/page/category-landing
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - true - true - false - - false - page-category-landing.png - - - ^/site/website/(?!articles/)(.*) - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/category-landing/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/category-landing/form-definition.xml index 93d27bc620..c7c3694f15 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/category-landing/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/category-landing/form-definition.xml @@ -1,3 +1,4 @@ + -
- Category Landing - - page - /page/category-landing - page-category-landing.png - false - - - - display-template - - /templates/web/pages/category-landing.ftl - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Page Properties - - true - - - file-name - file-name - - Page URL - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - - - checkbox - disabled - - Disable Page - - - - - - readonly - - boolean - - - - - required - - boolean - - - - - page-nav-order - placeInNav - - Place in Nav - - - - - - readonly - - boolean - - - - - required - - boolean - - - - - input - navLabel - - Nav Label - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - escapeContent - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - input - title_t - - Title - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - node-selector - header_o - - Header - Default header is inherited from Section Defaults. Specify a new header to overwrite it. - - - - - minSize - 0 - int - - - maxSize - 1 - int - - - itemManager - components-header - datasource:item - - - readonly - - boolean - - - disableFlattening - false - boolean - - - useSingleValueFilename - - boolean - - - - - allowDuplicates - - boolean - - - - - node-selector - left_rail_o - - Left Rail - Default left-rail is inherited from Section Defaults. Specify a new left-rail to overwrite it. - - - - - minSize - 0 - int - - - maxSize - 1 - int - - - itemManager - components-left-rail - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - - - allowDuplicates - - boolean - - - - -
-
- Articles - - true - - - input - articles_title_t - articles - Articles Title - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - dropdown - category_s - articles - Category - - - - - - datasource - categories - datasource:item - - - emptyvalue - - boolean - - - readonly - - boolean - - - - - required - - boolean - - - - - numeric-input - max_articles_i - articles - Max Articles - - 10 - - - - size - 3 - int - - - maxlength - 3 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - -
-
- - - shared-content - components-header - Components Header - item - - - repoPath - /site/components/headers/ - undefined - - - browsePath - - undefined - - - type - - undefined - - - - - simpleTaxonomy - categories - Categories - item - - - dataType - [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] - undefined - - - componentPath - /site/taxonomy/categories.xml - undefined - - - - - shared-content - components-left-rail - Components Left Rail - item - - - repoPath - /site/components/left-rails/ - undefined - - - browsePath - - undefined - - - type - - undefined - - - - + Category Landing + + page + /page/category-landing + page-category-landing.png + false + + + + display-template + + /templates/web/pages/category-landing.ftl + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Page Properties + + true + + + file-name + file-name + + Page URL + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + + + checkbox + disabled + + Disable Page + + + + + + readonly + + boolean + + + + + required + + boolean + + + + + page-nav-order + placeInNav + + Place in Nav + + + + + + readonly + + boolean + + + + + required + + boolean + + + + + input + navLabel + + Nav Label + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + escapeContent + false + boolean + + + + + required + + boolean + + + pattern + + string + + + + + input + title_t + + Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + node-selector + header_o + + Header + Default header is inherited from Section Defaults. Specify a new header to overwrite it. + + + + + minSize + 0 + int + + + maxSize + 1 + int + + + itemManager + components-header + datasource:item + + + readonly + + boolean + + + disableFlattening + false + boolean + + + useSingleValueFilename + + boolean + + + + + allowDuplicates + + boolean + + + + + node-selector + left_rail_o + + Left Rail + Default left-rail is inherited from Section Defaults. Specify a new left-rail to overwrite it. + + + + + minSize + 0 + int + + + maxSize + 1 + int + + + itemManager + components-left-rail + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + + + allowDuplicates + + boolean + + + + +
+
+ Articles + + true + + + input + articles_title_t + articles + Articles Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + dropdown + category_s + articles + Category + + + + + + datasource + categories + datasource:item + + + emptyvalue + + boolean + + + readonly + + boolean + + + + + required + true + boolean + + + + + numeric-input + max_articles_i + articles + Max Articles + + 10 + + + + size + 3 + int + + + maxlength + 3 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + +
+
+ + + shared-content + components-header + Components Header + item + + + repoPath + /site/components/headers/ + undefined + + + browsePath + + undefined + + + type + + undefined + + + + + simpleTaxonomy + categories + Categories + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] + undefined + + + componentPath + /site/taxonomy/categories.xml + undefined + + + + + shared-content + components-left-rail + Components Left Rail + item + + + repoPath + /site/components/left-rails/ + undefined + + + browsePath + + undefined + + + type + + undefined + + + + + true + false + + + ^/site/website/(?!articles/)(.*) + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/home/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/home/config.xml deleted file mode 100644 index 13865b19ed..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/home/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/page/home
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - true - true - false - - false - page-home.png - - - ^/site/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/home/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/home/form-definition.xml index 4d121ee4ae..81d756b2d3 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/home/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/home/form-definition.xml @@ -1,3 +1,4 @@ + -
- Home - - page - /page/home - page-home.png - false - - - - display-template - - /templates/web/pages/home.ftl - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Page Properties - - true - - - file-name - file-name - - Page URL - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - true - boolean - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - - - required - - boolean - - - - - input - navLabel - - Nav Label - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - escapeContent - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - checkbox - disabled - - Disable Page - - - - - - readonly - - boolean - - - - - required - - boolean - - - - - input - title_t - core - Title - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - node-selector - header_o - core - Header - Default header is inherited from Section Defaults. Specify a new header to overwrite it. - - - - - minSize - 0 - int - - - maxSize - 1 - int - - - itemManager - components-header - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - contentTypes - /component/header - contentTypes - - - tags - - string - - - - - allowDuplicates - - boolean - - - - - node-selector - left_rail_o - - Left Rail - Default left-rail is inherited from Section Defaults. Specify a new left-rail to overwrite it. - - - - - minSize - 0 - int - - - maxSize - 1 - int - - - itemManager - components-left-rail - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - contentTypes - /component/left-rail - contentTypes - - - tags - - string - - - - - allowDuplicates - - boolean - - - - -
-
- Hero Section - - true - - - rte - hero_title_html - hero - Hero Title - - - - - - height - 410 - int - - - forceRootBlockPTag - true - boolean - - - forcePTags - true - boolean - - - forceBRTags - false - boolean - - - supportedChannels - - supportedChannels - - - rteConfiguration - generic - string - - - imageManager - uploadImages,existingImages - datasource:image - - - videoManager - - datasource:video - - - - - required - - boolean - - - - - rte - hero_text_html - hero - Hero Text - - - - - - height - 200 - int - - - forceRootBlockPTag - true - boolean - - - forcePTags - true - boolean - - - forceBRTags - false - boolean - - - supportedChannels - - supportedChannels - - - rteConfiguration - generic - string - - - imageManager - existingImages,uploadImages - datasource:image - - - videoManager - - datasource:video - - - - - required - - boolean - - - - - image-picker - hero_image_s - hero - Hero Image - - - - - - width - { "exact":"", "min":"", "max":"" } - range - - - height - { "exact":"", "min":"", "max":"" } - range - - - thumbnailWidth - - int - - - thumbnailHeight - - int - - - imageManager - existingImages,uploadImages - datasource:image - - - readonly - - boolean - - - - - required - - boolean - - - - -
-
- Features - - true - - - input - features_title_t - features - Features Title - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - node-selector - features_o - features - Features - - - - - - minSize - - int - - - maxSize - - int - - - itemManager - featuresComponents - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - contentTypes - /component/feature - contentTypes - - - tags - - string - - - - - allowDuplicates - - boolean - - - - -
-
- - - img-repository-upload - existingImages - Existing Images - image - - - repoPath - /static-assets/images/ - undefined - - - - - img-desktop-upload - uploadImages - Upload Images - image - - - repoPath - /static-assets/item/images/{yyyy}/{mm}/{dd}/ - undefined - - - - - shared-content - components-header - Components Header - item - - - repoPath - /site/components/headers/ - undefined - - - browsePath - - undefined - - - type - - undefined - - - - - shared-content - components-left-rail - Components Left Rail - item - - - repoPath - /site/components/left-rails/ - undefined - - - browsePath - - undefined - - - type - - undefined - - - enableCreateNew - true - boolean - - - enableBrowseExisting - true - boolean - - - enableSearchExisting - true - boolean - - - - - components - featuresComponents - Features Components - item - - - allowShared - true - boolean - - - allowEmbedded - true - boolean - - - enableBrowse - true - boolean - - - enableSearch - true - boolean - - - baseRepositoryPath - /site/components - string - - - baseBrowsePath - /site/components - string - - - contentTypes - /component/feature - contentTypes - - - tags - - string - - - - + Home + + page + /page/home + page-home.png + false + + + + display-template + + /templates/web/pages/home.ftl + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Page Properties + + true + + + file-name + file-name + + Page URL + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + true + boolean + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + + + required + true + boolean + + + + + input + navLabel + + Nav Label + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + escapeContent + false + boolean + + + + + required + + boolean + + + pattern + + string + + + + + checkbox + disabled + + Disable Page + + + + + + readonly + + boolean + + + + + required + + boolean + + + + + input + title_t + core + Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + node-selector + header_o + core + Header + Default header is inherited from Section Defaults. Specify a new header to overwrite it. + + + + + minSize + 0 + int + + + maxSize + 1 + int + + + itemManager + components-header + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + contentTypes + /component/header + contentTypes + + + tags + + string + + + + + allowDuplicates + + boolean + + + + + node-selector + left_rail_o + + Left Rail + Default left-rail is inherited from Section Defaults. Specify a new left-rail to overwrite it. + + + + + minSize + 0 + int + + + maxSize + 1 + int + + + itemManager + components-left-rail + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + contentTypes + /component/left-rail + contentTypes + + + tags + + string + + + + + allowDuplicates + + boolean + + + + +
+
+ Hero Section + + true + + + rte + hero_title_html + hero + Hero Title + + + + + + height + 410 + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + uploadImages,existingImages + datasource:image + + + videoManager + + datasource:video + + + + + required + true + boolean + + + + + rte + hero_text_html + hero + Hero Text + + + + + + height + 200 + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + existingImages,uploadImages + datasource:image + + + videoManager + + datasource:video + + + + + required + true + boolean + + + + + image-picker + hero_image_s + hero + Hero Image + + + + + + width + { "exact":"", "min":"", "max":"" } + range + + + height + { "exact":"", "min":"", "max":"" } + range + + + thumbnailWidth + + int + + + thumbnailHeight + + int + + + imageManager + existingImages,uploadImages + datasource:image + + + readonly + + boolean + + + + + required + + boolean + + + + +
+
+ Features + + true + + + input + features_title_t + features + Features Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + node-selector + features_o + features + Features + + + + + + minSize + + int + + + maxSize + + int + + + itemManager + featuresComponents + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + contentTypes + /component/feature + contentTypes + + + tags + + string + + + + + allowDuplicates + + boolean + + + + +
+
+ + + img-repository-upload + existingImages + Existing Images + image + + + repoPath + /static-assets/images/ + undefined + + + + + img-desktop-upload + uploadImages + Upload Images + image + + + repoPath + /static-assets/item/images/{yyyy}/{mm}/{dd}/ + undefined + + + + + shared-content + components-header + Components Header + item + + + repoPath + /site/components/headers/ + undefined + + + browsePath + + undefined + + + type + + undefined + + + + + shared-content + components-left-rail + Components Left Rail + item + + + repoPath + /site/components/left-rails/ + undefined + + + browsePath + + undefined + + + type + + undefined + + + enableCreateNew + true + boolean + + + enableBrowseExisting + true + boolean + + + enableSearchExisting + true + boolean + + + + + components + featuresComponents + Features Components + item + + + allowShared + true + boolean + + + allowEmbedded + true + boolean + + + enableBrowse + true + boolean + + + enableSearch + true + boolean + + + baseRepositoryPath + /site/components + string + + + baseBrowsePath + /site/components + string + + + contentTypes + /component/feature + contentTypes + + + tags + + string + + + + + true + false + + + ^/site/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/search-results/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/search-results/config.xml deleted file mode 100644 index cd3787e8b8..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/search-results/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/page/search-results
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - true - true - false - - false - page-search-results.png - - - ^/site/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/search-results/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/search-results/form-definition.xml index dd0471926d..d714ebe68f 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/search-results/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/page/search-results/form-definition.xml @@ -1,3 +1,4 @@ + -
- Search Results - - page - /page/search-results - page-search-results.png - false - - - - display-template - - /templates/web/pages/search-results.ftl - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Page - Search Results Properties - - true - - - file-name - file-name - - Page URL - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - - - checkbox - disabled - - Disable Page - - - - - - readonly - - boolean - - - - - required - - boolean - - - - - input - title_t - - Title - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - node-selector - header_o - - Header - - - - - - minSize - - int - - - maxSize - - int - - - itemManager - components-header - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - - - allowDuplicates - - boolean - - - - - node-selector - left_rail_o - - Left Rail - - - - - - minSize - - int - - - maxSize - - int - - - itemManager - components-left-rail - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - - - allowDuplicates - - boolean - - - - - node-selector - categories_o - - Categories - - - - - - minSize - 1 - int - - - maxSize - 1 - int - - - itemManager - categories - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - - - allowDuplicates - - boolean - - - - -
-
- - - shared-content - components-header - Components Header - item - - - repoPath - /site/components/headers/ - undefined - - - browsePath - - undefined - - - type - - undefined - - - - - shared-content - components-left-rail - Components Left Rail - item - - - repoPath - /site/components/left-rails/ - undefined - - - browsePath - - undefined - - - type - - undefined - - - - - shared-content - categories - Categories - item - - - repoPath - /site/taxonomy - undefined - - - browsePath - /site/taxonomy - undefined - - - type - /taxonomy - undefined - - - - + Search Results + + page + /page/search-results + page-search-results.png + false + + + + display-template + + /templates/web/pages/search-results.ftl + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Page - Search Results Properties + + true + + + file-name + file-name + + Page URL + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + + + checkbox + disabled + + Disable Page + + + + + + readonly + + boolean + + + + + required + + boolean + + + + + input + title_t + + Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + node-selector + header_o + + Header + + + + + + minSize + + int + + + maxSize + + int + + + itemManager + components-header + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + + + allowDuplicates + + boolean + + + + + node-selector + left_rail_o + + Left Rail + + + + + + minSize + + int + + + maxSize + + int + + + itemManager + components-left-rail + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + + + allowDuplicates + + boolean + + + + + node-selector + categories_o + + Categories + + + + + + minSize + 1 + int + + + maxSize + 1 + int + + + itemManager + categories + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + + + allowDuplicates + + boolean + + + + +
+
+ + + shared-content + components-header + Components Header + item + + + repoPath + /site/components/headers/ + undefined + + + browsePath + + undefined + + + type + + undefined + + + + + shared-content + components-left-rail + Components Left Rail + item + + + repoPath + /site/components/left-rails/ + undefined + + + browsePath + + undefined + + + type + + undefined + + + + + shared-content + categories + Categories + item + + + repoPath + /site/taxonomy + undefined + + + browsePath + /site/taxonomy + undefined + + + type + /taxonomy + undefined + + + + + true + false + + + ^/site/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/taxonomy/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/taxonomy/config.xml deleted file mode 100644 index 33891f41f1..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/taxonomy/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/taxonomy
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - false - taxonomy.png - - - ^/site/taxonomy/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/taxonomy/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/taxonomy/form-definition.xml index 249d4deb59..fafa03beaf 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/taxonomy/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/content-types/taxonomy/form-definition.xml @@ -1,3 +1,4 @@ + -
- Taxonomy - - component - /taxonomy - taxonomy.png - false - - - - display-template - - - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Taxonomy Properties - - true - - - file-name - file-name - - Component ID - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - - - required - - boolean - - - - - repeat - items - - Items - - 1 - * - - - minOccurs - 1 - string - - - maxOccurs - * - string - - - - - input - key - - Key - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - input - value - - Value - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - - -
-
- + Taxonomy + + component + /taxonomy + taxonomy.png + false + + + + display-template + + + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Taxonomy Properties + + true + + + file-name + file-name + + Component ID + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + + + required + true + boolean + + + + + repeat + items + + Items + + 1 + * + + + minOccurs + 1 + string + + + maxOccurs + * + string + + + + + input + key + + Key + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + input + value + + Value + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + + +
+
+ + false + false + + + ^/site/taxonomy/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/studio_version.xml b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/studio_version.xml index 1fb428280a..1adc2652d0 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/studio_version.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/1000_website_editorial/config/studio/studio_version.xml @@ -15,5 +15,5 @@ ~ along with this program. If not, see . --> - 5.0.0.1 + 5.0.0.2 diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/company/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/company/config.xml deleted file mode 100644 index 461a53be7e..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/company/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/component/company
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - true - - - - /site/items/companies/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/company/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/company/form-definition.xml index f98492da9c..17bf9365d6 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/company/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/company/form-definition.xml @@ -1,3 +1,4 @@ + -
- Item: Company - - component - /component/company - undefined - false - - - - display-template - - - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Item: Company Properties - - true - - - auto-filename - file-name - - Component ID - - - - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - - - checkbox - disabled - - Disable Item - - - - - - readonly - - boolean - - - - - required - - boolean - - - - - input - name_s - - Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - image-picker - logo_s - - Logo - - - - - - width - { "exact":"", "min":"50", "max":"150" } - range - - - height - { "exact":"", "min":"50", "max":"150" } - range - - - thumbnailWidth - 100 - int - - - thumbnailHeight - 100 - int - - - imageManager - upload_images,existing_images - datasource:image - - - readonly - - boolean - - - - - required - - boolean - - - - - rte - description_html - - Description - - - - - - height - 350 - int - - - forceRootBlockPTag - true - boolean - - - forcePTags - true - boolean - - - forceBRTags - false - boolean - - - supportedChannels - - supportedChannels - - - rteConfiguration - generic - string - - - imageManager - upload_images,existing_images - datasource:image - - - videoManager - - datasource:video - - - - - required - - boolean - - - - - input - website_s - - Website - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - input - email_s - - Email - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - input - phone_s - - Phone - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - -
-
- - - img-desktop-upload - upload_images - Upload Images - image - - - repoPath - /static-assets/item/images/companies/{yyyy}/{mm}/{dd}/ - undefined - - - - - img-repository-upload - existing_images - Existing Images - image - - - repoPath - /static-assets/images/companies - undefined - - - - + Item: Company + + component + /component/company + undefined + false + + + + display-template + + + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Item: Company Properties + + true + + + auto-filename + file-name + + Component ID + + + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + + + checkbox + disabled + + Disable Item + + + + + + readonly + + boolean + + + + + required + + boolean + + + + + input + name_s + + Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + image-picker + logo_s + + Logo + + + + + + width + { "exact":"", "min":"50", "max":"150" } + range + + + height + { "exact":"", "min":"50", "max":"150" } + range + + + thumbnailWidth + 100 + int + + + thumbnailHeight + 100 + int + + + imageManager + upload_images,existing_images + datasource:image + + + readonly + + boolean + + + + + required + + boolean + + + + + rte + description_html + + Description + + + + + + height + 350 + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + upload_images,existing_images + datasource:image + + + videoManager + + datasource:video + + + + + required + true + boolean + + + + + input + website_s + + Website + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + input + email_s + + Email + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + input + phone_s + + Phone + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + +
+
+ + + img-desktop-upload + upload_images + Upload Images + image + + + repoPath + /static-assets/item/images/companies/{yyyy}/{mm}/{dd}/ + undefined + + + + + img-repository-upload + existing_images + Existing Images + image + + + repoPath + /static-assets/images/companies + undefined + + + + + false + true + + + /site/items/companies/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/level-descriptor/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/level-descriptor/config.xml deleted file mode 100644 index 9812cb9bc9..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/level-descriptor/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/component/level-descriptor
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - true - - - - ^/site/website/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/level-descriptor/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/level-descriptor/form-definition.xml index 76bca6ecfe..67ba87c6d8 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/level-descriptor/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/level-descriptor/form-definition.xml @@ -1,3 +1,4 @@ + -
- Section Defaults - Section Defaults provides inherited values to all children and sibling content items. To learn more about content inheritance see craftercms.com/docs topic "Content Inheritance" - component - /component/level-descriptor - false - - - - display-template - - - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Section Defaults Properties - - true - - - file-name - file-name - - File Name - - crafter-level-descriptor.level - - - - size - 100 - int - - - maxlength - 50 - int - - - readonly - true - boolean - - - - - - -
-
- + Section Defaults + Section Defaults provides inherited values to all children and sibling content items. To learn more about content inheritance see craftercms.com/docs topic "Content Inheritance" + component + /component/level-descriptor + false + + + + display-template + + + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Section Defaults Properties + + true + + + file-name + file-name + + File Name + + crafter-level-descriptor.level + + + + size + 100 + int + + + maxlength + 50 + int + + + readonly + true + boolean + + + + + +
+
+ + false + true + + + ^/site/website/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/product/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/product/config.xml deleted file mode 100644 index 5b347b45ea..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/product/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/component/product
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - true - - - - /site/items/products/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/product/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/product/form-definition.xml index 0ec373f573..9e6e735573 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/product/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/product/form-definition.xml @@ -1,3 +1,4 @@ + -
- Item: Product - - component - /component/product - undefined - false - - - - display-template - - - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Item: Product Properties - - true - - - auto-filename - file-name - - Component ID - - - - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - - - checkbox - disabled - - Disable Item - - false - - - - readonly - - boolean - - - - - required - - boolean - - - - - input - name_s - - Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - rte - description_html - - Description - - - - - - height - 350 - int - - - forceRootBlockPTag - true - boolean - - - forcePTags - true - boolean - - - forceBRTags - false - boolean - - - supportedChannels - - supportedChannels - - - rteConfiguration - generic - string - - - imageManager - existing_images,upload_images - datasource:image - - - videoManager - - datasource:video - - - - - required - - boolean - - - - - image-picker - image_s - - Image - - - - - - width - { "exact":"", "min":"", "max":"400" } - range - - - height - { "exact":"", "min":"", "max":"400" } - range - - - thumbnailWidth - 200 - int - - - thumbnailHeight - 200 - int - - - imageManager - upload_images,existing_images - datasource:image - - - readonly - - boolean - - - - - required - - boolean - - - - - checkbox-group - categories_o - - Categories - - - - - - datasource - categories - datasource:item - - - selectAll - - boolean - - - readonly - - boolean - - - - - minSize - - int - - - - - checkbox-group - tags_o - - Tags - - - - - - datasource - tags - datasource:item - - - selectAll - - boolean - - - readonly - - boolean - - - - - minSize - - int - - - - - input - price_d - - Price - Enter the price as a numerical value. - - - - - size - 12 - int - - - maxlength - 10 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - node-selector - company_o - - Company - - - - - - minSize - 1 - int - - - maxSize - 1 - int - - - itemManager - company_components - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - - - allowDuplicates - - boolean - - - - -
-
- - - img-desktop-upload - upload_images - Upload Images - image - - - repoPath - /static-assets/item/images/products/{yyyy}/{mm}/{dd}/ - undefined - - - - - img-repository-upload - existing_images - Existing Images - image - - - repoPath - /static-assets/images/products - undefined - - - - - simpleTaxonomy - categories_o - Categories - item - - - dataType - [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] - undefined - - - componentPath - /site/taxonomy/categories.xml - undefined - - - - - simpleTaxonomy - tags - Tags - item - - - dataType - [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] - undefined - - - componentPath - /site/taxonomy/tags.xml - undefined - - - - - shared-content - company_components - Company Components - item - - - repoPath - /site/items/companies - undefined - - - browsePath - /site/items/companies - undefined - - - type - /component/company - undefined - - - - + Item: Product + + component + /component/product + undefined + false + + + + display-template + + + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Item: Product Properties + + true + + + auto-filename + file-name + + Component ID + + + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + + + checkbox + disabled + + Disable Item + + false + + + + readonly + + boolean + + + + + required + + boolean + + + + + input + name_s + + Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + rte + description_html + + Description + + + + + + height + 350 + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + existing_images,upload_images + datasource:image + + + videoManager + + datasource:video + + + + + required + true + boolean + + + + + image-picker + image_s + + Image + + + + + + width + { "exact":"", "min":"", "max":"400" } + range + + + height + { "exact":"", "min":"", "max":"400" } + range + + + thumbnailWidth + 200 + int + + + thumbnailHeight + 200 + int + + + imageManager + upload_images,existing_images + datasource:image + + + readonly + + boolean + + + + + required + true + boolean + + + + + checkbox-group + categories_o + + Categories + + + + + + datasource + categories + datasource:item + + + selectAll + + boolean + + + readonly + + boolean + + + + + minSize + + int + + + + + checkbox-group + tags_o + + Tags + + + + + + datasource + tags + datasource:item + + + selectAll + + boolean + + + readonly + + boolean + + + + + minSize + + int + + + + + input + price_d + + Price + Enter the price as a numerical value. + + + + + size + 12 + int + + + maxlength + 10 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + ^[\d\.]+$ + string + + + + + node-selector + company_o + + Company + + + + + + minSize + 1 + int + + + maxSize + 1 + int + + + itemManager + company_components + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + + + allowDuplicates + + boolean + + + + +
+
+ + + img-desktop-upload + upload_images + Upload Images + image + + + repoPath + /static-assets/item/images/products/{yyyy}/{mm}/{dd}/ + undefined + + + + + img-repository-upload + existing_images + Existing Images + image + + + repoPath + /static-assets/images/products + undefined + + + + + simpleTaxonomy + categories_o + Categories + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] + undefined + + + componentPath + /site/taxonomy/categories.xml + undefined + + + + + simpleTaxonomy + tags + Tags + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] + undefined + + + componentPath + /site/taxonomy/tags.xml + undefined + + + + + shared-content + company_components + Company Components + item + + + repoPath + /site/items/companies + undefined + + + browsePath + /site/items/companies + undefined + + + type + /component/company + undefined + + + + + false + true + + + /site/items/products/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/page/catalog/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/page/catalog/config.xml deleted file mode 100644 index 6d735d4093..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/page/catalog/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/page/catalog
- simple - not-used - xml - true - true - false - - true - - - - /site/website/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/page/catalog/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/page/catalog/form-definition.xml index 85d80f8ee6..f9bae645f7 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/page/catalog/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/page/catalog/form-definition.xml @@ -1,3 +1,4 @@ + -
- Catalog - Catalog - page - /page/catalog - undefined - false - - - - placeInNav - - true - boolean - - - display-template - - /templates/web/catalog.ftl - template - - - no-template-required - - - boolean - - - descriptor-mapper - - hierarchical-mapper - string - - - -
- Page Settings - - true - - - file-name - file-name - - Page URL - - - - - - size - 50 - int - - - maxlength - 50 - int - - - path - - string - - - readonly - true - boolean - - - - - - - input - internal-name - - File Title - - - - - - size - 50 - int - - - maxlength - 60 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - int - - - - - checkbox - disabled - - Disable Catalog - - - - - - readonly - - boolean - - - - - required - - boolean - - - - -
-
- Main Content - - true - - - input - title_t - title - Title - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - -
-
- + Catalog + Catalog + page + /page/catalog + undefined + false + + + + placeInNav + + true + boolean + + + display-template + + /templates/web/catalog.ftl + template + + + no-template-required + + + boolean + + + descriptor-mapper + + hierarchical-mapper + string + + + +
+ Page Settings + + true + + + file-name + file-name + + Page URL + + + + + + size + 50 + int + + + maxlength + 50 + int + + + path + + string + + + readonly + true + boolean + + + + + + input + internal-name + + File Title + + + + + + size + 50 + int + + + maxlength + 60 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + + + checkbox + disabled + + Disable Catalog + + + + + + readonly + + boolean + + + + + required + + boolean + + + + +
+
+ Main Content + + true + + + input + title_t + title + Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + +
+
+ + true + true + + + /site/website/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/taxonomy/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/taxonomy/config.xml deleted file mode 100644 index 3dd3c26aa5..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/taxonomy/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/taxonomy
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - true - - - - /site/taxonomy/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/taxonomy/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/taxonomy/form-definition.xml index 284d71d701..2c8626efdd 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/taxonomy/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/taxonomy/form-definition.xml @@ -1,3 +1,4 @@ + -
- Taxonomy - - component - /taxonomy - undefined - false - - - - display-template - - - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Taxonomy Properties - - true - - - file-name - file-name - - Component ID - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - - - required - - boolean - - - - - repeat - items - - Items - - 1 - * - - - minOccurs - 1 - string - - - maxOccurs - * - string - - - - - input - key - - Key - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - input - value - - Value - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - - -
-
- + Taxonomy + + component + /taxonomy + undefined + false + + + + display-template + + + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Taxonomy Properties + + true + + + file-name + file-name + + Component ID + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + + + required + true + boolean + + + + + repeat + items + + Items + + 1 + * + + + minOccurs + 1 + string + + + maxOccurs + * + string + + + + + input + key + + Key + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + input + value + + Value + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + + +
+
+ + false + true + + + ^/site/taxonomy/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/studio_version.xml b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/studio_version.xml index 1fb428280a..1adc2652d0 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/studio_version.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/studio_version.xml @@ -15,5 +15,5 @@ ~ along with this program. If not, see . --> - 5.0.0.1 + 5.0.0.2 diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/component/level-descriptor/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/component/level-descriptor/config.xml deleted file mode 100644 index 0f11a557a8..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/component/level-descriptor/config.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - -
/component/level-descriptor
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - true - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/component/level-descriptor/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/component/level-descriptor/form-definition.xml index 891daae2d6..b117a07615 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/component/level-descriptor/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/component/level-descriptor/form-definition.xml @@ -1,3 +1,4 @@ + -
- Section Defaults - Section Defaults provides inherited values to all children and sibling content items. To learn more about content inheritance see craftercms.com/docs topic "Content Inheritance" - component - /component/level-descriptor - undefined - false - - - - display-template - - - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Section Defaults Properties - - true - - - file-name - file-name - - File Name - - crafter-level-descriptor.level - - - - size - 100 - int - - - maxlength - 50 - int - - - readonly - true - boolean - - - - - - -
-
- + Section Defaults + Section Defaults provides inherited values to all children and sibling content items. To learn more about content inheritance see craftercms.com/docs topic "Content Inheritance" + component + /component/level-descriptor + undefined + false + + + + display-template + + + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Section Defaults Properties + + true + + + file-name + file-name + + File Name + + crafter-level-descriptor.level + + + + size + 100 + int + + + maxlength + 50 + int + + + readonly + true + boolean + + + + + +
+
+ + false + true diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/page/entry/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/page/entry/config.xml deleted file mode 100644 index f5e3b8753f..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/page/entry/config.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - -
/page/entry
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - true - true - false - - true - image.jpg -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/page/entry/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/page/entry/form-definition.xml index 413e6eed83..b67d9609b7 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/page/entry/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/content-types/page/entry/form-definition.xml @@ -1,3 +1,4 @@ + -
- A Page - A Simple Page - page - /page/entry - undefined - false - - - - display-template - - /templates/web/entry.ftl - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Page Settings - - true - - - file-name - file-name - - Page URL - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - - - - - input - internal-name - - File Title - - - - - - size - 50 - int - - - maxlength - 60 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - - - page-nav-order - placeInNav - - Place in Nav - - - - - - readonly - - boolean - - - - - required - - boolean - - - - - checkbox - disabled - - Disable Page - - - - - - readonly - - boolean - - - - - required - - boolean - - - - -
-
- Main Content - - true - - - input - title_t - title - Title - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - rte - body_html - main - Body - - - - - - height - 300 - int - - - forceRootBlockPTag - true - boolean - - - forcePTags - true - boolean - - - forceBRTags - false - boolean - - - supportedChannels - - supportedChannels - - - rteConfiguration - generic - string - - - imageManager - desktopImages - datasource:image - - - videoManager - - datasource:video - - - - - required - - boolean - - - - -
-
- - - img-desktop-upload - desktopImages - Desktop Images - image - - - repoPath - /static-assets/item/images/{yyyy}/{mm}/{dd}/ - undefined - - - - + A Page + A Simple Page + page + /page/entry + undefined + false + + + + display-template + + /templates/web/entry.ftl + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Page Settings + + true + + + file-name + file-name + + Page URL + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + input + internal-name + + File Title + + + + + + size + 50 + int + + + maxlength + 60 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + + + page-nav-order + placeInNav + + Place in Nav + + + + + + readonly + + boolean + + + + + required + + boolean + + + + + checkbox + disabled + + Disable Page + + + + + + readonly + + boolean + + + + + required + + boolean + + + + +
+
+ Main Content + + true + + + input + title_t + title + Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + rte + body_html + main + Body + + + + + + height + 300 + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + desktopImages + datasource:image + + + videoManager + + datasource:video + + + + + required + true + boolean + + + + +
+
+ + + img-desktop-upload + desktopImages + Desktop Images + image + + + repoPath + /static-assets/item/images/{yyyy}/{mm}/{dd}/ + undefined + + + + + true + true diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/studio_version.xml b/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/studio_version.xml index 1fb428280a..1adc2652d0 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/studio_version.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/4000_empty/config/studio/studio_version.xml @@ -15,5 +15,5 @@ ~ along with this program. If not, see . --> - 5.0.0.1 + 5.0.0.2 diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/author/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/author/config.xml deleted file mode 100644 index 38d021ffd4..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/author/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/component/author
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - true - - - - /site/items/authors/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/author/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/author/form-definition.xml index 951656dcb9..88a300b9df 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/author/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/author/form-definition.xml @@ -1,3 +1,4 @@ + -
- Item: Author - - component - /component/author - undefined - false - - - - display-template - - - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Author Properties - - true - - - auto-filename - file-name - - Component ID - - - - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - - - checkbox - disabled - - Disable Item - - false - - - - readonly - - boolean - - - - - required - - boolean - - - - - input - name_s - - Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - image-picker - photo_s - - Photo - - - - - - width - { "exact":"", "min":"50", "max":"100" } - range - - - height - { "exact":"", "min":"50", "max":"100" } - range - - - thumbnailWidth - 50 - int - - - thumbnailHeight - 50 - int - - - imageManager - upload_images,existing_images - datasource:image - - - readonly - - boolean - - - - - required - - boolean - - - - - input - website_s - - Website - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - rte - biography_html - - Biography - - - - - - height - 400 - int - - - forceRootBlockPTag - true - boolean - - - forcePTags - true - boolean - - - forceBRTags - false - boolean - - - supportedChannels - - supportedChannels - - - rteConfiguration - generic - string - - - imageManager - upload_images,existing_images - datasource:image - - - videoManager - - datasource:video - - - - - required - - boolean - - - - -
-
- - - img-desktop-upload - upload_images - Upload Images - image - - - repoPath - /static-assets/item/images/avatars/{yyyy}/{mm}/{dd} - undefined - - - - - img-repository-upload - existing_images - Existing Images - image - - - repoPath - /static-assets/images/avatars - undefined - - - - + Item: Author + + component + /component/author + undefined + false + + + + display-template + + + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Author Properties + + true + + + auto-filename + file-name + + Component ID + + + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + + + checkbox + disabled + + Disable Item + + false + + + + readonly + + boolean + + + + + required + + boolean + + + + + input + name_s + + Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + image-picker + photo_s + + Photo + + + + + + width + { "exact":"", "min":"50", "max":"100" } + range + + + height + { "exact":"", "min":"50", "max":"100" } + range + + + thumbnailWidth + 50 + int + + + thumbnailHeight + 50 + int + + + imageManager + upload_images,existing_images + datasource:image + + + readonly + + boolean + + + + + required + true + boolean + + + + + input + website_s + + Website + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + rte + biography_html + + Biography + + + + + + height + 400 + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + upload_images,existing_images + datasource:image + + + videoManager + + datasource:video + + + + + required + true + boolean + + + + +
+
+ + + img-desktop-upload + upload_images + Upload Images + image + + + repoPath + /static-assets/item/images/avatars/{yyyy}/{mm}/{dd} + undefined + + + + + img-repository-upload + existing_images + Existing Images + image + + + repoPath + /static-assets/images/avatars + undefined + + + + + false + true + + + /site/items/authors/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/level-descriptor/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/level-descriptor/config.xml deleted file mode 100644 index 9812cb9bc9..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/level-descriptor/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/component/level-descriptor
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - true - - - - ^/site/website/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/level-descriptor/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/level-descriptor/form-definition.xml index 76bca6ecfe..67ba87c6d8 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/level-descriptor/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/level-descriptor/form-definition.xml @@ -1,3 +1,4 @@ + -
- Section Defaults - Section Defaults provides inherited values to all children and sibling content items. To learn more about content inheritance see craftercms.com/docs topic "Content Inheritance" - component - /component/level-descriptor - false - - - - display-template - - - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Section Defaults Properties - - true - - - file-name - file-name - - File Name - - crafter-level-descriptor.level - - - - size - 100 - int - - - maxlength - 50 - int - - - readonly - true - boolean - - - - - - -
-
- + Section Defaults + Section Defaults provides inherited values to all children and sibling content items. To learn more about content inheritance see craftercms.com/docs topic "Content Inheritance" + component + /component/level-descriptor + false + + + + display-template + + + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Section Defaults Properties + + true + + + file-name + file-name + + File Name + + crafter-level-descriptor.level + + + + size + 100 + int + + + maxlength + 50 + int + + + readonly + true + boolean + + + + + +
+
+ + false + true + + + ^/site/website/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/post/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/post/config.xml deleted file mode 100644 index de4729acbb..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/post/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/component/post
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - true - - - - /site/items/posts/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/post/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/post/form-definition.xml index 7e5c731e1c..73bce38642 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/post/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/component/post/form-definition.xml @@ -1,3 +1,4 @@ + -
- Item: Post - - component - /component/post - undefined - false - - - - display-template - - - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Post Properties - - true - - - auto-filename - file-name - - Component ID - - - - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - - - checkbox - disabled - - Disable Item - - - - - - readonly - - boolean - - - - - required - - boolean - - - - - date-time - expired_dt - - Expire Date - - - - - - showDate - true - boolean - - - showTime - true - boolean - - - showClear - false - boolean - - - showNowLink - false - boolean - - - populate - true - boolean - - - allowPastDate - true - boolean - - - populateDateExp - +1years - string - - - useCustomTimezone - false - boolean - - - readonly - - boolean - - - readonlyEdit - false - boolean - - - - - required - - boolean - - - - expired_dt_tz - - - - node-selector - authors_o - - Authors - - - - - - minSize - 1 - int - - - maxSize - - int - - - itemManager - author_components - datasource:item - - - readonly - - boolean - - - disableFlattening - - boolean - - - useSingleValueFilename - - boolean - - - - - allowDuplicates - - boolean - - - - - input - title_s - - Title - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - image-picker - featuredImage_s - - Featured Image - - - - - - width - { "exact":"", "min":"", "max":"500" } - range - - - height - { "exact":"", "min":"", "max":"400" } - range - - - thumbnailWidth - 300 - int - - - thumbnailHeight - 200 - int - - - imageManager - uploadImage,browseImage,upload_images,existing_images - datasource:image - - - readonly - - boolean - - - - - required - - boolean - - - - - rte - body_html - - Body - - - - - - height - 300 - int - - - forceRootBlockPTag - true - boolean - - - forcePTags - true - boolean - - - forceBRTags - false - boolean - - - supportedChannels - - supportedChannels - - - rteConfiguration - generic - string - - - imageManager - upload_images,existing_images - datasource:image - - - videoManager - - datasource:video - - - - - required - - boolean - - - - - checkbox-group - categories_o - - Categories - - - - - - datasource - categories - datasource:item - - - selectAll - true - boolean - - - readonly - - boolean - - - - - minSize - - int - - - - - checkbox-group - tags_o - - Tags - - - - - - datasource - tags - datasource:item - - - selectAll - true - boolean - - - readonly - - boolean - - - - - minSize - - int - - - - -
-
- - - simpleTaxonomy - categories - Categories - item - - - dataType - [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] - undefined - - - componentPath - /site/taxonomy/categories.xml - undefined - - - - - shared-content - author_components - Author Components - item - - - repoPath - /site/items/authors - undefined - - - browsePath - /site/items/authors - undefined - - - type - /component/author - undefined - - - - - simpleTaxonomy - tags - Tags - item - - - dataType - [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] - undefined - - - componentPath - /site/taxonomy/tags.xml - undefined - - - - - img-desktop-upload - upload_images - Upload Images - image - - - repoPath - /static-assets/item/images/featured/{yyyy}/{mm}/{dd} - undefined - - - - - img-repository-upload - existing_images - Existing Images - image - - - repoPath - /static-assets/images/featured - undefined - - - - + Item: Post + + component + /component/post + undefined + false + + + + display-template + + + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Post Properties + + true + + + auto-filename + file-name + + Component ID + + + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + + + checkbox + disabled + + Disable Item + + + + + + readonly + + boolean + + + + + required + + boolean + + + + + date-time + expired_dt + + Expire Date + + + + + + showDate + true + boolean + + + showTime + true + boolean + + + showClear + false + boolean + + + showNowLink + false + boolean + + + populate + true + boolean + + + allowPastDate + true + boolean + + + populateDateExp + +1years + string + + + useCustomTimezone + false + boolean + + + readonly + + boolean + + + readonlyEdit + false + boolean + + + + + required + + boolean + + + + expired_dt_tz + + + + node-selector + authors_o + + Authors + + + + + + minSize + 1 + int + + + maxSize + + int + + + itemManager + author_components + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + + + allowDuplicates + + boolean + + + + + input + title_s + + Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + image-picker + featuredImage_s + + Featured Image + + + + + + width + { "exact":"", "min":"", "max":"500" } + range + + + height + { "exact":"", "min":"", "max":"400" } + range + + + thumbnailWidth + 300 + int + + + thumbnailHeight + 200 + int + + + imageManager + uploadImage,browseImage,upload_images,existing_images + datasource:image + + + readonly + + boolean + + + + + required + + boolean + + + + + rte + body_html + + Body + + + + + + height + 300 + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + upload_images,existing_images + datasource:image + + + videoManager + + datasource:video + + + + + required + true + boolean + + + + + checkbox-group + categories_o + + Categories + + + + + + datasource + categories + datasource:item + + + selectAll + true + boolean + + + readonly + + boolean + + + + + minSize + + int + + + + + checkbox-group + tags_o + + Tags + + + + + + datasource + tags + datasource:item + + + selectAll + true + boolean + + + readonly + + boolean + + + + + minSize + + int + + + + +
+
+ + + simpleTaxonomy + categories + Categories + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] + undefined + + + componentPath + /site/taxonomy/categories.xml + undefined + + + + + shared-content + author_components + Author Components + item + + + repoPath + /site/items/authors + undefined + + + browsePath + /site/items/authors + undefined + + + type + /component/author + undefined + + + + + simpleTaxonomy + tags + Tags + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] + undefined + + + componentPath + /site/taxonomy/tags.xml + undefined + + + + + img-desktop-upload + upload_images + Upload Images + image + + + repoPath + /static-assets/item/images/featured/{yyyy}/{mm}/{dd} + undefined + + + + + img-repository-upload + existing_images + Existing Images + image + + + repoPath + /static-assets/images/featured + undefined + + + + + false + true + + + /site/items/posts/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/page/item-explorer/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/page/item-explorer/config.xml deleted file mode 100644 index 337b9784ec..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/page/item-explorer/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/page/item-explorer
- simple - not-used - xml - true - true - false - - true - - - - /site/website/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/page/item-explorer/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/page/item-explorer/form-definition.xml index ecce4b7599..fb1426daa4 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/page/item-explorer/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/page/item-explorer/form-definition.xml @@ -1,3 +1,4 @@ + -
- Item Explorer - - page - /page/item-explorer - undefined - false - - - - placeInNav - - true - boolean - - - display-template - - /templates/web/item-explorer.ftl - template - - - no-template-required - - - boolean - - - descriptor-mapper - - hierarchical-mapper - string - - - -
- Page Settings - - true - - - file-name - file-name - - Page URL - - - - - - size - 50 - int - - - maxlength - 50 - int - - - path - - string - - - readonly - true - boolean - - - - - - - input - internal-name - - File Title - - - - - - size - 50 - int - - - maxlength - 60 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - int - - - - - checkbox - disabled - - Disable Item Explorer - - - - - - readonly - - boolean - - - - - required - - boolean - - - - -
-
- Main Content - - true - - - input - title_s - title - Title - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - rte - body_html - main - Help Text - - - - - - height - 350 - int - - - forceRootBlockPTag - true - boolean - - - forcePTags - true - boolean - - - forceBRTags - false - boolean - - - supportedChannels - - supportedChannels - - - rteConfiguration - generic - string - - - imageManager - - datasource:image - - - videoManager - - datasource:video - - - - - required - - boolean - - - - -
-
- + Item Explorer + + page + /page/item-explorer + undefined + false + + + + placeInNav + + true + boolean + + + display-template + + /templates/web/item-explorer.ftl + template + + + no-template-required + + + boolean + + + descriptor-mapper + + hierarchical-mapper + string + + + +
+ Page Settings + + true + + + file-name + file-name + + Page URL + + + + + + size + 50 + int + + + maxlength + 50 + int + + + path + + string + + + readonly + true + boolean + + + + + + input + internal-name + + File Title + + + + + + size + 50 + int + + + maxlength + 60 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + + + checkbox + disabled + + Disable Item Explorer + + + + + + readonly + + boolean + + + + + required + + boolean + + + + +
+
+ Main Content + + true + + + input + title_s + title + Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + rte + body_html + main + Help Text + + + + + + height + 350 + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + + datasource:image + + + videoManager + + datasource:video + + + + + required + + boolean + + + + +
+
+ + true + true + + + /site/website/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/taxonomy/config.xml b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/taxonomy/config.xml deleted file mode 100644 index 3dd3c26aa5..0000000000 --- a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/taxonomy/config.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - -
/taxonomy
- simple - NOT-USED-BY-SIMPLE-FORM-ENGINE - xml - false - false - false - - true - - - - /site/taxonomy/.* - - -
diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/taxonomy/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/taxonomy/form-definition.xml index 284d71d701..6156b8c77a 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/taxonomy/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/content-types/taxonomy/form-definition.xml @@ -1,3 +1,4 @@ + -
- Taxonomy - - component - /taxonomy - undefined - false - - - - display-template - - - template - - - no-template-required - - - boolean - - - merge-strategy - - inherit-levels - string - - - -
- Taxonomy Properties - - true - - - file-name - file-name - - Component ID - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - - - - - input - internal-name - - Internal Name - - - - - - size - 50 - int - - - maxlength - 50 - int - - - - - required - - boolean - - - - - repeat - items - - Items - - 1 - * - - - minOccurs - 1 - string - - - maxOccurs - * - string - - - - - input - key - - Key - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - input - value - - Value - - - - - - size - 50 - int - - - maxlength - 50 - int - - - readonly - - boolean - - - tokenize - false - boolean - - - - - required - - boolean - - - pattern - - string - - - - - - -
-
- + Taxonomy + + component + /taxonomy + undefined + false + + + + display-template + + + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Taxonomy Properties + + true + + + file-name + file-name + + Component ID + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + + + required + true + boolean + + + + + repeat + items + + Items + + 1 + * + + + minOccurs + 1 + string + + + maxOccurs + * + string + + + + + input + key + + Key + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + input + value + + Value + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + + +
+
+ + false + true + + + /site/taxonomy/.* + + diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/studio_version.xml b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/studio_version.xml index 1fb428280a..1adc2652d0 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/studio_version.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/5000_headless_blog/config/studio/studio_version.xml @@ -15,5 +15,5 @@ ~ along with this program. If not, see . --> - 5.0.0.1 + 5.0.0.2 From 0613a5e5c3b0e6dc6f20ff68c6952ca91a7dae46 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Wed, 22 Apr 2026 10:46:11 -0600 Subject: [PATCH 06/38] ContentType APIs minor fixes --- src/main/api/studio-api.yaml | 2 +- .../studio/controller/rest/v2/ContentTypeController.java | 2 +- .../studio/controller/rest/v2/RequestMappingConstants.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/api/studio-api.yaml b/src/main/api/studio-api.yaml index f2791da4c9..19d844252a 100644 --- a/src/main/api/studio-api.yaml +++ b/src/main/api/studio-api.yaml @@ -3899,7 +3899,7 @@ paths: '500': $ref: '#/components/responses/InternalServerError' - /api/2/configuration/content-types/{siteId}/allowed_types: + /api/2/configuration/content_types/{siteId}/allowed_types: get: tags: - contentTypes diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java b/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java index 9d6e2b07cb..2e4948678e 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java @@ -47,7 +47,7 @@ @Validated @RestController -@RequestMapping(API_2 + CONFIGURATION + CONTENT_TYPE) +@RequestMapping(API_2 + CONFIGURATION + CONTENT_TYPES) public class ContentTypeController { private final ContentTypeService contentTypeService; diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java b/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java index 9180d38219..960d081ece 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java @@ -173,7 +173,7 @@ public final class RequestMappingConstants { public static final String WRITE_CONFIGURATION = "/write_configuration"; public static final String GET_CONFIGURATION_HISTORY = "/get_configuration_history"; public static final String TRANSLATION = "/translation"; - public static final String CONTENT_TYPE = "/content-type"; + public static final String CONTENT_TYPES = "/content_types"; public static final String USAGE = "/usage"; public static final String PREVIEW_IMAGE = "/preview_image"; public static final String FORM_CONTROLLER = "/form_controller"; From eb73f074c8310153ddce7cf0c516905067864d74 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Wed, 22 Apr 2026 17:23:36 -0600 Subject: [PATCH 07/38] ContentType APIs --- .../service/content/ContentTypeService.java | 13 +- .../studio/api/v2/utils/StudioUtils.java | 22 + .../rest/v2/ContentTypeController.java | 23 +- .../controller/rest/v2/ResultConstants.java | 2 +- .../configuration/ContentTypesConfigImpl.java | 24 +- .../content/ContentTypeServiceImpl.java | 12 +- .../ContentTypeServiceInternalImpl.java | 196 ++-- .../studio/impl/v2/utils/Wrapper.java | 39 + .../studio/impl/v2/utils/db/DBUtils.java | 16 +- .../studio/model/contentType/ContentType.java | 139 ++- .../model/contentType/CopyDependency.java | 1 - .../model/contentType/DeleteDependency.java | 5 +- .../contentType/PathIncludeExcludes.java | 29 + .../studio/model/contentType/PathPattern.java | 34 + .../studio/studio-services-context.xml | 1 + .../scripts/api/ServiceFactory.groovy | 1 - .../ContentTypeServiceInternalImplTest.java | 21 + .../myContentType/form-definition.xml | 905 ++++++++++++++++++ 18 files changed, 1367 insertions(+), 116 deletions(-) create mode 100644 src/main/java/org/craftercms/studio/impl/v2/utils/Wrapper.java create mode 100644 src/main/java/org/craftercms/studio/model/contentType/PathIncludeExcludes.java create mode 100644 src/main/java/org/craftercms/studio/model/contentType/PathPattern.java create mode 100644 src/test/resources/crafter/studio/content-type/myContentType/form-definition.xml diff --git a/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java b/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java index 3b32aeb701..e9d30c8a10 100644 --- a/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java +++ b/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java @@ -20,7 +20,6 @@ import org.craftercms.studio.api.v1.exception.SiteNotFoundException; import org.craftercms.studio.api.v1.exception.security.AuthenticationException; import org.craftercms.studio.api.v1.exception.security.UserNotFoundException; -import org.craftercms.studio.api.v1.to.ContentTypeConfigTO; import org.craftercms.studio.api.v2.dal.QuickCreateItem; import org.craftercms.studio.model.contentType.ContentType; import org.craftercms.studio.model.contentType.ContentTypeUsage; @@ -113,6 +112,14 @@ void deleteContentType(String siteId, String contentType, boolean deleteDependen */ List getQuickCreatableContentTypes(String siteId) throws ServiceLayerException; + /** + * Get all content types for the given site. + * @param siteId the id of the site + * @return a collection of content types + * @throws SiteNotFoundException if the site with the given id does not exist + */ + Collection getAllContentTypes(String siteId) throws ServiceLayerException; + /** * Get the content type configuration for a given content type id * @@ -120,7 +127,7 @@ void deleteContentType(String siteId, String contentType, boolean deleteDependen * @param contentTypeId the id of the content type * @return the content type configuration */ - ContentType getContentType(String siteId, String contentTypeId) throws SiteNotFoundException; + ContentType getContentType(String siteId, String contentTypeId) throws ServiceLayerException; /** * Get a collection of the ids of the content types allowed for the given site and path @@ -129,5 +136,5 @@ void deleteContentType(String siteId, String contentType, boolean deleteDependen * @param path the path of the content item to be created * @return a collection of the ids of the content types allowed for the given site and path */ - Collection getAllowedContentTypes(String siteId, String path); + Collection getAllowedContentTypes(String siteId, String path) throws ServiceLayerException; } diff --git a/src/main/java/org/craftercms/studio/api/v2/utils/StudioUtils.java b/src/main/java/org/craftercms/studio/api/v2/utils/StudioUtils.java index 0c43f19310..93f4b3c779 100644 --- a/src/main/java/org/craftercms/studio/api/v2/utils/StudioUtils.java +++ b/src/main/java/org/craftercms/studio/api/v2/utils/StudioUtils.java @@ -21,6 +21,7 @@ import org.apache.commons.io.IOUtils; import org.craftercms.commons.http.RequestContext; import org.craftercms.studio.api.v1.constant.StudioConstants; +import org.craftercms.studio.model.contentType.ContentType; import org.dom4j.Document; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,6 +36,7 @@ import java.nio.file.Paths; import java.util.List; import java.util.UUID; +import java.util.regex.Pattern; import static org.apache.commons.io.FilenameUtils.directoryContains; import static org.apache.commons.lang3.StringUtils.isEmpty; @@ -241,4 +243,24 @@ public static boolean underPagesRoot(String path) { public static String movePath(String sourceRoot, String targetRoot, String sourcePath) { return Path.of(targetRoot).resolve(Path.of(sourceRoot).relativize(Path.of(sourcePath))).toString(); } + + /** + * Get the content type type by its id, which is determined by the content type naming convention. + * + * @param contentTypeId the content type id to check + * @return
    + *
  • component if the name matches component naming convention
  • + *
  • page if the name matches page naming convention
  • + *
  • unknown if name don't match any known convention
  • + *
+ */ + public static ContentType.Type getContentTypeTypeById(String contentTypeId) { + if (Pattern.matches("/component/.*?", contentTypeId)) { + return ContentType.Type.component; + } + if (Pattern.matches("/page/.*?", contentTypeId)){ + return ContentType.Type.page; + } + return ContentType.Type.unknown; + } } diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java b/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java index 2e4948678e..b6bf30eda3 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java @@ -21,6 +21,7 @@ import org.craftercms.commons.validation.annotations.param.ValidConfigurationPath; import org.craftercms.commons.validation.annotations.param.ValidExistingContentPath; import org.craftercms.commons.validation.annotations.param.ValidSiteId; +import org.craftercms.commons.validation.annotations.param.ValidateSecurePathParam; import org.craftercms.studio.api.v1.exception.ServiceLayerException; import org.craftercms.studio.api.v1.exception.SiteNotFoundException; import org.craftercms.studio.api.v1.exception.security.AuthenticationException; @@ -39,7 +40,10 @@ import org.springframework.web.bind.annotation.*; import java.beans.ConstructorProperties; +import java.util.Collection; +import java.util.List; +import static org.apache.commons.lang3.StringUtils.isEmpty; import static org.craftercms.studio.controller.rest.v2.RequestMappingConstants.*; import static org.craftercms.studio.controller.rest.v2.ResultConstants.*; import static org.craftercms.studio.model.rest.ApiResponse.DELETED; @@ -76,23 +80,30 @@ public ResponseEntity getContentTypeFormController(@ValidSiteId @Reque @GetMapping(PREVIEW_IMAGE) public ResponseEntity getContentTypePreviewImage(@ValidSiteId @RequestParam String siteId, - @ValidConfigurationPath @RequestParam String contentTypeId) + @ValidConfigurationPath @ValidateSecurePathParam @RequestParam String contentTypeId) throws ServiceLayerException { ImmutablePair resource = contentTypeService.getContentTypePreviewImage(siteId, contentTypeId); return getResourceResponse(resource.getKey(), resource.getValue()); } @GetMapping(SITE_ID) - public ResultOne getContentType(@ValidSiteId @PathVariable String siteId, - @ValidConfigurationPath @RequestParam String contentTypeId) throws SiteNotFoundException { - var result = new ResultOne(); + public ResultList getContentTypes(@ValidSiteId @PathVariable String siteId, + @ValidConfigurationPath @RequestParam(required = false) String contentTypeId) throws ServiceLayerException { + var result = new ResultList(); result.setResponse(OK); - result.setEntity(RESULT_KEY_CONTENT_TYPE, contentTypeService.getContentType(siteId, contentTypeId)); + + Collection contentTypes; + if (isEmpty(contentTypeId)) { + contentTypes = contentTypeService.getAllContentTypes(siteId); + } else { + contentTypes = List.of(contentTypeService.getContentType(siteId, contentTypeId)); + } + result.setEntities(RESULT_KEY_CONTENT_TYPES, contentTypes); return result; } @GetMapping(SITE_ID + ALLOWED_TYPES) - public ResultList getAllowedContentTypes(@ValidSiteId @PathVariable String siteId, @ValidExistingContentPath @RequestParam String path) { + public ResultList getAllowedContentTypes(@ValidSiteId @PathVariable String siteId, @ValidExistingContentPath @RequestParam String path) throws ServiceLayerException { ResultList result = new ResultList<>(); result.setResponse(OK); result.setEntities(RESULT_KEY_ALLOWED_TYPES, contentTypeService.getAllowedContentTypes(siteId, path)); diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/ResultConstants.java b/src/main/java/org/craftercms/studio/controller/rest/v2/ResultConstants.java index 502cb7b0d7..8f106760c9 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/ResultConstants.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/ResultConstants.java @@ -120,7 +120,7 @@ public final class ResultConstants { /** * Content types controller */ - public static final String RESULT_KEY_CONTENT_TYPE = "contentType"; + public static final String RESULT_KEY_CONTENT_TYPES = "contentTypes"; public static final String RESULT_KEY_ALLOWED_TYPES = "allowedTypes"; /** diff --git a/src/main/java/org/craftercms/studio/impl/v1/service/configuration/ContentTypesConfigImpl.java b/src/main/java/org/craftercms/studio/impl/v1/service/configuration/ContentTypesConfigImpl.java index 0c9756b345..6b283b7581 100644 --- a/src/main/java/org/craftercms/studio/impl/v1/service/configuration/ContentTypesConfigImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v1/service/configuration/ContentTypesConfigImpl.java @@ -33,6 +33,7 @@ import org.craftercms.studio.api.v2.dal.security.NormalizedRole; import org.craftercms.studio.api.v2.service.config.ConfigurationService; import org.craftercms.studio.api.v2.utils.StudioConfiguration; +import org.craftercms.studio.api.v2.utils.StudioUtils; import org.craftercms.studio.impl.v1.util.ContentFormatUtils; import org.craftercms.studio.impl.v2.utils.DateUtils; import org.dom4j.Document; @@ -51,6 +52,7 @@ import static org.craftercms.studio.api.v1.constant.StudioConstants.FILE_SEPARATOR; import static org.craftercms.studio.api.v2.utils.StudioConfiguration.CONFIGURATION_SITE_CONTENT_TYPES_CONFIG_FILE_NAME; import static org.craftercms.studio.api.v2.utils.StudioConfiguration.CONFIGURATION_SITE_CONTENT_TYPES_CONFIG_PATH; +import static org.craftercms.studio.api.v2.utils.StudioUtils.getContentTypeTypeById; /** * @author Dejan Brkic @@ -127,7 +129,7 @@ public ContentTypeConfigTO loadConfiguration(@ValidateStringParam String site, loadDeleteDependencies(contentTypeConfig, root.selectNodes("delete-dependencies/delete-dependency")); loadCopyDependencyPatterns(contentTypeConfig, root.selectNodes("copy-dependencies/copy-dependency")); contentTypeConfig.setLastUpdated(DateUtils.getCurrentTime()); - contentTypeConfig.setType(getContentTypeTypeByName(name)); + contentTypeConfig.setType(getContentTypeTypeById(name).name()); boolean quickCreate = ContentFormatUtils.getBooleanValue(root.valueOf(QUICK_CREATE)); contentTypeConfig.setQuickCreate(quickCreate); contentTypeConfig.setQuickCreatePath(root.valueOf(QUICK_CREATE_PATH)); @@ -172,26 +174,6 @@ protected void loadDeleteDependencies(ContentTypeConfigTO contentTypeConfig, Lis } } - /** - * Checks name for naming convention. - * - * @param name Name to be check - * @return
    - *
  • component if the name matches component naming convention
  • - *
  • page if the name matches page naming convention
  • - *
  • unknown if name don't match any known convention
  • - *
- */ - private String getContentTypeTypeByName(String name) { - if (Pattern.matches("/component/.*?", name)) { - return "component"; - } else if (Pattern.matches("/page/.*?", name)) - return "page"; - else { - return "unknown"; - } - } - /** * get paths * diff --git a/src/main/java/org/craftercms/studio/impl/v2/service/content/ContentTypeServiceImpl.java b/src/main/java/org/craftercms/studio/impl/v2/service/content/ContentTypeServiceImpl.java index 9bbd3ec07e..3f29bd9214 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/service/content/ContentTypeServiceImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v2/service/content/ContentTypeServiceImpl.java @@ -19,7 +19,6 @@ import org.craftercms.commons.security.permissions.DefaultPermission; import org.craftercms.commons.security.permissions.annotations.HasPermission; import org.craftercms.studio.api.v1.exception.ServiceLayerException; -import org.craftercms.studio.api.v1.exception.SiteNotFoundException; import org.craftercms.studio.api.v1.exception.security.AuthenticationException; import org.craftercms.studio.api.v1.exception.security.UserNotFoundException; import org.craftercms.studio.api.v2.annotation.ContentPath; @@ -122,14 +121,21 @@ public List getQuickCreatableContentTypes(@SiteId String siteId @Override @RequireSiteReady @HasPermission(type = DefaultPermission.class, action = PERMISSION_CONTENT_READ) - public ContentType getContentType(@SiteId String siteId, String contentTypeId) throws SiteNotFoundException { + public Collection getAllContentTypes(@SiteId String siteId) throws ServiceLayerException { + return contentTypeServiceInternal.getAllContentTypes(siteId); + } + + @Override + @RequireSiteReady + @HasPermission(type = DefaultPermission.class, action = PERMISSION_CONTENT_READ) + public ContentType getContentType(@SiteId String siteId, String contentTypeId) throws ServiceLayerException { return contentTypeServiceInternal.getContentType(siteId, contentTypeId); } @Override @RequireSiteReady @HasPermission(type = DefaultPermission.class, action = PERMISSION_CONTENT_READ) - public Collection getAllowedContentTypes(@SiteId String siteId, @ContentPath String path) { + public Collection getAllowedContentTypes(@SiteId String siteId, @ContentPath String path) throws ServiceLayerException { return contentTypeServiceInternal.getAllowedContentTypes(siteId, path); } diff --git a/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImpl.java b/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImpl.java index 83fa2a1d00..b14f0a8dba 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2025 Crafter Software Corporation. All Rights Reserved. + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by @@ -16,11 +16,13 @@ package org.craftercms.studio.impl.v2.service.content.internal; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.google.common.cache.Cache; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.craftercms.commons.lang.UrlUtils; -import org.craftercms.commons.validation.annotations.param.ValidateSecurePathParam; +import org.craftercms.studio.api.v1.constant.StudioConstants; import org.craftercms.studio.api.v1.exception.ContentNotFoundException; import org.craftercms.studio.api.v1.exception.ServiceLayerException; import org.craftercms.studio.api.v1.exception.SiteNotFoundException; @@ -35,10 +37,13 @@ import org.craftercms.studio.api.v2.dal.ItemDAO; import org.craftercms.studio.api.v2.dal.QuickCreateItem; import org.craftercms.studio.api.v2.dal.item.LightItem; +import org.craftercms.studio.api.v2.exception.configuration.ConfigurationException; import org.craftercms.studio.api.v2.service.config.ConfigurationService; import org.craftercms.studio.api.v2.service.content.ContentService; import org.craftercms.studio.api.v2.service.publish.PublishService; import org.craftercms.studio.api.v2.utils.GitRepositoryHelper; +import org.craftercms.studio.api.v2.utils.StudioConfiguration; +import org.craftercms.studio.impl.v2.utils.Wrapper; import org.craftercms.studio.impl.v2.utils.security.SecurityUtils; import org.craftercms.studio.model.contentType.ContentType; import org.craftercms.studio.model.contentType.ContentTypeUsage; @@ -53,28 +58,30 @@ import java.beans.ConstructorProperties; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; +import java.util.*; import static java.lang.String.format; import static java.nio.file.Files.walkFileTree; -import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; +import static org.apache.commons.collections4.CollectionUtils.isEmpty; import static org.apache.commons.io.FilenameUtils.normalize; import static org.apache.commons.lang3.RegExUtils.replaceAll; -import static org.apache.commons.lang3.StringUtils.*; +import static org.apache.commons.lang3.StringUtils.isNotEmpty; +import static org.apache.commons.lang3.Strings.CI; import static org.craftercms.studio.api.v1.constant.GitRepositories.SANDBOX; import static org.craftercms.studio.api.v1.constant.StudioConstants.*; import static org.craftercms.studio.permissions.StudioPermissionsConstants.PERMISSION_CONTENT_CREATE; +/** + * Internal implementation of {@link org.craftercms.studio.api.v2.service.content.ContentTypeService}. + */ public class ContentTypeServiceInternalImpl implements org.craftercms.studio.api.v2.service.content.ContentTypeService { private static final Logger logger = LoggerFactory.getLogger(ContentTypeServiceInternalImpl.class); @@ -96,23 +103,27 @@ public class ContentTypeServiceInternalImpl implements org.craftercms.studio.api protected final String defaultPreviewImagePath; protected final String formControllerFilePath; protected final ServicesConfig servicesConfig; + protected final StudioConfiguration studioConfiguration; private final GitRepositoryHelper gitRepositoryHelper; + private final Cache cache; + private final XmlMapper xmlMapper; @ConstructorProperties({"contentTypeService", "securityService", "configurationService", "itemDao", - "contentTypeBasePathPattern", "contentTypeDefinitionFilename", "contentTypeConfigFilename", - "contentTypesRootPath", - "templateXPath", "controllerPattern", "controllerFormat", "previewImageXPath", "defaultPreviewImagePath", - "formControllerFilePath", "gitRepositoryHelper", - "servicesConfig"}) + "contentTypeBasePathPattern", "contentTypeDefinitionFilename", "contentTypeConfigFilename", + "contentTypesRootPath", + "templateXPath", "controllerPattern", "controllerFormat", "previewImageXPath", "defaultPreviewImagePath", + "formControllerFilePath", "gitRepositoryHelper", + "servicesConfig", "studioConfiguration", + "cache"}) public ContentTypeServiceInternalImpl(ContentTypeService contentTypeService, SecurityService securityService, ConfigurationService configurationService, ItemDAO itemDao, String contentTypeBasePathPattern, String contentTypeDefinitionFilename, String contentTypeConfigFilename, String contentTypesRootPath, String templateXPath, String controllerPattern, String controllerFormat, String previewImageXPath, String defaultPreviewImagePath, - String formControllerFilePath, - GitRepositoryHelper gitRepositoryHelper, - ServicesConfig servicesConfig) { + String formControllerFilePath, GitRepositoryHelper gitRepositoryHelper, + ServicesConfig servicesConfig, StudioConfiguration studioConfiguration, + Cache cache) { this.contentTypeService = contentTypeService; this.securityService = securityService; this.configurationService = configurationService; @@ -129,6 +140,9 @@ public ContentTypeServiceInternalImpl(ContentTypeService contentTypeService, Sec this.formControllerFilePath = formControllerFilePath; this.gitRepositoryHelper = gitRepositoryHelper; this.servicesConfig = servicesConfig; + this.studioConfiguration = studioConfiguration; + this.cache = cache; + this.xmlMapper = new XmlMapper(); } public void setContentService(ContentService contentService) { @@ -138,37 +152,109 @@ public void setContentService(ContentService contentService) { @Override public List getQuickCreatableContentTypes(String siteId) throws ServiceLayerException { return contentTypeService.getAllContentTypes(siteId, true).stream() - .filter(ContentTypeConfigTO::isQuickCreate) - .filter(contentType -> { - try { - return securityService.getUserPermissions(siteId, contentType.getQuickCreatePath(), SecurityUtils.getCurrentUsername()) - .contains(PERMISSION_CONTENT_CREATE); - } catch (SiteNotFoundException e) { - // This should never happen. If the site does not exist then getAllContentTypes() call above should have thrown an exception - return false; + .filter(ContentTypeConfigTO::isQuickCreate) + .filter(contentType -> { + try { + return securityService.getUserPermissions(siteId, contentType.getQuickCreatePath(), SecurityUtils.getCurrentUsername()) + .contains(PERMISSION_CONTENT_CREATE); + } catch (SiteNotFoundException e) { + // This should never happen. If the site does not exist then getAllContentTypes() call above should have thrown an exception + return false; + } + }) + .map(contentType -> { + QuickCreateItem item = new QuickCreateItem(); + item.setSiteId(siteId); + item.setContentTypeId(contentType.getForm()); + item.setLabel(contentType.getLabel()); + item.setPath(contentType.getQuickCreatePath()); + return item; + }) + .collect(toList()); + } + + @Override + public Collection getAllContentTypes(String siteId) throws ServiceLayerException { + Collection contentTypes = new ArrayList<>(); + + Path repoRootPath = gitRepositoryHelper.buildRepoPath(SANDBOX, siteId); + Path contentTypesRepoPath = repoRootPath.resolve(gitRepositoryHelper.getGitPath(contentTypesRootPath)); + try { + Wrapper fileVisitorException = new Wrapper<>(); + walkFileTree(contentTypesRepoPath, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + if (!file.getFileName().toString().equals(contentTypeDefinitionFilename)) { + return FileVisitResult.CONTINUE; + } + try { + contentTypes.add(getContentType(siteId, contentTypesRepoPath.relativize(file.getParent()).toString())); + } catch (ServiceLayerException e) { + fileVisitorException.set(e); + return FileVisitResult.TERMINATE; + } + return FileVisitResult.SKIP_SIBLINGS; } - }) - .map(contentType -> { - QuickCreateItem item = new QuickCreateItem(); - item.setSiteId(siteId); - item.setContentTypeId(contentType.getForm()); - item.setLabel(contentType.getLabel()); - item.setPath(contentType.getQuickCreatePath()); - return item; - }) - .collect(toList()); + }); + if (fileVisitorException.hasValue()) { + throw fileVisitorException.get(); + } + } catch (Exception e) { + throw new ServiceLayerException(format("Failed to retrieve content types for site '%s'", siteId), e); + } + + return contentTypes; } @Override - public ContentType getContentType(String siteId, String contentTypeId) throws SiteNotFoundException { - // TODO: implement - return null; + public ContentType getContentType(String siteId, String contentTypeId) throws ServiceLayerException { + String configFileFullPath = getContentTypeFormPath(siteId, contentTypeId); + var cacheKey = configurationService.getCacheKey(siteId, null, configFileFullPath, + null, "object"); + ContentType contentType = cache.getIfPresent(cacheKey); + if (contentType == null) { + logger.debug("Cache miss for key '{}'", cacheKey); + contentType = loadContentType(siteId, contentTypeId); + cache.put(cacheKey, contentType); + } + + return contentType; + } + + /** + * Get content type form-definition.xml full path in content repository + */ + private String getContentTypeFormPath(String siteId, String contentTypeId) { + String siteConfigPath = contentTypeBasePathPattern.replaceAll(StudioConstants.PATTERN_SITE, siteId) + .replaceAll(StudioConstants.PATTERN_CONTENT_TYPE, contentTypeId); + String configFileFullPath = siteConfigPath + FILE_SEPARATOR + contentTypeDefinitionFilename; + return configFileFullPath; + } + + /** + * Load content type form-definition.xml from content repository and map it to ContentType object + * + * @param siteId the site id + * @param contentTypeId the content type id + * @return the ContentType object mapped from form-definition.xml + * @throws ConfigurationException if there is any error reading the content type configuration + */ + protected ContentType loadContentType(String siteId, String contentTypeId) throws ConfigurationException, ContentNotFoundException { + InputStream configurationAsStream = contentService.getContent(siteId, getContentTypeFormPath(siteId, contentTypeId)); + try { + return xmlMapper.readValue(configurationAsStream, ContentType.class); + } catch (IOException e) { + throw new ConfigurationException(format("Failed to read content type configuration for content type '%s' in site '%s'", contentTypeId, siteId), e); + } } @Override - public Collection getAllowedContentTypes(String siteId, String path) { - // TODO: implement - return emptyList(); + public Collection getAllowedContentTypes(String siteId, String path) throws ServiceLayerException { + return getAllContentTypes(siteId).stream() + .filter(ct -> isEmpty(ct.getPathIncludes()) || ct.getPathIncludes().stream().anyMatch(path::matches)) + .filter(ct -> ct.getPathExcludes().stream().noneMatch(path::matches)) + .map(ContentType::getId) + .collect(toList()); } @Override @@ -186,21 +272,21 @@ public ContentTypeUsage getContentTypeUsage(String siteId, String contentType) t List items = itemDao.getContentTypeUsages(siteId, contentType, scriptPath); usages.setContent(items.stream() - .filter(i -> equalsAnyIgnoreCase(i.getMetadata().systemType(), CONTENT_TYPE_PAGE, CONTENT_TYPE_COMPONENT)) - .map(LightItem::getPath) - .collect(toList())); + .filter(i -> CI.equalsAny(i.getMetadata().systemType(), CONTENT_TYPE_PAGE, CONTENT_TYPE_COMPONENT)) + .map(LightItem::getPath) + .collect(toList())); usages.setScripts(items.stream() - .filter(i -> equalsIgnoreCase(i.getMetadata().systemType(), (CONTENT_TYPE_SCRIPT))) - .map(LightItem::getPath) - .collect(toList())); + .filter(i -> CI.equals(i.getMetadata().systemType(), (CONTENT_TYPE_SCRIPT))) + .map(LightItem::getPath) + .collect(toList())); return usages; } @Override public ImmutablePair getContentTypePreviewImage(String siteId, - @ValidateSecurePathParam String contentTypeId) throws ServiceLayerException { + String contentTypeId) throws ServiceLayerException { String filename = getContentTypePreviewImageFilename(siteId, contentTypeId); boolean hasPreviewImage = isNotEmpty(filename) && !filename.equals("undefined"); // form-definition could have undefined value for imageThumbnail @@ -224,7 +310,7 @@ public ImmutablePair getContentTypeFormController(String siteI @Override public void deleteContentType(String siteId, String contentType, boolean deleteDependencies) - throws ServiceLayerException, AuthenticationException, UserNotFoundException { + throws ServiceLayerException, AuthenticationException, UserNotFoundException { ContentTypeUsage usage = getContentTypeUsage(siteId, contentType); var files = new HashSet(); @@ -232,7 +318,7 @@ public void deleteContentType(String siteId, String contentType, boolean deleteD if (CollectionUtils.isNotEmpty(usage.getContent())) { if (!deleteDependencies) { throw new ServiceLayerException("The content-type " + contentType + " in site " + siteId + - " can't be deleted because there is content using it"); + " can't be deleted because there is content using it"); } files.addAll(usage.getContent()); @@ -301,10 +387,10 @@ protected String getContentTypePath(String contentType) { /** * Get preview image filename extract from form-definition.xml * - * @param siteId - * @param contentTypeId + * @param siteId the site id + * @param contentTypeId the content type id * @return preview image filename - * @throws ServiceLayerException + * @throws ServiceLayerException if there is any error reading the content type definition */ protected String getContentTypePreviewImageFilename(String siteId, String contentTypeId) throws ServiceLayerException { Document definition = getFormDefinitionDocument(siteId, contentTypeId); @@ -321,10 +407,10 @@ protected String getContentTypePreviewImageFilename(String siteId, String conten /** * Get form-definition.xml as Document of a content type * - * @param siteId - * @param contentTypeId + * @param siteId the site id + * @param contentTypeId the content type id * @return Document of form-definition.xml - * @throws ServiceLayerException + * @throws ServiceLayerException if there is any error reading the content type definition or if the definition file does not exist */ @RequireSiteExists protected Document getFormDefinitionDocument(@SiteId String siteId, String contentTypeId) throws ServiceLayerException { diff --git a/src/main/java/org/craftercms/studio/impl/v2/utils/Wrapper.java b/src/main/java/org/craftercms/studio/impl/v2/utils/Wrapper.java new file mode 100644 index 0000000000..cca58946f7 --- /dev/null +++ b/src/main/java/org/craftercms/studio/impl/v2/utils/Wrapper.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.impl.v2.utils; + +/** + * A simple wrapper class to hold a value of type T. This can be used to work + * around the fact that Java does not to modify variables from within lambda expressions or anonymous classes. + * + * @param + */ +public class Wrapper { + private T value; + + public T get() { + return value; + } + + public void set(T value) { + this.value = value; + } + + public boolean hasValue() { + return this.value != null; + } +} diff --git a/src/main/java/org/craftercms/studio/impl/v2/utils/db/DBUtils.java b/src/main/java/org/craftercms/studio/impl/v2/utils/db/DBUtils.java index a255343166..4d5a5355f4 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/utils/db/DBUtils.java +++ b/src/main/java/org/craftercms/studio/impl/v2/utils/db/DBUtils.java @@ -16,6 +16,7 @@ package org.craftercms.studio.impl.v2.utils.db; +import org.craftercms.studio.impl.v2.utils.Wrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.transaction.PlatformTransactionManager; @@ -158,19 +159,4 @@ public interface ThrowingRunnable { void run() throws Exception; } - private static class Wrapper { - private T value; - - public T get() { - return value; - } - - public void set(T value) { - this.value = value; - } - - public boolean hasValue() { - return this.value != null; - } - } } diff --git a/src/main/java/org/craftercms/studio/model/contentType/ContentType.java b/src/main/java/org/craftercms/studio/model/contentType/ContentType.java index eb170209c5..83bf4e0211 100644 --- a/src/main/java/org/craftercms/studio/model/contentType/ContentType.java +++ b/src/main/java/org/craftercms/studio/model/contentType/ContentType.java @@ -16,30 +16,151 @@ package org.craftercms.studio.model.contentType; +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; import org.craftercms.studio.api.v2.dal.security.NormalizedRole; +import org.craftercms.studio.api.v2.utils.StudioUtils; -import java.util.List; -import java.util.Set; +import java.util.*; + +import static java.util.Collections.emptyList; +import static org.apache.commons.collections4.CollectionUtils.emptyIfNull; /** * Represents a content type in the system. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class ContentType { + @JsonAlias("content-type") + @JsonProperty("id") protected String id; + @JsonProperty("title") protected String label; - protected Type type; - protected Set allowedRoles; - protected List deleteDependencies; - protected List copyDependencies; + @JsonAlias("allowed-roles") + @JsonProperty("allowedRoles") + protected Collection allowedRoles = emptyList(); + @JsonAlias("delete-dependencies") + @JsonProperty("deleteDependencies") + protected List deleteDependencies = emptyList(); + @JsonAlias("copy-dependencies") + @JsonProperty("copyDependencies") + protected List copyDependencies = emptyList(); protected boolean previewable; protected String imageThumbnail; protected boolean noThumbnail; - protected List pathIncludes; - protected List pathExcludes; + // Because both excludes and excludes need to be set together, we use a single property for both, and ignore it during serialization + // so the JSON representation still has the same structure as before, with separate includes and excludes properties + @JsonProperty(value = "paths", access = JsonProperty.Access.WRITE_ONLY) + protected PathIncludeExcludes pathIncludeExcludes; protected boolean quickCreate; protected String quickCreatePath; + public Collection getAllowedRoles() { + return allowedRoles; + } + + public void setAllowedRoles(Collection allowedRoles) { + Set normalizedRoles = new HashSet<>(); + for (String role : emptyIfNull(allowedRoles)) { + normalizedRoles.add(new NormalizedRole(role)); + } + this.allowedRoles = normalizedRoles; + } + + public List getCopyDependencies() { + return copyDependencies; + } + + public void setCopyDependencies(List copyDependencies) { + this.copyDependencies = copyDependencies; + } + + public List getDeleteDependencies() { + return deleteDependencies; + } + + public void setDeleteDependencies(List deleteDependencies) { + this.deleteDependencies = deleteDependencies; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getImageThumbnail() { + return imageThumbnail; + } + + public void setImageThumbnail(String imageThumbnail) { + this.imageThumbnail = imageThumbnail; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public boolean isNoThumbnail() { + return noThumbnail; + } + + public void setNoThumbnail(boolean noThumbnail) { + this.noThumbnail = noThumbnail; + } + + public Collection getPathIncludes() { + return emptyIfNull(pathIncludeExcludes.includes()).stream() + .map(PathPattern::getPattern) + .toList(); + } + + public Collection getPathExcludes() { + return emptyIfNull(pathIncludeExcludes.excludes()).stream() + .map(PathPattern::getPattern) + .toList(); + } + + public void setPathIncludeExcludes(PathIncludeExcludes pathIncludeExcludes) { + this.pathIncludeExcludes = pathIncludeExcludes; + } + + public boolean isPreviewable() { + return previewable; + } + + public void setPreviewable(boolean previewable) { + this.previewable = previewable; + } + + public boolean isQuickCreate() { + return quickCreate; + } + + public void setQuickCreate(boolean quickCreate) { + this.quickCreate = quickCreate; + } + + public String getQuickCreatePath() { + return quickCreatePath; + } + + public void setQuickCreatePath(String quickCreatePath) { + this.quickCreatePath = quickCreatePath; + } + + public Type getType() { + return StudioUtils.getContentTypeTypeById(id); + } + public enum Type { - PAGE, COMPONENT, UNKNOWN + page, component, unknown } } diff --git a/src/main/java/org/craftercms/studio/model/contentType/CopyDependency.java b/src/main/java/org/craftercms/studio/model/contentType/CopyDependency.java index 893635e0c4..e29b6cd393 100644 --- a/src/main/java/org/craftercms/studio/model/contentType/CopyDependency.java +++ b/src/main/java/org/craftercms/studio/model/contentType/CopyDependency.java @@ -24,5 +24,4 @@ */ public record CopyDependency(String pattern, String target) { - } diff --git a/src/main/java/org/craftercms/studio/model/contentType/DeleteDependency.java b/src/main/java/org/craftercms/studio/model/contentType/DeleteDependency.java index cb7b66fd6f..8e3b002497 100644 --- a/src/main/java/org/craftercms/studio/model/contentType/DeleteDependency.java +++ b/src/main/java/org/craftercms/studio/model/contentType/DeleteDependency.java @@ -16,6 +16,9 @@ package org.craftercms.studio.model.contentType; +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; + /** * Represents a delete dependency for a content type. * @@ -23,5 +26,5 @@ * @param removeEmptyFolder a flag indicating whether to remove empty folders after deletion */ public record DeleteDependency(String pattern, - boolean removeEmptyFolder) { + @JsonAlias("remove-empty-folder") boolean removeEmptyFolder) { } diff --git a/src/main/java/org/craftercms/studio/model/contentType/PathIncludeExcludes.java b/src/main/java/org/craftercms/studio/model/contentType/PathIncludeExcludes.java new file mode 100644 index 0000000000..f0d245ce0e --- /dev/null +++ b/src/main/java/org/craftercms/studio/model/contentType/PathIncludeExcludes.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.model.contentType; + +import java.util.Collection; + +/** + * Represents the includes and excludes for content type paths. + * + * @param includes the included path patterns for the content type + * @param excludes the excluded path patterns for the content type + */ +public record PathIncludeExcludes(Collection includes, + Collection excludes) { +} diff --git a/src/main/java/org/craftercms/studio/model/contentType/PathPattern.java b/src/main/java/org/craftercms/studio/model/contentType/PathPattern.java new file mode 100644 index 0000000000..a0889f9d7d --- /dev/null +++ b/src/main/java/org/craftercms/studio/model/contentType/PathPattern.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.model.contentType; + +/** + * Represents a pattern for content type paths includes and excludes. + * This is a class and not a record to avoid issues with Jackson deserialization when used in + * a Collection. See {@link PathIncludeExcludes} + */ +public class PathPattern { + private final String pattern; + + public PathPattern(String pattern) { + this.pattern = pattern; + } + + public String getPattern() { + return pattern; + } +} diff --git a/src/main/resources/crafter/studio/studio-services-context.xml b/src/main/resources/crafter/studio/studio-services-context.xml index a07fd0c9cc..260f3669fb 100644 --- a/src/main/resources/crafter/studio/studio-services-context.xml +++ b/src/main/resources/crafter/studio/studio-services-context.xml @@ -449,6 +449,7 @@ + diff --git a/src/main/webapp/default-site/scripts/api/ServiceFactory.groovy b/src/main/webapp/default-site/scripts/api/ServiceFactory.groovy index 140f5d711f..ddadbfe4f4 100644 --- a/src/main/webapp/default-site/scripts/api/ServiceFactory.groovy +++ b/src/main/webapp/default-site/scripts/api/ServiceFactory.groovy @@ -18,7 +18,6 @@ package scripts.api import scripts.api.impl.content.SpringContentServices import scripts.api.impl.content.SpringPageNavigationOrderServices -import scripts.api.impl.dependency.SpringDependencyServices import scripts.api.impl.security.SpringSecurityServices import scripts.api.impl.site.SpringSiteServices import scripts.api.impl.user.SpringUserServices diff --git a/src/test/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImplTest.java b/src/test/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImplTest.java index 7c70a06045..3a2482e0e9 100644 --- a/src/test/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImplTest.java +++ b/src/test/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImplTest.java @@ -16,12 +16,14 @@ package org.craftercms.studio.impl.v2.service.content.internal; +import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang3.tuple.ImmutablePair; import org.craftercms.studio.api.v1.exception.ContentNotFoundException; import org.craftercms.studio.api.v1.exception.ServiceLayerException; import org.craftercms.studio.api.v1.service.site.SiteService; import org.craftercms.studio.api.v2.service.config.ConfigurationService; import org.craftercms.studio.api.v2.service.content.ContentService; +import org.craftercms.studio.model.contentType.ContentType; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; @@ -31,9 +33,13 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.test.util.ReflectionTestUtils; +import java.io.IOException; +import java.io.InputStream; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.when; @@ -138,4 +144,19 @@ public void getFormControllerReturnResource() throws ServiceLayerException { assertEquals(resultPair.getKey(), CONTENT_TYPE_WITH_FORM_CONTROLLER_FULL_FORM_CONTROLLER_PATH); assertEquals(resultPair.getValue(), resource); } + + @Test + public void getContentTypeTest() throws ServiceLayerException, IOException { + InputStream inputStream = new ClassPathResource("crafter/studio/content-type/" + CONTENT_TYPE + "/form-definition.xml").getInputStream(); + when(contentService.getContent(SITE_ID, CONTENT_TYPE_DEFINITION_PATH)).thenReturn(inputStream); + ContentType contentType = service.loadContentType(SITE_ID, CONTENT_TYPE); + + String expectedJson = "{\"previewable\":true,\"imageThumbnail\":\"page-test1.png\",\"noThumbnail\":false,\"quickCreate\":true," + + "\"quickCreatePath\":\"/site/website/tests/{year}/{month}\",\"type\":\"unknown\",\"pathIncludes\":[\"^/site/website/tests/.*\"]," + + "\"pathExcludes\":[\"^/site/website/tests/excluded.*\",\"^/site/website/tests/excluded2.*\"],\"id\":\"myContentType\"," + + "\"title\":\"Test Content Type\",\"allowedRoles\":[{\"name\":\"author\"},{\"name\":\"admin\"}]," + + "\"deleteDependencies\":[{\"pattern\":\"^/site/website/articles/.*\",\"removeEmptyFolder\":true}]," + + "\"copyDependencies\":[{\"pattern\":\"^/site/website/articles/.*\",\"target\":\"/site/website/articles2\"}]}"; + assertEquals(expectedJson, new ObjectMapper().writeValueAsString(contentType)); + } } diff --git a/src/test/resources/crafter/studio/content-type/myContentType/form-definition.xml b/src/test/resources/crafter/studio/content-type/myContentType/form-definition.xml new file mode 100644 index 0000000000..95174f4ef1 --- /dev/null +++ b/src/test/resources/crafter/studio/content-type/myContentType/form-definition.xml @@ -0,0 +1,905 @@ + + +
+ Test Content Type + + page + myContentType + page-test1.png + true + /site/website/tests/{year}/{month} + + + display-template + + /templates/web/pages/test-page.ftl + template + + + no-template-required + + + boolean + + + merge-strategy + + inherit-levels + string + + + +
+ Page Properties + + true + + + file-name + file-name + + Page URL + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + + + + input + internal-name + + Internal Name + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + + + checkbox + disabled + + Disable Page + + + + + + readonly + + boolean + + + + + required + + boolean + + + + + input + title_t + core + Title + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + + boolean + + + pattern + + string + + + + + node-selector + header_o + core + Header + Default header is inherited from Section Defaults. Specify a new header to overwrite it. + + + + + minSize + 0 + int + + + maxSize + 1 + int + + + itemManager + components-header + datasource:item + + + readonly + + boolean + + + disableFlattening + false + boolean + + + useSingleValueFilename + + boolean + + + contentTypes + /component/header + contentTypes + + + tags + + string + + + + + allowDuplicates + + boolean + + + + + node-selector + left_rail_o + + Left Rail + Default left-rail is inherited from Section Defaults. Specify a new left-rail to overwrite it. + + + + + minSize + 0 + int + + + maxSize + 1 + int + + + itemManager + components-left-rail + datasource:item + + + readonly + + boolean + + + disableFlattening + + boolean + + + useSingleValueFilename + + boolean + + + contentTypes + /component/left-rail + contentTypes + + + tags + + string + + + + + allowDuplicates + + boolean + + + + +
+
+ Metadata + + true + + + checkbox-group + categories_o + + Categories + + + + + + datasource + categories + datasource:item + + + selectAll + true + boolean + + + readonly + + boolean + + + listDirection + [{"value":"horizontal","label":"Horizonal","selected":true},{"value":"vertical","label":"Vertical","selected":false}] + dropdown + + + + + minSize + 1 + int + + + + + checkbox-group + segments_o + + Segments + + + + + + datasource + segments + datasource:item + + + selectAll + true + boolean + + + readonly + + boolean + + + + + minSize + 1 + int + + + + + checkbox + featured_b + + Featured + + + + + + readonly + + boolean + + + + + required + + boolean + + + + +
+
+ Content + + true + + + input + subject_t + subject + Subject + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + input + author_s + subject + Author + + + + + + size + 50 + int + + + maxlength + 50 + int + + + readonly + + boolean + + + tokenize + false + boolean + + + + + required + true + boolean + + + pattern + + string + + + + + date-time + date_dt + + Date + + + + + + showDate + true + boolean + + + showTime + + boolean + + + showClear + true + boolean + + + showNowLink + true + boolean + + + populate + true + boolean + + + allowPastDate + true + boolean + + + populateDateExp + now + string + + + useCustomTimezone + false + boolean + + + readonly + + boolean + + + readonlyEdit + false + boolean + + + + + required + true + boolean + + + + date_dt_tz + + + + textarea + summary_t + + Summary + + + + + + cols + 50 + int + + + rows + 5 + int + + + maxlength + 100000 + int + + + allowResize + true + boolean + + + readonly + + boolean + + + + + required + true + boolean + + + + + image-picker + image_s + + Image + + + + + + width + { "exact":"", "min":"", "max":"" } + range + + + height + { "exact":"", "min":"", "max":"" } + range + + + thumbnailWidth + + int + + + thumbnailHeight + + int + + + imageManager + upload_images,existing_images + datasource:image + + + readonly + + boolean + + + + + required + + boolean + + + + + repeat + sections_o + article + Sections + + 1 + * + + + minOccurs + 1 + string + + + maxOccurs + * + string + + + + + rte + section_html + article + Section + + + + + + height + + int + + + forceRootBlockPTag + true + boolean + + + forcePTags + true + boolean + + + forceBRTags + false + boolean + + + supportedChannels + + supportedChannels + + + rteConfiguration + generic + string + + + imageManager + upload_images,existing_images + datasource:image + + + videoManager + + datasource:video + + + + + required + true + boolean + + + + + + +
+
+ + + shared-content + components-header + Components Header + item + + + repoPath + /site/components/headers + undefined + + + browsePath + + undefined + + + type + + undefined + + + enableCreateNew + true + boolean + + + enableBrowseExisting + true + boolean + + + enableSearchExisting + true + boolean + + + + + img-desktop-upload + upload_images + Upload Images + image + + + repoPath + /static-assets/item/images/{yyyy}/{mm}/{dd}/ + undefined + + + + + img-repository-upload + existing_images + Existing Images + image + + + repoPath + /static-assets/images + undefined + + + + + simpleTaxonomy + categories + Categories + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] + undefined + + + componentPath + /site/taxonomy/categories.xml + undefined + + + + + simpleTaxonomy + segments + Segments + item + + + dataType + [{"value":"value","label":"","selected":false},{"value":"value_s","label":"String","selected":true},{"value":"value_i","label":"Integer","selected":false},{"value":"value_f","label":"Float","selected":false},{"value":"value_dt","label":"Date","selected":false},{"value":"value_html","label":"HTML","selected":false}] + undefined + + + componentPath + /site/taxonomy/segments.xml + undefined + + + + + shared-content + components-left-rail + Components Left Rail + item + + + repoPath + /site/components/left-rails/ + undefined + + + browsePath + + undefined + + + type + + undefined + + + enableCreateNew + true + boolean + + + enableBrowseExisting + true + boolean + + + enableSearchExisting + true + boolean + + + + + true + false + + + ^/site/website/tests/.* + + + ^/site/website/tests/excluded.* + ^/site/website/tests/excluded2.* + + + + + ^/site/website/articles/.* + true + + + + + ^/site/website/articles/.* + /site/website/articles2 + + + + author + admin + + From 566504aee2754c1a9fb64d91838db5f6b6ede622 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Thu, 23 Apr 2026 09:04:43 -0600 Subject: [PATCH 08/38] Make all content types APIs have the same path --- src/main/api/studio-api.yaml | 106 +++++++++--------- .../rest/v2/ContentTypeController.java | 19 ++-- .../contentType/DeleteContentTypeRequest.java | 13 --- 3 files changed, 63 insertions(+), 75 deletions(-) diff --git a/src/main/api/studio-api.yaml b/src/main/api/studio-api.yaml index 19d844252a..7a2bd222af 100644 --- a/src/main/api/studio-api.yaml +++ b/src/main/api/studio-api.yaml @@ -3798,16 +3798,16 @@ paths: # '403': # $ref: '#/components/responses/Forbidden' - /api/2/configuration/content-type/usage: + /api/2/configuration/content_types/{siteId}/usage: get: tags: - - configuration + - contentTypes summary: Get all usage of a given content-type description: 'Required permission "content_read"' operationId: getContentTypeUsage parameters: - name: siteId - in: query + in: path description: site ID required: true schema: @@ -3852,16 +3852,16 @@ paths: '403': $ref: '#/components/responses/Forbidden' - /api/2/configuration/content-type/preview_image: + /api/2/configuration/content_types/{siteId}/preview_image: get: tags: - - configuration + - contentTypes summary: Get preview image of a given content type description: 'Required permission "content_read"' operationId: getContentTypePreviewImage parameters: - name: siteId - in: query + in: path description: site ID required: true schema: @@ -3989,16 +3989,61 @@ paths: '500': $ref: '#/components/responses/InternalServerError' - /api/2/configuration/content-type/form_controller: + delete: + tags: + - contentTypes + summary: Delete files related to a given content-type + description: 'Required permission "write_configuration"' + operationId: deleteContentType + params: + - name: siteId + in: path + description: site ID + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + type: object + properties: + contentType: + type: string + description: The content-type to delete + deleteDependencies: + type: boolean + description: Indicates if all dependencies of the content-type should be deleted (defaults to false) + required: + - siteId + - contentType + responses: + '200': + description: Deleted + content: + application/json: + schema: + type: object + properties: + response: + $ref: '#/components/schemas/ApiResponse' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + + /api/2/configuration/content_types/{siteId}/form_controller: get: tags: - - configuration + - contentTypes summary: Get the form controller (if it exists) script of a given content type description: 'Required permission "content_read"' operationId: getContentTypeFormController parameters: - name: siteId - in: query + in: path description: site ID required: true schema: @@ -4036,49 +4081,6 @@ paths: '500': $ref: '#/components/responses/InternalServerError' - /api/2/configuration/content-type/delete: - post: - tags: - - configuration - summary: Delete files related to a given content-type - description: 'Required permission "write_configuration"' - operationId: deleteContentType - requestBody: - content: - application/json: - schema: - type: object - properties: - siteId: - type: string - description: The id of the site - contentType: - type: string - description: The content-type to delete - deleteDependencies: - type: boolean - description: Indicates if all dependencies of the content-type should be deleted (defaults to false) - required: - - siteId - - contentType - responses: - '200': - description: Deleted - content: - application/json: - schema: - type: object - properties: - response: - $ref: '#/components/schemas/ApiResponse' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - - /api/2/plugin/file: # Override the server to change the prefix servers: diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java b/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java index b6bf30eda3..6891bcff47 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/ContentTypeController.java @@ -23,7 +23,6 @@ import org.craftercms.commons.validation.annotations.param.ValidSiteId; import org.craftercms.commons.validation.annotations.param.ValidateSecurePathParam; import org.craftercms.studio.api.v1.exception.ServiceLayerException; -import org.craftercms.studio.api.v1.exception.SiteNotFoundException; import org.craftercms.studio.api.v1.exception.security.AuthenticationException; import org.craftercms.studio.api.v1.exception.security.UserNotFoundException; import org.craftercms.studio.api.v2.service.content.ContentTypeService; @@ -51,7 +50,7 @@ @Validated @RestController -@RequestMapping(API_2 + CONFIGURATION + CONTENT_TYPES) +@RequestMapping(API_2 + CONFIGURATION + CONTENT_TYPES + SITE_ID) public class ContentTypeController { private final ContentTypeService contentTypeService; @@ -61,7 +60,7 @@ public ContentTypeController(ContentTypeService contentTypeService) { } @GetMapping(USAGE) - public ResultOne getContentTypeUsage(@ValidSiteId @RequestParam String siteId, + public ResultOne getContentTypeUsage(@ValidSiteId @PathVariable String siteId, @ValidConfigurationPath @RequestParam String contentType) throws Exception { var result = new ResultOne<>(); @@ -72,21 +71,21 @@ public ResultOne getContentTypeUsage(@ValidSiteId @RequestParam String s } @GetMapping(FORM_CONTROLLER) - public ResponseEntity getContentTypeFormController(@ValidSiteId @RequestParam String siteId, + public ResponseEntity getContentTypeFormController(@ValidSiteId @PathVariable String siteId, @ValidConfigurationPath @RequestParam String contentTypeId) throws ServiceLayerException { ImmutablePair resource = contentTypeService.getContentTypeFormController(siteId, contentTypeId); return getResourceResponse(resource.getKey(), resource.getValue()); } @GetMapping(PREVIEW_IMAGE) - public ResponseEntity getContentTypePreviewImage(@ValidSiteId @RequestParam String siteId, + public ResponseEntity getContentTypePreviewImage(@ValidSiteId @PathVariable String siteId, @ValidConfigurationPath @ValidateSecurePathParam @RequestParam String contentTypeId) throws ServiceLayerException { ImmutablePair resource = contentTypeService.getContentTypePreviewImage(siteId, contentTypeId); return getResourceResponse(resource.getKey(), resource.getValue()); } - @GetMapping(SITE_ID) + @GetMapping public ResultList getContentTypes(@ValidSiteId @PathVariable String siteId, @ValidConfigurationPath @RequestParam(required = false) String contentTypeId) throws ServiceLayerException { var result = new ResultList(); @@ -102,7 +101,7 @@ public ResultList getContentTypes(@ValidSiteId @PathVariable String return result; } - @GetMapping(SITE_ID + ALLOWED_TYPES) + @GetMapping(ALLOWED_TYPES) public ResultList getAllowedContentTypes(@ValidSiteId @PathVariable String siteId, @ValidExistingContentPath @RequestParam String path) throws ServiceLayerException { ResultList result = new ResultList<>(); result.setResponse(OK); @@ -110,10 +109,10 @@ public ResultList getAllowedContentTypes(@ValidSiteId @PathVariable Stri return result; } - @PostMapping(DELETE) - public Result deleteContentType(@RequestBody @Valid DeleteContentTypeRequest request) + @DeleteMapping + public Result deleteContentType(@ValidSiteId @PathVariable String siteId, @RequestBody @Valid DeleteContentTypeRequest request) throws ServiceLayerException, AuthenticationException, UserNotFoundException { - contentTypeService.deleteContentType(request.getSiteId(), request.getContentType(), + contentTypeService.deleteContentType(siteId, request.getContentType(), request.isDeleteDependencies()); var result = new Result(); result.setResponse(DELETED); diff --git a/src/main/java/org/craftercms/studio/model/rest/contentType/DeleteContentTypeRequest.java b/src/main/java/org/craftercms/studio/model/rest/contentType/DeleteContentTypeRequest.java index 49feef16e0..b66b1537d8 100644 --- a/src/main/java/org/craftercms/studio/model/rest/contentType/DeleteContentTypeRequest.java +++ b/src/main/java/org/craftercms/studio/model/rest/contentType/DeleteContentTypeRequest.java @@ -18,30 +18,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.craftercms.commons.validation.annotations.param.ValidConfigurationPath; -import org.craftercms.commons.validation.annotations.param.ValidSiteId; /** * Request for deleting a content-type. */ @JsonIgnoreProperties public class DeleteContentTypeRequest { - - @ValidSiteId - protected String siteId; - @ValidConfigurationPath protected String contentType; protected boolean deleteDependencies; - public String getSiteId() { - return siteId; - } - - public void setSiteId(String siteId) { - this.siteId = siteId; - } - public String getContentType() { return contentType; } From 682b6fd28adda16c16bda9b51049cb9e80c4e545 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Thu, 23 Apr 2026 10:06:06 -0600 Subject: [PATCH 09/38] Handle content type in use scenario when trying to delete a content type --- src/main/api/studio-api.yaml | 1 + .../ContentTypeUsageException.java | 29 +++++++++++++++++++ .../controller/rest/v2/ExceptionHandlers.java | 9 ++++++ .../ContentTypeServiceInternalImpl.java | 4 +-- .../studio/model/rest/ApiResponse.java | 4 +++ 5 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/craftercms/studio/api/v2/exception/contentType/ContentTypeUsageException.java diff --git a/src/main/api/studio-api.yaml b/src/main/api/studio-api.yaml index 7a2bd222af..66a714c81f 100644 --- a/src/main/api/studio-api.yaml +++ b/src/main/api/studio-api.yaml @@ -8263,6 +8263,7 @@ components: * `CODE:` 52004, `MESSAGE:` S3 FORBIDDEN, `REMEDIAL ACTION:` Check your AWS credentials * `CODE:` 52005, `MESSAGE:` S3 key not found, `REMEDIAL ACTION:` Check your network configuration and S3 availability * `CODE:` 53000, `MESSAGE:` Logger not found, `REMEDIAL ACTION:` Check if you sent in the right logger name or add 'createIfAbsent=true' parameter to create the logger if it does not exist + * `CODE:` 54000, `MESSAGE:` The content type cannot be deleted because it is still in use by content items, `REMEDIAL ACTION:` Check if you sent in the right content type id or add 'deleteDependencies' to force delete properties: code: type: integer diff --git a/src/main/java/org/craftercms/studio/api/v2/exception/contentType/ContentTypeUsageException.java b/src/main/java/org/craftercms/studio/api/v2/exception/contentType/ContentTypeUsageException.java new file mode 100644 index 0000000000..e572c73a48 --- /dev/null +++ b/src/main/java/org/craftercms/studio/api/v2/exception/contentType/ContentTypeUsageException.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.api.v2.exception.contentType; + +import org.craftercms.studio.api.v1.exception.ServiceLayerException; + +/** + * Exception to be thrown when trying to delete a content type that is still in use by content items + */ +public class ContentTypeUsageException extends ServiceLayerException { + + public ContentTypeUsageException(String siteId, String contentType) { + super(String.format("Content type '%s' is still in use by content items in site '%s'", contentType, siteId)); + } +} diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/ExceptionHandlers.java b/src/main/java/org/craftercms/studio/controller/rest/v2/ExceptionHandlers.java index 9c079d3f41..9e83e1fb15 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/ExceptionHandlers.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/ExceptionHandlers.java @@ -41,6 +41,7 @@ import org.craftercms.studio.api.v2.exception.content.ContentInPublishQueueException; import org.craftercms.studio.api.v2.exception.content.ContentLockedByAnotherUserException; import org.craftercms.studio.api.v2.exception.content.ContentMoveInvalidLocation; +import org.craftercms.studio.api.v2.exception.contentType.ContentTypeUsageException; import org.craftercms.studio.api.v2.exception.git.MergeInProgressException; import org.craftercms.studio.api.v2.exception.git.NoMergeStateException; import org.craftercms.studio.api.v2.exception.logger.LoggerNotFoundException; @@ -681,6 +682,14 @@ public Result handleException(HttpServletRequest request, NoMergeStateException return handleExceptionInternal(request, e, response); } + @ExceptionHandler + @ResponseStatus(CONFLICT) + public Result handleException(HttpServletRequest request, ContentTypeUsageException e) { + ApiResponse response = new ApiResponse(ApiResponse.CONTENT_TYPE_IN_USE); + response.setMessage(e.getMessage()); + return handleExceptionInternal(request, e, response); + } + @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Result handleException(HttpServletRequest request, Exception e) { diff --git a/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImpl.java b/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImpl.java index b14f0a8dba..6ba3ecd90a 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v2/service/content/internal/ContentTypeServiceInternalImpl.java @@ -38,6 +38,7 @@ import org.craftercms.studio.api.v2.dal.QuickCreateItem; import org.craftercms.studio.api.v2.dal.item.LightItem; import org.craftercms.studio.api.v2.exception.configuration.ConfigurationException; +import org.craftercms.studio.api.v2.exception.contentType.ContentTypeUsageException; import org.craftercms.studio.api.v2.service.config.ConfigurationService; import org.craftercms.studio.api.v2.service.content.ContentService; import org.craftercms.studio.api.v2.service.publish.PublishService; @@ -317,8 +318,7 @@ public void deleteContentType(String siteId, String contentType, boolean deleteD if (CollectionUtils.isNotEmpty(usage.getContent())) { if (!deleteDependencies) { - throw new ServiceLayerException("The content-type " + contentType + " in site " + siteId + - " can't be deleted because there is content using it"); + throw new ContentTypeUsageException(siteId, contentType); } files.addAll(usage.getContent()); diff --git a/src/main/java/org/craftercms/studio/model/rest/ApiResponse.java b/src/main/java/org/craftercms/studio/model/rest/ApiResponse.java index eca1259be9..1ca597611d 100644 --- a/src/main/java/org/craftercms/studio/model/rest/ApiResponse.java +++ b/src/main/java/org/craftercms/studio/model/rest/ApiResponse.java @@ -211,6 +211,10 @@ public class ApiResponse { public static final ApiResponse CONFIGURATION_PROFILE_NOT_FOUND = new ApiResponse(54000, "The profile was not found", "Check if you sent in the right profileId name", StringUtils.EMPTY); + // 54000 - 55000 + public static final ApiResponse CONTENT_TYPE_IN_USE = new ApiResponse(54000, "The content type cannot be deleted because it is still in use by content items", + "Check if you sent in the right content type id or add 'deleteDependencies' to force delete", StringUtils.EMPTY); + private int code; private String message; private String remedialAction; From 15f716c51a5637c1ba96cded9e70ecaa7d14f2fe Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Thu, 23 Apr 2026 10:13:35 -0600 Subject: [PATCH 10/38] Use unique config file name for test --- .../ContentTypeConfigMergeUpgraderTest.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/craftercms/studio/impl/v2/upgrade/operations/contentType/ContentTypeConfigMergeUpgraderTest.java b/src/test/java/org/craftercms/studio/impl/v2/upgrade/operations/contentType/ContentTypeConfigMergeUpgraderTest.java index 4859b8727b..bd21f8d4b1 100644 --- a/src/test/java/org/craftercms/studio/impl/v2/upgrade/operations/contentType/ContentTypeConfigMergeUpgraderTest.java +++ b/src/test/java/org/craftercms/studio/impl/v2/upgrade/operations/contentType/ContentTypeConfigMergeUpgraderTest.java @@ -20,7 +20,6 @@ import org.apache.commons.configuration2.HierarchicalConfiguration; import org.apache.commons.io.IOUtils; import org.craftercms.studio.api.v2.utils.StudioConfiguration; -import org.craftercms.studio.api.v2.utils.StudioUtils; import org.craftercms.studio.impl.v2.upgrade.StudioUpgradeContext; import org.craftercms.studio.impl.v2.upgrade.operations.site.AbstractXsltFileUpgradeOperation; import org.craftercms.studio.impl.v2.upgrade.operations.site.BatchXsltFileUpgradeOperation; @@ -43,12 +42,14 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.util.UUID; import java.util.stream.Stream; import static org.craftercms.studio.api.v2.utils.StudioConfiguration.CONFIGURATION_SITE_CONTENT_TYPES_CONFIG_FILE_NAME; +import static org.craftercms.studio.api.v2.utils.StudioUtils.createTempFile; import static org.craftercms.studio.api.v2.utils.StudioUtils.getStudioTemporaryFilesRoot; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.*; -import static org.testng.Assert.assertEquals; @RunWith(MockitoJUnitRunner.class) public class ContentTypeConfigMergeUpgraderTest { @@ -60,12 +61,15 @@ public class ContentTypeConfigMergeUpgraderTest { @InjectMocks private ContentTypeConfigMergeUpgrader upgrader; + private String configFileName; + @Before public void setUp() throws Exception { + configFileName = UUID.randomUUID() + "config.xml"; var config = mock(HierarchicalConfiguration.class); when(config.getString(BatchXsltFileUpgradeOperation.CONFIG_KEY_REGEX)).thenReturn("config/studio/content-types/.+/form-definition\\.xml"); when(config.getString(AbstractXsltFileUpgradeOperation.CONFIG_KEY_TEMPLATE)).thenReturn("crafter/studio/upgrade/5.0.x/content-type/content-type-merge-v5.0.0.2.xslt"); - when(studioConfiguration.getProperty(CONFIGURATION_SITE_CONTENT_TYPES_CONFIG_FILE_NAME)).thenReturn("config.xml"); + when(studioConfiguration.getProperty(CONFIGURATION_SITE_CONTENT_TYPES_CONFIG_FILE_NAME)).thenReturn(configFileName); upgrader.init("1", "2", config); } @@ -74,8 +78,8 @@ public void testUpgrade() throws Exception { String basePath = "src/test/resources/crafter/studio/upgrade/content-type/5.0/5.0.0.2/"; File originalFormFile = new File(basePath + "form-definition.xml"); File originalConfigFile = new File(basePath + "config.xml"); - Path configFilePath = StudioUtils.getStudioTemporaryFilesRoot().resolve("config.xml"); - Path formFilePath = StudioUtils.createTempFile("form-definition.xml"); + Path configFilePath = getStudioTemporaryFilesRoot().resolve(configFileName); + Path formFilePath = createTempFile("form-definition.xml"); formFilePath.toFile().deleteOnExit(); configFilePath.toFile().deleteOnExit(); Files.copy(originalFormFile.toPath(), formFilePath, StandardCopyOption.REPLACE_EXISTING); @@ -114,7 +118,7 @@ public void testUpgrade() throws Exception { } // there should not be any differences - assertEquals(IterableUtils.size(diff.getDifferences()), 0, + assertEquals(0, IterableUtils.size(diff.getDifferences()), "The result XML should be equal to the expected XML"); } } From 1a597580ce3a7aeab35f5e07b6e5f207737d58f9 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Thu, 23 Apr 2026 11:40:44 -0600 Subject: [PATCH 11/38] Fix datasource reference in content type --- .../studio/content-types/component/product/form-definition.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/product/form-definition.xml b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/product/form-definition.xml index 9e6e735573..a7982d8230 100644 --- a/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/product/form-definition.xml +++ b/src/main/webapp/repo-bootstrap/global/blueprints/2000_headless_store/config/studio/content-types/component/product/form-definition.xml @@ -280,7 +280,7 @@ datasource - categories + categories_o datasource:item From 7f33fd8a7a4411d665e7310f764d0a479f857980 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Thu, 23 Apr 2026 12:26:28 -0600 Subject: [PATCH 12/38] Update copyright --- .../studio/api/v2/service/content/ContentTypeService.java | 2 +- .../java/org/craftercms/studio/api/v2/utils/StudioUtils.java | 2 +- .../studio/controller/rest/v2/ConfigurationController.java | 2 +- .../impl/v1/service/configuration/ContentTypesConfigImpl.java | 2 +- .../studio/impl/v2/service/content/ContentTypeServiceImpl.java | 2 +- .../operations/site/AbstractXsltFileUpgradeOperation.java | 2 +- .../upgrade/operations/site/BatchXsltFileUpgradeOperation.java | 2 +- .../java/org/craftercms/studio/impl/v2/utils/db/DBUtils.java | 2 +- .../crafter/studio/extension/rendering-overlay-context.xml | 2 +- src/main/resources/crafter/studio/studio-upgrade-context.xml | 2 +- src/main/webapp/default-site/scripts/api/ContentServices.groovy | 2 +- src/main/webapp/default-site/scripts/api/ServiceFactory.groovy | 2 +- .../content-types/component/articles-widget/form-definition.xml | 2 +- .../content-types/component/contact-widget/form-definition.xml | 2 +- .../studio/content-types/component/feature/form-definition.xml | 2 +- .../studio/content-types/component/header/form-definition.xml | 2 +- .../content-types/component/left-rail/form-definition.xml | 2 +- .../component/level-descriptor/form-definition.xml | 2 +- .../studio/content-types/page/article/form-definition.xml | 2 +- .../content-types/page/category-landing/form-definition.xml | 2 +- .../config/studio/content-types/page/home/form-definition.xml | 2 +- .../content-types/page/search-results/form-definition.xml | 2 +- .../config/studio/content-types/taxonomy/form-definition.xml | 2 +- .../studio/content-types/component/company/form-definition.xml | 2 +- .../component/level-descriptor/form-definition.xml | 2 +- .../studio/content-types/component/product/form-definition.xml | 2 +- .../studio/content-types/page/catalog/form-definition.xml | 2 +- .../config/studio/content-types/taxonomy/form-definition.xml | 2 +- .../component/level-descriptor/form-definition.xml | 2 +- .../config/studio/content-types/page/entry/form-definition.xml | 2 +- .../studio/content-types/component/author/form-definition.xml | 2 +- .../component/level-descriptor/form-definition.xml | 2 +- .../studio/content-types/component/post/form-definition.xml | 2 +- .../studio/content-types/page/item-explorer/form-definition.xml | 2 +- .../config/studio/content-types/taxonomy/form-definition.xml | 2 +- .../content/internal/ContentTypeServiceInternalImplTest.java | 2 +- .../site/ContentTypeControllerUpgradeOperationTest.java | 2 +- 37 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java b/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java index e9d30c8a10..c3b3741625 100644 --- a/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java +++ b/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2025 Crafter Software Corporation. All Rights Reserved. + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by diff --git a/src/main/java/org/craftercms/studio/api/v2/utils/StudioUtils.java b/src/main/java/org/craftercms/studio/api/v2/utils/StudioUtils.java index 93f4b3c779..fdb6398af7 100644 --- a/src/main/java/org/craftercms/studio/api/v2/utils/StudioUtils.java +++ b/src/main/java/org/craftercms/studio/api/v2/utils/StudioUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2025 Crafter Software Corporation. All Rights Reserved. + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/ConfigurationController.java b/src/main/java/org/craftercms/studio/controller/rest/v2/ConfigurationController.java index b466f009a4..9ce2d8d892 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/ConfigurationController.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/ConfigurationController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2023 Crafter Software Corporation. All Rights Reserved. + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by diff --git a/src/main/java/org/craftercms/studio/impl/v1/service/configuration/ContentTypesConfigImpl.java b/src/main/java/org/craftercms/studio/impl/v1/service/configuration/ContentTypesConfigImpl.java index 6b283b7581..b17903aac1 100644 --- a/src/main/java/org/craftercms/studio/impl/v1/service/configuration/ContentTypesConfigImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v1/service/configuration/ContentTypesConfigImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2025 Crafter Software Corporation. All Rights Reserved. + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by diff --git a/src/main/java/org/craftercms/studio/impl/v2/service/content/ContentTypeServiceImpl.java b/src/main/java/org/craftercms/studio/impl/v2/service/content/ContentTypeServiceImpl.java index 3f29bd9214..f0bd472fb3 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/service/content/ContentTypeServiceImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v2/service/content/ContentTypeServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2025 Crafter Software Corporation. All Rights Reserved. + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by diff --git a/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/AbstractXsltFileUpgradeOperation.java b/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/AbstractXsltFileUpgradeOperation.java index a028494735..008eb79d57 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/AbstractXsltFileUpgradeOperation.java +++ b/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/AbstractXsltFileUpgradeOperation.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by diff --git a/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/BatchXsltFileUpgradeOperation.java b/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/BatchXsltFileUpgradeOperation.java index 1ca4bdb63a..70a5345b3f 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/BatchXsltFileUpgradeOperation.java +++ b/src/main/java/org/craftercms/studio/impl/v2/upgrade/operations/site/BatchXsltFileUpgradeOperation.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by diff --git a/src/main/java/org/craftercms/studio/impl/v2/utils/db/DBUtils.java b/src/main/java/org/craftercms/studio/impl/v2/utils/db/DBUtils.java index 4d5a5355f4..05eddba699 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/utils/db/DBUtils.java +++ b/src/main/java/org/craftercms/studio/impl/v2/utils/db/DBUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2025 Crafter Software Corporation. All Rights Reserved. + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by diff --git a/src/main/resources/crafter/studio/extension/rendering-overlay-context.xml b/src/main/resources/crafter/studio/extension/rendering-overlay-context.xml index b71ff09eed..0b60cce11e 100644 --- a/src/main/resources/crafter/studio/extension/rendering-overlay-context.xml +++ b/src/main/resources/crafter/studio/extension/rendering-overlay-context.xml @@ -1,6 +1,6 @@ - - - - - - - - - - - - - - - - - - - - @@ -122,7 +102,6 @@ - @@ -131,7 +110,6 @@ - @@ -144,23 +122,6 @@ - - - - - - - - - - - - - - - - - @@ -410,6 +371,7 @@ + @@ -447,8 +409,6 @@ value="#{studioConfiguration.getProperty('studio.configuration.contentType.formControllerFilePath')}" /> - - @@ -1186,7 +1146,6 @@ - diff --git a/src/main/resources/org/craftercms/studio/api/v1/dal/SiteFeedMapper.xml b/src/main/resources/org/craftercms/studio/api/v1/dal/SiteFeedMapper.xml index 31143444d9..ec6802bc46 100644 --- a/src/main/resources/org/craftercms/studio/api/v1/dal/SiteFeedMapper.xml +++ b/src/main/resources/org/craftercms/studio/api/v1/dal/SiteFeedMapper.xml @@ -1,6 +1,6 @@ - - - - - - - - - - - diff --git a/src/main/resources/org/craftercms/studio/api/v1/dal/SiteFeedMapper.xml b/src/main/resources/org/craftercms/studio/api/v1/dal/SiteFeedMapper.xml deleted file mode 100644 index ec6802bc46..0000000000 --- a/src/main/resources/org/craftercms/studio/api/v1/dal/SiteFeedMapper.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UPDATE site - - name = #{name}, - description = #{description} - - WHERE site_id = #{siteId} AND deleted = 0 - - diff --git a/src/main/resources/org/craftercms/studio/api/v2/dal/GroupDAO.xml b/src/main/resources/org/craftercms/studio/api/v2/dal/GroupDAO.xml index 24c96d710f..f43ad82bb6 100644 --- a/src/main/resources/org/craftercms/studio/api/v2/dal/GroupDAO.xml +++ b/src/main/resources/org/craftercms/studio/api/v2/dal/GroupDAO.xml @@ -1,6 +1,6 @@ @@ -122,8 +115,7 @@ - + @@ -455,9 +447,10 @@ - + + @@ -483,13 +476,6 @@ - - - - - - @@ -873,48 +859,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -944,7 +888,7 @@ - + @@ -1001,17 +945,6 @@ - - - - - - - - - - - @@ -1020,13 +953,6 @@ - - - - - - - @@ -1146,6 +1072,7 @@ class="org.craftercms.studio.impl.v2.service.marketplace.internal.MarketplaceServiceInternalImpl"> + diff --git a/src/main/resources/org/craftercms/studio/api/v2/dal/ItemDAO.xml b/src/main/resources/org/craftercms/studio/api/v2/dal/ItemDAO.xml index ce258e409f..cf7e066085 100644 --- a/src/main/resources/org/craftercms/studio/api/v2/dal/ItemDAO.xml +++ b/src/main/resources/org/craftercms/studio/api/v2/dal/ItemDAO.xml @@ -326,26 +326,6 @@ )) - - UPDATE item - SET site_id = #{siteId}, - path = #{path}, - preview_url = #{previewUrl}, - state = #{state}, - locked_by = #{lockedBy}, - last_modified_by = #{lastModifiedBy}, - last_modified_on = #{lastModifiedOn}, - label = #{label}, - content_type_id = #{contentTypeId}, - system_type = #{systemType}, - mime_type = #{mimeType}, - locale_code = #{localeCode}, - translation_source_id = #{translationSourceId}, - size = #{size}, - parent_id = #{parentId} - WHERE id = #{id} - - DELETE FROM item WHERE site_id = #{siteId} diff --git a/src/test/java/org/craftercms/studio/impl/v1/service/dependency/RegexDependencyResolverTest.java b/src/test/java/org/craftercms/studio/impl/v1/service/dependency/RegexDependencyResolverTest.java index 2ee62364cd..e71e10f197 100644 --- a/src/test/java/org/craftercms/studio/impl/v1/service/dependency/RegexDependencyResolverTest.java +++ b/src/test/java/org/craftercms/studio/impl/v1/service/dependency/RegexDependencyResolverTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by @@ -17,9 +17,9 @@ import org.apache.commons.io.IOUtils; import org.craftercms.studio.api.v1.exception.ServiceLayerException; -import org.craftercms.studio.api.v1.service.content.ContentService; import org.craftercms.studio.api.v1.service.dependency.DependencyResolver.ResolvedDependency; import org.craftercms.studio.api.v2.service.config.ConfigurationService; +import org.craftercms.studio.api.v2.service.content.ContentService; import org.craftercms.studio.api.v2.utils.StudioConfiguration; import org.dom4j.Document; import org.dom4j.DocumentException; @@ -98,16 +98,10 @@ public void setUp() throws IOException, DocumentException, ServiceLayerException .thenReturn(doc); } - try (InputStream is = FORM_CONTENT.getInputStream()) { - String form = IOUtils.toString(is, UTF_8); - - when(contentService.getContentAsString(SITE_ID, FORM_DEFINITION_PATH)).thenReturn(form); - } - + when(contentService.getContent(SITE_ID, FORM_DEFINITION_PATH)).thenReturn(FORM_CONTENT.getInputStream()); when(contentService.shallowContentExists(SITE_ID, PAGE_A_PATH)).thenReturn(true); when(contentService.shallowContentExists(SITE_ID, COMPONENT_A_PATH)).thenReturn(true); when(contentService.shallowContentExists(SITE_ID, COMPONENT_B_PATH)).thenReturn(true); - } @Test diff --git a/src/test/java/org/craftercms/studio/impl/v1/service/dependency/RelativePageDependencyResolverTest.java b/src/test/java/org/craftercms/studio/impl/v1/service/dependency/RelativePageDependencyResolverTest.java index 8a1acf7f1c..256b03739c 100644 --- a/src/test/java/org/craftercms/studio/impl/v1/service/dependency/RelativePageDependencyResolverTest.java +++ b/src/test/java/org/craftercms/studio/impl/v1/service/dependency/RelativePageDependencyResolverTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2025 Crafter Software Corporation. All Rights Reserved. + * Copyright (C) 2007-2026 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by @@ -17,10 +17,11 @@ package org.craftercms.studio.impl.v1.service.dependency; import org.apache.commons.io.IOUtils; +import org.craftercms.studio.api.v1.exception.ContentNotFoundException; import org.craftercms.studio.api.v1.exception.ServiceLayerException; -import org.craftercms.studio.api.v1.service.content.ContentService; import org.craftercms.studio.api.v1.service.dependency.DependencyResolver; import org.craftercms.studio.api.v2.service.config.ConfigurationService; +import org.craftercms.studio.api.v2.service.content.ContentService; import org.craftercms.studio.api.v2.utils.StudioConfiguration; import org.dom4j.Document; import org.dom4j.DocumentException; @@ -40,6 +41,7 @@ import java.util.Set; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.commons.io.IOUtils.toInputStream; import static org.craftercms.studio.api.v1.constant.StudioConstants.MODULE_STUDIO; import static org.craftercms.studio.api.v2.utils.StudioConfiguration.*; import static org.junit.Assert.*; @@ -83,7 +85,7 @@ public void setUp() throws IOException, DocumentException, ServiceLayerException } @Test - public void testRelativePageDependency() { + public void testRelativePageDependency() throws ContentNotFoundException { String content = """ @@ -92,7 +94,7 @@ public void testRelativePageDependency() { """; - when(contentService.getContentAsString(SITE_ID, PAGE_PATH)).thenReturn(content); + when(contentService.getContent(SITE_ID, PAGE_PATH)).thenReturn(toInputStream(content, UTF_8)); Map> deps = dependencyResolver.resolve(SITE_ID, PAGE_PATH); @@ -106,7 +108,7 @@ public void testRelativePageDependency() { } @Test - public void testHrefStartsWithReservedPath() { + public void testHrefStartsWithReservedPath() throws ContentNotFoundException { String content = """ @@ -114,7 +116,7 @@ public void testHrefStartsWithReservedPath() { """; - when(contentService.getContentAsString(SITE_ID, PAGE_PATH)).thenReturn(content); + when(contentService.getContent(SITE_ID, PAGE_PATH)).thenReturn(toInputStream(content, UTF_8)); Map> deps = dependencyResolver.resolve(SITE_ID, PAGE_PATH); assertNotNull(deps); Set pageDeps = deps.get("page"); @@ -123,7 +125,7 @@ public void testHrefStartsWithReservedPath() { } @Test - public void testQueryStringHrefs() { + public void testQueryStringHrefs() throws ContentNotFoundException { String content = """ @@ -131,7 +133,7 @@ public void testQueryStringHrefs() { """; - when(contentService.getContentAsString(SITE_ID, PAGE_PATH)).thenReturn(content); + when(contentService.getContent(SITE_ID, PAGE_PATH)).thenReturn(toInputStream(content, UTF_8)); Map> deps = dependencyResolver.resolve(SITE_ID, PAGE_PATH); assertNotNull(deps); Set pageDeps = deps.get("page"); @@ -140,7 +142,7 @@ public void testQueryStringHrefs() { } @Test - public void testFragmentsHrefs() { + public void testFragmentsHrefs() throws ContentNotFoundException { String content = """ @@ -148,7 +150,7 @@ public void testFragmentsHrefs() { """; - when(contentService.getContentAsString(SITE_ID, PAGE_PATH)).thenReturn(content); + when(contentService.getContent(SITE_ID, PAGE_PATH)).thenReturn(toInputStream(content, UTF_8)); Map> deps = dependencyResolver.resolve(SITE_ID, PAGE_PATH); assertNotNull(deps); Set pageDeps = deps.get("page"); From 75489203af0942fe90d9dbd11606836490445abe Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Wed, 6 May 2026 12:26:36 -0600 Subject: [PATCH 31/38] Remove old API from spec --- src/main/api/studio-api.yaml | 49 ------------------------------------ 1 file changed, 49 deletions(-) diff --git a/src/main/api/studio-api.yaml b/src/main/api/studio-api.yaml index 2ad951a503..3473c0209f 100644 --- a/src/main/api/studio-api.yaml +++ b/src/main/api/studio-api.yaml @@ -2437,55 +2437,6 @@ paths: '401': $ref: '#/components/responses/Unauthorized' - /api/1/services/api/1/content/get-pages.json: - get: - tags: - - content - summary: Get pages. Gets tree of content items for given path. - description: "Required role: N/A" - operationId: getPages - parameters: - - name: site_id - in: query - description: Project/Site ID to use - required: true - schema: - type: string - - name: path - in: query - schema: - type: string - description: Path of the content - required: true - example: /site/website/index.xml - - name: depth - in: query - schema: - type: integer - description: Depth of the tree to display - required: true - example: 1 - - name: order - in: query - schema: - type: string - description: Order of content items. - required: true - example: default - responses: - '200': - description: OK - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ContentItemV1' - '400': - $ref: '#/components/responses/api1BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - /api/1/services/api/1/content/reorder-items.json: get: tags: From bc510fb158345f4e6205ac2f54fa497450a71fef Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Wed, 6 May 2026 12:29:46 -0600 Subject: [PATCH 32/38] Update spec wrong propery name --- src/main/api/studio-api.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/api/studio-api.yaml b/src/main/api/studio-api.yaml index 3473c0209f..a067e6bb4c 100644 --- a/src/main/api/studio-api.yaml +++ b/src/main/api/studio-api.yaml @@ -3738,7 +3738,7 @@ paths: properties: response: $ref: '#/components/schemas/ApiResponse' - dependencies: + usage: type: object properties: templates: From 4de2a92f023bacb0f7002444bb6a5817fd70217e Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Wed, 6 May 2026 12:32:06 -0600 Subject: [PATCH 33/38] Add missing tags --- src/main/api/studio-api.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/api/studio-api.yaml b/src/main/api/studio-api.yaml index a067e6bb4c..637a3244e5 100644 --- a/src/main/api/studio-api.yaml +++ b/src/main/api/studio-api.yaml @@ -66,6 +66,10 @@ tags: description: Server operations - name: system description: System operations + - name: model + description: Data models definitions + - name: contentTypes + description: Content type operations paths: From 9863dfa58fcfff093d469f28f7c72686d5acd2b7 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Wed, 6 May 2026 12:35:12 -0600 Subject: [PATCH 34/38] Remove obsolete API --- .../server/get-available-languages.get.groovy | 30 ------------------- 1 file changed, 30 deletions(-) delete mode 100644 src/main/webapp/default-site/scripts/rest/api/1/server/get-available-languages.get.groovy diff --git a/src/main/webapp/default-site/scripts/rest/api/1/server/get-available-languages.get.groovy b/src/main/webapp/default-site/scripts/rest/api/1/server/get-available-languages.get.groovy deleted file mode 100644 index bd9585fb44..0000000000 --- a/src/main/webapp/default-site/scripts/rest/api/1/server/get-available-languages.get.groovy +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -def result = [] -result[0] = [:] -result[0].id = "en" -result[0].label = "English" -result[1] = [:] -result[1].id = "es" -result[1].label = "Español" -result[2] = [:] -result[2].id = "ko" -result[2].label = "한국어" -result[3] = [:] -result[3].id = "de" -result[3].label = "Deutsch" -return result From e150f3d61a0118e00b551d5360ee4a88e0d29558 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Wed, 6 May 2026 12:54:50 -0600 Subject: [PATCH 35/38] Calculate content type class based on destination path --- .../craftercms/studio/impl/v2/sync/SyncFromRepositoryTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/craftercms/studio/impl/v2/sync/SyncFromRepositoryTask.java b/src/main/java/org/craftercms/studio/impl/v2/sync/SyncFromRepositoryTask.java index 0231b5a332..1a6fadf6f7 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/sync/SyncFromRepositoryTask.java +++ b/src/main/java/org/craftercms/studio/impl/v2/sync/SyncFromRepositoryTask.java @@ -673,7 +673,7 @@ private void processMove(ItemDAO itemDao, DependencyDAO dependencyDao, SqlSessio updateItemRow(itemDao, site.getId(), repoOperation.getPath(), metadata.previewUrl, onStateBitMap, offStateBitmap, user.getId(), repoOperation.getDateTime(), metadata.label, metadata.contentTypeId, - getContentTypeClass(servicesConfig, studioConfiguration, site.getSiteId(), repoOperation.getPath()), + getContentTypeClass(servicesConfig, studioConfiguration, site.getSiteId(), repoOperation.getMoveToPath()), StudioUtils.getMimeType(FilenameUtils.getName(repoOperation.getPath())), contentRepository.getContentSize(site.getSiteId(), repoOperation.getPath())); From 455edd6805949c46cce827bfb333a029ebe5193a Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Wed, 6 May 2026 13:26:01 -0600 Subject: [PATCH 36/38] Remove unncessary semicolon --- src/main/webapp/default-site/scripts/pages/preview.groovy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/webapp/default-site/scripts/pages/preview.groovy b/src/main/webapp/default-site/scripts/pages/preview.groovy index 0d91fe0deb..d65ccc4704 100644 --- a/src/main/webapp/default-site/scripts/pages/preview.groovy +++ b/src/main/webapp/default-site/scripts/pages/preview.groovy @@ -19,10 +19,10 @@ import org.apache.commons.text.StringEscapeUtils import org.craftercms.studio.impl.v2.utils.security.SecurityUtils import scripts.libs.EnvironmentOverrides -def ticket = request.getSession().getValue("alf_ticket"); -def username = request.getSession().getValue("username"); +def ticket = request.getSession().getValue("alf_ticket") +def username = request.getSession().getValue("username") -def currentUser = SecurityUtils.getCurrentUser(); +def currentUser = SecurityUtils.getCurrentUser() model.envConfig = EnvironmentOverrides.getMinimalValuesForSite(applicationContext, request) model.userEmail = currentUser?.email From 2e179ce2ba214452b8491edd5fd4716629af1239 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Wed, 6 May 2026 13:26:19 -0600 Subject: [PATCH 37/38] Complete javadoc --- .../studio/api/v2/service/content/ContentTypeService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java b/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java index 1630bf3650..c3a082a95e 100644 --- a/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java +++ b/src/main/java/org/craftercms/studio/api/v2/service/content/ContentTypeService.java @@ -110,6 +110,7 @@ void deleteContentType(String siteId, String contentType, boolean deleteDependen * * @param siteId site identifier * @return List of quick creatable content types + * @throws ServiceLayerException if there is any error getting the content types */ List getQuickCreatableContentTypes(String siteId) throws ServiceLayerException; From bc35b62b1a21d6bdf6124a378608aa085205a3c1 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Wed, 6 May 2026 13:26:38 -0600 Subject: [PATCH 38/38] Handle blank parameters in updateSite --- .../studio/impl/v2/service/site/SitesServiceImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/craftercms/studio/impl/v2/service/site/SitesServiceImpl.java b/src/main/java/org/craftercms/studio/impl/v2/service/site/SitesServiceImpl.java index d7657923d6..300fe1f692 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/service/site/SitesServiceImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v2/service/site/SitesServiceImpl.java @@ -48,7 +48,7 @@ import java.util.Collection; import java.util.List; -import static org.apache.commons.lang3.StringUtils.defaultIfEmpty; +import static org.apache.commons.lang3.StringUtils.defaultIfBlank; import static org.craftercms.studio.permissions.StudioPermissionsConstants.*; public class SitesServiceImpl implements SitesService { @@ -81,8 +81,8 @@ public String getBlueprintLocation(String blueprintId) throws ServiceLayerExcept public void updateSite(@SiteId String siteId, String name, String description) throws SiteNotFoundException, SiteAlreadyExistsException, InvalidParametersException { - String normalizedName = defaultIfEmpty(name, null); - String normalizedDescription = defaultIfEmpty(description, null); + String normalizedName = defaultIfBlank(name, null); + String normalizedDescription = defaultIfBlank(description, null); if (normalizedDescription == null && normalizedName == null) { throw new InvalidParametersException("The request needs to include a name or a description");