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(); + } + +}