diff --git a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java index 752023b2d9df..db0f7a6f4851 100644 --- a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java @@ -952,38 +952,27 @@ protected List findAllCurrent() throws DotDataException { } @Override - protected List findAllCurrent (final int offset, final int limit ) throws ElasticsearchException { + protected List findAllCurrent(final int offset, final int limit) throws DotDataException { - final String indexToHit; - - try { - indexToHit = APILocator.getIndiciesAPI().loadIndicies().getWorking(); - } - catch(DotDataException ee) { - Logger.fatal(this, "Can't get indicies information",ee); - return null; - } - - final SearchRequest searchRequest = new SearchRequest(indexToHit); - final SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); - searchSourceBuilder.query(QueryBuilders.matchAllQuery()); - searchSourceBuilder.size(limit); - searchSourceBuilder.from(offset); - searchSourceBuilder.timeout(TimeValue.timeValueMillis(INDEX_OPERATIONS_TIMEOUT_IN_MS)); - searchSourceBuilder.fetchSource(new String[] {"inode"}, null); - searchRequest.source(searchSourceBuilder); - - final SearchHits hits = cachedIndexSearch(searchRequest); - + final int ultimateLimit = Math.min(limit, MAX_LIMIT); final List contentlets = new ArrayList<>(); - for (final SearchHit hit : hits ) { - try { - final Map sourceMap = hit.getSourceAsMap(); - contentlets.add( find( sourceMap.get("inode").toString()) ); - } catch ( Exception e ) { - throw new ElasticsearchException( e.getMessage(), e ); + try { + final DotConnect dotConnect = new DotConnect(); + dotConnect.setSQL("SELECT working_inode FROM contentlet_version_info LIMIT ? OFFSET ?"); + dotConnect.addParam(ultimateLimit); + dotConnect.addParam(offset); + + final List> results = dotConnect.loadObjectResults(); + for (final Map result : results) { + final Contentlet contentlet = find((String) result.get("working_inode")); + // Filter out null entries - content may have been deleted but version info not yet cleaned up + if (contentlet != null) { + contentlets.add(contentlet); + } } + } catch (Exception e) { + throw new DotDataException("Error finding all current contentlets", e); } return contentlets; diff --git a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentletAPIImpl.java b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentletAPIImpl.java index cbaf722c9f5c..332409de9f19 100644 --- a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentletAPIImpl.java +++ b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentletAPIImpl.java @@ -378,8 +378,12 @@ public Object loadField(final String inode, return contentFactory.loadField(inode, field.dbColumn()); } + /** + * @deprecated Do not use. For tests, use {@code ContentletDataGen.findAllContent(offset, limit)} instead. + */ @CloseDBIfOpened @Override + @Deprecated public List findAllContent(int offset, int limit) throws DotDataException { return contentFactory.findAllCurrent(offset, limit); } diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPI.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPI.java index ba374d138469..8cefe367f8b0 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPI.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPI.java @@ -84,15 +84,21 @@ public interface ContentletAPI { String dnsRegEx = "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$"; /** - * Use to retrieve all version of all content in the database. This is not a common method to use. - * Only use if you need to do maintenance tasks like search and replace something in every piece - * of content. Doesn't respect permissions. + * Retrieves contentlets from the database. Doesn't respect permissions. + * + *

DO NOT USE THIS METHOD.

+ * + *

This method is deprecated and should not be used in production code as it may cause + * severe performance issues. For test code, use {@code ContentletDataGen.findAllContent(offset, limit)} + * from the test module instead, which provides the same functionality in a test-appropriate context.

* * @param offset can be 0 if no offset - * @param limit can be 0 of no limit - * @return List list of contentlets - * @throws DotDataException + * @param limit can be 0 if no limit + * @return List of contentlets + * @throws DotDataException if a database error occurs + * @deprecated Do not use. For tests, use {@code ContentletDataGen.findAllContent(offset, limit)} instead. */ + @Deprecated public List findAllContent(int offset, int limit) throws DotDataException; /** diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPIInterceptor.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPIInterceptor.java index 837117f148ba..fd5082b66bf4 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPIInterceptor.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPIInterceptor.java @@ -783,7 +783,11 @@ public List find(List categories, long languageId, boolean return c; } + /** + * @deprecated Do not use. For tests, use {@code ContentletDataGen.findAllContent(offset, limit)} instead. + */ @Override + @Deprecated public List findAllContent(int offset, int limit) throws DotDataException { for(ContentletAPIPreHook pre : preHooks){ boolean preResult = pre.findAllContent(offset, limit); diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPIPostHook.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPIPostHook.java index 0c11ef0a9dd1..bfb55462b350 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPIPostHook.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPIPostHook.java @@ -43,9 +43,11 @@ public interface ContentletAPIPostHook { /** * @param offset can be 0 if no offset - * @param limit can be 0 of no limit + * @param limit can be 0 if no limit * @param returnValue - value returned by primary API Method + * @deprecated Do not use. For tests, use {@code ContentletDataGen.findAllContent(offset, limit)} instead. */ + @Deprecated public default void findAllContent(int offset, int limit, List returnValue){} /** diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPIPreHook.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPIPreHook.java index 7a7e17dd6c5b..5e4488e43631 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPIPreHook.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/ContentletAPIPreHook.java @@ -39,9 +39,11 @@ public interface ContentletAPIPreHook { /** * @param offset can be 0 if no offset - * @param limit can be 0 of no limit + * @param limit can be 0 if no limit * @return false if the hook should stop the transaction + * @deprecated Do not use. For tests, use {@code ContentletDataGen.findAllContent(offset, limit)} instead. */ + @Deprecated public default boolean findAllContent(int offset, int limit){ return true; } diff --git a/dotcms-integration/src/test/java/com/dotcms/content/elasticsearch/business/ContentletIndexAPIImplTest.java b/dotcms-integration/src/test/java/com/dotcms/content/elasticsearch/business/ContentletIndexAPIImplTest.java index e593be8e7411..6bb022594f53 100644 --- a/dotcms-integration/src/test/java/com/dotcms/content/elasticsearch/business/ContentletIndexAPIImplTest.java +++ b/dotcms-integration/src/test/java/com/dotcms/content/elasticsearch/business/ContentletIndexAPIImplTest.java @@ -203,8 +203,7 @@ public void test_indexContentList_with_diff_refresh_strategies() throws Exceptio generateTestContentlets(); - final List contentlets = contentletAPI.findAllContent(0, 100) - .stream().filter(Objects::nonNull).collect(Collectors.toList()); + final List contentlets = ContentletDataGen.findAllContent(0, 100); assertNotNull(contentlets); assertTrue("The number of contentlet returned is: " + contentlets.size(), diff --git a/dotcms-integration/src/test/java/com/dotcms/datagen/ContentletDataGen.java b/dotcms-integration/src/test/java/com/dotcms/datagen/ContentletDataGen.java index 96c5bb70a736..6c63b9f55ca3 100644 --- a/dotcms-integration/src/test/java/com/dotcms/datagen/ContentletDataGen.java +++ b/dotcms-integration/src/test/java/com/dotcms/datagen/ContentletDataGen.java @@ -363,6 +363,7 @@ public static Contentlet publish(Contentlet contentlet) { @WrapInTransaction public static void archive(Contentlet contentlet) { try{ + contentlet.setIndexPolicy(IndexPolicy.WAIT_FOR); contentletAPI.archive(contentlet, APILocator.systemUser(), false); } catch (DotContentletStateException | DotDataException | DotSecurityException e) { throw new RuntimeException(e); @@ -377,6 +378,7 @@ public static void archive(Contentlet contentlet) { @WrapInTransaction public static void delete(Contentlet contentlet) { try{ + contentlet.setIndexPolicy(IndexPolicy.WAIT_FOR); contentletAPI.delete(contentlet, APILocator.systemUser(), false); } catch (DotContentletStateException | DotDataException | DotSecurityException e) { throw new RuntimeException(e); @@ -405,6 +407,7 @@ public static void destroy(final Contentlet contentlet, final Boolean failSilent if (null != contentlet) { try { + contentlet.setIndexPolicy(IndexPolicy.WAIT_FOR); APILocator.getContentletAPI().destroy(contentlet, APILocator.systemUser(), false); } catch (Exception e) { if (failSilently) { @@ -505,4 +508,36 @@ public static void update(final Contentlet contentlet, final Map } } + + /** + * Retrieves contentlets from the database for test purposes. + * This method queries the contentlet_version_info table directly to get working contentlet inodes, + * which is more reliable than using ES index (which may have stale entries after deletions). + * + * @param offset the starting position (0-based) + * @param limit the maximum number of contentlets to return + * @return list of contentlets (never null, may be empty) + * @throws DotDataException if a database error occurs + */ + public static List findAllContent(final int offset, final int limit) throws DotDataException { + final List contentlets = new ArrayList<>(); + try { + final com.dotmarketing.common.db.DotConnect dotConnect = new com.dotmarketing.common.db.DotConnect(); + dotConnect.setSQL("SELECT working_inode FROM contentlet_version_info LIMIT ? OFFSET ?"); + dotConnect.addParam(limit); + dotConnect.addParam(offset); + + final List> results = dotConnect.loadObjectResults(); + for (final Map result : results) { + final Contentlet contentlet = contentletAPI.find( + (String) result.get("working_inode"), APILocator.systemUser(), false); + if (contentlet != null) { + contentlets.add(contentlet); + } + } + } catch (DotSecurityException e) { + throw new DotDataException("Error finding all content", e); + } + return contentlets; + } } \ No newline at end of file diff --git a/dotcms-integration/src/test/java/com/dotcms/publisher/assets/business/PushedAssetsAPITest.java b/dotcms-integration/src/test/java/com/dotcms/publisher/assets/business/PushedAssetsAPITest.java index 7cacee251848..af6728eb7dbf 100644 --- a/dotcms-integration/src/test/java/com/dotcms/publisher/assets/business/PushedAssetsAPITest.java +++ b/dotcms-integration/src/test/java/com/dotcms/publisher/assets/business/PushedAssetsAPITest.java @@ -2,6 +2,7 @@ import com.dotcms.IntegrationTestBase; import com.dotcms.LicenseTestUtil; +import com.dotcms.datagen.ContentletDataGen; import com.dotcms.publisher.assets.bean.PushedAsset; import com.dotcms.publisher.bundle.bean.Bundle; import com.dotcms.publisher.bundle.business.BundleAPI; @@ -130,8 +131,7 @@ private List getPushedAssets(final PushedAssetsAPI pushedAssetsAPI, final Bundle bundle1, final User adminUser) throws DotDataException { PushedAsset pushedAsset = null; - final List contentlets = contentletAPI.findAllContent - ( 0, 30 ).stream().filter(Objects::nonNull).collect(Collectors.toList()); + final List contentlets = ContentletDataGen.findAllContent(0, 30); final List pushedAssets = new ArrayList<>(); final Date pushDate = new Date(); for (final Contentlet contentlet : contentlets) { diff --git a/dotcms-integration/src/test/java/com/dotcms/rendering/velocity/viewtools/content/ContentMapTest.java b/dotcms-integration/src/test/java/com/dotcms/rendering/velocity/viewtools/content/ContentMapTest.java index a8a022c4bf87..94401a655e36 100644 --- a/dotcms-integration/src/test/java/com/dotcms/rendering/velocity/viewtools/content/ContentMapTest.java +++ b/dotcms-integration/src/test/java/com/dotcms/rendering/velocity/viewtools/content/ContentMapTest.java @@ -147,6 +147,8 @@ public void testGet_showCategories_AsAnonUser() throws DotDataException, DotSecu APILocator.getPermissionAPI().save(catsPermsSystemHost, APILocator.systemHost(), APILocator.systemUser(), false); + // Ensure permissions are properly propagated to child categories + APILocator.getPermissionAPI().resetPermissionsUnder(APILocator.systemHost()); //Create Categories final Category categoryChild1 = new CategoryDataGen().setCategoryName("RoadBike-"+System.currentTimeMillis()).setKey("RoadBike").setKeywords("RoadBike").setCategoryVelocityVarName("roadBike").next(); @@ -475,7 +477,7 @@ private Field createKeyValueField(final String fieldName, final String contentTy @Test public void testGetRecycledRequest() throws DotDataException, DotSecurityException { - final List contentlets = APILocator.getContentletAPI().findAllContent(1, 5); + final List contentlets = ContentletDataGen.findAllContent(1, 5); if(contentlets.isEmpty()) { throw new DotDataException("No contentlets found"); } diff --git a/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/business/ContentletAPITest.java b/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/business/ContentletAPITest.java index d96d0ad229fc..eb979795b51c 100644 --- a/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/business/ContentletAPITest.java +++ b/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/business/ContentletAPITest.java @@ -635,11 +635,11 @@ public void testCheckinNoDefaultActions() throws DotDataException, DotSecurityEx } /** - * Testing {@link ContentletAPI#findAllContent(int, int)} + * Testing {@link ContentletDataGen#findAllContent(int, int)} * * @throws com.dotmarketing.exception.DotDataException * @throws com.dotmarketing.exception.DotSecurityException - * @see ContentletAPI + * @see ContentletDataGen * @see Contentlet */ @Ignore("Not Ready to Run.") @@ -647,7 +647,7 @@ public void testCheckinNoDefaultActions() throws DotDataException, DotSecurityEx public void findAllContent() throws DotDataException, DotSecurityException { //Getting all contentlets live/working contentlets - List contentlets = contentletAPI.findAllContent(0, 5); + List contentlets = ContentletDataGen.findAllContent(0, 5); //Validations assertTrue(contentlets != null && !contentlets.isEmpty());