diff --git a/dotCMS/src/main/java/com/dotmarketing/business/FactoryLocator.java b/dotCMS/src/main/java/com/dotmarketing/business/FactoryLocator.java index fb8f1a4a515f..cb3d99958d92 100644 --- a/dotCMS/src/main/java/com/dotmarketing/business/FactoryLocator.java +++ b/dotCMS/src/main/java/com/dotmarketing/business/FactoryLocator.java @@ -38,6 +38,8 @@ import com.dotcms.publisher.environment.business.EnvironmentFactoryImpl; import com.dotcms.variant.VariantFactory; import com.dotcms.variant.VariantFactoryImpl; +import com.dotmarketing.business.portal.PortletFactory; +import com.dotmarketing.business.portal.PortletFactoryImpl; import com.dotmarketing.common.reindex.ReindexQueueFactory; import com.dotmarketing.exception.DotRuntimeException; import com.dotmarketing.plugin.business.PluginFactory; @@ -290,6 +292,15 @@ public static ContentAnalyticsFactory getContentAnalyticsFactory() { return (ContentAnalyticsFactory) getInstance(FactoryIndex.CONTENT_ANALYTICS_FACTORY); } + /** + * Returns a singleton of the {@link PortletFactory} class. + * + * @return The {@link PortletFactory} singleton. + */ + public static PortletFactory getPortletFactory() { + return (PortletFactory) getInstance(FactoryIndex.PORTLET_FACTORY); + } + private static Object getInstance(FactoryIndex index) { if(instance == null){ @@ -369,7 +380,8 @@ enum FactoryIndex SYSTEM_TABLE_FACTORY, CUBEJS_CLIENT_FACTORY, LANGUAGE_VARIABLE_FACTORY, - CONTENT_ANALYTICS_FACTORY; + CONTENT_ANALYTICS_FACTORY, + PORTLET_FACTORY; Object create() { switch(this) { @@ -414,8 +426,9 @@ Object create() { case CUBEJS_CLIENT_FACTORY: return new CubeJSClientFactoryImpl(); case LANGUAGE_VARIABLE_FACTORY: return new LanguageVariableFactoryImpl(); case CONTENT_ANALYTICS_FACTORY: CDIUtils.getBean(ContentAnalyticsFactory.class).orElseThrow(() -> new DotRuntimeException("ContentAnalyticsFactory not found")); + case PORTLET_FACTORY: return new PortletFactoryImpl(); } throw new AssertionError("Unknown Factory Index: " + this); } -} +} diff --git a/dotCMS/src/main/java/com/dotmarketing/startup/runonce/Task241016AddCustomLanguageVariablesPortletToLayout.java b/dotCMS/src/main/java/com/dotmarketing/startup/runonce/Task241016AddCustomLanguageVariablesPortletToLayout.java new file mode 100644 index 000000000000..8834e90ea414 --- /dev/null +++ b/dotCMS/src/main/java/com/dotmarketing/startup/runonce/Task241016AddCustomLanguageVariablesPortletToLayout.java @@ -0,0 +1,164 @@ +package com.dotmarketing.startup.runonce; + +import com.dotcms.exception.ExceptionUtil; +import com.dotmarketing.business.CacheLocator; +import com.dotmarketing.business.FactoryLocator; +import com.dotmarketing.common.db.DotConnect; +import com.dotmarketing.exception.DotDataException; +import com.dotmarketing.startup.StartupTask; +import com.dotmarketing.util.Logger; +import com.dotmarketing.util.UUIDUtil; +import com.dotmarketing.util.UtilMethods; +import com.liferay.portal.model.Portlet; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Adds the custom 'Language Variables' portlet to all layouts which have 'Locales' portlet too, if + * it does not already exist. If there is already a Language Variables portlet, that one will be + * used instead. + * + * @author Jose Castro + * @since Oct 15th, 2024 + */ +public class Task241016AddCustomLanguageVariablesPortletToLayout implements StartupTask { + + public static final String LANGUAGE_VARIABLES_PORTLET_ID = "c_Language-Variables"; + public static final String LANGUAGE_VARIABLES_PORTLET_NAME = "Language Variables"; + public static final String LANGUAGE_VARIABLES_CT_VAR_NAME = "Languagevariable"; + + private static final String LOCALES_PORTLET_ID = "locales"; + + /** + * Verifies if the custom {@code Language Variables} portlet must be added or not. It performs + * the following data checks: + * + * + * @return If the UT must run, returns {@code true}. + */ + @Override + public boolean forceRun() { + try { + final List layoutIDs = this.getLayoutIDsContainingLocalesPortletID(); + if (UtilMethods.isNotSet(layoutIDs)) { + Logger.warn(this, "The 'Locales' portlet has not been added to any Layout yet. " + + "The custom 'Language Variables' portlet cannot be added automatically. Please add it manually"); + return false; + } + final Set layoutsContainingLangVarPortlet = + layoutIDs.stream().map(layoutId -> new DotConnect() + .setSQL("SELECT COUNT(portlet_id) AS count FROM cms_layouts_portlets WHERE layout_id = ? AND portlet_id = ?") + .addParam(layoutId) + .addParam(LANGUAGE_VARIABLES_PORTLET_ID) + .getInt("count")) + .collect(Collectors.toSet()); + return layoutsContainingLangVarPortlet.stream().anyMatch(count -> count == 0); + } catch (final DotDataException e) { + Logger.error(this, String.format("An error occurred when adding the custom 'Language Variables' portlet. " + + "Please add it manually: %s", ExceptionUtil.getErrorMessage(e)), e); + } + return false; + } + + /** + * Adds the custom {@code Language Variables} portlet to the appropriate Layouts by either + * creating it from scratch, or using the exising one. + * + * @throws DotDataException An error occurred when adding the custom 'Language Variables' + * portlet. + */ + @Override + public void executeUpgrade() throws DotDataException { + Logger.info(this, "Adding the custom 'Language Variables' portlet to existing layouts"); + String languageVariablesPortletId = this.getExistingLanguageVariablesPortletID(); + if (UtilMethods.isNotSet(languageVariablesPortletId)) { + final Map newMap = Map.of( + "name", LANGUAGE_VARIABLES_PORTLET_NAME, + "baseTypes", "", + "dataViewMode", "list", + "view-action", "/ext/contentlet/view_contentlets", + "portletSource", "db", + "contentTypes", LANGUAGE_VARIABLES_CT_VAR_NAME + ); + FactoryLocator.getPortletFactory().insertPortlet( + new Portlet(LANGUAGE_VARIABLES_PORTLET_ID, "SHARED_KEY", + "com.liferay.portlet.StrutsPortlet", newMap)); + languageVariablesPortletId = LANGUAGE_VARIABLES_PORTLET_ID; + Logger.info(this, "The 'Language Variables' portlet has been created"); + } else { + Logger.warn(this, String.format("There is already a 'Language Variables' portlet [ID = '%s'" + + "] in the system. Adding it to the same Layouts as the 'Locales' portlet" + , languageVariablesPortletId)); + } + final List layoutIDs = this.getLayoutIDsContainingLocalesPortletID(); + for (final Object layoutID : layoutIDs) { + final boolean isLayoutMissingLangVarPortlet = 0 == new DotConnect() + .setSQL("SELECT COUNT(portlet_id) AS count FROM cms_layouts_portlets WHERE layout_id = ? AND portlet_id = ?") + .addParam(layoutID) + .addParam(languageVariablesPortletId) + .getInt("count"); + if (isLayoutMissingLangVarPortlet) { + final int portletOrder = new DotConnect() + .setSQL("SELECT max(portlet_order) AS portlet_order FROM cms_layouts_portlets WHERE layout_id = ?") + .setMaxRows(1) + .addParam(layoutID) + .getInt("portlet_order"); + new DotConnect() + .setSQL("INSERT INTO cms_layouts_portlets(id, layout_id, portlet_id, portlet_order) VALUES (?, ?, ?, ?)") + .addParam(UUIDUtil.uuid()) + .addParam(layoutID) + .addParam(languageVariablesPortletId) + .addParam(portletOrder + 1) + .loadResult(); + } + } + CacheLocator.getLayoutCache().clearCache(); + Logger.info(this, String.format("The 'Language Variables' portlet has been added to %d menu group(s) successfully!", + layoutIDs.size())); + } + + /** + * Returns all the Layout IDs; i.e., menu groups, containing the {@code Locales} portlet. That + * information will allow us to add the {@code Language Variables} portlet in the expected + * location. + * + * @return List of Layout IDs where the {@code Locales} portlet is part of. + * + * @throws DotDataException An error occurred while querying the database. + */ + private List getLayoutIDsContainingLocalesPortletID() throws DotDataException { + return new DotConnect().setSQL("SELECT layout_id FROM cms_layouts_portlets WHERE portlet_id = ?") + .addParam(LOCALES_PORTLET_ID) + .loadObjectResults().stream().map(row -> row.get("layout_id")) + .collect(Collectors.toList()); + } + + /** + * Returns the ID of the {@code Language Variables} portlet, in case it already exists in the + * system, or {@code null} if not present. + * + * @return The ID of the existing {@code Language Variables} portlet. + * + * @throws DotDataException An error occurred while querying the database. + */ + private String getExistingLanguageVariablesPortletID() throws DotDataException { + final List> results = new DotConnect() + .setSQL("SELECT portletid FROM portlet WHERE portletid = ? OR LOWER(defaultpreferences) LIKE '%language variables%'") + .addParam(LANGUAGE_VARIABLES_PORTLET_ID) + .loadObjectResults(); + return results.isEmpty() || !UtilMethods.isSet(results.get(0)) + ? null + : results.get(0).get("portletid").toString(); + } + +} diff --git a/dotCMS/src/main/java/com/dotmarketing/util/TaskLocatorUtil.java b/dotCMS/src/main/java/com/dotmarketing/util/TaskLocatorUtil.java index 281ea2f9b541..e48669802f32 100644 --- a/dotCMS/src/main/java/com/dotmarketing/util/TaskLocatorUtil.java +++ b/dotCMS/src/main/java/com/dotmarketing/util/TaskLocatorUtil.java @@ -27,7 +27,231 @@ import com.dotmarketing.startup.runalways.Task00007RemoveSitesearchQuartzJob; import com.dotmarketing.startup.runalways.Task00040CheckAnonymousUser; import com.dotmarketing.startup.runalways.Task00050LoadAppsSecrets; -import com.dotmarketing.startup.runonce.*; +import com.dotmarketing.startup.runonce.Task00760AddContentletStructureInodeIndex; +import com.dotmarketing.startup.runonce.Task00765AddUserForeignKeys; +import com.dotmarketing.startup.runonce.Task00766AddFieldVariableTable; +import com.dotmarketing.startup.runonce.Task00767FieldVariableValueTypeChange; +import com.dotmarketing.startup.runonce.Task00768CreateTagStorageFieldOnHostStructure; +import com.dotmarketing.startup.runonce.Task00769UpdateTagDataModel; +import com.dotmarketing.startup.runonce.Task00775DropUnusedTables; +import com.dotmarketing.startup.runonce.Task00780UUIDTypeChange; +import com.dotmarketing.startup.runonce.Task00782CleanDataInconsistencies; +import com.dotmarketing.startup.runonce.Task00785DataModelChanges; +import com.dotmarketing.startup.runonce.Task00790DataModelChangesForWebAssets; +import com.dotmarketing.startup.runonce.Task00795LiveWorkingToIdentifier; +import com.dotmarketing.startup.runonce.Task00800CreateTemplateContainers; +import com.dotmarketing.startup.runonce.Task00805AddRenameFolderProcedure; +import com.dotmarketing.startup.runonce.Task00810FilesAsContentChanges; +import com.dotmarketing.startup.runonce.Task00815WorkFlowTablesChanges; +import com.dotmarketing.startup.runonce.Task00820CreateNewWorkFlowTables; +import com.dotmarketing.startup.runonce.Task00825UpdateLoadRecordsToIndex; +import com.dotmarketing.startup.runonce.Task00835CreateIndiciesTables; +import com.dotmarketing.startup.runonce.Task00840FixContentletVersionInfo; +import com.dotmarketing.startup.runonce.Task00845ChangeLockedOnToTimeStamp; +import com.dotmarketing.startup.runonce.Task00850DropOldFilesConstraintInWorkflow; +import com.dotmarketing.startup.runonce.Task00855FixRenameFolder; +import com.dotmarketing.startup.runonce.Task00860ExtendServerIdsMSSQL; +import com.dotmarketing.startup.runonce.Task00865AddTimestampToVersionTables; +import com.dotmarketing.startup.runonce.Task00900CreateLogConsoleTable; +import com.dotmarketing.startup.runonce.Task00905FixAddFolderAfterDelete; +import com.dotmarketing.startup.runonce.Task00910AddEscalationFields; +import com.dotmarketing.startup.runonce.Task00920AddContentletVersionSystemHost; +import com.dotmarketing.startup.runonce.Task00922FixdotfolderpathMSSQL; +import com.dotmarketing.startup.runonce.Task00925UserIdTypeChange; +import com.dotmarketing.startup.runonce.Task00930AddIdentifierIndex; +import com.dotmarketing.startup.runonce.Task00935LogConsoleTableData; +import com.dotmarketing.startup.runonce.Task00940AlterTemplateTable; +import com.dotmarketing.startup.runonce.Task00945AddTableContentPublishing; +import com.dotmarketing.startup.runonce.Task00950AddTablePublishingEndpoint; +import com.dotmarketing.startup.runonce.Task01000LinkChequerTable; +import com.dotmarketing.startup.runonce.Task01005TemplateThemeField; +import com.dotmarketing.startup.runonce.Task01015AddPublishExpireDateToIdentifier; +import com.dotmarketing.startup.runonce.Task01016AddStructureExpireFields; +import com.dotmarketing.startup.runonce.Task01020CreateDefaultWorkflow; +import com.dotmarketing.startup.runonce.Task01030AddSiteSearchAuditTable; +import com.dotmarketing.startup.runonce.Task01035FixTriggerVarLength; +import com.dotmarketing.startup.runonce.Task01045FixUpgradeTriggerVarLength; +import com.dotmarketing.startup.runonce.Task01050AddPushPublishLogger; +import com.dotmarketing.startup.runonce.Task01055CreatePushPublishEnvironmentTable; +import com.dotmarketing.startup.runonce.Task01060CreatePushPublishPushedAssets; +import com.dotmarketing.startup.runonce.Task01065IndexOnPublishingQueueAuditStatus; +import com.dotmarketing.startup.runonce.Task01070BundleNameDropUnique; +import com.dotmarketing.startup.runonce.Task01080CreateModDateForMissingObjects; +import com.dotmarketing.startup.runonce.Task01085CreateBundleTablesIfNotExists; +import com.dotmarketing.startup.runonce.Task01090AddWorkflowSchemeUniqueNameContraint; +import com.dotmarketing.startup.runonce.Task01095CreateIntegrityCheckerResultTables; +import com.dotmarketing.startup.runonce.Task01096CreateContainerStructuresTable; +import com.dotmarketing.startup.runonce.Task03000CreateContainertStructures; +import com.dotmarketing.startup.runonce.Task03005CreateModDateForFieldIfNeeded; +import com.dotmarketing.startup.runonce.Task03010AddContentletIdentifierIndex; +import com.dotmarketing.startup.runonce.Task03015CreateClusterConfigModel; +import com.dotmarketing.startup.runonce.Task03020PostgresqlIndiciesFK; +import com.dotmarketing.startup.runonce.Task03025CreateFoundationForNotificationSystem; +import com.dotmarketing.startup.runonce.Task03030CreateIndicesForVersionTables; +import com.dotmarketing.startup.runonce.Task03035FixContainerCheckTrigger; +import com.dotmarketing.startup.runonce.Task03040AddIndexesToStructureFields; +import com.dotmarketing.startup.runonce.Task03042AddLicenseRepoModel; +import com.dotmarketing.startup.runonce.Task03045TagnameTypeChangeMSSQL; +import com.dotmarketing.startup.runonce.Task03050updateFormTabName; +import com.dotmarketing.startup.runonce.Task03055RemoveLicenseManagerPortlet; +import com.dotmarketing.startup.runonce.Task03060AddClusterServerAction; +import com.dotmarketing.startup.runonce.Task03065AddHtmlPageIR; +import com.dotmarketing.startup.runonce.Task03100HTMLPageAsContentChanges; +import com.dotmarketing.startup.runonce.Task03105HTMLPageGenericPermissions; +import com.dotmarketing.startup.runonce.Task03120AddInodeToContainerStructure; +import com.dotmarketing.startup.runonce.Task03130ActionletsFromPlugin; +import com.dotmarketing.startup.runonce.Task03135FixStructurePageDetail; +import com.dotmarketing.startup.runonce.Task03140AddFileAssetsIntegrityResultTable; +import com.dotmarketing.startup.runonce.Task03150LoweCaseURLOnVirtualLinksTable; +import com.dotmarketing.startup.runonce.Task03160PublishingPushedAssetsTable; +import com.dotmarketing.startup.runonce.Task03165ModifyLoadRecordsToIndex; +import com.dotmarketing.startup.runonce.Task03500RulesEngineDataModel; +import com.dotmarketing.startup.runonce.Task03505PublishingQueueAuditTable; +import com.dotmarketing.startup.runonce.Task03510CreateDefaultPersona; +import com.dotmarketing.startup.runonce.Task03515AlterPasswordColumnFromUserTable; +import com.dotmarketing.startup.runonce.Task03520AlterTagsForPersonas; +import com.dotmarketing.startup.runonce.Task03525LowerTagsTagname; +import com.dotmarketing.startup.runonce.Task03530AlterTagInode; +import com.dotmarketing.startup.runonce.Task03535RemoveTagsWithoutATagname; +import com.dotmarketing.startup.runonce.Task03540UpdateTagInodesReferences; +import com.dotmarketing.startup.runonce.Task03545FixVarcharSizeInFolderOperations; +import com.dotmarketing.startup.runonce.Task03550RenameContainersTable; +import com.dotmarketing.startup.runonce.Task03555AddFlagToDeleteUsers; +import com.dotmarketing.startup.runonce.Task03560TemplateLayoutCanonicalName; +import com.dotmarketing.startup.runonce.Task03565FixContainerVersionsCheck; +import com.dotmarketing.startup.runonce.Task03600UpdateMssqlVarcharTextColumns; +import com.dotmarketing.startup.runonce.Task03605FixMSSQLMissingConstraints; +import com.dotmarketing.startup.runonce.Task03700ModificationDateColumnAddedToUserTable; +import com.dotmarketing.startup.runonce.Task03705AddingSystemEventTable; +import com.dotmarketing.startup.runonce.Task03710AddFKForIntegrityCheckerTables; +import com.dotmarketing.startup.runonce.Task03715AddFKForPublishingBundleTable; +import com.dotmarketing.startup.runonce.Task03720AddRolesIntegrityCheckerTable; +import com.dotmarketing.startup.runonce.Task03725NewNotificationTable; +import com.dotmarketing.startup.runonce.Task03735UpdatePortletsIds; +import com.dotmarketing.startup.runonce.Task03740UpdateLayoutIcons; +import com.dotmarketing.startup.runonce.Task03745DropLegacyHTMLPageAndFileTables; +import com.dotmarketing.startup.runonce.Task03800AddIndexLowerStructureTable; +import com.dotmarketing.startup.runonce.Task04100DeleteUnusedJobEntries; +import com.dotmarketing.startup.runonce.Task04105LowercaseVanityUrls; +import com.dotmarketing.startup.runonce.Task04110AddColumnsPublishingPushedAssetsTable; +import com.dotmarketing.startup.runonce.Task04115LowercaseIdentifierUrls; +import com.dotmarketing.startup.runonce.Task04120IncreaseHostColumnOnClusterServerTable; +import com.dotmarketing.startup.runonce.Task04200CreateDefaultVanityURL; +import com.dotmarketing.startup.runonce.Task04205MigrateVanityURLToContent; +import com.dotmarketing.startup.runonce.Task04210CreateDefaultLanguageVariable; +import com.dotmarketing.startup.runonce.Task04215MySQLMissingConstraints; +import com.dotmarketing.startup.runonce.Task04220RemoveDeleteInactiveClusterServersJob; +import com.dotmarketing.startup.runonce.Task04230FixVanityURLInconsistencies; +import com.dotmarketing.startup.runonce.Task04235RemoveFKFromWorkflowTaskTable; +import com.dotmarketing.startup.runonce.Task04300UpdateSystemFolderIdentifier; +import com.dotmarketing.startup.runonce.Task04305UpdateWorkflowActionTable; +import com.dotmarketing.startup.runonce.Task04310CreateWorkflowRoles; +import com.dotmarketing.startup.runonce.Task04315UpdateMultiTreePK; +import com.dotmarketing.startup.runonce.Task04320WorkflowActionRemoveNextStepConstraint; +import com.dotmarketing.startup.runonce.Task04330WorkflowTaskAddLanguageIdColumn; +import com.dotmarketing.startup.runonce.Task04335CreateSystemWorkflow; +import com.dotmarketing.startup.runonce.Task04340TemplateShowOnMenu; +import com.dotmarketing.startup.runonce.Task04345AddSystemWorkflowToContentType; +import com.dotmarketing.startup.runonce.Task04350AddDefaultWorkflowActionStates; +import com.dotmarketing.startup.runonce.Task04355SystemEventAddServerIdColumn; +import com.dotmarketing.startup.runonce.Task04360WorkflowSchemeDropUniqueNameConstraint; +import com.dotmarketing.startup.runonce.Task04365RelationshipUniqueConstraint; +import com.dotmarketing.startup.runonce.Task04370AddVisitorLogger; +import com.dotmarketing.startup.runonce.Task04375UpdateColors; +import com.dotmarketing.startup.runonce.Task04380AddSubActionToWorkflowActions; +import com.dotmarketing.startup.runonce.Task04385UpdateCategoryKey; +import com.dotmarketing.startup.runonce.Task04390ShowEditingListingWorkflowActionTable; +import com.dotmarketing.startup.runonce.Task05030UpdateSystemContentTypesHost; +import com.dotmarketing.startup.runonce.Task05035CreateIndexForQRTZ_EXCL_TRIGGERSTable; +import com.dotmarketing.startup.runonce.Task05040LanguageTableIdentityOff; +import com.dotmarketing.startup.runonce.Task05050FileAssetContentTypeReadOnlyFileName; +import com.dotmarketing.startup.runonce.Task05060CreateApiTokensIssuedTable; +import com.dotmarketing.startup.runonce.Task05070AddIdentifierVirtualColumn; +import com.dotmarketing.startup.runonce.Task05080RecreateIdentifierIndex; +import com.dotmarketing.startup.runonce.Task05150CreateIndicesForContentVersionInfoMSSQL; +import com.dotmarketing.startup.runonce.Task05160MultiTreeAddPersonalizationColumnAndChangingPK; +import com.dotmarketing.startup.runonce.Task05165CreateContentTypeWorkflowActionMappingTable; +import com.dotmarketing.startup.runonce.Task05170DefineFrontEndAndBackEndRoles; +import com.dotmarketing.startup.runonce.Task05175AssignDefaultActionsToTheSystemWorkflow; +import com.dotmarketing.startup.runonce.Task05180UpdateFriendlyNameField; +import com.dotmarketing.startup.runonce.Task05190UpdateFormsWidgetCodeField; +import com.dotmarketing.startup.runonce.Task05195CreatesDestroyActionAndAssignDestroyDefaultActionsToTheSystemWorkflow; +import com.dotmarketing.startup.runonce.Task05200WorkflowTaskUniqueKey; +import com.dotmarketing.startup.runonce.Task05210CreateDefaultDotAsset; +import com.dotmarketing.startup.runonce.Task05215AddSystemWorkflowToDotAssetContentType; +import com.dotmarketing.startup.runonce.Task05220MakeFileAssetContentTypeBinaryFieldIndexedListed; +import com.dotmarketing.startup.runonce.Task05225RemoveLoadRecordsToIndex; +import com.dotmarketing.startup.runonce.Task05300UpdateIndexNameLength; +import com.dotmarketing.startup.runonce.Task05305AddPushPublishFilterColumn; +import com.dotmarketing.startup.runonce.Task05350AddDotSaltClusterColumn; +import com.dotmarketing.startup.runonce.Task05370AddAppsPortletToLayout; +import com.dotmarketing.startup.runonce.Task05380ChangeContainerPathToAbsolute; +import com.dotmarketing.startup.runonce.Task05390MakeRoomForLongerJobDetail; +import com.dotmarketing.startup.runonce.Task05395RemoveEndpointIdForeignKeyInIntegrityResolverTables; +import com.dotmarketing.startup.runonce.Task201013AddNewColumnsToIdentifierTable; +import com.dotmarketing.startup.runonce.Task201014UpdateColumnsValuesInIdentifierTable; +import com.dotmarketing.startup.runonce.Task201102UpdateColumnSitelicTable; +import com.dotmarketing.startup.runonce.Task210218MigrateUserProxyTable; +import com.dotmarketing.startup.runonce.Task210316UpdateLayoutIcons; +import com.dotmarketing.startup.runonce.Task210319CreateStorageTable; +import com.dotmarketing.startup.runonce.Task210321RemoveOldMetadataFiles; +import com.dotmarketing.startup.runonce.Task210506UpdateStorageTable; +import com.dotmarketing.startup.runonce.Task210510UpdateStorageTableDropMetadataColumn; +import com.dotmarketing.startup.runonce.Task210520UpdateAnonymousEmail; +import com.dotmarketing.startup.runonce.Task210527DropReviewFieldsFromContentletTable; +import com.dotmarketing.startup.runonce.Task210719CleanUpTitleField; +import com.dotmarketing.startup.runonce.Task210802UpdateStructureTable; +import com.dotmarketing.startup.runonce.Task210805DropUserProxyTable; +import com.dotmarketing.startup.runonce.Task210816DeInodeRelationship; +import com.dotmarketing.startup.runonce.Task210901UpdateDateTimezones; +import com.dotmarketing.startup.runonce.Task211007RemoveNotNullConstraintFromCompanyMXColumn; +import com.dotmarketing.startup.runonce.Task211012AddCompanyDefaultLanguage; +import com.dotmarketing.startup.runonce.Task211020CreateHostIntegrityCheckerResultTables; +import com.dotmarketing.startup.runonce.Task211101AddContentletAsJsonColumn; +import com.dotmarketing.startup.runonce.Task211103RenameHostNameLabel; +import com.dotmarketing.startup.runonce.Task220202RemoveFKStructureFolderConstraint; +import com.dotmarketing.startup.runonce.Task220203RemoveFolderInodeConstraint; +import com.dotmarketing.startup.runonce.Task220214AddOwnerAndIDateToFolderTable; +import com.dotmarketing.startup.runonce.Task220215MigrateDataFromInodeToFolder; +import com.dotmarketing.startup.runonce.Task220330ChangeVanityURLSiteFieldType; +import com.dotmarketing.startup.runonce.Task220401CreateClusterLockTable; +import com.dotmarketing.startup.runonce.Task220402UpdateDateTimezones; +import com.dotmarketing.startup.runonce.Task220413IncreasePublishedPushedAssetIdCol; +import com.dotmarketing.startup.runonce.Task220512UpdateNoHTMLRegexValue; +import com.dotmarketing.startup.runonce.Task220606UpdatePushNowActionletName; +import com.dotmarketing.startup.runonce.Task220822CreateVariantTable; +import com.dotmarketing.startup.runonce.Task220824CreateDefaultVariant; +import com.dotmarketing.startup.runonce.Task220825CreateVariantField; +import com.dotmarketing.startup.runonce.Task220829CreateExperimentsTable; +import com.dotmarketing.startup.runonce.Task220912UpdateCorrectShowOnMenuProperty; +import com.dotmarketing.startup.runonce.Task220928AddLookbackWindowColumnToExperiment; +import com.dotmarketing.startup.runonce.Task221007AddVariantIntoPrimaryKey; +import com.dotmarketing.startup.runonce.Task221018CreateVariantFieldInMultiTree; +import com.dotmarketing.startup.runonce.Task230110MakeSomeSystemFieldsRemovableByBaseType; +import com.dotmarketing.startup.runonce.Task230119MigrateContentToProperPersonaTagAndRemoveDupTags; +import com.dotmarketing.startup.runonce.Task230320FixMissingContentletAsJSON; +import com.dotmarketing.startup.runonce.Task230328AddMarkedForDeletionColumn; +import com.dotmarketing.startup.runonce.Task230426AlterVarcharLengthOfLockedByCol; +import com.dotmarketing.startup.runonce.Task230523CreateVariantFieldInContentlet; +import com.dotmarketing.startup.runonce.Task230630CreateRunningIdsExperimentField; +import com.dotmarketing.startup.runonce.Task230701AddHashIndicesToWorkflowTables; +import com.dotmarketing.startup.runonce.Task230707CreateSystemTable; +import com.dotmarketing.startup.runonce.Task230713IncreaseDisabledWysiwygColumnSize; +import com.dotmarketing.startup.runonce.Task231109AddPublishDateToContentletVersionInfo; +import com.dotmarketing.startup.runonce.Task231207AddMetadataColumnToWorkflowAction; +import com.dotmarketing.startup.runonce.Task240102AlterVarcharLengthOfRelationType; +import com.dotmarketing.startup.runonce.Task240111AddInodeAndIdentifierLeftIndexes; +import com.dotmarketing.startup.runonce.Task240112AddMetadataColumnToStructureTable; +import com.dotmarketing.startup.runonce.Task240131UpdateLanguageVariableContentType; +import com.dotmarketing.startup.runonce.Task240306MigrateLegacyLanguageVariables; +import com.dotmarketing.startup.runonce.Task240513UpdateContentTypesSystemField; +import com.dotmarketing.startup.runonce.Task240530AddDotAIPortletToLayout; +import com.dotmarketing.startup.runonce.Task240606AddVariableColumnToWorkflow; +import com.dotmarketing.startup.runonce.Task241009CreatePostgresJobQueueTables; +import com.dotmarketing.startup.runonce.Task241013RemoveFullPathLcColumnFromIdentifier; +import com.dotmarketing.startup.runonce.Task241014AddTemplateValueOnContentletIndex; +import com.dotmarketing.startup.runonce.Task241015ReplaceLanguagesWithLocalesPortlet; +import com.dotmarketing.startup.runonce.Task241016AddCustomLanguageVariablesPortletToLayout; import com.google.common.collect.ImmutableList; import java.util.ArrayList; @@ -352,6 +576,7 @@ public static List> getStartupRunOnceTaskClasses() { .add(Task241013RemoveFullPathLcColumnFromIdentifier.class) .add(Task241014AddTemplateValueOnContentletIndex.class) .add(Task241015ReplaceLanguagesWithLocalesPortlet.class) + .add(Task241016AddCustomLanguageVariablesPortletToLayout.class) .build(); return ret.stream().sorted(classNameComparator).collect(Collectors.toList()); } diff --git a/dotcms-integration/src/test/java/com/dotcms/MainSuite2b.java b/dotcms-integration/src/test/java/com/dotcms/MainSuite2b.java index bd20f8376271..86b17f60063f 100644 --- a/dotcms-integration/src/test/java/com/dotcms/MainSuite2b.java +++ b/dotcms-integration/src/test/java/com/dotcms/MainSuite2b.java @@ -177,9 +177,11 @@ import com.dotmarketing.startup.runonce.Task240513UpdateContentTypesSystemFieldTest; import com.dotmarketing.startup.runonce.Task240530AddDotAIPortletToLayoutTest; import com.dotmarketing.startup.runonce.Task240606AddVariableColumnToWorkflowTest; +import com.dotmarketing.startup.runonce.Task241007CreateUniqueFieldsTableTest; import com.dotmarketing.startup.runonce.Task241009CreatePostgresJobQueueTablesTest; -import com.dotmarketing.startup.runonce.Task241015ReplaceLanguagesWithLocalesPortletTest; import com.dotmarketing.startup.runonce.Task241013RemoveFullPathLcColumnFromIdentifierTest; +import com.dotmarketing.startup.runonce.Task241015ReplaceLanguagesWithLocalesPortletTest; +import com.dotmarketing.startup.runonce.Task241016AddCustomLanguageVariablesPortletToLayoutTest; import com.dotmarketing.util.ConfigUtilsTest; import com.dotmarketing.util.ITConfigTest; import com.dotmarketing.util.MaintenanceUtilTest; @@ -187,7 +189,6 @@ import com.dotmarketing.util.UtilMethodsITest; import com.dotmarketing.util.contentlet.pagination.PaginatedContentletsIntegrationTest; import org.apache.velocity.tools.view.tools.CookieToolTest; -import com.dotmarketing.startup.runonce.Task241007CreateUniqueFieldsTableTest; import org.junit.runner.RunWith; import org.junit.runners.Suite.SuiteClasses; @@ -388,7 +389,8 @@ Task241013RemoveFullPathLcColumnFromIdentifierTest.class, Task241009CreatePostgresJobQueueTablesTest.class, Task241013RemoveFullPathLcColumnFromIdentifierTest.class, - Task241015ReplaceLanguagesWithLocalesPortletTest.class + Task241015ReplaceLanguagesWithLocalesPortletTest.class, + Task241016AddCustomLanguageVariablesPortletToLayoutTest.class }) public class MainSuite2b { diff --git a/dotcms-integration/src/test/java/com/dotmarketing/startup/runonce/Task241016AddCustomLanguageVariablesPortletToLayoutTest.java b/dotcms-integration/src/test/java/com/dotmarketing/startup/runonce/Task241016AddCustomLanguageVariablesPortletToLayoutTest.java new file mode 100644 index 000000000000..3f729965cad8 --- /dev/null +++ b/dotcms-integration/src/test/java/com/dotmarketing/startup/runonce/Task241016AddCustomLanguageVariablesPortletToLayoutTest.java @@ -0,0 +1,95 @@ +package com.dotmarketing.startup.runonce; + +import com.dotcms.util.IntegrationTestInitService; +import com.dotmarketing.common.db.DotConnect; +import com.dotmarketing.exception.DotDataException; +import com.dotmarketing.util.Logger; +import org.junit.BeforeClass; +import org.junit.Test; + +import static com.dotmarketing.startup.runonce.Task241016AddCustomLanguageVariablesPortletToLayout.LANGUAGE_VARIABLES_PORTLET_ID; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Verifies that the {@link Task241016AddCustomLanguageVariablesPortletToLayout} task works + * correctly. + * + * @author Jose Castro + * @since Oct 15th, 2024 + */ +public class Task241016AddCustomLanguageVariablesPortletToLayoutTest { + + @BeforeClass + public static void prepare() throws Exception { + // Setting web app environment + IntegrationTestInitService.getInstance().init(); + } + + /** + *
    + *
  • Method to test: + * {@link Task241016AddCustomLanguageVariablesPortletToLayout#executeUpgrade()}
  • + *
  • Given Scenario: Runs the UT.
  • + *
  • Expected Result: The Language Variables portlet is added successfully.
  • + *
+ */ + @Test + public void runUpgradeTask() throws DotDataException { + // ╔══════════════════╗ + // ║ Initialization ║ + // ╚══════════════════╝ + final DotConnect dotConnect = new DotConnect(); + this.deleteLanguageVariablesPortlet(dotConnect); + final Task241016AddCustomLanguageVariablesPortletToLayout task = + new Task241016AddCustomLanguageVariablesPortletToLayout(); + task.executeUpgrade(); + + // ╔══════════════╗ + // ║ Assertions ║ + // ╚══════════════╝ + assertFalse("The Language Variables portlet already exists, this must return 'false'" + , task.forceRun()); + } + + /** + *
    + *
  • Method to test: + * {@link Task241016AddCustomLanguageVariablesPortletToLayout#executeUpgrade()}
  • + *
  • Given Scenario: Runs the UT twice.
  • + *
  • Expected Result: The UT must be executable as many times as desired without + * failure.
  • + *
+ */ + @Test + public void checkUpgradeTaskIdempotency() throws DotDataException { + // ╔══════════════════╗ + // ║ Initialization ║ + // ╚══════════════════╝ + final DotConnect dotConnect = new DotConnect(); + this.deleteLanguageVariablesPortlet(dotConnect); + final Task241016AddCustomLanguageVariablesPortletToLayout task = + new Task241016AddCustomLanguageVariablesPortletToLayout(); + + task.executeUpgrade(); + // Run again to verify idempotency; i.e., no Java exception/error is thrown + task.executeUpgrade(); + } + + /** + * Attempts to delete the custom Language Variable portlet to double-check that it doesn't exist + * before the test begins. + * + * @param dotConnect The {@link DotConnect} object. + */ + private void deleteLanguageVariablesPortlet(final DotConnect dotConnect) { + try { + dotConnect.setSQL("delete from cms_layouts_portlets where portlet_id = ?") + .addParam(LANGUAGE_VARIABLES_PORTLET_ID) + .loadResult(); + } catch (final Exception e) { + Logger.info(this, "Failed deleting the portlet_id " + LANGUAGE_VARIABLES_PORTLET_ID); + } + } + +}