From f6a617bdccf6dcecfb84b1e71ba34c07a886755c Mon Sep 17 00:00:00 2001 From: Jonathan Gamba Date: Tue, 9 Apr 2024 14:08:49 -0600 Subject: [PATCH] #27448 Updating code to support in the language file descriptor only the language name and the ISO code. This update modifies the `ContentComparator` interface to include a `localFile` parameter in its findMatchingServerContent and localContains methods. Also, modifications have been made to all applicable classes that implement this interface, including support for file renaming if content changes. A NameUtil class has been added to generate standardized file names for Site, Language, and ContentType. Other enhancements include updating the push and pull handlers for Site, Language, and ContentType and improving their respective functionalities. --- .../business/LanguageFactoryImpl.java | 6 ++ .../main/java/com/dotcms/api/LanguageAPI.java | 21 +++++- .../model/language/AbstractLanguage.java | 13 +++- .../com/dotcms/model/views/CommonViews.java | 15 +++++ .../contenttype/ContentTypePullHandler.java | 3 +- .../client/pull/language/LanguageFetcher.java | 2 +- .../pull/language/LanguagePullHandler.java | 12 ++-- .../api/client/pull/site/SitePullHandler.java | 3 +- .../api/client/push/ContentComparator.java | 18 +++++- .../client/push/PushAnalysisServiceImpl.java | 3 +- .../dotcms/api/client/push/PushHandler.java | 7 ++ .../contenttype/ContentTypeComparator.java | 7 +- .../contenttype/ContentTypePushHandler.java | 6 ++ .../push/language/LanguageComparator.java | 64 +++++++++++++++---- .../push/language/LanguagePushHandler.java | 30 ++++++++- .../api/client/push/site/SiteComparator.java | 6 +- .../api/client/push/site/SitePushHandler.java | 6 ++ .../dotcms/api/client/push/task/PushTask.java | 19 ++++++ .../com/dotcms/api/client/util/NameUtil.java | 47 ++++++++++++++ 19 files changed, 249 insertions(+), 39 deletions(-) create mode 100644 tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/util/NameUtil.java diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/languagesmanager/business/LanguageFactoryImpl.java b/dotCMS/src/main/java/com/dotmarketing/portlets/languagesmanager/business/LanguageFactoryImpl.java index b35c8a2b4a11..c5fd9cda2e3a 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/languagesmanager/business/LanguageFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/languagesmanager/business/LanguageFactoryImpl.java @@ -404,6 +404,12 @@ protected void saveLanguage(final Language lang) { } dbUpsert(lang); CacheLocator.getLanguageCache().clearLanguages(); + // Cleaning up the createDefaultLanguageLock if we are updating the default language, + // otherwise changes won't be reflected. + if (createDefaultLanguageLock.get() != null + && createDefaultLanguageLock.get().getId() == lang.getId()) { + createDefaultLanguageLock.set(null); + } } catch (DotDataException e) { throw new DotRuntimeException("saveLanguage failed to save the language:" + lang, e); diff --git a/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/api/LanguageAPI.java b/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/api/LanguageAPI.java index 4860e8aa07a2..934bee9644e0 100644 --- a/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/api/LanguageAPI.java +++ b/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/api/LanguageAPI.java @@ -5,6 +5,7 @@ import com.dotcms.model.ResponseEntityView; import com.dotcms.model.language.Language; import com.dotcms.model.views.CommonViews; +import com.dotcms.model.views.CommonViews.LanguageFileView; import com.fasterxml.jackson.annotation.JsonView; import java.util.List; import javax.ws.rs.Consumes; @@ -41,6 +42,7 @@ public interface LanguageAPI { @Operation( summary = " Returns the Language that matches the specified id" ) + @JsonView(LanguageFileView.class) ResponseEntityView findById(@PathParam("languageid") String languageId); @@ -51,6 +53,14 @@ public interface LanguageAPI { ) ResponseEntityView getFromLanguageIsoCode(@PathParam("languageTag") String languageIsoCode); + @GET + @Operation( + summary = " Returns all the languages in the system but using a different view, a " + + "reduced one, for pull operations and the generation of the language files." + ) + @JsonView(LanguageFileView.class) + ResponseEntityView> listForPull(); + @GET @Operation( summary = " Returns all the languages in the system" @@ -61,23 +71,28 @@ public interface LanguageAPI { @Operation( summary = " Creates a new language in the system" ) + @JsonView(CommonViews.LanguageFileView.class) ResponseEntityView create( - @JsonView(CommonViews.ExternalView.class) Language language); + @JsonView(CommonViews.LanguageExternalView.class) Language language); @POST @Path("/{languageTag}") @Operation( summary = " Creates a new language in the system given its ISO code" ) - ResponseEntityView create(@PathParam("languageTag") String languageIsoCode); + @JsonView(CommonViews.LanguageFileView.class) + ResponseEntityView create( + @JsonView(CommonViews.LanguageExternalView.class) + @PathParam("languageTag") String languageIsoCode); @PUT @Path("/{languageId}") @Operation( summary = " Updates an existing language in the system" ) + @JsonView(CommonViews.LanguageFileView.class) ResponseEntityView update(@PathParam("languageId") String languageId, - @JsonView(CommonViews.ExternalView.class) Language language); + @JsonView(CommonViews.LanguageExternalView.class) Language language); @DELETE @Path("/{languageId}") diff --git a/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/model/language/AbstractLanguage.java b/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/model/language/AbstractLanguage.java index d9271ef4974d..422827d607b6 100644 --- a/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/model/language/AbstractLanguage.java +++ b/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/model/language/AbstractLanguage.java @@ -1,7 +1,8 @@ package com.dotcms.model.language; import com.dotcms.model.annotation.ValueType; -import com.dotcms.model.views.CommonViews; +import com.dotcms.model.views.CommonViews.LanguageExternalView; +import com.dotcms.model.views.CommonViews.LanguageFileView; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -19,25 +20,31 @@ public interface AbstractLanguage { String TYPE = "Language"; - @JsonView(CommonViews.InternalView.class) + @JsonView(LanguageFileView.class) @Value.Derived default String dotCMSObjectType() { return TYPE; } + @JsonView(LanguageExternalView.class) Optional id(); + @JsonView(LanguageExternalView.class) Optional languageCode(); + @JsonView(LanguageExternalView.class) Optional countryCode(); + @JsonView({LanguageFileView.class, LanguageExternalView.class}) Optional language(); + @JsonView(LanguageExternalView.class) Optional country(); - @JsonView(CommonViews.InternalView.class) + @JsonView(LanguageFileView.class) Optional defaultLanguage(); + @JsonView({LanguageFileView.class, LanguageExternalView.class}) String isoCode(); } diff --git a/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/model/views/CommonViews.java b/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/model/views/CommonViews.java index f46dec2e9cf3..26e418bdb8fa 100644 --- a/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/model/views/CommonViews.java +++ b/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/model/views/CommonViews.java @@ -46,4 +46,19 @@ public interface InternalView extends ExternalView { } + /** + * The LanguageFileView interface defines the view used for the language file descriptor + */ + public interface LanguageFileView { + + } + + /** + * The LanguageExternalView interface defines the view used for some server operations as those + * server operations require more data than the one displayed in the language file descriptor + */ + public interface LanguageExternalView { + + } + } \ No newline at end of file diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/contenttype/ContentTypePullHandler.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/contenttype/ContentTypePullHandler.java index 13fe35e1b326..01cc3c07f3db 100644 --- a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/contenttype/ContentTypePullHandler.java +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/contenttype/ContentTypePullHandler.java @@ -1,6 +1,7 @@ package com.dotcms.api.client.pull.contenttype; import com.dotcms.api.client.pull.GeneralPullHandler; +import com.dotcms.api.client.util.NameUtil; import com.dotcms.contenttype.model.type.ContentType; import com.dotcms.model.pull.PullOptions; import java.text.SimpleDateFormat; @@ -32,7 +33,7 @@ public String displayName(final ContentType contentType) { @Override public String fileName(final ContentType contentType) { - return contentType.variable(); + return NameUtil.contentTypeFileName(contentType); } @Override diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/language/LanguageFetcher.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/language/LanguageFetcher.java index c618eb0be1b6..19c1d4fff223 100644 --- a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/language/LanguageFetcher.java +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/language/LanguageFetcher.java @@ -27,7 +27,7 @@ public class LanguageFetcher implements ContentFetcher, Serializable { public List fetch(final boolean failFast, final Map customOptions) { final var languageAPI = clientFactory.getClient(LanguageAPI.class); - return languageAPI.list().entity(); + return languageAPI.listForPull().entity(); } @ActivateRequestContext diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/language/LanguagePullHandler.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/language/LanguagePullHandler.java index 649ec92c12e5..79c0412e2c7b 100644 --- a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/language/LanguagePullHandler.java +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/language/LanguagePullHandler.java @@ -1,6 +1,7 @@ package com.dotcms.api.client.pull.language; import com.dotcms.api.client.pull.GeneralPullHandler; +import com.dotcms.api.client.util.NameUtil; import com.dotcms.model.language.Language; import com.dotcms.model.pull.PullOptions; import java.util.List; @@ -30,19 +31,18 @@ public String displayName(final Language language) { @Override public String fileName(final Language language) { - return language.isoCode(); + return NameUtil.languageFileName(language); } @Override public String shortFormat(final Language language, final PullOptions pullOptions) { return String.format( - "language: [@|bold,underline,blue %s|@] id: [@|bold,underline,cyan %s|@] code: [@|bold,underline,green %s|@] country:[@|bold,yellow %s|@] countryCode: [@|bold,yellow %s|@] isoCode: [@|bold,yellow %s|@]", + "language: [@|bold,underline,blue %s|@] " + + "defaultLanguage: [@|bold,underline,cyan %b|@] " + + "isoCode: [@|bold,yellow %s|@]", language.language().orElse(""), - language.id().isPresent() ? language.id().get() : "", - language.languageCode().orElse(""), - language.country().orElse(""), - language.countryCode().orElse(""), + language.defaultLanguage().orElse(false), language.isoCode() ); } diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/site/SitePullHandler.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/site/SitePullHandler.java index 7c4f074c3726..acae58c3c071 100644 --- a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/site/SitePullHandler.java +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/pull/site/SitePullHandler.java @@ -1,6 +1,7 @@ package com.dotcms.api.client.pull.site; import com.dotcms.api.client.pull.GeneralPullHandler; +import com.dotcms.api.client.util.NameUtil; import com.dotcms.model.pull.PullOptions; import com.dotcms.model.site.SiteView; import java.util.List; @@ -31,7 +32,7 @@ public String displayName(final SiteView site) { @Override public String fileName(final SiteView site) { - return site.hostName(); + return NameUtil.siteFileName(site); } @Override diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/ContentComparator.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/ContentComparator.java index 2eafbecb0bb9..30190460660a 100644 --- a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/ContentComparator.java +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/ContentComparator.java @@ -1,5 +1,6 @@ package com.dotcms.api.client.push; +import java.io.File; import java.util.Comparator; import java.util.List; import java.util.Optional; @@ -22,22 +23,24 @@ public interface ContentComparator { /** * Finds matching server content based on local content and a list of server contents. * + * @param localFile the local file representing the local content * @param localContent the local content to compare against server contents * @param serverContents the list of server contents to search for matches * @return an Optional containing the matching server content if found, otherwise an empty * Optional. */ - Optional findMatchingServerContent(T localContent, List serverContents); + Optional findMatchingServerContent(File localFile, T localContent, List serverContents); /** * Checks if the given server content is contained within the list of local contents. * * @param serverContent the server content to check for containment + * @param localFiles the list of local files representing the local contents * @param localContents the list of local contents to search for containment * @return an Optional containing the matching local content if found, or an empty Optional if * not found. */ - Optional localContains(T serverContent, List localContents); + Optional localContains(T serverContent, List localFiles, List localContents); /** * Checks if the given local content and server content are equal. @@ -48,6 +51,17 @@ public interface ContentComparator { */ boolean contentEquals(T localContent, T serverContent); + /** + * Retrieves the file name without the extension from a given File object. + * + * @param file the File object representing the file + * @return the file name without the extension + */ + default String getFileName(File file) { + String fileName = file.getName(); + return fileName.substring(0, fileName.lastIndexOf('.')); + } + /** * Retrieves a comparator that can be used to sort a list of contents in the order they should * be processed. diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/PushAnalysisServiceImpl.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/PushAnalysisServiceImpl.java index 9a80f8337a39..a3b395dd13e8 100644 --- a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/PushAnalysisServiceImpl.java +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/PushAnalysisServiceImpl.java @@ -92,6 +92,7 @@ private List> checkLocal(List localFiles, var localContent = map(localFile, comparator.type()); var matchingServerContent = comparator.findMatchingServerContent( + localFile, localContent, serverContents ); @@ -161,7 +162,7 @@ private List> checkServerForRemovals(List localF for (T serverContent : serverContents) { - var local = comparator.localContains(serverContent, localContents); + var local = comparator.localContains(serverContent, localFiles, localContents); if (local.isEmpty()) { removals.add( PushAnalysisResult.builder(). diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/PushHandler.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/PushHandler.java index 0bbc38047b4c..25617312e777 100644 --- a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/PushHandler.java +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/PushHandler.java @@ -23,6 +23,13 @@ public interface PushHandler { */ String title(); + /** + * Returns the file name for a given T elements used to save the content to a file. + * + * @param content the content to be saved to a file. + */ + String fileName(T content); + /** * Generates a simple String representation of a content to use on the console. * diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/contenttype/ContentTypeComparator.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/contenttype/ContentTypeComparator.java index 5b0a0ffe4b21..0cc2cb1b6c0b 100644 --- a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/contenttype/ContentTypeComparator.java +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/contenttype/ContentTypeComparator.java @@ -4,6 +4,7 @@ import com.dotcms.api.client.model.RestClientFactory; import com.dotcms.api.client.push.ContentComparator; import com.dotcms.contenttype.model.type.ContentType; +import java.io.File; import java.util.List; import java.util.Optional; import javax.enterprise.context.Dependent; @@ -23,8 +24,8 @@ public Class type() { @ActivateRequestContext @Override - public Optional findMatchingServerContent(ContentType localContentType, - List serverContents) { + public Optional findMatchingServerContent(File localFile, + ContentType localContentType, List serverContents) { // Compare by identifier first. var result = findById(localContentType.id(), serverContents); @@ -40,7 +41,7 @@ public Optional findMatchingServerContent(ContentType localContentT @ActivateRequestContext @Override - public Optional localContains(ContentType serverContent, + public Optional localContains(ContentType serverContent, List localFiles, List localSites) { // Compare by identifier first. diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/contenttype/ContentTypePushHandler.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/contenttype/ContentTypePushHandler.java index 69e335284a16..c4c933a7914f 100644 --- a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/contenttype/ContentTypePushHandler.java +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/contenttype/ContentTypePushHandler.java @@ -3,6 +3,7 @@ import com.dotcms.api.ContentTypeAPI; import com.dotcms.api.client.model.RestClientFactory; import com.dotcms.api.client.push.PushHandler; +import com.dotcms.api.client.util.NameUtil; import com.dotcms.contenttype.model.type.ContentType; import com.dotcms.model.contenttype.AbstractSaveContentTypeRequest.Builder; import com.dotcms.model.contenttype.SaveContentTypeRequest; @@ -32,6 +33,11 @@ public String title() { return "ContentTypes"; } + @Override + public String fileName(final ContentType contentType) { + return NameUtil.contentTypeFileName(contentType); + } + @Override public String contentSimpleDisplay(ContentType contentType) { diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/language/LanguageComparator.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/language/LanguageComparator.java index 5d52f1f6ae34..7f163b02c16f 100644 --- a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/language/LanguageComparator.java +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/language/LanguageComparator.java @@ -2,8 +2,11 @@ import com.dotcms.api.client.push.ContentComparator; import com.dotcms.model.language.Language; +import java.io.File; import java.util.List; +import java.util.Objects; import java.util.Optional; +import javax.annotation.Nullable; import javax.enterprise.context.Dependent; import javax.enterprise.context.control.ActivateRequestContext; @@ -17,16 +20,24 @@ public Class type() { @ActivateRequestContext @Override - public Optional findMatchingServerContent(Language localLanguage, - List serverContents) { + public Optional findMatchingServerContent(File localFile, + Language localLanguage, List serverContents) { - // Compare by id first. - var result = findById(localLanguage.id(), serverContents); + // Compare by ISO code first. + var result = findByISOCode(localLanguage.isoCode(), serverContents); - if (result.isEmpty()) { + if (result.isEmpty() && localLanguage.id().isPresent()) { + + // If not found by ISO code, compare by id + result = findById(localLanguage.id(), serverContents); + } - // If not found by id, compare by ISO code. - result = findByISOCode(localLanguage.isoCode(), serverContents); + // If nothing was found let's use the file name as a last resort, this is useful because the + // file name is the ISO code, and someone might have changed the ISO code in the json file, + // confusing the validation process, processing it as a new language. + if (result.isEmpty() && !getFileName(localFile).equalsIgnoreCase(localLanguage.isoCode())) { + // The ISO changed + result = findByISOCode(getFileName(localFile), serverContents); } return result; @@ -34,15 +45,16 @@ public Optional findMatchingServerContent(Language localLanguage, @ActivateRequestContext @Override - public Optional localContains(Language serverContent, List localLanguages) { + public Optional localContains(Language serverContent, List localFiles, + List localLanguages) { - // Compare by id first. - var result = findById(serverContent.id(), localLanguages); + // Compare by ISO code first. + var result = findByISOCode(serverContent.isoCode(), localLanguages); if (result.isEmpty()) { - // If not found by id, compare by ISO code. - result = findByISOCode(serverContent.isoCode(), localLanguages); + // If not found by ISO code, compare by id + result = findById(serverContent.id(), localLanguages); } return result; @@ -58,7 +70,33 @@ public boolean contentEquals(Language localLanguage, Language serverContent) { } // Comparing the local and server content in order to determine if we need to update or not the content - return localLanguage.equals(serverContent); + return equals(localLanguage, serverContent); + } + + /** + * Checks if two Language objects are equal based on their language, default language, and ISO + * code. + * + * @param toCompare the Language object to compare + * @param another the Language object to compare against + * @return true if the two Language objects are equal, false otherwise + */ + private boolean equals(@Nullable Language toCompare, @Nullable Language another) { + + if (toCompare == another) { + return true; + } + + if (toCompare == null || another == null) { + return false; + } + + return Objects.equals( + toCompare.language().orElse(""), another.language().orElse("") + ) && Objects.equals( + toCompare.defaultLanguage().orElse(false), + another.defaultLanguage().orElse(false) + ) && toCompare.isoCode().equalsIgnoreCase(another.isoCode()); } /** diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/language/LanguagePushHandler.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/language/LanguagePushHandler.java index cc0f67875e73..7dd87dcbd2ad 100644 --- a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/language/LanguagePushHandler.java +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/language/LanguagePushHandler.java @@ -3,6 +3,7 @@ import com.dotcms.api.LanguageAPI; import com.dotcms.api.client.model.RestClientFactory; import com.dotcms.api.client.push.PushHandler; +import com.dotcms.api.client.util.NameUtil; import com.dotcms.model.language.Language; import java.io.File; import java.util.Map; @@ -27,6 +28,11 @@ public String title() { return "Languages"; } + @Override + public String fileName(final Language language) { + return NameUtil.languageFileName(language); + } + @Override public String contentSimpleDisplay(Language language) { @@ -49,7 +55,7 @@ public String contentSimpleDisplay(Language language) { public Language add(File localFile, Language localLanguage, Map customOptions) { // Check if the language is missing some required values and trying to set them - localLanguage = setMissingValues(localLanguage); + localLanguage = setMissingValues(localLanguage, Optional.empty()); final LanguageAPI languageAPI = clientFactory.getClient(LanguageAPI.class); final var response = languageAPI.create( @@ -65,7 +71,7 @@ public Language edit(File localFile, Language localLanguage, Language serverLang Map customOptions) { // Check if the language is missing some required values and trying to set them - localLanguage = setMissingValues(localLanguage); + localLanguage = setMissingValues(localLanguage, Optional.of(serverLanguage)); final LanguageAPI languageAPI = clientFactory.getClient(LanguageAPI.class); final var response = languageAPI.update( @@ -89,7 +95,25 @@ public void remove(Language serverLanguage, Map customOptions) { ); } - private Language setMissingValues(Language localLanguage) { + /** + * Sets missing values in the given Language object by filling in the values from the + * matchingServerLanguage object, if they are missing in the localLanguage object. + * + * @param localLanguage The Language object to update with missing values. + * @param matchingServerLanguage An optional Language object containing the missing values. + * @return The updated Language object with missing values filled in. + */ + private Language setMissingValues(Language localLanguage, + Optional matchingServerLanguage) { + + if (localLanguage.id().isEmpty() && matchingServerLanguage.isPresent()) { + localLanguage = localLanguage.withId(matchingServerLanguage.get().id()); + } + + if (localLanguage.defaultLanguage().isEmpty() && matchingServerLanguage.isPresent()) { + localLanguage = localLanguage.withDefaultLanguage( + matchingServerLanguage.get().defaultLanguage()); + } final String isoCode = localLanguage.isoCode(); if (localLanguage.languageCode().isEmpty()) { diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/site/SiteComparator.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/site/SiteComparator.java index a96e08c68841..d5b47cb296ff 100644 --- a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/site/SiteComparator.java +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/site/SiteComparator.java @@ -5,6 +5,7 @@ import com.dotcms.api.client.push.ContentComparator; import com.dotcms.model.ResponseEntityView; import com.dotcms.model.site.SiteView; +import java.io.File; import java.util.Comparator; import java.util.List; import java.util.Optional; @@ -25,7 +26,7 @@ public Class type() { @ActivateRequestContext @Override - public Optional findMatchingServerContent(SiteView localSite, + public Optional findMatchingServerContent(File localFile, SiteView localSite, List serverContents) { // Compare by identifier first. @@ -42,7 +43,8 @@ public Optional findMatchingServerContent(SiteView localSite, @ActivateRequestContext @Override - public Optional localContains(SiteView serverContent, List localSites) { + public Optional localContains(SiteView serverContent, List localFiles, + List localSites) { // Compare by identifier first. var result = findByIdentifier(serverContent.identifier(), localSites); diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/site/SitePushHandler.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/site/SitePushHandler.java index 87a79fb9aefe..878179cee151 100644 --- a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/site/SitePushHandler.java +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/site/SitePushHandler.java @@ -5,6 +5,7 @@ import com.dotcms.api.SiteAPI; import com.dotcms.api.client.model.RestClientFactory; import com.dotcms.api.client.push.PushHandler; +import com.dotcms.api.client.util.NameUtil; import com.dotcms.model.ResponseEntityView; import com.dotcms.model.site.CreateUpdateSiteRequest; import com.dotcms.model.site.GetSiteByNameRequest; @@ -42,6 +43,11 @@ public String title() { return "Sites"; } + @Override + public String fileName(final SiteView site) { + return NameUtil.siteFileName(site); + } + @Override public String contentSimpleDisplay(SiteView site) { return String.format( diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/task/PushTask.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/task/PushTask.java index a5aa9703358b..0e544aff8726 100644 --- a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/task/PushTask.java +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/push/task/PushTask.java @@ -316,6 +316,25 @@ private void updateFile(final T content, final File localFile) { final Path path = Path.of(localFile.getAbsolutePath()); Files.writeString(path, asString); + // Check if we need to rename the file + String localFileName = localFile.getName(); + int lastDotPosition = localFileName.lastIndexOf('.'); + String localDileNameWithoutExtension = localFileName.substring(0, lastDotPosition); + String localFileNameExtension = localFileName.substring(lastDotPosition + 1); + + final var expectedFileName = this.params.pushHandler().fileName(content); + if (!localDileNameWithoutExtension.equals(expectedFileName)) { + + // Something changed in the content that requires a file rename + + final String renamedFileName = String.format( + "%s.%s", expectedFileName, localFileNameExtension + ); + + final var renamedFile = new File(localFile.getParent(), renamedFileName); + Files.move(path, renamedFile.toPath()); + } + } catch (Exception e) { var message = String.format( diff --git a/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/util/NameUtil.java b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/util/NameUtil.java new file mode 100644 index 000000000000..32e16ff0d0ab --- /dev/null +++ b/tools/dotcms-cli/cli/src/main/java/com/dotcms/api/client/util/NameUtil.java @@ -0,0 +1,47 @@ +package com.dotcms.api.client.util; + +import com.dotcms.contenttype.model.type.ContentType; +import com.dotcms.model.language.Language; +import com.dotcms.model.site.SiteView; + +/** + * The NameUtil class provides utility methods for generating file names based on different + * objects. + */ +public class NameUtil { + + private NameUtil() { + //Hide public constructor + } + + /** + * Retrieves the file name for the given Language object. + * + * @param language The Language object for which the file name is to be retrieved. + * @return The file name for the given Language object. + */ + public static String languageFileName(final Language language) { + return language.isoCode(); + } + + /** + * Retrieves the file name for the given ContentType. + * + * @param contentType The ContentType object for which the file name is to be retrieved. + * @return The file name for the given ContentType object. + */ + public static String contentTypeFileName(final ContentType contentType) { + return contentType.variable(); + } + + /** + * Retrieves the file name for the given SiteView object. + * + * @param site The SiteView object for which the file name is to be retrieved. + * @return The file name for the given SiteView object. + */ + public static String siteFileName(final SiteView site) { + return site.hostName(); + } + +}