From 1c5f0a6a85487db2287d2de557f170292be6a775 Mon Sep 17 00:00:00 2001 From: Jose Castro Date: Thu, 7 Nov 2024 11:04:46 -0600 Subject: [PATCH 1/3] feat(multi-language) #30591 : Create endpoints to feed the Multi-language Component for the Edit Contentlet sidebar --- .../rest/api/v1/content/ContentResource.java | 79 ++- .../ExistingLanguagesForContentletView.java | 26 + .../v1/page/ExistingLanguagesForPageView.java | 3 + .../dotcms/rest/api/v1/page/PageResource.java | 4 + .../rest/api/v1/page/PageResourceHelper.java | 3 + .../api/v2/languages/LanguagesResource.java | 22 + .../ContentResourceV1.postman_collection.json | 455 +++++------------- .../postman/LanguageResourceTests.json | 47 +- 8 files changed, 299 insertions(+), 340 deletions(-) create mode 100644 dotCMS/src/main/java/com/dotcms/rest/api/v1/content/ExistingLanguagesForContentletView.java diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/content/ContentResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/content/ContentResource.java index 7a237dedf344..871cfed3a8fb 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/content/ContentResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/content/ContentResource.java @@ -37,6 +37,7 @@ import com.dotmarketing.portlets.contentlet.model.IndexPolicy; import com.dotmarketing.portlets.contentlet.transform.DotTransformerBuilder; import com.dotmarketing.portlets.htmlpageasset.model.IHTMLPage; +import com.dotmarketing.portlets.languagesmanager.business.LanguageAPI; import com.dotmarketing.portlets.languagesmanager.model.Language; import com.dotmarketing.portlets.structure.model.ContentletRelationships; import com.dotmarketing.portlets.structure.model.Relationship; @@ -47,6 +48,7 @@ import com.dotmarketing.util.UtilMethods; import com.dotmarketing.util.json.JSONException; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; import com.liferay.portal.language.LanguageUtil; import com.liferay.portal.model.User; import io.swagger.v3.oas.annotations.Operation; @@ -77,6 +79,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.function.LongSupplier; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -92,29 +95,30 @@ public class ContentResource { private final ContentletAPI contentletAPI; private final IdentifierAPI identifierAPI; private final LanguageWebAPI languageWebAPI; + private final LanguageAPI languageAPI; private final Lazy isDefaultContentToDefaultLanguageEnabled = Lazy.of( () -> Config.getBooleanProperty("DEFAULT_CONTENT_TO_DEFAULT_LANGUAGE", false)); - public ContentResource() { - this(new WebResource(), APILocator.getContentletAPI(), APILocator.getIdentifierAPI(), - WebAPILocator.getLanguageWebAPI()); + WebAPILocator.getLanguageWebAPI(), + APILocator.getLanguageAPI()); } @VisibleForTesting public ContentResource(final WebResource webResource, final ContentletAPI contentletAPI, final IdentifierAPI identifierAPI, - final LanguageWebAPI languageWebAPI) { - + final LanguageWebAPI languageWebAPI, + final LanguageAPI languageAPI) { this.webResource = webResource; this.contentletAPI = contentletAPI; this.identifierAPI = identifierAPI; this.languageWebAPI = languageWebAPI; + this.languageAPI = languageAPI; } /** @@ -590,5 +594,70 @@ public Response pullRelated(@Context final HttpServletRequest request, } + /** + * Receives the Identifier of a {@link Contentlet }, returns all the available languages in + * dotCMS and, for each of them, adds a flag indicating whether the Contentlet is available in + * that language or not. This may be particularly useful when requiring the system to provide a + * specific action when a Contentlet is NOT available in a given language. Here's an example of + * how you can use it: + *
+     *     GET http://localhost:8080/api/v1/content/${CONTENT_ID}/languages
+     * 
+ * + * @param request The current instance of the {@link HttpServletRequest}. + * @param response The current instance of the {@link HttpServletResponse}. + * @param identifier The Identifier of the Contentlet whose available languages will be + * checked. + * + * @return A {@link Response} object containing the list of languages and the flag indicating + * whether the Contentlet is available in such a language or not. + * + * @throws DotDataException An error occurred when interacting with the database. + */ + @GET + @Path("/{identifier}/languages") + @JSONP + @NoCache + @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) + public Response checkContentLanguageVersions(@Context final HttpServletRequest request, + @Context final HttpServletResponse response, + @PathParam("identifier") final String identifier) throws DotDataException { + final User user = new WebResource.InitBuilder(webResource).requestAndResponse(request, response) + .rejectWhenNoUser(true) + .requiredBackendUser(true) + .init().getUser(); + Logger.debug(this, () -> String.format("Check the languages that the Contentlet '%s' is available on", identifier)); + final List languagesForContent = this.getExistingLanguagesForContent(identifier, user); + return Response.ok(new ResponseEntityView<>(languagesForContent)).build(); + } + + /** + * Returns a list of ALL languages in dotCMS and, for each of them, adds a boolean indicating + * whether the specified Contentlet Identifier is available in such a language or not. This is + * particularly useful for the UI layer to be able to easily check what languages a Contentlet + * is available on, and what languages it is not. + * + * @param identifier The Identifier of the {@link Contentlet} whose languages are being + * checked. + * @param user The {@link User} performing this action. + * + * @return The list of languages and the flag indicating whether the Contentlet is available in + * such a language or not. + * + * @throws DotDataException An error occurred when interacting with the database. + */ + private List getExistingLanguagesForContent(final String identifier, final User user) throws DotDataException { + DotPreconditions.checkNotNull(identifier, "Contentlet ID cannot be null"); + DotPreconditions.checkNotNull(user, "User cannot be null"); + final ImmutableList.Builder languagesForContent = new ImmutableList.Builder<>(); + final Set existingContentLanguages = + APILocator.getVersionableAPI().findContentletVersionInfos(identifier) + .stream().map(ContentletVersionInfo::getLang) + .collect(Collectors.toSet()); + final List allLanguages = this.languageAPI.getLanguages(); + allLanguages.forEach(language -> languagesForContent.add(new ExistingLanguagesForContentletView(language, + existingContentLanguages.contains(language.getId())))); + return languagesForContent.build(); + } } diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/content/ExistingLanguagesForContentletView.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/content/ExistingLanguagesForContentletView.java new file mode 100644 index 000000000000..4a0542221e94 --- /dev/null +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/content/ExistingLanguagesForContentletView.java @@ -0,0 +1,26 @@ +package com.dotcms.rest.api.v1.content; + +import com.dotmarketing.portlets.languagesmanager.model.Language; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * This View is used to indicate what language a + * {@link com.dotmarketing.portlets.contentlet.model.Contentlet} is available on, and what language + * it is not. This is particularly useful for the UI to be aware of such a situation, and then + * provide the user the option to create it using that language. + * + * @author Jose Castro + * @since Jan 5th, 2023 + */ +public class ExistingLanguagesForContentletView extends HashMap implements Serializable { + + public ExistingLanguagesForContentletView(final Language language, final boolean translated) { + final Map dataMap = new HashMap<>(language.toMap()); + this.putAll(dataMap); + this.put("translated", translated); + } + +} diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/ExistingLanguagesForPageView.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/ExistingLanguagesForPageView.java index 8eb0bdf26e4c..7724756b47d4 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/ExistingLanguagesForPageView.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/ExistingLanguagesForPageView.java @@ -13,7 +13,10 @@ * * @author Jose Castro * @since Jan 5th, 2023 + * + * @deprecated This class is deprecated and will be removed in a future version of dotCMS. */ +@Deprecated public class ExistingLanguagesForPageView extends HashMap implements Serializable { public ExistingLanguagesForPageView(final Language language, final boolean translated) { diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResource.java index 06bc5c37c5b4..d18faf949609 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResource.java @@ -1385,12 +1385,16 @@ public ResponseEntityPageWorkflowActionsView findAvailableActions(@Context final * whether the page is available in such a language or not. * * @throws DotDataException An error occurred when interacting with the database. + * @deprecated This method is deprecated and will be removed in future versions. Please use the + * more generic REST Endpoint + * {@link com.dotcms.rest.api.v1.content.ContentResource#getExistingLanguagesForContent(String, User)} instead. */ @GET @Path("/{pageId}/languages") @JSONP @NoCache @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) + @Deprecated public Response checkPageLanguageVersions(@Context final HttpServletRequest request, @Context final HttpServletResponse response, @PathParam("pageId") final String pageId) throws DotDataException { diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResourceHelper.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResourceHelper.java index fc544d524e36..8cdb72e1f132 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResourceHelper.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResourceHelper.java @@ -568,7 +568,10 @@ private Tuple2 copyContent(final CopyContentletForm copy * language or not. * * @throws DotDataException An error occurred when interacting with the database. + * + * @deprecated This method is deprecated and will be removed in future versions. */ + @Deprecated public List getExistingLanguagesForPage(final String pageId, final User user) throws DotDataException { DotPreconditions.checkNotNull(pageId, "Page ID cannot be null"); DotPreconditions.checkNotNull(user, "User cannot be null"); diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v2/languages/LanguagesResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v2/languages/LanguagesResource.java index d1936ce91b00..f2945709f969 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v2/languages/LanguagesResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v2/languages/LanguagesResource.java @@ -637,4 +637,26 @@ public Response getIsoLanguagesAndCountries ( ).build(); } + /** + * Returns the current default {@link Language} in the dotCMS instance. + * + * @param request The current instance of the {@link HttpServletRequest}. + * @param response The current instance of the {@link HttpServletResponse}. + * + * @return A {@link Response} object containing the default {@link Language} in the dotCMS + * instance. + * + * @throws DotDataException An error occurred when retrieving the default {@link Language}. + */ + @GET + @Path("/_getdefault") + @JSONP + @NoCache + @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) + public Response getDefaultLanguage(@Context final HttpServletRequest request, + @Context final HttpServletResponse response) throws DotDataException, DotSecurityException { + Logger.debug(this, () -> "Retrieving the current default Language"); + return Response.ok(new ResponseEntityView<>(this.languageAPI.getDefaultLanguage())).build(); + } + } diff --git a/dotcms-postman/src/main/resources/postman/ContentResourceV1.postman_collection.json b/dotcms-postman/src/main/resources/postman/ContentResourceV1.postman_collection.json index 3a0801ab25d8..202aa641b55b 100644 --- a/dotcms-postman/src/main/resources/postman/ContentResourceV1.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/ContentResourceV1.postman_collection.json @@ -1,10 +1,10 @@ { "info": { - "_postman_id": "ab448a87-b3b3-4836-8b29-75ac9397ae99", + "_postman_id": "432048a5-eb89-43a5-9828-e4d69ff200dc", "name": "ContentResourceV1", "description": "This folder contains a comprehensive set of API requests related to the `ContentResourceV1` API endpoints. These requests cover various operations such as creating, retrieving and updating content. The folder is organized to help developers and testers efficiently validate and interact with the content resource endpoints in the system.\n\n#### Objectives:\n\n1. **Create Content**:\n \n - Test the creation of new content items with valid and invalid data.\n \n - Ensure that the response includes all necessary details for the created content.\n \n2. **Retrieve Content**:\n \n - Validate the retrieval of content items by ID.\n \n - Ensure the response contains accurate and complete content details.\n \n3. **Update Content**:\n \n - Test updating existing content items with valid and invalid data.\n \n - Verify that the response reflects the updated content accurately.\n \n - Ensure that only authorized users can update content.\n \n4. **Error Handling**:\n \n - Verify that the API returns appropriate error messages for invalid requests.\n \n - Ensure the correct HTTP status codes are used for different error scenarios.\n \n5. **Security**:\n \n - Validate that only authorized users can perform operations on the content.\n \n - Ensure that all security protocols are enforced during API interactions.", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "781456" + "_exporter_id": "5403727" }, "item": [ { @@ -474,16 +474,11 @@ "listen": "test", "script": { "exec": [ - "var jsonData = pm.response.json();", - "", "pm.test(\"Valid response\", function () {", " pm.expect(pm.response.text()).to.include(\"SucessRequest\");", - "", - " pm.expect(jsonData.entity).to.have.property('shortyId');", - " pm.expect(jsonData.entity).to.have.property('identifier');", "});", "", - "", + "var jsonData = pm.response.json();", "pm.collectionVariables.set(\"contentletIdentifier\", jsonData.entity.identifier);", "pm.collectionVariables.set(\"contentletInode\", jsonData.entity.inode);", "", @@ -495,16 +490,6 @@ } ], "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{jwt}}", - "type": "string" - } - ] - }, "method": "PUT", "header": [ { @@ -514,7 +499,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"contentlet\": {\n \"stInode\": \"f4d7c1b8-2c88-4071-abf1-a5328977b07d\",\n \"languageId\": 1,\n \"key\": \"SucessRequest{{$timestamp}}\",\n \"value\": \"SucessRequest{{$timestamp}}\"\n }\n}" + "raw": "{ \"contentlet\" : {\n \"stInode\" : \"f4d7c1b8-2c88-4071-abf1-a5328977b07d\",\n \"languageId\" : 1,\n \"key\": \"SucessRequest{{$timestamp}}\",\n \"value\": \"SucessRequest{{$timestamp}}\"\n}\n}" }, "url": { "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH", @@ -2474,326 +2459,150 @@ "description": "This folder contains a comprehensive set of requests designed to handle the creation, relationship management, and updating of content within our application. These requests are essential for ensuring that content operations are performed correctly and efficiently. \n \nThis will include both possitive and negative testing." }, { - "name": "References", + "name": "Retrieving Content", "item": [ { - "name": "CreatePage", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const pagePost = Math.floor(Math.random()*100+1)", - "pm.globals.set(\"pageRefPost\", pagePost)" - ], - "type": "text/javascript", - "packages": {} - } - }, + "name": "Available Langs for Contentlet", + "item": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"HTTP Status code must be 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Test Page created successfully\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.errors.length).to.eql(0);", - " pm.collectionVariables.set(\"pageIdentifier\", jsonData.entity.identifier);", - " pm.collectionVariables.set(\"host_id\", jsonData.entity.host);", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ + "name": "Creating Test Generic Content", + "event": [ { - "key": "token", - "value": "{{jwt}}", - "type": "string" - } - ] - }, - "method": "PUT", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n\t\n\t\"contentlet\": {\n\t\t\"contentType\":\"htmlpageasset\",\n \"title\":\"testPageCopy{{pageRefPost}}\",\n \"url\":\"testPageCopy{{pageRefPost}}\",\n \"hostFolder\":\"default\",\n \"template\":\"SYSTEM_TEMPLATE\",\n \"friendlyName\":\"testPageCopy{{pageRefPost}}\",\n \"cachettl\":0\n\t\t\n\t}\n}", - "options": { - "raw": { - "language": "json" + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test content created successfully\", function () {", + " const jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + " ", + " const jsonKey = Object.keys(jsonData.entity.results[0]);", + " const potentialErrorMsg = jsonData.entity.results[0][jsonKey].errorMessage;", + " pm.expect(potentialErrorMsg).to.equal(undefined, \"An error occurred when creating the test Contentlet\")", + " ", + " pm.collectionVariables.set(\"testContentId\", jsonData.entity.results[0][jsonKey].identifier);", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH?indexPolicy=WAIT_FOR", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "workflow", - "actions", - "default", - "fire", - "PUBLISH" ], - "query": [ - { - "key": "indexPolicy", - "value": "WAIT_FOR" - } - ] - } - }, - "response": [] - }, - { - "name": "CreateContentRich", - "event": [ + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"contentlets\": [\n {\n \"contentType\": \"webPageContent\",\n \"title\": \"Test Generic Content\",\n \"contentHost\": \"default\",\n \"body\": \"This is my Test Generic Content\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "workflow", + "actions", + "default", + "fire", + "PUBLISH" + ] + }, + "description": "\nThe API endpoint triggers the publication of specified content items. Upon successful execution, the response is returned in the form of a JSON schema.\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"entity\": {\n \"type\": \"object\",\n \"properties\": {\n \"results\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"additionalProperties\": {\n \"type\": \"object\",\n \"properties\": {\n \"errorMessage\": {\n \"type\": \"string\"\n },\n \"identifier\": {\n \"type\": [\"string\", \"null\"]\n },\n \"inode\": {\n \"type\": [\"string\", \"null\"]\n }\n }\n }\n }\n },\n \"summary\": {\n \"type\": \"object\",\n \"properties\": {\n \"affected\": {\n \"type\": \"integer\"\n },\n \"failCount\": {\n \"type\": \"integer\"\n },\n \"successCount\": {\n \"type\": \"integer\"\n },\n \"time\": {\n \"type\": \"integer\"\n }\n }\n }\n }\n },\n \"errors\": {\n \"type\": \"array\",\n \"items\": {}\n },\n \"i18nMessagesMap\": {\n \"type\": \"object\"\n },\n \"messages\": {\n \"type\": \"array\",\n \"items\": {}\n },\n \"permissions\": {\n \"type\": \"array\",\n \"items\": {}\n }\n }\n}\n```\n" + }, + "response": [] + }, { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"HTTP Status code must be 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Test Page created successfully\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.errors.length).to.eql(0);", - " pm.collectionVariables.set(\"contentIdentifier\", jsonData.entity.identifier);", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ + "name": "Get Available Langs for Content", + "event": [ { - "key": "token", - "value": "{{jwt}}", - "type": "string" - } - ] - }, - "method": "PUT", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n\t\n\t\"contentlet\": {\n\t\t\"contentType\":\"webPageContent\",\n \"title\":\"test\",\n\t\t\"body\":\"Test body\",\n \"contentHost\":\"default\"\n\t}\n}", - "options": { - "raw": { - "language": "json" + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Check that the test Contentlet is available in English, no matter how many languages there are\", function () {", + " const entity = pm.response.json().entity;", + " var isTranslated = false;", + " entity.forEach(function(lang) {", + " if (1 == lang.id && lang.translated) {", + " isTranslated = true;", + " }", + " });", + " pm.expect(isTranslated).to.be.equal(true, 'The test Contentlet must be available in English');", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH?indexPolicy=WAIT_FOR", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "workflow", - "actions", - "default", - "fire", - "PUBLISH" ], - "query": [ - { - "key": "indexPolicy", - "value": "WAIT_FOR" + "request": { + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "admin@dotcms.com", + "type": "string" + }, + { + "key": "password", + "value": "admin", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{serverURL}}/api/v1/content/{{testContentId}}/languages", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "content", + "{{testContentId}}", + "languages" + ] } - ] + }, + "response": [] } - }, - "response": [] - }, - { - "name": "AddContentToPage", + ], "event": [ { - "listen": "test", + "listen": "prerequest", "script": { + "type": "text/javascript", + "packages": {}, "exec": [ - "pm.test(\"HTTP Status code must be 200\", function () {", - " pm.response.to.have.status(200);", - "});", "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{jwt}}", - "type": "string" - } - ] - }, - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{contentIdentifier}}\"\n ]\n }\n]", - "options": { - "raw": { - "language": "json" - } + ] } }, - "url": { - "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "{{pageIdentifier}}", - "content" - ] - } - }, - "response": [] - }, - { - "name": "CheckCount", - "event": [ { "listen": "test", "script": { - "exec": [ - "pm.test(\"HTTP Status code must be 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"count successfully\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.entity.count).to.gte(1);", - "});" - ], "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{jwt}}", - "type": "string" - } - ] - }, - "method": "GET", - "header": [], - "url": { - "raw": "{{serverURL}}/api/v1/content/{{contentIdentifier}}/references/count", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "content", - "{{contentIdentifier}}", - "references", - "count" - ] - } - }, - "response": [] - }, - { - "name": "CheckReferences", - "event": [ - { - "listen": "test", - "script": { + "packages": {}, "exec": [ - "pm.test(\"HTTP Status code must be 200\", function () {", - " pm.response.to.have.status(200);", + "pm.test(\"HTTP Status code must be successful\", function() {", + " pm.response.to.be.ok ", "});", - "", - "pm.test(\"References successfully\", function () {", - " var jsonData = pm.response.json();", - " var pageIdCreated = pm.collectionVariables.get(\"pageIdentifier\");", - " console.log(\"pageIdCreated\", pageIdCreated);", - " console.log(\"pageIdCreated\", pageIdCreated, jsonData.entity[0].page.identifier);", - " pm.expect(jsonData.entity[0].page.identifier).to.eql(pageIdCreated);", - "});" - ], - "type": "text/javascript", - "packages": {} + "" + ] } } - ], - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{jwt}}", - "type": "string" - } - ] - }, - "method": "GET", - "header": [], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/content/{{contentIdentifier}}/references", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "content", - "{{contentIdentifier}}", - "references" - ] - } - }, - "response": [] + ] } ] } @@ -2869,27 +2678,5 @@ ] } } - ], - "variable": [ - { - "key": "pageIdentifier", - "value": "" - }, - { - "key": "host_id", - "value": "" - }, - { - "key": "contentIdentifier", - "value": "" - }, - { - "key": "contentletIdentifier", - "value": "" - }, - { - "key": "contentletInode", - "value": "" - } ] } \ No newline at end of file diff --git a/dotcms-postman/src/main/resources/postman/LanguageResourceTests.json b/dotcms-postman/src/main/resources/postman/LanguageResourceTests.json index 81be582bb04d..94601ef9ffb2 100644 --- a/dotcms-postman/src/main/resources/postman/LanguageResourceTests.json +++ b/dotcms-postman/src/main/resources/postman/LanguageResourceTests.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "0a7ed4a9-b343-4a56-8d63-39ef0ec770e1", + "_postman_id": "0bd5957a-5481-401c-a2bf-47d85e8be155", "name": "LanguageResource", "description": "This collections is focused on the /v2/languages resource\nThis should cover Language CRUD Operations", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", @@ -499,6 +499,51 @@ } }, "response": [] + }, + { + "name": "Get Default Language", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"HTTP Status code must be successful\", function() {", + " pm.response.to.be.ok ", + "});", + "", + "pm.test(\"Test content must only be available in English\", function() {", + " const jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + " pm.expect(jsonData.entity.id).to.equal(1, \"The expected default Language must be ID 1\");", + " pm.expect(jsonData.entity.language).to.equal(\"English\", \"The expected default Language must be English\");", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{serverURL}}/api/v2/languages/_getdefault", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v2", + "languages", + "_getdefault" + ] + } + }, + "response": [] } ] }, From 2737d896d7f60fb713d91351196123394df9740e Mon Sep 17 00:00:00 2001 From: Jose Castro Date: Thu, 7 Nov 2024 11:56:28 -0600 Subject: [PATCH 2/3] Implementing SonarQube feedback --- .../dotcms/rest/api/v1/page/ExistingLanguagesForPageView.java | 2 +- .../src/main/java/com/dotcms/rest/api/v1/page/PageResource.java | 2 +- .../java/com/dotcms/rest/api/v1/page/PageResourceHelper.java | 2 +- .../com/dotcms/rest/api/v2/languages/LanguagesResource.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/ExistingLanguagesForPageView.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/ExistingLanguagesForPageView.java index 7724756b47d4..a60e052eebf0 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/ExistingLanguagesForPageView.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/ExistingLanguagesForPageView.java @@ -16,7 +16,7 @@ * * @deprecated This class is deprecated and will be removed in a future version of dotCMS. */ -@Deprecated +@Deprecated(since = "Nov 7th, 24", forRemoval = true) public class ExistingLanguagesForPageView extends HashMap implements Serializable { public ExistingLanguagesForPageView(final Language language, final boolean translated) { diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResource.java index d18faf949609..a1f42224f21d 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResource.java @@ -1394,7 +1394,7 @@ public ResponseEntityPageWorkflowActionsView findAvailableActions(@Context final @JSONP @NoCache @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) - @Deprecated + @Deprecated(since = "Nov 7th, 24", forRemoval = true) public Response checkPageLanguageVersions(@Context final HttpServletRequest request, @Context final HttpServletResponse response, @PathParam("pageId") final String pageId) throws DotDataException { diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResourceHelper.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResourceHelper.java index 8cdb72e1f132..420b3d1a9982 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResourceHelper.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResourceHelper.java @@ -571,7 +571,7 @@ private Tuple2 copyContent(final CopyContentletForm copy * * @deprecated This method is deprecated and will be removed in future versions. */ - @Deprecated + @Deprecated(since = "Nov 7th, 24", forRemoval = true) public List getExistingLanguagesForPage(final String pageId, final User user) throws DotDataException { DotPreconditions.checkNotNull(pageId, "Page ID cannot be null"); DotPreconditions.checkNotNull(user, "User cannot be null"); diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v2/languages/LanguagesResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v2/languages/LanguagesResource.java index f2945709f969..314c6f312f88 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v2/languages/LanguagesResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v2/languages/LanguagesResource.java @@ -654,7 +654,7 @@ public Response getIsoLanguagesAndCountries ( @NoCache @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) public Response getDefaultLanguage(@Context final HttpServletRequest request, - @Context final HttpServletResponse response) throws DotDataException, DotSecurityException { + @Context final HttpServletResponse response) throws DotDataException { Logger.debug(this, () -> "Retrieving the current default Language"); return Response.ok(new ResponseEntityView<>(this.languageAPI.getDefaultLanguage())).build(); } From 8b4e362efde1fbc285a26180b1c5413ee3d03742 Mon Sep 17 00:00:00 2001 From: Jose Castro Date: Sat, 9 Nov 2024 16:13:46 -0600 Subject: [PATCH 3/3] Implementing Code Review feedback from Jonathan Sanchez. --- .../rest/api/v1/content/ContentResource.java | 19 +++++++++++-------- .../api/v2/languages/LanguagesResource.java | 4 ++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/content/ContentResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/content/ContentResource.java index 871cfed3a8fb..b79fe14d9f0d 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/content/ContentResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/content/ContentResource.java @@ -619,16 +619,19 @@ public Response pullRelated(@Context final HttpServletRequest request, @JSONP @NoCache @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) - public Response checkContentLanguageVersions(@Context final HttpServletRequest request, - @Context final HttpServletResponse response, - @PathParam("identifier") final String identifier) throws DotDataException { + public ResponseEntityView> checkContentLanguageVersions(@Context final HttpServletRequest request, + @Context final HttpServletResponse response, + @PathParam("identifier") final String identifier) throws DotDataException { + Logger.debug(this, () -> String.format("Check the languages that Contentlet '%s' is " + + "available on", identifier)); final User user = new WebResource.InitBuilder(webResource).requestAndResponse(request, response) .rejectWhenNoUser(true) - .requiredBackendUser(true) - .init().getUser(); - Logger.debug(this, () -> String.format("Check the languages that the Contentlet '%s' is available on", identifier)); - final List languagesForContent = this.getExistingLanguagesForContent(identifier, user); - return Response.ok(new ResponseEntityView<>(languagesForContent)).build(); + .requiredBackendUser(false) + .init() + .getUser(); + final List languagesForContent = + this.getExistingLanguagesForContent(identifier, user); + return new ResponseEntityView<>(languagesForContent); } /** diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v2/languages/LanguagesResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v2/languages/LanguagesResource.java index 314c6f312f88..9d9cea7fc92d 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v2/languages/LanguagesResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v2/languages/LanguagesResource.java @@ -653,10 +653,10 @@ public Response getIsoLanguagesAndCountries ( @JSONP @NoCache @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) - public Response getDefaultLanguage(@Context final HttpServletRequest request, + public ResponseEntityView getDefaultLanguage(@Context final HttpServletRequest request, @Context final HttpServletResponse response) throws DotDataException { Logger.debug(this, () -> "Retrieving the current default Language"); - return Response.ok(new ResponseEntityView<>(this.languageAPI.getDefaultLanguage())).build(); + return new ResponseEntityView<>(this.languageAPI.getDefaultLanguage()); } }