diff --git a/dotCMS/dependencies.gradle b/dotCMS/dependencies.gradle index 1acdcff1e507..7a7ff0b4852b 100644 --- a/dotCMS/dependencies.gradle +++ b/dotCMS/dependencies.gradle @@ -72,7 +72,7 @@ dependencies { compile group: 'com.dotcms.lib', name: 'dot.guava', version:'11.0.1_2' compile group: 'com.dotcms.lib', name: 'dot.hadoop-dev-core', version:'0.20.3_2' compile group: 'com.dotcms.lib', name: 'dot.hadoop-dev-tools', version:'0.20.3_2' - compile group: 'com.hazelcast', name: 'hazelcast-all', version: '3.8.4' + compile group: 'com.hazelcast', name: 'hazelcast-all', version: '3.9.2' compile group: 'com.dotcms.lib', name: 'dot.hibernate', version:'2.1.7_2' compile group: 'com.dotcms.lib', name: 'dot.httpbridge', version:'ukv_2' compile group: 'com.dotcms.lib', name: 'dot.httpclient', version:'4.2.2_2' diff --git a/dotCMS/gradle.properties b/dotCMS/gradle.properties index 4982407eaf23..147cde14cdff 100644 --- a/dotCMS/gradle.properties +++ b/dotCMS/gradle.properties @@ -2,8 +2,8 @@ dotcmsReleaseVersion=4.3.0 coreWebReleaseVersion=latest tomcatInstallRepo=https://github.com/dotCMS/tomcat.git -tomcatInstallBranch=8.0.18-4.2 -tomcatInstallVersion=8.0.18 +tomcatInstallBranch=8.5.24 +tomcatInstallVersion=8.5.24 tomcatInstallLocation=../../tomcat8 jboss7InstallVersion=7.1.1 diff --git a/dotCMS/src/functional-test/java/com/dotmarketing/portlets/structure/business/URLMapTest.java b/dotCMS/src/functional-test/java/com/dotmarketing/portlets/structure/business/URLMapTest.java index bae9a0a6966d..ccada195703f 100644 --- a/dotCMS/src/functional-test/java/com/dotmarketing/portlets/structure/business/URLMapTest.java +++ b/dotCMS/src/functional-test/java/com/dotmarketing/portlets/structure/business/URLMapTest.java @@ -68,60 +68,11 @@ public void createAssets() throws Exception { HibernateUtil.startTransaction(); // CONTAINER - container = new Container(); + container = APILocator.getContainerAPI().find("dde0b865-6cea-4ff0-8582-85e5974cf94f", user, false); Structure simpleWidgetSt = CacheLocator.getContentTypeCache().getStructureByVelocityVarName("SimpleWidget"); - container.setCode( "$!{story}" ); - container.setFriendlyName( "newsTestContainer" ); - container.setIDate(new Date()); - container.setLuceneQuery(""); - container.setMaxContentlets(1); - container.setModDate(new Date()); - container.setModUser(user.getUserId()); - container.setNotes("newsTestContainer"); - container.setOwner(user.getUserId()); - container.setPostLoop(""); - container.setPreLoop(""); - container.setShowOnMenu(true); - container.setSortContentletsBy(""); - container.setSortOrder(2); - container.setStaticify(true); - container.setTitle("News Test Container"); - container.setType(Inode.Type.CONTAINERS.getValue()); - container.setUseDiv( true ); - - List csList = new ArrayList(); - ContainerStructure cs = new ContainerStructure(); - cs.setStructureId(simpleWidgetSt.getInode()); - cs.setCode("$!{story}"); - csList.add(cs); - - container = APILocator.getContainerAPI().save(container, csList, demoHost, user, false); - APILocator.getVersionableAPI().setLive( container ); - - - // TEMPLATE - template = new Template(); - - String body = "#parseContainer('" + container.getIdentifier() + "')"; - template.setBody( body ); - template.setFooter( "" ); - template.setFriendlyName( "newsTestTemplate" ); - template.setHeader( "" ); - template.setIDate( new Date() ); - template.setImage( "" ); - template.setModDate( new Date() ); - template.setModUser( user.getUserId() ); - template.setOwner( user.getUserId() ); - template.setSelectedimage( "" ); - template.setShowOnMenu( true ); - template.setSortOrder( 2 ); - template.setTitle( "News Test Template" ); - template.setType( "template" ); - - template = APILocator.getTemplateAPI().saveTemplate( template, demoHost, user, false ); - APILocator.getVersionableAPI().setLive(template); + template = APILocator.getTemplateAPI().find("941a3f59-0d87-4084-8d9c-aca29a26ec8c",user,false); // FOLDER @@ -327,11 +278,9 @@ public void testURLMaps() throws Exception { @After public void deleteAssets() throws Exception { - try{ + try{ HibernateUtil.startTransaction(); if(testFolder!=null) APILocator.getFolderAPI().delete(testFolder, user, false); - if(template!=null) APILocator.getTemplateAPI().delete(template, user, false); - if(container!=null) APILocator.getContainerAPI().delete(container, user, false); if(testSt!=null) APILocator.getStructureAPI().delete(testSt, user); if(widget!=null) APILocator.getContentletAPI().delete(widget, user, false); diff --git a/dotCMS/src/integration-test/java/com/dotcms/contenttype/test/ContentTypeResourceTest.java b/dotCMS/src/integration-test/java/com/dotcms/contenttype/test/ContentTypeResourceTest.java index ed6df70d9f10..b14bcf1a1901 100644 --- a/dotCMS/src/integration-test/java/com/dotcms/contenttype/test/ContentTypeResourceTest.java +++ b/dotCMS/src/integration-test/java/com/dotcms/contenttype/test/ContentTypeResourceTest.java @@ -2,6 +2,7 @@ import static org.hamcrest.MatcherAssert.assertThat; +import com.dotmarketing.util.UtilMethods; import java.io.File; import java.io.InputStream; import java.net.URL; @@ -9,9 +10,9 @@ import javax.servlet.http.HttpServletRequest; +import com.dotcms.rest.api.v1.contenttype.ContentTypeForm; import com.dotcms.util.ConfigTestHelper; import org.apache.commons.io.IOUtils; -import org.junit.Assert; import org.junit.Test; import com.dotcms.contenttype.exception.NotFoundInDbException; @@ -55,20 +56,26 @@ public void testJson(String jsonFile) throws Exception { List delTypes = new JsonContentTypeTransformer(json).asList(); for(ContentType delType:delTypes){ try { - contentTypeApi.delete(contentTypeApi.find(delType.id())); + if (UtilMethods.isSet(delType.id())){ + contentTypeApi.delete(contentTypeApi.find(delType.id())); + } } catch (NotFoundInDbException e) { } try { - contentTypeApi.delete(contentTypeApi.find(delType.variable())); + if (UtilMethods.isSet(delType.variable())){ + contentTypeApi.delete(contentTypeApi.find(delType.variable())); + } } catch (NotFoundInDbException ee) { } } - ContentTypeResource resource = new ContentTypeResource(); + final ContentTypeResource resource = new ContentTypeResource(); - Response response = resource.createType(getHttpRequest(), json); + final ContentTypeForm.ContentTypeFormDeserialize contentTypeFormDeserialize = new ContentTypeForm.ContentTypeFormDeserialize(); + ContentTypeForm contentTypeForm = contentTypeFormDeserialize.buildForm(json); + Response response = resource.createType(getHttpRequest(), contentTypeForm); int x = response.getStatus(); assertThat("result:200 with json " + jsonFile + "got :" + x, x == 200); diff --git a/dotCMS/src/integration-test/java/com/dotcms/rendering/velocity/viewtools/content/ContentToolTest.java b/dotCMS/src/integration-test/java/com/dotcms/rendering/velocity/viewtools/content/ContentToolTest.java index da26a29bd677..22520167cfb2 100644 --- a/dotCMS/src/integration-test/java/com/dotcms/rendering/velocity/viewtools/content/ContentToolTest.java +++ b/dotCMS/src/integration-test/java/com/dotcms/rendering/velocity/viewtools/content/ContentToolTest.java @@ -9,6 +9,7 @@ import com.dotmarketing.portlets.contentlet.model.Contentlet; import com.liferay.portal.model.User; +import javax.servlet.http.HttpSession; import org.apache.velocity.context.Context; import org.apache.velocity.tools.view.context.ViewContext; import org.junit.Assert; @@ -35,7 +36,7 @@ public static void prepare() throws Exception { public void testPullMultiLanguage() throws Exception { // https://github.com/dotCMS/core/issues/11172 // Test uses Spanish language - long LANGUAGE_ID = 2; + final long languageId = 2; User user = APILocator.getUserAPI().getSystemUser(); @@ -45,7 +46,7 @@ public void testPullMultiLanguage() throws Exception { // https://github.com/dot // Create dummy "News" content in Spanish language - ContentletDataGen contentletDataGen = new ContentletDataGen(contentType.inode()).host(host).languageId(LANGUAGE_ID); + ContentletDataGen contentletDataGen = new ContentletDataGen(contentType.inode()).host(host).languageId(languageId); contentletDataGen.setProperty("title", "El Titulo"); contentletDataGen.setProperty("byline", "El Sub Titulo"); @@ -61,11 +62,14 @@ public void testPullMultiLanguage() throws Exception { // https://github.com/dot ViewContext viewContext = mock(ViewContext.class); Context velocityContext = mock(Context.class); HttpServletRequest request = mock(HttpServletRequest.class); + HttpSession session = mock(HttpSession.class); when(viewContext.getVelocityContext()).thenReturn(velocityContext); when(viewContext.getRequest()).thenReturn(request); when(request.getParameter("host_id")).thenReturn(host.getInode()); - when(request.getParameter("language_id")).thenReturn(String.valueOf(LANGUAGE_ID)); + when(request.getParameter("language_id")).thenReturn(String.valueOf(languageId)); + when(request.getSession(false)).thenReturn(session); + when(session.getAttribute(com.dotmarketing.util.WebKeys.CMS_USER)).thenReturn(user); ContentTool contentTool = new ContentTool(); contentTool.init(viewContext); @@ -88,7 +92,7 @@ public void testPullMultiLanguage() throws Exception { // https://github.com/dot // Ensure that every returned content is in Spanish Language Assert.assertFalse(results.isEmpty()); for(ContentMap cm : results) { - Assert.assertEquals(cm.getContentObject().getLanguageId(), LANGUAGE_ID); + Assert.assertEquals(cm.getContentObject().getLanguageId(), languageId); } } finally { diff --git a/dotCMS/src/integration-test/java/com/dotcms/rest/api/v1/contenttype/ContentTypeResourceTest.java b/dotCMS/src/integration-test/java/com/dotcms/rest/api/v1/contenttype/ContentTypeResourceTest.java index 4e70df0ca930..ea052b10a930 100644 --- a/dotCMS/src/integration-test/java/com/dotcms/rest/api/v1/contenttype/ContentTypeResourceTest.java +++ b/dotCMS/src/integration-test/java/com/dotcms/rest/api/v1/contenttype/ContentTypeResourceTest.java @@ -56,14 +56,16 @@ public void testMain() throws Exception { Response response = null; Map fieldMap = null; + ContentTypeForm.ContentTypeFormDeserialize contentTypeFormDeserialize = new ContentTypeForm.ContentTypeFormDeserialize(); + // Test INVALID Content Type Creation assertResponse_BAD_REQUEST( - response = resource.createType(getHttpRequest(), JSON_CONTENT_TYPE_UPDATE.replace("CONTENT_TYPE_ID", "INVALID_CONTENT_TYPE_ID")) + response = resource.createType(getHttpRequest(), contentTypeFormDeserialize.buildForm(JSON_CONTENT_TYPE_UPDATE.replace("CONTENT_TYPE_ID", "INVALID_CONTENT_TYPE_ID"))) ); // Test Content Type Creation RestUtilTest.verifySuccessResponse( - response = resource.createType(getHttpRequest(), JSON_CONTENT_TYPE_CREATE) + response = resource.createType(getHttpRequest(), contentTypeFormDeserialize.buildForm(JSON_CONTENT_TYPE_CREATE)) ); try { @@ -93,7 +95,7 @@ public void testMain() throws Exception { assertResponse_BAD_REQUEST( response = resource.updateType( (String) fieldMap.get("id"), - JSON_CONTENT_TYPE_UPDATE.replace("CONTENT_TYPE_ID", "INVALID_CONTENT_TYPE_ID"), + contentTypeFormDeserialize.buildForm(JSON_CONTENT_TYPE_UPDATE.replace("CONTENT_TYPE_ID", "INVALID_CONTENT_TYPE_ID")), getHttpRequest() ) ); @@ -102,7 +104,7 @@ public void testMain() throws Exception { RestUtilTest.verifySuccessResponse( response = resource.updateType( (String) fieldMap.get("id"), - JSON_CONTENT_TYPE_UPDATE.replace("CONTENT_TYPE_ID", (String) fieldMap.get("id")), + contentTypeFormDeserialize.buildForm(JSON_CONTENT_TYPE_UPDATE.replace("CONTENT_TYPE_ID", (String) fieldMap.get("id"))), getHttpRequest() ) ); diff --git a/dotCMS/src/integration-test/java/com/dotmarketing/portlets/contentlet/business/ContentletAPITest.java b/dotCMS/src/integration-test/java/com/dotmarketing/portlets/contentlet/business/ContentletAPITest.java index a1d87e82f756..eb700c989e3d 100644 --- a/dotCMS/src/integration-test/java/com/dotmarketing/portlets/contentlet/business/ContentletAPITest.java +++ b/dotCMS/src/integration-test/java/com/dotmarketing/portlets/contentlet/business/ContentletAPITest.java @@ -11,6 +11,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import com.dotcms.business.WrapInTransaction; import com.dotcms.content.business.DotMappingException; import com.dotcms.content.elasticsearch.business.ESMappingAPIImpl; import com.dotcms.contenttype.business.ContentTypeAPIImpl; @@ -31,6 +32,7 @@ import com.dotcms.datagen.TemplateDataGen; import com.dotcms.mock.request.MockInternalRequest; import com.dotcms.mock.response.BaseResponse; +import com.dotcms.rendering.velocity.services.VelocityType; import com.dotcms.repackage.org.apache.commons.io.FileUtils; import com.dotcms.repackage.org.apache.commons.lang.time.FastDateFormat; import com.dotmarketing.beans.Host; @@ -72,8 +74,8 @@ import com.dotmarketing.portlets.structure.model.Structure; import com.dotmarketing.portlets.templates.model.Template; import com.dotmarketing.tag.model.Tag; -import com.dotmarketing.util.Config; import com.dotmarketing.util.Logger; +import com.dotmarketing.util.PageMode; import com.dotmarketing.util.UUIDGenerator; import com.dotmarketing.util.UtilMethods; import com.dotcms.rendering.velocity.util.VelocityUtil; @@ -2159,7 +2161,6 @@ public void widgetInvalidateAllLang() throws Exception { /* * For every language we should get the same content and contentMap template code */ - String contentEXT=Config.getStringProperty("VELOCITY_CONTENT_EXTENSION", "content"); VelocityEngine engine = VelocityUtil.getEngine(); SimpleNode contentTester = engine.getRuntimeServices().parse(new StringReader("code:$code"), "tester1"); @@ -2168,8 +2169,12 @@ public void widgetInvalidateAllLang() throws Exception { requestProxy.setAttribute(WebKeys.HTMLPAGE_LANGUAGE, "1"); requestProxy.setAttribute(com.liferay.portal.util.WebKeys.USER,APILocator.getUserAPI().getSystemUser()); - org.apache.velocity.Template teng1 = engine.getTemplate("/live/"+w.getIdentifier()+"_1."+contentEXT); - org.apache.velocity.Template tesp1 = engine.getTemplate("/live/"+w.getIdentifier()+"_2."+contentEXT); + org.apache.velocity.Template teng1 = engine.getTemplate( + File.separator + PageMode.LIVE.name() + File.separator + w.getIdentifier() + "_1." + + VelocityType.CONTENT.fileExtension); + org.apache.velocity.Template tesp1 = engine.getTemplate( + File.separator + PageMode.LIVE.name() + File.separator + w.getIdentifier() + "_2." + + VelocityType.CONTENT.fileExtension); Context ctx = VelocityUtil.getWebContext(requestProxy, responseProxy); StringWriter writer=new StringWriter(); @@ -2189,8 +2194,12 @@ public void widgetInvalidateAllLang() throws Exception { contentletAPI.isInodeIndexed(w2.getInode(),true); // now if everything have been cleared correctly those should match again - org.apache.velocity.Template teng3 = engine.getTemplate("/live/"+w.getIdentifier()+"_1."+contentEXT); - org.apache.velocity.Template tesp3 = engine.getTemplate("/live/"+w.getIdentifier()+"_2."+contentEXT); + org.apache.velocity.Template teng3 = engine.getTemplate( + File.separator + PageMode.LIVE.name() + File.separator + w.getIdentifier() + "_1." + + VelocityType.CONTENT.fileExtension); + org.apache.velocity.Template tesp3 = engine.getTemplate( + File.separator + PageMode.LIVE.name() + File.separator + w.getIdentifier() + "_2." + + VelocityType.CONTENT.fileExtension); ctx = VelocityUtil.getWebContext(requestProxy, responseProxy); writer=new StringWriter(); teng3.merge(ctx, writer); @@ -3403,26 +3412,27 @@ public void testCheckin1_ExistingContentWithRels_NullRels_ShouldKeepExistingRels Contentlet blogContent = null; try { + blogContent = getBlogContent(); final ContentletRelationships relationships = getACoupleOfRelationships(blogContent); + final Relationship relationship = relationships.getRelationshipsRecords().get(0).getRelationship(); + final List relatedContent = relationships.getRelationshipsRecords().get(0).getRecords(); final List categories = getACoupleOfCategories(); blogContent = contentletAPI.checkin(blogContent, relationships, categories, null, user, false); + List relatedContentFromDB = relationshipAPI.dbRelatedContent(relationship, blogContent); + + assertTrue(relatedContentFromDB.containsAll(relatedContent)); + Contentlet checkedoutBlogContent = contentletAPI.checkout(blogContent.getInode(), user, false); Contentlet reCheckedinContent = contentletAPI.checkin(checkedoutBlogContent, (ContentletRelationships) null, null, null, user, false); - Relationship relationship = relationships.getRelationshipsRecords().get(0).getRelationship(); - - List relatedContent = relationships.getRelationshipsRecords().get(0).getRecords(); - - RelationshipAPI relationshipAPI = APILocator.getRelationshipAPI(); - List existingRelationships = relationshipAPI.dbRelatedContent(relationship, reCheckedinContent); assertTrue(existingRelationships.containsAll(relatedContent)); @@ -3698,7 +3708,7 @@ public void testCheckinWithoutVersioning_ExistingContentWithRels_EmptyRels_Shoul } } - private ContentletRelationships getACoupleOfRelationships(Contentlet contentlet) + private ContentletRelationships getACoupleOfRelationships(Contentlet contentlet) throws DotDataException, DotSecurityException { ContentletRelationships relationships = new ContentletRelationships(contentlet); final Relationship blogComments = APILocator.getRelationshipAPI().byInode("631a07ea-c840-402d-a330-37ed2826ba30"); @@ -3714,7 +3724,7 @@ private ContentletRelationships getACoupleOfRelationships(Contentlet contentle comment1.setStringProperty("email", "email"); comment1.setStringProperty("comment", "comment"); - comment1 = contentletAPI.checkin(comment1, user, false); + comment1 = contentletAPI.checkin(comment1, new HashMap<>(), user, false); Contentlet comment2 = new Contentlet(); comment2.setContentTypeId(commentsType.id()); @@ -3722,7 +3732,7 @@ private ContentletRelationships getACoupleOfRelationships(Contentlet contentle comment2.setStringProperty("email", "email"); comment2.setStringProperty("comment", "comment"); - comment2 = contentletAPI.checkin(comment2, user, false); + comment2 = contentletAPI.checkin(comment2, new HashMap<>(), user, false); records.setRecords(Arrays.asList(comment1, comment2)); relationships.setRelationshipsRecords(Collections.singletonList(records)); diff --git a/dotCMS/src/integration-test/java/com/dotmarketing/portlets/contentlet/business/ContentletCheckInTest.java b/dotCMS/src/integration-test/java/com/dotmarketing/portlets/contentlet/business/ContentletCheckInTest.java index eb5eeadddb29..539ca2ebf931 100644 --- a/dotCMS/src/integration-test/java/com/dotmarketing/portlets/contentlet/business/ContentletCheckInTest.java +++ b/dotCMS/src/integration-test/java/com/dotmarketing/portlets/contentlet/business/ContentletCheckInTest.java @@ -1,49 +1,105 @@ package com.dotmarketing.portlets.contentlet.business; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.dotcms.contenttype.test.ContentTypeAPIImplTest; -import com.dotcms.util.IntegrationTestInitService; +import com.dotcms.uuid.shorty.ShortyIdAPI; +import com.dotmarketing.beans.Host; import com.dotmarketing.business.APILocator; -import com.dotmarketing.exception.DotDataException; -import com.dotmarketing.exception.DotSecurityException; import com.dotmarketing.portlets.ContentletBaseTest; import com.dotmarketing.portlets.contentlet.model.Contentlet; -import com.dotmarketing.portlets.structure.model.Structure; +import com.dotmarketing.portlets.fileassets.business.FileAsset; +import com.dotmarketing.portlets.fileassets.business.FileAssetAPI; +import com.dotmarketing.portlets.folders.business.FolderAPI; +import com.dotmarketing.portlets.folders.model.Folder; +import com.dotmarketing.portlets.languagesmanager.business.LanguageAPI; +import com.dotmarketing.portlets.languagesmanager.model.Language; +import com.liferay.portal.model.User; +import java.io.File; +import java.io.FileWriter; +import org.junit.BeforeClass; +import org.junit.Test; /** * Created by Jonathan Gamba. * Date: 3/20/12 * Time: 12:12 PM */ -public class ContentletCheckInTest extends ContentletBaseTest { +public class ContentletCheckInTest { + + private static ContentletAPI contentletAPI; + private static FileAssetAPI fileAssetAPI; + private static FolderAPI folderAPI; + private static HostAPI hostAPI; + private static LanguageAPI languageAPI; + private static ShortyIdAPI shortyIdAPI; + public ContentletCheckInTest() { + + } - @BeforeClass public static void prepare () throws Exception{ - - ContentletBaseTest.prepare(); - + + ContentletBaseTest.prepare(); + + hostAPI = APILocator.getHostAPI(); + folderAPI = APILocator.getFolderAPI(); + languageAPI = APILocator.getLanguageAPI(); + contentletAPI = APILocator.getContentletAPI(); + fileAssetAPI = APILocator.getFileAssetAPI(); + shortyIdAPI = APILocator.getShortyAPI(); } @Test - public void checkinContent () throws DotDataException, DotSecurityException { + public void checkinInvalidFileContent () throws Exception { + Folder folder1 = null; + final boolean respectFrontendRoles=false; + final String fileTypeId=APILocator.getContentTypeAPI(APILocator.systemUser()).find("fileAsset").id(); + final String uuid1 = shortyIdAPI.randomShorty(); + final String uuid3 = shortyIdAPI.randomShorty(); + + final User user = APILocator.systemUser(); + final Host host = hostAPI.findDefaultHost(user, false); + try { + folder1 = folderAPI.createFolders("/" + uuid1, host, user, false); + final Language lang = languageAPI.getDefaultLanguage(); + folder1.setFilesMasks("*.txt"); + folder1.setDefaultFileType(fileTypeId); + folderAPI.save(folder1, user, false); - + File file = File.createTempFile(uuid3, ".txt"); + try (FileWriter writer = new FileWriter(file)) { + while (file.length() < 1024 * 10) { + writer.write("Im writing\n"); + } + } - + final FileAsset asset = new FileAsset(); + asset.setLanguageId(lang.getId()); + asset.setBinary("fileAsset", file); + asset.setTitle(file.getName()); + asset.setFileName(file.getName()); + asset.setContentTypeId(fileTypeId); + asset.setHost(host.getIdentifier()); + asset.setFolder(folder1.getIdentifier()); + final Contentlet con = contentletAPI.checkin(asset, user, true); + final Contentlet con2 = contentletAPI.find(con.getInode(), user, true); - - - - - } + assert (con.equals(con2)); - + final FileAsset fileAsset = fileAssetAPI.fromContentlet(con2); + + // this fails becuase the name does not match the folder's file mask + // but it leaves the original file removed from the index + fileAssetAPI.renameFile(fileAsset, "test.fail", user, respectFrontendRoles); + assert (!folderAPI.getContent(folder1, user, respectFrontendRoles) + .isEmpty()); + }finally{ + if (folder1 != null) { + folderAPI.delete(folder1, user, false); + } + } + } } \ No newline at end of file diff --git a/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/business/BaseWorkflowIntegrationTest.java b/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/business/BaseWorkflowIntegrationTest.java index 277c861dbb29..57ebcf1fc2a2 100644 --- a/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/business/BaseWorkflowIntegrationTest.java +++ b/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/business/BaseWorkflowIntegrationTest.java @@ -17,6 +17,7 @@ public class BaseWorkflowIntegrationTest extends IntegrationTestBase { + /** * Creates a new scheme, with a new step, with a new action and action let. * the new action will be associated to the step @@ -29,9 +30,9 @@ public class BaseWorkflowIntegrationTest extends IntegrationTestBase { * @throws DotDataException */ protected static CreateSchemeStepActionResult createSchemeStepActionActionlet (final String schemeName, - final String stepName, - final String actionName, - final Class actionClass) throws AlreadyExistException, DotDataException { + final String stepName, + final String actionName, + final Class actionClass) throws AlreadyExistException, DotDataException { final WorkflowAPI workflowAPI = APILocator.getWorkflowAPI(); @@ -70,9 +71,9 @@ protected static CreateSchemeStepActionResult createSchemeStepActionActionlet (f * @throws DotDataException */ protected static CreateSchemeStepActionResult createActionActionlet (final String schemeId, - final String stepId, - final String actionName, - final Class actionClass) throws AlreadyExistException, DotDataException { + final String stepId, + final String actionName, + final Class actionClass) throws AlreadyExistException, DotDataException { final WorkflowAPI workflowAPI = APILocator.getWorkflowAPI(); @@ -89,7 +90,7 @@ protected static CreateSchemeStepActionResult createActionActionlet (final Strin workflowAPI.saveAction(action.getId(), stepId, APILocator.systemUser()); - WorkflowActionClass workflowActionClass = new WorkflowActionClass(); + final WorkflowActionClass workflowActionClass = new WorkflowActionClass(); workflowActionClass.setActionId(action.getId()); workflowActionClass.setClazz(actionClass.getName()); try { @@ -117,13 +118,13 @@ protected static void cleanScheme (final WorkflowScheme scheme) throws DotSecuri final WorkflowAPI workflowAPI = APILocator.getWorkflowAPI(); final List schemeActions = workflowAPI.findActions(scheme, APILocator.systemUser()); - for (WorkflowAction action: schemeActions) { + for (final WorkflowAction action: schemeActions) { workflowAPI.deleteAction(action); } final List workflowSteps = workflowAPI.findSteps(scheme); - for (WorkflowStep step: workflowSteps) { + for (final WorkflowStep step: workflowSteps) { workflowAPI.deleteStep(step); } @@ -139,7 +140,8 @@ public static final class CreateSchemeStepActionResult { private final WorkflowActionClass actionClass; - public CreateSchemeStepActionResult(WorkflowScheme scheme, WorkflowStep step, WorkflowAction action, WorkflowActionClass actionClass) { + public CreateSchemeStepActionResult( + final WorkflowScheme scheme, final WorkflowStep step, final WorkflowAction action, final WorkflowActionClass actionClass) { this.scheme = scheme; this.step = step; this.action = action; diff --git a/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/business/SaveContentActionletTest.java b/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/business/SaveContentActionletTest.java new file mode 100644 index 000000000000..e64355ada82d --- /dev/null +++ b/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/business/SaveContentActionletTest.java @@ -0,0 +1,158 @@ +package com.dotmarketing.portlets.workflows.business; + +import com.dotcms.contenttype.business.ContentTypeAPI; +import com.dotcms.contenttype.model.field.*; +import com.dotcms.contenttype.model.type.BaseContentType; +import com.dotcms.contenttype.model.type.ContentType; +import com.dotcms.contenttype.model.type.ContentTypeBuilder; +import com.dotcms.contenttype.transform.contenttype.StructureTransformer; +import com.dotcms.util.IntegrationTestInitService; +import com.dotmarketing.beans.Host; +import com.dotmarketing.business.APILocator; +import com.dotmarketing.exception.AlreadyExistException; +import com.dotmarketing.exception.DotDataException; +import com.dotmarketing.exception.DotSecurityException; +import com.dotmarketing.portlets.contentlet.business.ContentletAPI; +import com.dotmarketing.portlets.contentlet.model.Contentlet; +import com.dotmarketing.portlets.folders.business.FolderAPI; +import com.dotmarketing.portlets.workflows.actionlet.SaveContentActionlet; +import com.dotmarketing.portlets.workflows.model.WorkflowProcessor; +import com.dotmarketing.util.UUIDGenerator; +import com.liferay.portal.model.User; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +public class SaveContentActionletTest extends BaseWorkflowIntegrationTest { + + private static CreateSchemeStepActionResult schemeStepActionResult = null; + private static WorkflowAPI workflowAPI = null; + private static ContentletAPI contentletAPI = null; + private static ContentType type = null; + private static Contentlet contentlet = null; + + + @BeforeClass + public static void prepare() throws Exception { + //Setting web app environment + + IntegrationTestInitService.getInstance().init(); + SaveContentActionletTest.workflowAPI = APILocator.getWorkflowAPI(); + final ContentTypeAPI contentTypeAPI = APILocator.getContentTypeAPI(APILocator.systemUser()); + SaveContentActionletTest.contentletAPI = APILocator.getContentletAPI(); + + // creates the scheme and actions + SaveContentActionletTest.schemeStepActionResult = SaveContentActionletTest.createSchemeStepActionActionlet + ("saveContentScheme" + UUIDGenerator.generateUuid(), "step1", "action1", SaveContentActionlet.class); + + // creates the type to trigger the scheme + SaveContentActionletTest.createTestType(contentTypeAPI); + + // associated the scheme to the type + SaveContentActionletTest.workflowAPI.saveSchemesForStruct(new StructureTransformer(SaveContentActionletTest.type).asStructure(), + Arrays.asList(SaveContentActionletTest.schemeStepActionResult.getScheme())); + + } + + private static void createTestType(final ContentTypeAPI contentTypeAPI) throws DotDataException, DotSecurityException { + + SaveContentActionletTest.type = contentTypeAPI.save( + ContentTypeBuilder.builder(BaseContentType.CONTENT.immutableClass()) + .expireDateVar(null).folder(FolderAPI.SYSTEM_FOLDER).host(Host.SYSTEM_HOST) + .description("DotSaveContentActionletTest...") + .name("DotSaveContentActionletTest").owner(APILocator.systemUser().toString()) + .variable("DotSaveContentActionletTest").build()); + + final List fields = new ArrayList<>(SaveContentActionletTest.type.fields()); + + fields.add(FieldBuilder.builder(TextField.class).name("title").variable("title") + .contentTypeId(SaveContentActionletTest.type.id()).dataType(DataTypes.TEXT).indexed(true).build()); + fields.add(FieldBuilder.builder(TextField.class).name("txt").variable("txt") + .contentTypeId(SaveContentActionletTest.type.id()).dataType(DataTypes.TEXT).indexed(true).build()); + + SaveContentActionletTest.type = contentTypeAPI.save(SaveContentActionletTest.type, fields); + } + + /** + * Remove the content type and workflows created + */ + @AfterClass + public static void cleanup() throws DotDataException, DotSecurityException, AlreadyExistException { + + try { + + if (null != SaveContentActionletTest.contentlet) { + + SaveContentActionletTest.contentletAPI.delete(SaveContentActionletTest.contentlet, APILocator.systemUser(), false); + } + } finally { + + try { + + if (null != SaveContentActionletTest.schemeStepActionResult) { + + SaveContentActionletTest.cleanScheme(SaveContentActionletTest.schemeStepActionResult.getScheme()); + } + } finally { + + if (null != SaveContentActionletTest.type) { + + ContentTypeAPI contentTypeAPI = APILocator.getContentTypeAPI(APILocator.systemUser()); + contentTypeAPI.delete(SaveContentActionletTest.type); + } + } + } + } // cleanup + + @Test + public void saveContentTest() throws DotDataException, DotSecurityException { + + final long languageId = APILocator.getLanguageAPI().getDefaultLanguage().getId(); + final Contentlet contentlet = new Contentlet(); + final User user = APILocator.systemUser(); + contentlet.setContentTypeId(SaveContentActionletTest.type.id()); + contentlet.setOwner(APILocator.systemUser().toString()); + contentlet.setModDate(new Date()); + contentlet.setLanguageId(languageId); + contentlet.setStringProperty("title", "Test Save"); + contentlet.setStringProperty("txt", "Test Save Text"); + contentlet.setHost(Host.SYSTEM_HOST); + contentlet.setFolder(FolderAPI.SYSTEM_FOLDER); + + // first save + final Contentlet contentlet1 = SaveContentActionletTest.contentletAPI.checkin(contentlet, user, false); + final String firstInode = contentlet1.getInode(); + SaveContentActionletTest.contentlet = contentlet1; + + // triggering the save content action + contentlet1.setStringProperty(Contentlet.WORKFLOW_ACTION_KEY, + this.schemeStepActionResult.getAction().getId()); + contentlet1.setStringProperty("title", "Test Save 2"); + contentlet1.setStringProperty("txt", "Test Save Text 2"); + + final WorkflowProcessor processor = + SaveContentActionletTest.workflowAPI.fireWorkflowPreCheckin(contentlet1, user); + + SaveContentActionletTest.workflowAPI.fireWorkflowPostCheckin(processor); + + contentletAPI.isInodeIndexed(processor.getContentlet().getInode()); + + final Contentlet contentlet2 = SaveContentActionletTest.contentletAPI.findContentletByIdentifier + (SaveContentActionletTest.contentlet.getIdentifier(), + false, languageId, user, false); + + // the contentlet save by the action must be not null, should has a new version. + Assert.assertNotNull(contentlet2); + Assert.assertNotNull(contentlet2.getInode()); + Assert.assertFalse (contentlet2.getInode().equals(firstInode)); + Assert.assertEquals ("Test Save 2", contentlet2.getStringProperty("title")); + Assert.assertEquals ("Test Save Text 2", contentlet2.getStringProperty("txt")); + + } +} \ No newline at end of file diff --git a/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/business/SaveContentDraftActionletTest.java b/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/business/SaveContentDraftActionletTest.java new file mode 100644 index 000000000000..5efc26ea5884 --- /dev/null +++ b/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/business/SaveContentDraftActionletTest.java @@ -0,0 +1,179 @@ +package com.dotmarketing.portlets.workflows.business; + +import com.dotcms.contenttype.business.ContentTypeAPI; +import com.dotcms.contenttype.model.field.DataTypes; +import com.dotcms.contenttype.model.field.Field; +import com.dotcms.contenttype.model.field.FieldBuilder; +import com.dotcms.contenttype.model.field.TextField; +import com.dotcms.contenttype.model.type.BaseContentType; +import com.dotcms.contenttype.model.type.ContentType; +import com.dotcms.contenttype.model.type.ContentTypeBuilder; +import com.dotcms.contenttype.transform.contenttype.StructureTransformer; +import com.dotcms.util.IntegrationTestInitService; +import com.dotmarketing.beans.Host; +import com.dotmarketing.business.APILocator; +import com.dotmarketing.db.HibernateUtil; +import com.dotmarketing.exception.AlreadyExistException; +import com.dotmarketing.exception.DotDataException; +import com.dotmarketing.exception.DotSecurityException; +import com.dotmarketing.portlets.contentlet.business.ContentletAPI; +import com.dotmarketing.portlets.contentlet.model.Contentlet; +import com.dotmarketing.portlets.folders.business.FolderAPI; +import com.dotmarketing.portlets.workflows.actionlet.SaveContentAsDraftActionlet; +import com.dotmarketing.util.UUIDGenerator; +import com.liferay.portal.model.User; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +public class SaveContentDraftActionletTest extends BaseWorkflowIntegrationTest { + + private static CreateSchemeStepActionResult schemeStepActionResult = null; + private static WorkflowAPI workflowAPI = null; + private static ContentletAPI contentletAPI = null; + private static ContentType type = null; + private static Contentlet contentlet = null; + + + @BeforeClass + public static void prepare() throws Exception { + //Setting web app environment + + IntegrationTestInitService.getInstance().init(); + SaveContentDraftActionletTest.workflowAPI = APILocator.getWorkflowAPI(); + final ContentTypeAPI contentTypeAPI = APILocator.getContentTypeAPI(APILocator.systemUser()); + SaveContentDraftActionletTest.contentletAPI = APILocator.getContentletAPI(); + + // creates the scheme and actions + SaveContentDraftActionletTest.schemeStepActionResult = SaveContentDraftActionletTest.createSchemeStepActionActionlet + ("saveContentScheme" + UUIDGenerator.generateUuid(), "step1", "action1", SaveContentAsDraftActionlet.class); + + // creates the type to trigger the scheme + SaveContentDraftActionletTest.createTestType(contentTypeAPI); + + // associated the scheme to the type + SaveContentDraftActionletTest.workflowAPI.saveSchemesForStruct(new StructureTransformer(SaveContentDraftActionletTest.type).asStructure(), + Arrays.asList(SaveContentDraftActionletTest.schemeStepActionResult.getScheme())); + + } + + private static void createTestType(final ContentTypeAPI contentTypeAPI) throws DotDataException, DotSecurityException { + + SaveContentDraftActionletTest.type = contentTypeAPI.save( + ContentTypeBuilder.builder(BaseContentType.CONTENT.immutableClass()) + .expireDateVar(null).folder(FolderAPI.SYSTEM_FOLDER).host(Host.SYSTEM_HOST) + .description("SaveContentAsDraftActionletTest...") + .name("SaveContentDraftAsActionletTest").owner(APILocator.systemUser().toString()) + .variable("SaveContentAsDraftActionletTest").build()); + + final List fields = new ArrayList<>(SaveContentDraftActionletTest.type.fields()); + + fields.add(FieldBuilder.builder(TextField.class).name("title").variable("title") + .contentTypeId(SaveContentDraftActionletTest.type.id()).dataType(DataTypes.TEXT).indexed(true).build()); + fields.add(FieldBuilder.builder(TextField.class).name("txt").variable("txt") + .contentTypeId(SaveContentDraftActionletTest.type.id()).dataType(DataTypes.TEXT).indexed(true).build()); + + SaveContentDraftActionletTest.type = contentTypeAPI.save(SaveContentDraftActionletTest.type, fields); + } + + /** + * Remove the content type and workflows created + */ + @AfterClass + public static void cleanup() throws DotDataException, DotSecurityException, AlreadyExistException { + + try { + + if (null != SaveContentDraftActionletTest.contentlet) { + + SaveContentDraftActionletTest.contentletAPI.delete(SaveContentDraftActionletTest.contentlet, APILocator.systemUser(), false); + } + } finally { + + try { + + if (null != SaveContentDraftActionletTest.schemeStepActionResult) { + + SaveContentDraftActionletTest.cleanScheme(SaveContentDraftActionletTest.schemeStepActionResult.getScheme()); + } + } finally { + + if (null != SaveContentDraftActionletTest.type) { + + ContentTypeAPI contentTypeAPI = APILocator.getContentTypeAPI(APILocator.systemUser()); + contentTypeAPI.delete(SaveContentDraftActionletTest.type); + } + } + } + } // cleanup + + @Test + public void saveContentDraftTest() throws DotDataException, DotSecurityException { + + final long languageId = APILocator.getLanguageAPI().getDefaultLanguage().getId(); + final Contentlet contentlet = new Contentlet(); + final User user = APILocator.systemUser(); + contentlet.setContentTypeId(SaveContentDraftActionletTest.type.id()); + contentlet.setOwner(user.toString()); + contentlet.setModUser(user.getUserId()); + contentlet.setModDate(new Date()); + contentlet.setLanguageId(languageId); + contentlet.setStringProperty("title", "Test Save"); + contentlet.setStringProperty("txt", "Test Save Text"); + contentlet.setHost(Host.SYSTEM_HOST); + contentlet.setFolder(FolderAPI.SYSTEM_FOLDER); + + + // first save + final Contentlet contentlet1 = SaveContentDraftActionletTest.contentletAPI.checkin(contentlet, user, false); + SaveContentDraftActionletTest.contentlet = contentlet1; + + contentlet1.setStringProperty("title", "Test Save 1"); + contentlet1.setStringProperty("txt", "Test Save Text 1"); + + contentletAPI.isInodeIndexed(contentlet1.getInode()); + + final Contentlet contentlet2 = SaveContentDraftActionletTest.contentletAPI.checkout(contentlet1.getInode(), user, false); + + contentlet2.setStringProperty("title", "Test Save 2"); + contentlet2.setStringProperty("txt", "Test Save Text 2"); + + final Contentlet contentlet3 = SaveContentDraftActionletTest.contentletAPI.checkin(contentlet2, user, false); + + contentletAPI.isInodeIndexed(contentlet3.getInode()); + + final Contentlet contentlet4 = SaveContentDraftActionletTest.contentletAPI. + find(contentlet3.getInode(), user, false); + // triggering the save content action + + contentlet4.setStringProperty(Contentlet.WORKFLOW_ACTION_KEY, + this.schemeStepActionResult.getAction().getId()); + contentlet4.setStringProperty("title", "Test Save 3"); + contentlet4.setStringProperty("txt", "Test Save Text 3"); + + if (SaveContentDraftActionletTest.contentletAPI.canLock(contentlet4, user) && contentlet4.isLocked()) { + SaveContentDraftActionletTest.contentletAPI.unlock(contentlet4, user, false); + } + + SaveContentDraftActionletTest.workflowAPI.fireWorkflowNoCheckin(contentlet4, user); + + final Contentlet contentlet5 = SaveContentDraftActionletTest.contentletAPI.findContentletByIdentifier + (SaveContentDraftActionletTest.contentlet.getIdentifier(), + false, languageId, user, false); + + // the contentlet save by the action must be not null, should has the same version. + Assert.assertNotNull(contentlet5); + Assert.assertNotNull(contentlet5.getInode()); + Assert.assertTrue(contentlet5.getInode().equals(contentlet3.getInode())); + Assert.assertEquals("Test Save 3", contentlet5.getStringProperty("title")); + Assert.assertEquals("Test Save Text 3", contentlet5.getStringProperty("txt")); + + + } +} \ No newline at end of file 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 711762b78e7d..37db0e3f55d3 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 @@ -2555,10 +2555,7 @@ public void relateContent(Contentlet contentlet, ContentletRelationshipRecords r Tree treeToUpdate = TreeFactory.getTree(newTree); treeToUpdate.setTreeOrder(newTreePosistion); - if(treeToUpdate != null && UtilMethods.isSet(treeToUpdate.getRelationType())) - TreeFactory.saveTree(treeToUpdate); - else - TreeFactory.saveTree(newTree); + TreeFactory.saveTree(treeToUpdate != null && UtilMethods.isSet(treeToUpdate.getRelationType())?treeToUpdate:newTree); treePosition++; } @@ -2875,7 +2872,10 @@ private Contentlet checkin(Contentlet contentlet, ContentletRelationships conten WorkflowAPI wapi = APILocator.getWorkflowAPI(); WorkflowProcessor workflow=null; - if(contentlet.getMap().get(Contentlet.DISABLE_WORKFLOW)==null) { + if(contentlet.getMap().get(Contentlet.DISABLE_WORKFLOW)==null && + (null == contentlet.getMap().get(Contentlet.WORKFLOW_IN_PROGRESS) || + Boolean.FALSE.equals(contentlet.getMap().get(Contentlet.WORKFLOW_IN_PROGRESS)) + )) { workflow = wapi.fireWorkflowPreCheckin(contentlet,user); } @@ -2885,7 +2885,10 @@ private Contentlet checkin(Contentlet contentlet, ContentletRelationships conten String workingContentletInode = (workingContentlet==null) ? "" : workingContentlet.getInode(); boolean priority = contentlet.isLowIndexPriority(); + Boolean dontValidateMe = (Boolean)contentlet.getMap().get(Contentlet.DONT_VALIDATE_ME); + Boolean disableWorkflow = (Boolean)contentlet.getMap().get(Contentlet.DISABLE_WORKFLOW); + boolean isNewContent = false; if(!InodeUtils.isSet(workingContentletInode)){ isNewContent = true; @@ -3085,12 +3088,16 @@ private Contentlet checkin(Contentlet contentlet, ContentletRelationships conten // Publish once if needed and reindex once if needed. The publish // method reindexes. contentlet.setLowIndexPriority(priority); - //set again the don't validate me property if this was set + + //set again the don't validate me and disable workflow properties + //if they were set if(dontValidateMe != null){ contentlet.setProperty(Contentlet.DONT_VALIDATE_ME, dontValidateMe); } - + if(disableWorkflow != null){ + contentlet.setProperty(Contentlet.DISABLE_WORKFLOW, disableWorkflow); + } // http://jira.dotmarketing.net/browse/DOTCMS-1073 // storing binary files in file system. @@ -3606,7 +3613,6 @@ private void moveContentDependencies(Contentlet fromContentlet, Contentlet toCon categoryAPI.setParents(toContentlet, categories, user, respect); - //Handle Relationships if(contentRelationships == null){ @@ -3650,7 +3656,7 @@ private void moveContentDependencies(Contentlet fromContentlet, Contentlet toCon } //Adding to the list all the records the user was not able to see becuase permissions forcing them into the relationship - cons = getRelatedContent(fromContentlet, r, false, APILocator.getUserAPI().getSystemUser(), true); + cons = getRelatedContentFromIndex(fromContentlet, r, false, APILocator.getUserAPI().getSystemUser(), true); for (Contentlet contentlet : cons) { if (!permissionAPI.doesUserHavePermission(contentlet, PermissionAPI.PERMISSION_READ, user, false)) { selectedRecords.getRecords().add(0, contentlet); @@ -3682,6 +3688,7 @@ private void moveContentDependencies(Contentlet fromContentlet, Contentlet toCon } } } + for (ContentletRelationshipRecords cr : contentRelationships.getRelationshipsRecords()) { relateContent(toContentlet, cr, APILocator.getUserAPI().getSystemUser(), true); } @@ -4697,16 +4704,17 @@ private Contentlet findWorkingContentlet(Contentlet content)throws DotSecurityEx * @throws DotDataException * @throws DotSecurityException */ - private Map> findContentRelationships(Contentlet contentlet) throws DotDataException, DotSecurityException{ - Map> contentRelationships = new HashMap>(); + private Map> findContentRelationships(Contentlet contentlet) throws DotDataException{ + Map> contentRelationships = new HashMap<>(); if(contentlet == null) return contentRelationships; List rels = FactoryLocator.getRelationshipFactory().byContentType(contentlet.getStructure()); for (Relationship r : rels) { if(!contentRelationships.containsKey(r)){ - contentRelationships.put(r, new ArrayList()); + contentRelationships.put(r, new ArrayList<>()); } - List cons = getRelatedContent(contentlet, r, APILocator.getUserAPI().getSystemUser(), true); + List cons = relationshipAPI.dbRelatedContent(r, contentlet); + for (Contentlet c : cons) { List l = contentRelationships.get(r); l.add(c); diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/RelationshipFactoryImpl.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/RelationshipFactoryImpl.java index 6540b0bc7ead..f985f8caa998 100644 --- a/dotCMS/src/main/java/com/dotcms/contenttype/business/RelationshipFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/RelationshipFactoryImpl.java @@ -280,7 +280,7 @@ public List dbRelatedContent(Relationship relationship, Contentlet boolean hasParent, boolean live, String orderBy) throws DotDataException { List matches = new ArrayList(); - if(contentlet == null || !InodeUtils.isSet(contentlet.getInode())) + if(contentlet == null || !InodeUtils.isSet(contentlet.getIdentifier())) return matches; String iden = ""; try{ diff --git a/dotCMS/src/main/java/com/dotcms/integritycheckers/IntegrityUtil.java b/dotCMS/src/main/java/com/dotcms/integritycheckers/IntegrityUtil.java index ecdd25eff1fa..e86db5e02087 100644 --- a/dotCMS/src/main/java/com/dotcms/integritycheckers/IntegrityUtil.java +++ b/dotCMS/src/main/java/com/dotcms/integritycheckers/IntegrityUtil.java @@ -342,6 +342,9 @@ public void dropTempTables(final String endpointId) throws DotDataException { dc.executeStatement("drop table " + tempTableName); }else if (DbConnectionFactory.isMySql()){ dc.executeStatement("drop table if exists " + tempTableName); + } else if (DbConnectionFactory.isMsSql()){ + dc.executeStatement("IF OBJECT_ID('tempdb.dbo." + tempTableName + "', 'U') IS NOT NULL" + + " DROP TABLE " + tempTableName); } } } diff --git a/dotCMS/src/main/java/com/dotcms/rendering/velocity/directive/ParseContainer.java b/dotCMS/src/main/java/com/dotcms/rendering/velocity/directive/ParseContainer.java index e9e12bbfb109..9bc668c3f0ec 100644 --- a/dotCMS/src/main/java/com/dotcms/rendering/velocity/directive/ParseContainer.java +++ b/dotCMS/src/main/java/com/dotcms/rendering/velocity/directive/ParseContainer.java @@ -15,12 +15,11 @@ public class ParseContainer extends DotDirective { - + public static final String DEFAULT_UUID_VALUE = MultiTree.LEGACY_RELATION_TYPE; private static final long serialVersionUID = 1L; @Override public final String getName() { - return "parseContainer"; } @@ -33,9 +32,8 @@ public void init(RuntimeServices rs, InternalContextAdapter context, Node node) String resolveTemplatePath(final Context context, final Writer writer, final RenderParams params, final String[] arguments) { final String id = arguments[0]; - final String uid = (arguments.length>1 && UtilMethods.isSet(arguments[1])) ? arguments[1] : MultiTree.LEGACY_RELATION_TYPE; + final String uid = (arguments.length > 1 && UtilMethods.isSet(arguments[1])) ? arguments[1] : DEFAULT_UUID_VALUE; - return "/" +params.mode.name() + "/" + id + "/" + uid + "." + VelocityType.CONTAINER.fileExtension ; } diff --git a/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/ContainerLoader.java b/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/ContainerLoader.java index b3dce312b216..67dd4b27ee53 100644 --- a/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/ContainerLoader.java +++ b/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/ContainerLoader.java @@ -157,6 +157,7 @@ private InputStream buildVelocity(Container container, String uuid, PageMode mod if(it.hasNext()) { editWrapperDiv.append(","); } + editWrapperDiv.append("WIDGET,FORM"); } catch (DotDataException | DotSecurityException e) { Logger.warn(this.getClass(), "unable to find content type:" + struct); } diff --git a/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/PageContextBuilder.java b/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/PageContextBuilder.java index bc20e995356b..269e54f0d556 100644 --- a/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/PageContextBuilder.java +++ b/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/PageContextBuilder.java @@ -19,7 +19,6 @@ import com.dotmarketing.business.PermissionAPI; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotSecurityException; -import com.dotmarketing.factories.MultiTreeAPI; import com.dotmarketing.portlets.containers.model.Container; import com.dotmarketing.portlets.contentlet.model.Contentlet; import com.dotmarketing.portlets.htmlpageasset.model.IHTMLPage; @@ -158,7 +157,7 @@ private void populateContext() throws DotDataException, DotSecurityException { private void populateContainers() throws DotDataException, DotSecurityException { - Table> pageContents = new MultiTreeAPI().getPageMultiTrees(htmlPage, mode.showLive); + Table> pageContents = APILocator.getMultiTreeAPI().getPageMultiTrees(htmlPage, mode.showLive); diff --git a/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/VelocityType.java b/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/VelocityType.java index d5776ee9fe31..7a4cbccbb937 100644 --- a/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/VelocityType.java +++ b/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/VelocityType.java @@ -24,11 +24,11 @@ public enum VelocityType { public static VelocityType resolveVelocityType(final String path) { -; final String extenstion = UtilMethods.getFileExtension(path); +; final String extension = UtilMethods.getFileExtension(path); for (final VelocityType val : VelocityType.values()) { - if (extenstion.equals(val.fileExtension)) { + if (extension.equals(val.fileExtension)) { return val; } } diff --git a/dotCMS/src/main/java/com/dotcms/rendering/velocity/util/VelocityUtil.java b/dotCMS/src/main/java/com/dotcms/rendering/velocity/util/VelocityUtil.java index 6888793fbbce..be93619b5362 100644 --- a/dotCMS/src/main/java/com/dotcms/rendering/velocity/util/VelocityUtil.java +++ b/dotCMS/src/main/java/com/dotcms/rendering/velocity/util/VelocityUtil.java @@ -2,6 +2,10 @@ import com.dotcms.enterprise.LicenseUtil; import com.dotcms.enterprise.license.LicenseLevel; +import com.dotcms.rendering.velocity.servlet.VelocityEditMode; +import com.dotcms.rendering.velocity.servlet.VelocityLiveMode; +import com.dotcms.rendering.velocity.servlet.VelocityModeHandler; +import com.dotcms.rendering.velocity.servlet.VelocityPreviewMode; import com.dotcms.rendering.velocity.viewtools.LanguageWebAPI; import com.dotcms.rendering.velocity.viewtools.RequestWrapper; import com.dotcms.visitor.domain.Visitor; @@ -32,7 +36,7 @@ import java.io.StringWriter; import java.util.ArrayList; import java.util.List; - +import java.util.concurrent.ConcurrentHashMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -49,7 +53,7 @@ import com.liferay.portal.model.User; import com.liferay.util.SystemProperties; - +import java.util.Map; public class VelocityUtil { public final static String REFRESH="refresh"; @@ -57,7 +61,21 @@ public class VelocityUtil { public final static String DOTCACHE="dotcache"; private static VelocityEngine ve = null; private static boolean DEFAULT_PAGE_TO_DEFAULT_LANGUAGE = LanguageWebAPI.canDefaultPageToDefaultLanguage(); - + + private static final Map pageModeVelocityMap = new ConcurrentHashMap<>(); + + static { + pageModeVelocityMap.put(PageMode.PREVIEW_MODE, VelocityPreviewMode::new); + pageModeVelocityMap.put(PageMode.EDIT_MODE, VelocityEditMode::new); + pageModeVelocityMap.put(PageMode.LIVE, VelocityLiveMode::new); + pageModeVelocityMap.put(PageMode.ADMIN_MODE, VelocityLiveMode::new); + } + + @FunctionalInterface + private interface Function { + VelocityModeHandler apply(HttpServletRequest request, HttpServletResponse response, String uri, Host host); + } + private synchronized static void init(){ if(ve != null) return; @@ -377,7 +395,7 @@ public static List getAvailableContentPageLanguages( * This returns the proper ihtml page based on id, state and language * * @param id - * @param request + * @param tryLang * @param live * @return * @throws DotDataException @@ -403,7 +421,7 @@ public static IHTMLPage getPage(Identifier id, long tryLang, boolean live) APILocator.getLanguageAPI().getDefaultLanguage().getId(), APILocator.getUserAPI().getSystemUser(), false); htmlPage = APILocator.getHTMLPageAssetAPI().fromContentlet(contentlet); } else { - throw new DotDataException( + throw new ResourceNotFoundException( "Can't find content. Identifier: " + id.getId() + ", Live: " + live + ", Lang: " + tryLang, dse); } @@ -435,4 +453,19 @@ public static String getVelocityRootPath() { return velocityRootPath; } -} + /** + * Render a page in the specific {@link PageMode} + * + * @param pageMode + * @param request + * @param response + * @param uri + * @param host + * @return + */ + public static String eval(final PageMode pageMode, final HttpServletRequest request, + final HttpServletResponse response, final String uri, + final Host host) { + return pageModeVelocityMap.get(pageMode).apply(request, response, uri, host).eval(); + } +} \ No newline at end of file diff --git a/dotCMS/src/main/java/com/dotcms/rendering/velocity/viewtools/WebAPI.java b/dotCMS/src/main/java/com/dotcms/rendering/velocity/viewtools/WebAPI.java index 18804a681f31..b85a2498f825 100644 --- a/dotCMS/src/main/java/com/dotcms/rendering/velocity/viewtools/WebAPI.java +++ b/dotCMS/src/main/java/com/dotcms/rendering/velocity/viewtools/WebAPI.java @@ -1,4 +1,5 @@ package com.dotcms.rendering.velocity.viewtools; +import com.dotcms.rendering.velocity.services.VelocityType; import java.io.IOException; import java.io.StringWriter; import java.text.SimpleDateFormat; @@ -14,7 +15,6 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.context.Context; import org.apache.velocity.tools.view.context.ViewContext; import org.apache.velocity.tools.view.tools.ViewTool; @@ -49,7 +49,6 @@ import com.dotmarketing.util.PageMode; import com.dotmarketing.util.UtilHTML; import com.dotmarketing.util.UtilMethods; -import com.dotmarketing.util.VelocityUtil; import com.dotmarketing.util.WebKeys; import com.dotmarketing.util.XMLUtils; import com.liferay.portal.PortalException; @@ -290,7 +289,7 @@ public String getContentIdentifier(String parsePath) { public String getContentInode(String parsePath) { ContentletAPI conAPI = APILocator.getContentletAPI(); String id = ""; - if(parsePath.indexOf(Config.getStringProperty("VELOCITY_CONTENT_EXTENSION")) == -1 || parsePath.indexOf(Config.getStringProperty("VELOCITY_CONTENT_MAP_EXTENSION")) == -1){ + if(parsePath.indexOf(VelocityType.CONTENT.fileExtension) == -1 || parsePath.indexOf(VelocityType.CONTENT_MAP.fileExtension) == -1){ id = parsePath; }else{ id = getContentIdentifier(parsePath); @@ -317,7 +316,7 @@ public String getContentInode(String parsePath) { public String getContentPermissions(String parsePath) { String id = ""; - if(parsePath.indexOf(Config.getStringProperty("VELOCITY_CONTENT_EXTENSION")) == -1){ + if(parsePath.indexOf(VelocityType.CONTENT.fileExtension) == -1){ id = parsePath; }else{ id = getContentIdentifier(parsePath); diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/container/ContainerResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/container/ContainerResource.java index 22a99aa84d4c..68b4aa7ee0d6 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/container/ContainerResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/container/ContainerResource.java @@ -231,72 +231,6 @@ public final Response containerContent(@Context final HttpServletRequest req, @C } - - - @POST - @JSONP - @NoCache - @Consumes(MediaType.APPLICATION_JSON) - @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) - @Path("add/{containerId}/content/{contentletId}/uid/{uid}/order/{order}") - public final Response addContentToContainer(@Context final HttpServletRequest req, @Context final HttpServletResponse res, - @PathParam("containerId") final String containerId, @PathParam("contentletId") final String contentletId, - @QueryParam("order") final int order, @PathParam("uid") final String uid) throws DotDataException, - DotSecurityException, ParseErrorException, MethodInvocationException, ResourceNotFoundException, IOException, - IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException { - - - final InitDataObject initData = webResource.init(true, req, true); - final User user = initData.getUser(); - final PageMode mode = PageMode.get(req); - final Language id = WebAPILocator.getLanguageWebAPI() - .getLanguage(req); - - ShortyId contentShorty = APILocator.getShortyAPI() - .getShorty(contentletId) - .orElseGet(() -> { - throw new ResourceNotFoundException("Can't find contentlet:" + contentletId); - }); - final Contentlet contentlet = (contentShorty.subType == ShortType.CONTENTLET) ? APILocator.getContentletAPI() - .find(contentShorty.longId, user, !mode.showLive) - : APILocator.getContentletAPI() - .findContentletByIdentifier(contentShorty.longId, mode.showLive, id.getId(), user, mode.isAdmin); - - - - ShortyId containerShorty = APILocator.getShortyAPI() - .getShorty(containerId) - .orElseGet(() -> { - throw new ResourceNotFoundException("Can't find Container:" + containerId); - }); - Container container = (containerShorty.subType == ShortType.CONTAINER) ? APILocator.getContainerAPI() - .find(containerId, user, mode.isAdmin) - : (mode.showLive) ? (Container) APILocator.getVersionableAPI() - .findLiveVersion(containerShorty.longId, user, !mode.isAdmin) - : (Container) APILocator.getVersionableAPI() - .findWorkingVersion(containerShorty.longId, user, !mode.isAdmin); - - - APILocator.getPermissionAPI() - .checkPermission(contentlet, PermissionLevel.READ, user); - APILocator.getPermissionAPI() - .checkPermission(container, PermissionLevel.EDIT, user); - - - - MultiTree mt = new MultiTree().setContainer(containerId) - .setContentlet(contentletId) - .setRelationType(uid) - .setTreeOrder(order); - - MultiTreeFactory.saveMultiTree(mt); - - - return Response.ok("ok") - .build(); - } - - @DELETE @JSONP @NoCache @@ -421,8 +355,4 @@ public final Response containerContents(@Context final HttpServletRequest req, @ return responseBuilder.build(); } - - - } - diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/contenttype/ContentTypeForm.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/contenttype/ContentTypeForm.java new file mode 100644 index 000000000000..e8640b341965 --- /dev/null +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/contenttype/ContentTypeForm.java @@ -0,0 +1,135 @@ +package com.dotcms.rest.api.v1.contenttype; + +import com.dotcms.contenttype.model.type.ContentType; +import com.dotcms.contenttype.transform.contenttype.JsonContentTypeTransformer; +import com.dotcms.repackage.com.fasterxml.jackson.core.JsonParser; +import com.dotcms.repackage.com.fasterxml.jackson.databind.DeserializationContext; +import com.dotcms.repackage.com.fasterxml.jackson.databind.JsonDeserializer; +import com.dotcms.repackage.com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.dotcms.repackage.com.google.common.annotations.VisibleForTesting; +import com.dotmarketing.exception.DotRuntimeException; +import com.dotmarketing.util.json.JSONArray; +import com.dotmarketing.util.json.JSONException; +import com.dotmarketing.util.json.JSONObject; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * {@link ContentTypeResource}'s form + */ +@JsonDeserialize(using = ContentTypeForm.ContentTypeFormDeserialize.class) +public class ContentTypeForm { + + private final List entries; + private final String requestJson; + + public ContentTypeForm(final List entries, final String requestJson) { + this.requestJson = requestJson; + this.entries = entries; + } + + public Iterable getIterable() { + return entries; + } + + public ContentType getContentType() { + return entries.get(0).contentType; + } + + public List getWorkflowsIds() { + return entries.get(0).workflowsIds; + } + + public Object getRequestJson() { + return requestJson; + } + + + public static final class ContentTypeFormDeserialize extends JsonDeserializer { + + public static final String WORKFLOW_ATTRIBUTE_NAME = "workflow"; + + @Override + public ContentTypeForm deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) + throws IOException { + + final String json = jsonParser.readValueAsTree().toString(); + return buildForm(json); + } + + @VisibleForTesting + public ContentTypeForm buildForm(final String json) { + final List typesToSave = new JsonContentTypeTransformer(json).asList(); + final List> workflows = getWorkflowIdsFromJson(json); + + final List entries = getContentTypeFormEntries(typesToSave, workflows); + + return new ContentTypeForm(entries, json); + } + + private List getContentTypeFormEntries(final List typesToSave, + final List> workflows) { + + final List entries = new ArrayList<>(); + + for (int i = 0; i < workflows.size(); i++) { + final List worflows = workflows.get(i); + final ContentType contentType = typesToSave.get(i); + + final ContentTypeFormEntry entry = new ContentTypeFormEntry(contentType, worflows); + entries.add(entry); + } + return entries; + } + + private static List> getWorkflowIdsFromJson(final String json) { + final List> workflows = new ArrayList<>(); + + try { + final JSONArray jarr = new JSONArray(json); + + for (int i = 0; i < jarr.size(); i++) { + final JSONObject fieldJsonObject = (JSONObject) jarr.get(i); + List workflowsIds = getWorkflowsId(fieldJsonObject); + workflows.add(workflowsIds); + } + } catch (JSONException e) { + + try { + final JSONObject fieldJsonObject = new JSONObject(json); + List workflowsIds = getWorkflowsId(fieldJsonObject); + workflows.add(workflowsIds); + } catch (JSONException e1) { + throw new DotRuntimeException(e1); + } + } + return workflows; + } + + private static List getWorkflowsId(JSONObject fieldJsonObject) throws JSONException { + List worflowsArray = new ArrayList<>(); + + if (fieldJsonObject.has(WORKFLOW_ATTRIBUTE_NAME)) { + final JSONArray workflowsJaonArray = (JSONArray) fieldJsonObject.get(WORKFLOW_ATTRIBUTE_NAME); + + for (int k = 0; k < workflowsJaonArray.size(); k++) { + worflowsArray.add((String) workflowsJaonArray.get(k)); + } + } + + return worflowsArray; + } + } + + public static class ContentTypeFormEntry { + ContentType contentType; + List workflowsIds; + + ContentTypeFormEntry(final ContentType contentType, final List workflowsIds) { + this.contentType = contentType; + this.workflowsIds = workflowsIds; + } + } +} diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/contenttype/ContentTypeResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/contenttype/ContentTypeResource.java index 84aba72f5188..dcf1094aa0f3 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/contenttype/ContentTypeResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/contenttype/ContentTypeResource.java @@ -1,9 +1,7 @@ package com.dotcms.rest.api.v1.contenttype; import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; +import java.util.*; import javax.servlet.http.HttpServletRequest; @@ -46,7 +44,6 @@ import com.dotcms.repackage.javax.ws.rs.*; import static com.dotcms.util.CollectionsUtils.map; -import java.util.Map; @Path("/v1/contenttype") public class ContentTypeResource implements Serializable { @@ -78,7 +75,7 @@ public ContentTypeResource(final ContentTypeHelper contentletHelper, final WebRe @NoCache @Consumes(MediaType.APPLICATION_JSON) @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) - public final Response createType(@Context final HttpServletRequest req, final String json) + public final Response createType(@Context final HttpServletRequest req, final ContentTypeForm form) throws DotDataException, DotSecurityException { final InitDataObject initData = this.webResource.init(null, true, req, true, null); final User user = initData.getUser(); @@ -86,25 +83,28 @@ public final Response createType(@Context final HttpServletRequest req, final St Response response = null; try { - final List typesToSave = new JsonContentTypeTransformer(json).asList(); + Logger.debug(this, String.format("Saving new content type", form.getRequestJson())); + + final Iterable typesToSave = form.getIterable(); final List retTypes = new ArrayList<>(); // Validate input - for (ContentType type : typesToSave) { + for (final ContentTypeForm.ContentTypeFormEntry entry : typesToSave) { + final ContentType type = entry.contentType; + final List workflowsIds = entry.workflowsIds; + if (UtilMethods.isSet(type.id()) && !UUIDUtil.isUUID(type.id())) { return ExceptionMapperUtil.createResponse(null, "ContentType 'id' if set, should be a uuid"); } - retTypes.add(APILocator.getContentTypeAPI(user, true).save(type)); + final ContentType contentTypeSaved = APILocator.getContentTypeAPI(user, true).save(type); + retTypes.add(contentTypeSaved); + this.workflowHelper.saveSchemesByContentType(contentTypeSaved.inode(), user, workflowsIds); } response = Response.ok(new ResponseEntityView(new JsonContentTypeTransformer(retTypes).mapList())).build(); - } catch (DotStateException e) { - - response = ExceptionMapperUtil.createResponse(null, "Content-type is not valid ("+ e.getMessage() +")"); - - } catch (DotDataException e) { + } catch (DotStateException | DotDataException e) { response = ExceptionMapperUtil.createResponse(null, "Content-type is not valid ("+ e.getMessage() +")"); @@ -123,7 +123,7 @@ public final Response createType(@Context final HttpServletRequest req, final St @NoCache @Consumes(MediaType.APPLICATION_JSON) @Produces({ MediaType.APPLICATION_JSON, "application/javascript" }) - public Response updateType(@PathParam("id") final String id, final String json, + public Response updateType(@PathParam("id") final String id, final ContentTypeForm form, @Context final HttpServletRequest req) throws DotDataException, DotSecurityException { final InitDataObject initData = this.webResource.init(null, false, req, false, null); @@ -133,7 +133,10 @@ public Response updateType(@PathParam("id") final String id, final String json, Response response = null; try { - ContentType contentType = new JsonContentTypeTransformer(json).from(); + ContentType contentType = form.getContentType(); + + Logger.debug(this, String.format("Updating content type", form.getRequestJson())); + if (!UtilMethods.isSet(contentType.id())) { response = ExceptionMapperUtil.createResponse(null, "Field 'id' should be set"); @@ -150,18 +153,16 @@ public Response updateType(@PathParam("id") final String id, final String json, contentType = capi.save(contentType); + final List workflowsIds = form.getWorkflowsIds(); + workflowHelper.saveSchemesByContentType(id, user, workflowsIds); response = Response.ok(new ResponseEntityView(new JsonContentTypeTransformer(contentType).mapObject())).build(); } } - } catch (DotStateException e) { - - response = ExceptionMapperUtil.createResponse(null, "Content-type is not valid ("+ e.getMessage() +")"); - } catch (NotFoundInDbException e) { response = ExceptionMapperUtil.createResponse(e, Response.Status.NOT_FOUND); - } catch (DotDataException e) { + } catch ( DotStateException | DotDataException e) { response = ExceptionMapperUtil.createResponse(null, "Content-type is not valid ("+ e.getMessage() +")"); diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageContainerForm.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageContainerForm.java new file mode 100644 index 000000000000..98fcc1cb0a24 --- /dev/null +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageContainerForm.java @@ -0,0 +1,95 @@ +package com.dotcms.rest.api.v1.page; + +import com.dotcms.repackage.com.fasterxml.jackson.core.JsonParser; +import com.dotcms.repackage.com.fasterxml.jackson.databind.DeserializationContext; +import com.dotcms.repackage.com.fasterxml.jackson.databind.JsonDeserializer; +import com.dotcms.repackage.com.fasterxml.jackson.databind.JsonNode; +import com.dotcms.repackage.com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.dotcms.repackage.jersey.repackaged.com.google.common.collect.ImmutableList; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + + +/** + * {@link PageResource#addContent(HttpServletRequest, HttpServletResponse, String)}'s form + */ +@JsonDeserialize(using = PageContainerForm.ContainerDeserialize.class) +public class PageContainerForm { + + private final List entries; + private final String requestJson; + + public PageContainerForm(final List entries, final String requestJson) { + this.entries = ImmutableList.copyOf(entries); + this.requestJson = requestJson; + } + + public List getContainerEntries() { + return entries; + } + + public String getRequestJson() { + return requestJson; + } + + static final class ContainerDeserialize extends JsonDeserializer { + + private static final String CONTAINER_ID_ATTRIBUTE_NAME = "id"; + private static final String CONTAINER_UUID_ATTRIBUTE_NAME = "uuid"; + private static final String CONTAINER_CONTENTLETSID_ATTRIBUTE_NAME = "contentlets"; + + @Override + public PageContainerForm deserialize(final JsonParser jsonParser, + final DeserializationContext deserializationContext) + throws IOException { + + final JsonNode jsonNode = jsonParser.readValueAsTree(); + final List entries = new ArrayList<>(); + + for (final JsonNode jsonElement : jsonNode) { + final String containerId = jsonElement.get(CONTAINER_ID_ATTRIBUTE_NAME).asText(); + final String containerUUID = jsonElement.get(CONTAINER_UUID_ATTRIBUTE_NAME).asText(); + final ContainerEntry containerEntry = new ContainerEntry(containerId, containerUUID); + + final JsonNode containerNode = jsonElement.get(CONTAINER_CONTENTLETSID_ATTRIBUTE_NAME); + + containerNode.forEach((JsonNode contentId) -> containerEntry.addContentId(contentId.textValue())); + entries.add(containerEntry); + } + + return new PageContainerForm(entries, jsonNode.toString()); + } + } + + static final class ContainerEntry { + private final String id; + private final String uuid; + private final List contentIds; + + public ContainerEntry(final String id, final String uuid) { + this.id = id; + this.uuid = uuid; + contentIds = new ArrayList<>(); + } + + public String getContainerId() { + return id; + } + + public List getContentIds() { + return contentIds; + } + + public void addContentId(final String contentId) { + this.contentIds.add(contentId); + } + + public String getContainerUUID() { + return uuid; + } + } +} diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResource.java index 9e2eab3628ab..d80a57e4d699 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResource.java @@ -6,6 +6,7 @@ import com.dotcms.repackage.javax.ws.rs.core.Context; import com.dotcms.repackage.javax.ws.rs.core.MediaType; import com.dotcms.repackage.javax.ws.rs.core.Response; +import com.dotcms.repackage.org.glassfish.jersey.server.JSONP; import com.dotcms.rest.InitDataObject; import com.dotcms.rest.ResponseEntityView; import com.dotcms.rest.WebResource; @@ -13,8 +14,14 @@ import com.dotcms.rest.exception.BadRequestException; import com.dotcms.rest.exception.NotFoundException; import com.dotcms.rest.exception.mapper.ExceptionMapperUtil; +import com.dotmarketing.beans.MultiTree; +import com.dotmarketing.business.web.WebAPILocator; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotSecurityException; +import com.dotmarketing.portlets.containers.model.Container; +import com.dotmarketing.portlets.contentlet.model.Contentlet; +import com.dotmarketing.portlets.htmlpageasset.model.HTMLPageAsset; +import com.dotmarketing.portlets.languagesmanager.model.Language; import com.dotmarketing.portlets.templates.model.Template; import com.dotmarketing.util.Logger; import com.dotmarketing.util.PageMode; @@ -22,6 +29,9 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.google.common.collect.ImmutableMap; import com.liferay.portal.model.User; +import org.apache.velocity.exception.MethodInvocationException; +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.exception.ResourceNotFoundException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -77,8 +87,9 @@ protected PageResource(final PageResourceHelper pageResourceHelper, final WebRes @GET @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) @Path("/json/{uri: .*}") - public Response loadJson(@Context final HttpServletRequest request, @Context final - HttpServletResponse response, @PathParam("uri") final String uri, @QueryParam("live") @DefaultValue("true") final boolean live) { + public Response loadJson(@Context final HttpServletRequest request, @Context final HttpServletResponse response, + @PathParam("uri") final String uri, + @QueryParam("live") @DefaultValue("true") final boolean live) { // Force authentication final InitDataObject auth = webResource.init(false, request, true); final User user = auth.getUser(); @@ -181,19 +192,26 @@ public Response renderPageObject(@Context final HttpServletRequest request, @Con @GET @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) @Path("/renderHTML/{uri: .*}") - public Response renderHTMLOnly(@Context final HttpServletRequest request, @Context final - HttpServletResponse response, @PathParam("uri") final String uri, @QueryParam("mode") @DefaultValue("LIVE_ADMIN") String modeStr) { + public Response renderHTMLOnly(@Context final HttpServletRequest request, + @Context final HttpServletResponse response, + @PathParam("uri") final String uri, + @QueryParam("mode") @DefaultValue("LIVE_ADMIN") final String modeStr) { + + Logger.debug(this, String.format("Rendering page: uri -> %s mode-> %s", uri, modeStr)); + // Force authentication final InitDataObject auth = webResource.init(false, request, true); final User user = auth.getUser(); Response res = null; - PageMode mode = PageMode.get(modeStr); + final PageMode mode = PageMode.get(modeStr); PageMode.setPageMode(request, mode); try { - final String html = this.pageResourceHelper.getPageRendered(request, response, user, uri, mode); - final Response.ResponseBuilder responseBuilder = Response.ok(ImmutableMap.of("render",html)); + final HTMLPageAsset page = this.pageResourceHelper.getPage(request, user, uri, mode); + final String html = this.pageResourceHelper.getPageRendered(page, request, response, user, mode); + final Response.ResponseBuilder responseBuilder = Response.ok(ImmutableMap.of("render",html, "identifier", + page.getIdentifier(), "inode", page.getInode())); responseBuilder.header("Access-Control-Expose-Headers", "Authorization"); responseBuilder.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, " + "Content-Type, " + "Accept, Authorization"); @@ -315,4 +333,59 @@ public Response saveLayout(@Context final HttpServletRequest request, final Page return res; } + /** + * Update all the content's page receive a json object with the follow format: + * + * { + * container_1_id: [contentlet_1_id, contentlet_2_id,...,contentlet_n_id], + * container_2_id: [contentlet_1_id, contentlet_2_id,...,contentlet_n_id], + * ... + * container_n_id: [contentlet_1_id, contentlet_2_id,...,contentlet_n_id], + * } + * + * where: + * + * - container_1_id, container_2_id,..., container_n_id: Each container's identifier + * - contentlet_1_id, contentlet_2_id,...,contentlet_n_id: each contentlet identifier + * + * @param req + * @param pageId + * @param pageContainerForm + * @return + */ + @POST + @JSONP + @NoCache + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("{pageId}/content") + public final Response addContent(@Context final HttpServletRequest req, @PathParam("pageId") final String pageId, + final PageContainerForm pageContainerForm) { + + Logger.debug(this, String.format("Saving page's content: %s", pageContainerForm.getRequestJson())); + + final InitDataObject initData = webResource.init(true, req, true); + final User user = initData.getUser(); + Response res = null; + + try { + final Contentlet page = pageResourceHelper.getPage(user, pageId); + if (page == null) { + return ExceptionMapperUtil.createResponse(Response.Status.BAD_REQUEST); + } + + pageResourceHelper.checkPagePermission(user, page); + pageResourceHelper.saveContent(pageId, pageContainerForm.getContainerEntries()); + + res = Response.ok(new ResponseEntityView("ok")).build(); + } catch (DotSecurityException e) { + res = ExceptionMapperUtil.createResponse(e, Response.Status.UNAUTHORIZED); + Logger.error(this, e.getMessage(), e); + } catch (DotDataException e) { + res = ExceptionMapperUtil.createResponse(e, Response.Status.BAD_REQUEST); + Logger.error(this, e.getMessage(), e); + } + + return res; + } } diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResourceHelper.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResourceHelper.java index 9f2b7e05cc43..e4bb2b71ada1 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResourceHelper.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResourceHelper.java @@ -2,15 +2,14 @@ import com.dotcms.api.web.HttpServletRequestThreadLocal; import com.dotcms.business.CloseDB; -import com.dotcms.rendering.velocity.servlet.VelocityEditMode; -import com.dotcms.rendering.velocity.servlet.VelocityLiveMode; -import com.dotcms.rendering.velocity.servlet.VelocityPreviewMode; import com.dotcms.rendering.velocity.viewtools.DotTemplateTool; import com.dotcms.rest.exception.BadRequestException; import com.dotcms.rest.exception.NotFoundException; +import com.dotcms.uuid.shorty.ShortyId; import com.dotmarketing.beans.ContainerStructure; import com.dotmarketing.beans.Host; +import com.dotmarketing.beans.MultiTree; import com.dotmarketing.business.APILocator; import com.dotmarketing.business.PermissionLevel; import com.dotmarketing.business.VersionableAPI; @@ -19,6 +18,7 @@ import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotRuntimeException; import com.dotmarketing.exception.DotSecurityException; +import com.dotmarketing.factories.MultiTreeAPI; import com.dotmarketing.portlets.containers.business.ContainerAPI; import com.dotmarketing.portlets.containers.model.Container; import com.dotmarketing.portlets.contentlet.business.ContentletAPI; @@ -27,15 +27,18 @@ import com.dotmarketing.portlets.htmlpageasset.business.HTMLPageAssetAPI; import com.dotmarketing.portlets.htmlpageasset.model.HTMLPageAsset; import com.dotmarketing.portlets.languagesmanager.business.LanguageAPI; +import com.dotmarketing.portlets.languagesmanager.model.Language; import com.dotmarketing.portlets.templates.business.TemplateAPI; import com.dotmarketing.portlets.templates.design.bean.TemplateLayout; import com.dotmarketing.portlets.templates.model.Template; import com.dotmarketing.util.PageMode; +import com.dotmarketing.util.URLUtils; import com.dotmarketing.util.UtilMethods; import com.dotmarketing.util.VelocityUtil; import java.io.IOException; import java.io.Serializable; +import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -44,7 +47,6 @@ import javax.servlet.http.HttpServletResponse; import org.apache.velocity.context.Context; -import org.apache.velocity.exception.ParseErrorException; import org.apache.velocity.exception.ResourceNotFoundException; import com.fasterxml.jackson.core.JsonProcessingException; @@ -75,6 +77,7 @@ public class PageResourceHelper implements Serializable { private final ContentletAPI contentletAPI = APILocator.getContentletAPI(); private final HostAPI hostAPI = APILocator.getHostAPI(); private final LanguageAPI langAPI = APILocator.getLanguageAPI(); + private final MultiTreeAPI multiTreeAPI = APILocator.getMultiTreeAPI(); private static final boolean RESPECT_FE_ROLES = Boolean.TRUE; @@ -85,6 +88,42 @@ private PageResourceHelper() { } + public void saveContent(final String pageId, final List containerEntries) throws DotDataException { + final List multiTres = new ArrayList<>(); + + for (final PageContainerForm.ContainerEntry containerEntry : containerEntries) { + int i = 0; + final List contentIds = containerEntry.getContentIds(); + + for (final String contentletId : contentIds) { + final MultiTree multiTree = new MultiTree().setContainer(containerEntry.getContainerId()) + .setContentlet(contentletId) + .setRelationType(containerEntry.getContainerUUID()) + .setTreeOrder(i++) + .setHtmlPage(pageId); + + multiTres.add(multiTree); + } + } + + multiTreeAPI.saveMultiTrees(pageId, multiTres); + } + + public void saveMultiTree(final String containerId, + final String contentletId, + final int order, + final String uid, + final Contentlet page) throws DotDataException { + + final MultiTree multiTree = new MultiTree().setContainer(containerId) + .setContentlet(contentletId) + .setRelationType(uid) + .setTreeOrder(order) + .setHtmlPage(page.getIdentifier()); + + multiTreeAPI.saveMultiTree(multiTree); + } + /** * Provides a singleton instance of the {@link PageResourceHelper} */ @@ -141,18 +180,21 @@ public PageView getPageMetadataRendered(final HttpServletRequest request, final return getPageMetadata(request, response, user, uri, true, PageMode.get(request)); } + public String getPageRendered(final HttpServletRequest request, final HttpServletResponse response, final User user, + final String uri, final PageMode mode) throws Exception { + + final HTMLPageAsset page = this.getPage(request, user, uri, mode); + return this.getPageRendered(page, request, response, user, mode); + } + @CloseDB - public String getPageRendered(final HttpServletRequest request, final - HttpServletResponse response, final User user, final String uri, PageMode mode) throws DotDataException, DotSecurityException, IOException { - + public String getPageRendered(final HTMLPageAsset page, final HttpServletRequest request, + final HttpServletResponse response, final User user, final PageMode mode) throws Exception { + final String siteName = null == request.getParameter(Host.HOST_VELOCITY_VAR_NAME) ? request.getServerName() : request.getParameter(Host.HOST_VELOCITY_VAR_NAME); final Host site = this.hostWebAPI.resolveHostName(siteName, user, RESPECT_FE_ROLES); - final String pageUri = (uri.length()>0 && '/' == uri.charAt(0)) ? uri : ("/" + uri); - final HTMLPageAsset page = (HTMLPageAsset) this.htmlPageAssetAPI.getPageByPath(pageUri, - site, this.languageAPI.getDefaultLanguage().getId(), mode.respectAnonPerms); - if(null==page) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return null; @@ -160,25 +202,22 @@ public String getPageRendered(final HttpServletRequest request, final if(mode.isAdmin ) { APILocator.getPermissionAPI().checkPermission(page, PermissionLevel.READ, user); } - - switch (mode) { - case PREVIEW_MODE: - return new VelocityPreviewMode(request, response, pageUri, site).eval(); - case EDIT_MODE: - return new VelocityEditMode(request, response, pageUri, site).eval(); + return VelocityUtil.eval(mode, request, response, page.getURI(), site); + } - default: - return new VelocityLiveMode(request, response, pageUri, site).eval(); + public HTMLPageAsset getPage(final HttpServletRequest request, final User user, + final String uri, final PageMode mode) throws DotSecurityException, DotDataException { - } - - - + final String siteName = null == request.getParameter(Host.HOST_VELOCITY_VAR_NAME) ? + request.getServerName() : request.getParameter(Host.HOST_VELOCITY_VAR_NAME); + final Host site = this.hostWebAPI.resolveHostName(siteName, user, RESPECT_FE_ROLES); + + final String pageUri = URLUtils.addSlashIfNeeded(uri); + return (HTMLPageAsset) this.htmlPageAssetAPI.getPageByPath(pageUri, + site, this.languageAPI.getDefaultLanguage().getId(), mode.respectAnonPerms); } - - /** * @param request The {@link HttpServletRequest} object. * @param response The {@link HttpServletResponse} object. @@ -204,8 +243,6 @@ private PageView getPageMetadata(final HttpServletRequest request, final HttpSer final HTMLPageAsset page = (HTMLPageAsset) this.htmlPageAssetAPI.getPageByPath(pageUri, site, this.languageAPI.getDefaultLanguage().getId(), mode.showLive); - - if (isRendered) { try { page.setProperty("rendered", getPageRendered(request, response, user, uri, mode)); @@ -220,12 +257,9 @@ private PageView getPageMetadata(final HttpServletRequest request, final HttpSer final List templateContainers = this.templateAPI.getContainersInTemplate (template, user, RESPECT_FE_ROLES); - - templateContainers.addAll(APILocator.getContainerAPI().getContainersOnPage(page)); - + templateContainers.addAll(APILocator.getContainerAPI().getContainersOnPage(page)); - final Map mappedContainers = new LinkedHashMap<>(); for (final Container container : templateContainers) { final List containerStructures = this.containerAPI @@ -264,7 +298,7 @@ public String asJson(final PageView pageView) throws JsonProcessingException { return objectWriter.writeValueAsString(pageView); } - public Template saveTemplate(final User user, String pageId, final PageForm pageForm) + public Template saveTemplate(final User user, final String pageId, final PageForm pageForm) throws BadRequestException, DotDataException, DotSecurityException, IOException { final Contentlet page = this.contentletAPI.findContentletByIdentifier(pageId, false, @@ -291,6 +325,11 @@ public Template saveTemplate(final User user, String pageId, final PageForm page } } + public Contentlet getPage(final User user, final String pageId) throws DotSecurityException, DotDataException { + return this.contentletAPI.findContentletByIdentifier(pageId, false, + langAPI.getDefaultLanguage().getId(), user, false); + } + public Template saveTemplate(final Contentlet page, final User user, final PageForm pageForm) throws BadRequestException, DotDataException, DotSecurityException, IOException { @@ -332,7 +371,7 @@ private Template getTemplate(Contentlet page, User user, PageForm form) throws D return result; } - private Host getHost(final String hostId, User user) { + private Host getHost(final String hostId, final User user) { try { return UtilMethods.isSet(hostId) ? hostAPI.find(hostId, user, false) : hostWebAPI.getCurrentHost(HttpServletRequestThreadLocal.INSTANCE.getRequest()); @@ -340,4 +379,43 @@ private Host getHost(final String hostId, User user) { throw new DotRuntimeException(e); } } + + public Contentlet getContentlet(final User user, final PageMode mode, final Language id, final String contentletId) + throws DotDataException, DotSecurityException { + + final ShortyId contentShorty = APILocator.getShortyAPI() + .getShorty(contentletId) + .orElseGet(() -> { + throw new ResourceNotFoundException("Can't find contentlet:" + contentletId); + }); + + return APILocator.getContentletAPI() + .findContentletByIdentifier(contentShorty.longId, mode.showLive, id.getId(), user, mode.isAdmin); + } + + public Container getContainer(final String containerId, final User user, final PageMode mode) + throws DotDataException, DotSecurityException { + + final ShortyId containerShorty = APILocator.getShortyAPI() + .getShorty(containerId) + .orElseGet(() -> { + throw new ResourceNotFoundException("Can't find Container:" + containerId); + }); + return (mode.showLive) ? (Container) APILocator.getVersionableAPI() + .findLiveVersion(containerShorty.longId, user, !mode.isAdmin) + : (Container) APILocator.getVersionableAPI() + .findWorkingVersion(containerShorty.longId, user, !mode.isAdmin); + } + + public void checkPermission(final User user, final Contentlet contentlet, final Container container) throws DotSecurityException { + APILocator.getPermissionAPI() + .checkPermission(contentlet, PermissionLevel.READ, user); + APILocator.getPermissionAPI() + .checkPermission(container, PermissionLevel.EDIT, user); + } + + public void checkPagePermission(final User user, final Contentlet htmlPageAsset) throws DotSecurityException { + APILocator.getPermissionAPI() + .checkPermission(htmlPageAsset, PermissionLevel.EDIT, user); + } } diff --git a/dotCMS/src/main/java/com/dotcms/system/SimpleMapAppContext.java b/dotCMS/src/main/java/com/dotcms/system/SimpleMapAppContext.java index 053059646bb6..1c716dddf3cf 100644 --- a/dotCMS/src/main/java/com/dotcms/system/SimpleMapAppContext.java +++ b/dotCMS/src/main/java/com/dotcms/system/SimpleMapAppContext.java @@ -22,4 +22,14 @@ public void setAttribute(String attributeName, T attributeValue) { this.context.put(attributeName, attributeValue); } + + public T getAttribute(Enum attribute) { + return (T)this.context.get(attribute.toString()); + } + + public void setAttribute(Enum attribute, T attributeValue) { + + this.context.put(attribute.toString(), attributeValue); + } + } // E:O:F:SimpleMapAppContext. diff --git a/dotCMS/src/main/java/com/dotcms/util/DotAssert.java b/dotCMS/src/main/java/com/dotcms/util/DotAssert.java deleted file mode 100644 index d07d46a0341d..000000000000 --- a/dotCMS/src/main/java/com/dotcms/util/DotAssert.java +++ /dev/null @@ -1,393 +0,0 @@ -package com.dotcms.util; - -import java.util.Collection; -import java.util.Map; -import java.util.function.Supplier; - -/** - * Handles assertions. - * @author jsanca - */ -public class DotAssert { - - /** - * Assert true, throws IllegalArgumentException if the expression is false. - * - *
DotAssert.isTrue(!contentletAPI.canLock(contentlet, user), "Can not lock the content" );
- * @param expression boolean expression to test - * @param errorMessage String message to pass to the IllegalArgumentException - * @throws IllegalArgumentException if expression is false - */ - public static void isTrue(final boolean expression, final String errorMessage) { - - if (!expression) { - throw new IllegalArgumentException(errorMessage); - } - } // isTrue. - - /** - * Assert true, throws IllegalArgumentException if the expression is false. - * - *
DotAssert.isTrue(contentletAPI.canLock(contentlet, user), ()->"Can not lock the content" );
- * @param expression boolean expression to test - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - * @throws IllegalArgumentException if expression is false - */ - public static void isTrue(final boolean expression, final Supplier errorMessage) { - - if (!expression) { - throw new IllegalArgumentException(errorMessage.get()); - } - } // isTrue. - - /** - * Assert true, throws Custom Throwable if the expression is false. - * - *
DotAssert.isTrue(contentletAPI.canLock(contentlet, user), ()->"Can not lock the content", CannotLockContent.class );
- * @param expression boolean expression to test - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - * @param errorClazz Class of Throwable, pre: the Throwable must have a constructor that receives a string (the error message) - * @throws IllegalArgumentException if expression is false - */ - public static void isTrue(final boolean expression, final Supplier errorMessage, - final Class errorClazz) throws T { - - if (!expression) { - throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); - } - } // isTrue. - - /** - * Assert true, throws RuntimeException if the expression is false. - * - *
DotAssert.isTrue(contentletAPI.canLock(contentlet, user), CannotLockContent.class, ()->"Can not lock the content");
- * @param expression boolean expression to test - * @param errorClazz Class of RuntimeException, pre: the RuntimeException must have a constructor that receives a string (the error message) - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - * @throws IllegalArgumentException if expression is false - */ - public static void isTrue(final boolean expression, - final Class errorClazz, - final Supplier errorMessage) { - - if (!expression) { - throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); - } - } // isTrue. - - ////////// - // is NULL - - /** - * Assert isNull, throws IllegalArgumentException if the parameter is not null. - * - *
DotAssert.isNull(user, "User must be null" );
- * @param parameter Object parameter to test if it is null - * @param errorMessage String message to pass to the IllegalArgumentException - * @throws IllegalArgumentException if expression is false - */ - public static void isNull(final Object parameter, final String errorMessage) { - - isTrue(null == parameter, errorMessage); - } // isNull. - - /** - * Assert isNull, throws IllegalArgumentException if the parameter is not null. - * - *
DotAssert.isNull(user, ()->"User must be null" );
- * @param parameter Object parameter to test if it is null - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - * @throws IllegalArgumentException if expression is false - */ - public static void isNull(final Object parameter, final Supplier errorMessage) { - - isTrue(null == parameter, errorMessage); - } // isNull. - - /** - * Assert isNull, throws Custom Throwable if the parameter is not null. - * - *
DotAssert.isNull(user, ()->"User must be null", UserMustBeNullException.class );
- * @param parameter Object parameter to test if it is null - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - * @param errorClazz Class of Throwable, pre: the Throwable must have a constructor that receives a string (the error message) - */ - public static void isNull(final Object parameter, final Supplier errorMessage, - final Class errorClazz) throws T { - - isTrue(null == parameter, errorMessage, errorClazz); - } // isNull. - - /** - * Assert isNull, throws RuntimeException if the parameter is not null. - * - *
DotAssert.isNull(user, UserMustBeNullException.class, ()->"User must be null");
- * @param parameter Object parameter to test if it is null - * @param errorClazz Class of RuntimeException, pre: the RuntimeException must have a constructor that receives a string (the error message) - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - */ - public static void isNull(final Object parameter, - final Class errorClazz, - final Supplier errorMessage) { - - isTrue(null == parameter, errorClazz, errorMessage); - } // isNull. - - ////////// - // is NOT NULL - - /** - * Assert notNull, throws IllegalArgumentException if the parameter is null. - * - *
DotAssert.notNull(user, "User must be not null" );
- * @param parameter Object parameter to test if it is not null - * @param errorMessage String message to pass to the IllegalArgumentException - * @throws IllegalArgumentException if expression is false - */ - public static void notNull(final Object parameter, final String errorMessage) { - - isTrue(null != parameter, errorMessage); - } // notNull. - - /** - * Assert notNull, throws IllegalArgumentException if the parameter is null. - * - *
DotAssert.notNull(user, ()->"User must be not null" );
- * @param parameter Object parameter to test if it is not null - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - * @throws IllegalArgumentException if expression is false - */ - public static void notNull(final Object parameter, final Supplier errorMessage) { - - isTrue(null != parameter, errorMessage); - } // notNull. - - /** - * Assert notNull, throws Custom Throwable if the parameter is null. - * - *
DotAssert.notNull(user, ()->"User must be not null", UserMustBeNullException.class );
- * @param parameter Object parameter to test if it is not null - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - * @param errorClazz Class of Throwable, pre: the Throwable must have a constructor that receives a string (the error message) - * @throws IllegalArgumentException if expression is false - */ - public static void notNull(final Object parameter, final Supplier errorMessage, - final Class errorClazz) throws T { - - isTrue(null != parameter, errorMessage, errorClazz); - } // notNull. - - /** - * Assert notNull, throws RuntimeException if the parameter is null. - * - *
DotAssert.notNull(user, UserMustBeNullException.class, ()->"User must be  notnull");
- * @param parameter Object parameter to test if it is not null - * @param errorClazz Class of RuntimeException, pre: the RuntimeException must have a constructor that receives a string (the error message) - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - * @throws IllegalArgumentException if expression is false - */ - public static void notNull(final Object parameter, - final Class errorClazz, - final Supplier errorMessage) { - - isTrue(null != parameter, errorClazz, errorMessage); - } // notNull. - - - //////// - // NOT EMPTY - - /** - * Assert notEmpty, throws IllegalArgumentException if the array is null or empty (zero items). - * - *
DotAssert.notEmpty(array, "Array is empty" );
- * @param array Object array - * @param message String message to pass to the IllegalArgumentException - */ - public static void notEmpty(final Object[] array, - final String message) { - - if (null == array || 0 == array.length) { - throw new IllegalArgumentException(message); - } - } // notEmpty. - - /** - * Assert notEmpty, throws IllegalArgumentException if the array is null or empty (zero items). - * - *
DotAssert.notEmpty(array, ()->"Array is empty" );
- * @param array Object array - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - */ - public static void notEmpty(final Object[] array, - final Supplier errorMessage) { - - if (null == array || 0 == array.length) { - throw new IllegalArgumentException(errorMessage.get()); - } - } // notEmpty. - - /** - * Assert notEmpty, throws Custom Throwable if the array is null or empty (zero items). - * - *
DotAssert.notEmpty(array, ()->"Array is empty", ArrayEmptyException.class );
- * @param array Object array - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - * @param errorClazz Class of Throwable, pre: the Throwable must have a constructor that receives a string (the error message) - */ - public static void notEmpty(final Object[] array, final Supplier errorMessage, - final Class errorClazz) throws T { - - if (null == array || 0 == array.length) { - throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); - } - } // notEmpty. - - /** - * Assert notEmpty, throws RuntimeException if the array is null or empty (zero items). - * - *
DotAssert.notEmpty(array, ArrayEmptyException.class, ()->"Array is empty");
- * @param array Object array - * @param errorClazz Class of RuntimeException, pre: the RuntimeException must have a constructor that receives a string (the error message) - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - */ - public static void notEmpty(final Object[] array, - final Class errorClazz, - final Supplier errorMessage) { - - if (null == array || 0 == array.length) { - throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); - } - } // notEmpty. - - /// - - /** - * Assert notEmpty, throws IllegalArgumentException if the collection is null or empty (zero items). - * - *
DotAssert.notEmpty(list, "Collection is empty" );
- * @param collection Collection - * @param message String message to pass to the IllegalArgumentException - */ - public static void notEmpty(final Collection collection, - final String message) { - - if (null == collection || collection.isEmpty()) { - throw new IllegalArgumentException(message); - } - } // notEmpty. - - /** - * Assert notEmpty, throws IllegalArgumentException if the collection is null or empty (zero items). - * - *
DotAssert.notEmpty(list, ()->"Collection is empty" );
- * @param collection Collection - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - */ - public static void notEmpty(final Collection collection, - final Supplier errorMessage) { - - if (null == collection || collection.isEmpty()) { - throw new IllegalArgumentException(errorMessage.get()); - } - } // notEmpty. - - /** - * Assert notEmpty, throws Custom Throwable if the collection is null or empty (zero items). - * - *
DotAssert.notEmpty(list, ()->"Collection is empty"  );
- * @param collection Collection - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - * @param errorClazz Class of Throwable, pre: the Throwable must have a constructor that receives a string (the error message) - */ - public static void notEmpty(final Collection collection, final Supplier errorMessage, - final Class errorClazz) throws T { - - if (null == collection || collection.isEmpty()) { - throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); - } - } // notEmpty. - - /** - * Assert notEmpty, throws RuntimeException if the collection is null or empty (zero items). - * - *
DotAssert.notEmpty(list, CollectionEmptyException.class, ()->"Collection is empty");
- * @param collection Collection - * @param errorClazz Class of RuntimeException, pre: the RuntimeException must have a constructor that receives a string (the error message) - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - */ - public static void notEmpty(final Collection collection, - final Class errorClazz, - final Supplier errorMessage) { - - if (null == collection || collection.isEmpty()) { - throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); - } - } // notEmpty. - - - /// - - /** - * Assert notEmpty, throws IllegalArgumentException if the collection is null or empty (zero items). - * - *
DotAssert.notEmpty(list, "Collection is empty" );
- * @param collection Map - * @param message String message to pass to the IllegalArgumentException - */ - public static void notEmpty(final Map collection, - final String message) { - - if (null == collection || collection.isEmpty()) { - throw new IllegalArgumentException(message); - } - } // notEmpty. - - /** - * Assert notEmpty, throws IllegalArgumentException if the collection is null or empty (zero items). - * - *
DotAssert.notEmpty(list, ()->"Collection is empty" );
- * @param collection Map - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - */ - public static void notEmpty(final Map collection, - final Supplier errorMessage) { - - if (null == collection || collection.isEmpty()) { - throw new IllegalArgumentException(errorMessage.get()); - } - } // notEmpty. - - /** - * Assert notEmpty, throws Custom Throwable if the collection is null or empty (zero items). - * - *
DotAssert.notEmpty(list, ()->"Collection is empty"  );
- * @param collection Map - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - * @param errorClazz Class of Throwable, pre: the Throwable must have a constructor that receives a string (the error message) - */ - public static void notEmpty(final Map collection, final Supplier errorMessage, - final Class errorClazz) throws T { - - if (null == collection || collection.isEmpty()) { - throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); - } - } // notEmpty. - - /** - * Assert notEmpty, throws RuntimeException if the collection is null or empty (zero items). - * - *
DotAssert.notEmpty(list, CollectionEmptyException.class, ()->"Collection is empty");
- * @param collection Map - * @param errorClazz Class of RuntimeException, pre: the RuntimeException must have a constructor that receives a string (the error message) - * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) - */ - public static void notEmpty(final Map collection, - final Class errorClazz, - final Supplier errorMessage) { - - if (null == collection || collection.isEmpty()) { - throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); - } - } // notEmpty. -} // E:O:F:DotAssert. diff --git a/dotCMS/src/main/java/com/dotcms/util/DotPreconditions.java b/dotCMS/src/main/java/com/dotcms/util/DotPreconditions.java index 536d4bf9530b..9868b2369c21 100644 --- a/dotCMS/src/main/java/com/dotcms/util/DotPreconditions.java +++ b/dotCMS/src/main/java/com/dotcms/util/DotPreconditions.java @@ -4,6 +4,9 @@ import com.dotcms.repackage.org.apache.commons.lang.StringUtils; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.Map; +import java.util.function.Supplier; /** * Simple Precondition checks, wrapping Google's version. @@ -1175,4 +1178,386 @@ public static RuntimeException newException(String message, ClassDotAssert.isTrue(!contentletAPI.canLock(contentlet, user), "Can not lock the content" ); + * @param expression boolean expression to test + * @param errorMessage String message to pass to the IllegalArgumentException + * @throws IllegalArgumentException if expression is false + */ + public static void isTrue(final boolean expression, final String errorMessage) { + + if (!expression) { + throw new IllegalArgumentException(errorMessage); + } + } // isTrue. + + /** + * Assert true, throws IllegalArgumentException if the expression is false. + * + *
DotAssert.isTrue(contentletAPI.canLock(contentlet, user), ()->"Can not lock the content" );
+ * @param expression boolean expression to test + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + * @throws IllegalArgumentException if expression is false + */ + public static void isTrue(final boolean expression, final Supplier errorMessage) { + + if (!expression) { + throw new IllegalArgumentException(errorMessage.get()); + } + } // isTrue. + + /** + * Assert true, throws Custom Throwable if the expression is false. + * + *
DotAssert.isTrue(contentletAPI.canLock(contentlet, user), ()->"Can not lock the content", CannotLockContent.class );
+ * @param expression boolean expression to test + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + * @param errorClazz Class of Throwable, pre: the Throwable must have a constructor that receives a string (the error message) + * @throws IllegalArgumentException if expression is false + */ + public static void isTrue(final boolean expression, final Supplier errorMessage, + final Class errorClazz) throws T { + + if (!expression) { + throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); + } + } // isTrue. + + /** + * Assert true, throws RuntimeException if the expression is false. + * + *
DotAssert.isTrue(contentletAPI.canLock(contentlet, user), CannotLockContent.class, ()->"Can not lock the content");
+ * @param expression boolean expression to test + * @param errorClazz Class of RuntimeException, pre: the RuntimeException must have a constructor that receives a string (the error message) + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + * @throws IllegalArgumentException if expression is false + */ + public static void isTrue(final boolean expression, + final Class errorClazz, + final Supplier errorMessage) { + + if (!expression) { + throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); + } + } // isTrue. + + ////////// + // is NULL + + /** + * Assert isNull, throws IllegalArgumentException if the parameter is not null. + * + *
DotAssert.isNull(user, "User must be null" );
+ * @param parameter Object parameter to test if it is null + * @param errorMessage String message to pass to the IllegalArgumentException + * @throws IllegalArgumentException if expression is false + */ + public static void isNull(final Object parameter, final String errorMessage) { + + isTrue(null == parameter, errorMessage); + } // isNull. + + /** + * Assert isNull, throws IllegalArgumentException if the parameter is not null. + * + *
DotAssert.isNull(user, ()->"User must be null" );
+ * @param parameter Object parameter to test if it is null + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + * @throws IllegalArgumentException if expression is false + */ + public static void isNull(final Object parameter, final Supplier errorMessage) { + + isTrue(null == parameter, errorMessage); + } // isNull. + + /** + * Assert isNull, throws Custom Throwable if the parameter is not null. + * + *
DotAssert.isNull(user, ()->"User must be null", UserMustBeNullException.class );
+ * @param parameter Object parameter to test if it is null + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + * @param errorClazz Class of Throwable, pre: the Throwable must have a constructor that receives a string (the error message) + */ + public static void isNull(final Object parameter, final Supplier errorMessage, + final Class errorClazz) throws T { + + isTrue(null == parameter, errorMessage, errorClazz); + } // isNull. + + /** + * Assert isNull, throws RuntimeException if the parameter is not null. + * + *
DotAssert.isNull(user, UserMustBeNullException.class, ()->"User must be null");
+ * @param parameter Object parameter to test if it is null + * @param errorClazz Class of RuntimeException, pre: the RuntimeException must have a constructor that receives a string (the error message) + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + */ + public static void isNull(final Object parameter, + final Class errorClazz, + final Supplier errorMessage) { + + isTrue(null == parameter, errorClazz, errorMessage); + } // isNull. + + ////////// + // is NOT NULL + + /** + * Assert notNull, throws IllegalArgumentException if the parameter is null. + * + *
DotAssert.notNull(user, "User must be not null" );
+ * @param parameter Object parameter to test if it is not null + * @param errorMessage String message to pass to the IllegalArgumentException + * @throws IllegalArgumentException if expression is false + */ + public static void notNull(final Object parameter, final String errorMessage) { + + isTrue(null != parameter, errorMessage); + } // notNull. + + /** + * Assert notNull, throws IllegalArgumentException if the parameter is null. + * + *
DotAssert.notNull(user, ()->"User must be not null" );
+ * @param parameter Object parameter to test if it is not null + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + * @throws IllegalArgumentException if expression is false + */ + public static void notNull(final Object parameter, final Supplier errorMessage) { + + isTrue(null != parameter, errorMessage); + } // notNull. + + /** + * Assert notNull, throws Custom Throwable if the parameter is null. + * + *
DotAssert.notNull(user, ()->"User must be not null", UserMustBeNullException.class );
+ * @param parameter Object parameter to test if it is not null + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + * @param errorClazz Class of Throwable, pre: the Throwable must have a constructor that receives a string (the error message) + * @throws IllegalArgumentException if expression is false + */ + public static void notNull(final Object parameter, final Supplier errorMessage, + final Class errorClazz) throws T { + + isTrue(null != parameter, errorMessage, errorClazz); + } // notNull. + + /** + * Assert notNull, throws RuntimeException if the parameter is null. + * + *
DotAssert.notNull(user, UserMustBeNullException.class, ()->"User must be  notnull");
+ * @param parameter Object parameter to test if it is not null + * @param errorClazz Class of RuntimeException, pre: the RuntimeException must have a constructor that receives a string (the error message) + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + * @throws IllegalArgumentException if expression is false + */ + public static void notNull(final Object parameter, + final Class errorClazz, + final Supplier errorMessage) { + + isTrue(null != parameter, errorClazz, errorMessage); + } // notNull. + + + //////// + // NOT EMPTY + + /** + * Assert notEmpty, throws IllegalArgumentException if the array is null or empty (zero items). + * + *
DotAssert.notEmpty(array, "Array is empty" );
+ * @param array Object array + * @param message String message to pass to the IllegalArgumentException + */ + public static void notEmpty(final Object[] array, + final String message) { + + if (null == array || 0 == array.length) { + throw new IllegalArgumentException(message); + } + } // notEmpty. + + /** + * Assert notEmpty, throws IllegalArgumentException if the array is null or empty (zero items). + * + *
DotAssert.notEmpty(array, ()->"Array is empty" );
+ * @param array Object array + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + */ + public static void notEmpty(final Object[] array, + final Supplier errorMessage) { + + if (null == array || 0 == array.length) { + throw new IllegalArgumentException(errorMessage.get()); + } + } // notEmpty. + + /** + * Assert notEmpty, throws Custom Throwable if the array is null or empty (zero items). + * + *
DotAssert.notEmpty(array, ()->"Array is empty", ArrayEmptyException.class );
+ * @param array Object array + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + * @param errorClazz Class of Throwable, pre: the Throwable must have a constructor that receives a string (the error message) + */ + public static void notEmpty(final Object[] array, final Supplier errorMessage, + final Class errorClazz) throws T { + + if (null == array || 0 == array.length) { + throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); + } + } // notEmpty. + + /** + * Assert notEmpty, throws RuntimeException if the array is null or empty (zero items). + * + *
DotAssert.notEmpty(array, ArrayEmptyException.class, ()->"Array is empty");
+ * @param array Object array + * @param errorClazz Class of RuntimeException, pre: the RuntimeException must have a constructor that receives a string (the error message) + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + */ + public static void notEmpty(final Object[] array, + final Class errorClazz, + final Supplier errorMessage) { + + if (null == array || 0 == array.length) { + throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); + } + } // notEmpty. + + /// + + /** + * Assert notEmpty, throws IllegalArgumentException if the collection is null or empty (zero items). + * + *
DotAssert.notEmpty(list, "Collection is empty" );
+ * @param collection Collection + * @param message String message to pass to the IllegalArgumentException + */ + public static void notEmpty(final Collection collection, + final String message) { + + if (null == collection || collection.isEmpty()) { + throw new IllegalArgumentException(message); + } + } // notEmpty. + + /** + * Assert notEmpty, throws IllegalArgumentException if the collection is null or empty (zero items). + * + *
DotAssert.notEmpty(list, ()->"Collection is empty" );
+ * @param collection Collection + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + */ + public static void notEmpty(final Collection collection, + final Supplier errorMessage) { + + if (null == collection || collection.isEmpty()) { + throw new IllegalArgumentException(errorMessage.get()); + } + } // notEmpty. + + /** + * Assert notEmpty, throws Custom Throwable if the collection is null or empty (zero items). + * + *
DotAssert.notEmpty(list, ()->"Collection is empty"  );
+ * @param collection Collection + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + * @param errorClazz Class of Throwable, pre: the Throwable must have a constructor that receives a string (the error message) + */ + public static void notEmpty(final Collection collection, final Supplier errorMessage, + final Class errorClazz) throws T { + + if (null == collection || collection.isEmpty()) { + throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); + } + } // notEmpty. + + /** + * Assert notEmpty, throws RuntimeException if the collection is null or empty (zero items). + * + *
DotAssert.notEmpty(list, CollectionEmptyException.class, ()->"Collection is empty");
+ * @param collection Collection + * @param errorClazz Class of RuntimeException, pre: the RuntimeException must have a constructor that receives a string (the error message) + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + */ + public static void notEmpty(final Collection collection, + final Class errorClazz, + final Supplier errorMessage) { + + if (null == collection || collection.isEmpty()) { + throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); + } + } // notEmpty. + + + /// + + /** + * Assert notEmpty, throws IllegalArgumentException if the collection is null or empty (zero items). + * + *
DotAssert.notEmpty(list, "Collection is empty" );
+ * @param collection Map + * @param message String message to pass to the IllegalArgumentException + */ + public static void notEmpty(final Map collection, + final String message) { + + if (null == collection || collection.isEmpty()) { + throw new IllegalArgumentException(message); + } + } // notEmpty. + + /** + * Assert notEmpty, throws IllegalArgumentException if the collection is null or empty (zero items). + * + *
DotAssert.notEmpty(list, ()->"Collection is empty" );
+ * @param collection Map + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + */ + public static void notEmpty(final Map collection, + final Supplier errorMessage) { + + if (null == collection || collection.isEmpty()) { + throw new IllegalArgumentException(errorMessage.get()); + } + } // notEmpty. + + /** + * Assert notEmpty, throws Custom Throwable if the collection is null or empty (zero items). + * + *
DotAssert.notEmpty(list, ()->"Collection is empty"  );
+ * @param collection Map + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + * @param errorClazz Class of Throwable, pre: the Throwable must have a constructor that receives a string (the error message) + */ + public static void notEmpty(final Map collection, final Supplier errorMessage, + final Class errorClazz) throws T { + + if (null == collection || collection.isEmpty()) { + throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); + } + } // notEmpty. + + /** + * Assert notEmpty, throws RuntimeException if the collection is null or empty (zero items). + * + *
DotAssert.notEmpty(list, CollectionEmptyException.class, ()->"Collection is empty");
+ * @param collection Map + * @param errorClazz Class of RuntimeException, pre: the RuntimeException must have a constructor that receives a string (the error message) + * @param errorMessage Supplier String message to pass to the IllegalArgumentException (lazy mode) + */ + public static void notEmpty(final Map collection, + final Class errorClazz, + final Supplier errorMessage) { + + if (null == collection || collection.isEmpty()) { + throw ReflectionUtils.newInstance(errorClazz, errorMessage.get()); + } + } // notEmpty. + } diff --git a/dotCMS/src/main/java/com/dotcms/util/transform/TransformerLocator.java b/dotCMS/src/main/java/com/dotcms/util/transform/TransformerLocator.java index de35cec2b2b4..57867976ff77 100644 --- a/dotCMS/src/main/java/com/dotcms/util/transform/TransformerLocator.java +++ b/dotCMS/src/main/java/com/dotcms/util/transform/TransformerLocator.java @@ -6,6 +6,8 @@ import com.dotmarketing.beans.transform.TreeTransformer; import com.dotmarketing.portlets.containers.model.Container; import com.dotmarketing.portlets.containers.transform.ContainerTransformer; +import com.dotmarketing.portlets.contentlet.model.Contentlet; +import com.dotmarketing.portlets.contentlet.transform.ContentletTransformer; import com.dotmarketing.portlets.folders.model.Folder; import com.dotmarketing.portlets.folders.transform.TemplateTransformer; import com.dotmarketing.portlets.links.model.Link; @@ -43,6 +45,7 @@ private TransformerLocator() { transformerMapping.put (Link.class, TransformerLocator::createLinkTransformer); transformerMapping.put (Identifier.class, TransformerLocator::createIdentifierTransformer); transformerMapping.put (Tree.class, TransformerLocator::createTreeTransformer); + transformerMapping.put (Contentlet.class, TransformerLocator::createContentletTransformer); } public static DBTransformer createDBTransformer(List> list, Class clazz) { @@ -104,6 +107,17 @@ public static ContainerTransformer createContainerTransformer( return new ContainerTransformer(initList); } + /** + * Creates a DBTransformer for Contentlet objects + * @param initList List of DB results to be transformed + * @return + */ + public static ContentletTransformer createContentletTransformer( + List> initList) { + + return new ContentletTransformer(initList); + } + /** * Creates a DBTransformer for Link objects * @param initList List of DB results to be transformed diff --git a/dotCMS/src/main/java/com/dotcms/uuid/shorty/ShortyIdAPI.java b/dotCMS/src/main/java/com/dotcms/uuid/shorty/ShortyIdAPI.java index 9c216711fb5d..0110b109daef 100644 --- a/dotCMS/src/main/java/com/dotcms/uuid/shorty/ShortyIdAPI.java +++ b/dotCMS/src/main/java/com/dotcms/uuid/shorty/ShortyIdAPI.java @@ -19,4 +19,6 @@ default ShortyId noShorty(String shorty){ String shortify(String shorty); + String randomShorty(); + } diff --git a/dotCMS/src/main/java/com/dotcms/uuid/shorty/ShortyIdAPIImpl.java b/dotCMS/src/main/java/com/dotcms/uuid/shorty/ShortyIdAPIImpl.java index 9fdd1ca75824..d5851c57e301 100644 --- a/dotCMS/src/main/java/com/dotcms/uuid/shorty/ShortyIdAPIImpl.java +++ b/dotCMS/src/main/java/com/dotcms/uuid/shorty/ShortyIdAPIImpl.java @@ -10,6 +10,7 @@ import com.dotmarketing.portlets.contentlet.model.Contentlet; import com.dotmarketing.util.Config; import com.dotmarketing.util.Logger; +import com.dotmarketing.util.UUIDGenerator; import com.dotmarketing.util.UUIDUtil; public class ShortyIdAPIImpl implements ShortyIdAPI { @@ -50,7 +51,12 @@ public ShortyId noShorty(String shorty) { return new ShortyId(shorty, ShortType.CACHE_MISS.toString(), ShortType.CACHE_MISS, ShortType.CACHE_MISS); } - + + @Override + public String randomShorty() { + return shortify(UUIDGenerator.generateUuid()); + } + @Override public String shortify(final String shortStr) { try { @@ -129,6 +135,11 @@ private ShortyId viaDbLike(final String shorty) { } + + + + + private ShortyId transformMap(final String shorty, final List> results) { if (results == null || results.size() < 1) { return noShorty(shorty); diff --git a/dotCMS/src/main/java/com/dotcms/workflow/helper/WorkflowHelper.java b/dotCMS/src/main/java/com/dotcms/workflow/helper/WorkflowHelper.java index 1db2767ec1ce..1c935d38043e 100644 --- a/dotCMS/src/main/java/com/dotcms/workflow/helper/WorkflowHelper.java +++ b/dotCMS/src/main/java/com/dotcms/workflow/helper/WorkflowHelper.java @@ -302,6 +302,25 @@ public List findSchemesByContentType(final String contentTypeId, return schemes; } // findSchemesByContentType. + public void saveSchemesByContentType(final String contentTypeId, final User user, final List workflowIds) { + + final ContentTypeAPI contentTypeAPI = APILocator.getContentTypeAPI(user); + + try { + + Logger.debug(this, String.format("Saving the schemes: %s by content type: %s", + String.join(",", workflowIds), contentTypeId)); + + this.workflowAPI.saveSchemeIdsForContentType(contentTypeAPI.find(contentTypeId), workflowIds); + } catch (DotDataException | DotSecurityException e) { + + Logger.error(this, e.getMessage()); + Logger.debug(this, e.getMessage(), e); + throw new DotWorkflowException(e.getMessage(), e); + } + + } + /** * Finds the non-archived schemes * @return List diff --git a/dotCMS/src/main/java/com/dotmarketing/business/APILocator.java b/dotCMS/src/main/java/com/dotmarketing/business/APILocator.java index 3f8d94f292a0..957f65dbe9b9 100644 --- a/dotCMS/src/main/java/com/dotmarketing/business/APILocator.java +++ b/dotCMS/src/main/java/com/dotmarketing/business/APILocator.java @@ -61,6 +61,8 @@ import com.dotmarketing.common.business.journal.DistributedJournalAPIImpl; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotRuntimeException; +import com.dotmarketing.factories.MultiTreeAPI; +import com.dotmarketing.factories.MultiTreeAPIImpl; import com.dotmarketing.plugin.business.PluginAPI; import com.dotmarketing.plugin.business.PluginAPIImpl; import com.dotmarketing.portlets.calendar.business.CalendarReminderAPI; @@ -754,6 +756,10 @@ public static ContentTypeAPI getContentTypeAPI(User user, boolean respectFronten return getAPILocatorInstance().getContentTypeAPIImpl(user, respectFrontendRoles); } + public static MultiTreeAPI getMultiTreeAPI() { + return (MultiTreeAPI) getInstance( APIIndex.MULTI_TREE_API ); + } + @VisibleForTesting protected ContentTypeAPI getContentTypeAPIImpl(User user, boolean respectFrontendRoles) { return new ContentTypeAPIImpl(user, respectFrontendRoles); @@ -989,7 +995,8 @@ enum APIIndex KEY_VALUE_API, LOCAL_SYSTEM_EVENTS_API, LANGUAGE_VARIABLE_API, - VANITY_URLS_API; + VANITY_URLS_API, + MULTI_TREE_API; Object create() { switch(this) { @@ -1057,6 +1064,7 @@ Object create() { case KEY_VALUE_API: return new KeyValueAPIImpl(); case LANGUAGE_VARIABLE_API: return new LanguageVariableAPIImpl(); case LOCAL_SYSTEM_EVENTS_API: return LocalSystemEventsAPIFactory.getInstance().getLocalSystemEventsAPI(); + case MULTI_TREE_API: return new MultiTreeAPIImpl(); } throw new AssertionError("Unknown API index: " + this); } diff --git a/dotCMS/src/main/java/com/dotmarketing/business/PermissionBitFactoryImpl.java b/dotCMS/src/main/java/com/dotmarketing/business/PermissionBitFactoryImpl.java index d87a35722073..4fa3a991d6e9 100644 --- a/dotCMS/src/main/java/com/dotmarketing/business/PermissionBitFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotmarketing/business/PermissionBitFactoryImpl.java @@ -9,6 +9,7 @@ import com.dotcms.contenttype.transform.contenttype.StructureTransformer; import com.dotcms.rendering.velocity.viewtools.navigation.NavResult; +import com.dotcms.system.SimpleMapAppContext; import com.dotmarketing.beans.Host; import com.dotmarketing.beans.Identifier; import com.dotmarketing.beans.Inode; @@ -19,6 +20,9 @@ import com.dotmarketing.common.db.DotConnect; import com.dotmarketing.db.DbConnectionFactory; import com.dotmarketing.db.HibernateUtil; +import com.dotmarketing.db.commands.DatabaseCommand.QueryReplacements; +import com.dotmarketing.db.commands.UpsertCommand; +import com.dotmarketing.db.commands.UpsertCommandFactory; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotHibernateException; import com.dotmarketing.exception.DotRuntimeException; @@ -105,23 +109,6 @@ public class PermissionBitFactoryImpl extends PermissionFactory { private static final String LOAD_PERMISSION_REFERENCES_BY_REFERENCEID_HSQL = "from " + PermissionReference.class.getCanonicalName() + " permission_reference where reference_id = ?"; - /* - * To insert a single permission reference for an asset - * Parameters - * 1. Asset id - * 2. Reference id - * 3. Type - */ - - private static final String INSERT_PERMISSION_REFERENCE_SQL = - DbConnectionFactory.isMySql() || DbConnectionFactory.isMsSql() || DbConnectionFactory.isH2() ? - "insert into permission_reference (asset_id, reference_id, permission_type) " + - " values (?, ?, ?)": - DbConnectionFactory.isOracle() ? - "insert into permission_reference (id, asset_id, reference_id, permission_type) " + - " values (permission_reference_seq.NEXTVAL, ?, ?, ?)": - "insert into permission_reference (id, asset_id, reference_id, permission_type) " + - " values (nextval('permission_reference_seq'), ?, ?, ?)"; /* * To update a permission reference by who it is currently pointing to @@ -2268,6 +2255,13 @@ private List loadPermissions(Permissionable permissionable) throws D } + + protected static final String PERMISSION_REFERENCE = "permission_reference"; + protected static final String ASSET_ID = "asset_id"; + protected static final String REFERENCE_ID = "reference_id"; + protected static final String PERMISSION_TYPE = "permission_type"; + protected static final String ID = "id"; + @WrapInTransaction private void deleteInsertPermission(Permissionable permissionable, String type, Permissionable newReference) throws DotDataException { @@ -2290,7 +2284,7 @@ private void deleteInsertPermission(Permissionable permissionable, String type, if((inodeList != null && inodeList.size()>0) || (identifierList!=null && identifierList.size()>0)){ dc1.executeUpdate(DELETE_PERMISSIONABLE_REFERENCE_SQL, permissionId); - dc1.executeUpdate(INSERT_PERMISSION_REFERENCE_SQL, permissionId, newReference.getPermissionId(), type); + upsertPermission(dc1, permissionId, newReference, type); } } catch(Exception exception){ @@ -2310,6 +2304,37 @@ private void deleteInsertPermission(Permissionable permissionable, String type, } } + /** + * Method to Insert or Update a Permission Reference + * @param dc DotConnect + * @param permissionId the asset id to be inserted in the permission reference + * @param newReference the reference + * @param type the asset type + * @throws DotDataException + */ + private void upsertPermission(DotConnect dc, String permissionId, Permissionable newReference, String type) + throws DotDataException { + UpsertCommand upsertCommand = UpsertCommandFactory.getUpsertCommand(); + + SimpleMapAppContext replacements = new SimpleMapAppContext(); + replacements.setAttribute(QueryReplacements.TABLE, PERMISSION_REFERENCE); + replacements.setAttribute(QueryReplacements.CONDITIONAL_COLUMN, ASSET_ID); + replacements.setAttribute(QueryReplacements.CONDITIONAL_VALUE, permissionId); + replacements.setAttribute(QueryReplacements.EXTRA_COLUMNS, new String[]{REFERENCE_ID, PERMISSION_TYPE}); + + if (DbConnectionFactory.isPostgres()) { + replacements.setAttribute(QueryReplacements.ID_COLUMN, ID); + replacements.setAttribute(QueryReplacements.ID_VALUE, "nextval('permission_reference_seq')"); + } + if (DbConnectionFactory.isOracle()) { + replacements.setAttribute(QueryReplacements.ID_COLUMN, ID); + replacements.setAttribute(QueryReplacements.ID_VALUE, "permission_reference_seq.NEXTVAL"); + } + + String query = upsertCommand.generateSQLQuery(replacements); + upsertCommand.execute(dc, query, permissionId, newReference.getPermissionId(), type); + } + private List filterOnlyNonInheritablePermissions(List permissions, String permissionableId) { List filteredList = new ArrayList(); for(Permission p: permissions) { diff --git a/dotCMS/src/main/java/com/liferay/portlet/PortletUtil.java b/dotCMS/src/main/java/com/dotmarketing/business/ajax/DwrUtil.java similarity index 92% rename from dotCMS/src/main/java/com/liferay/portlet/PortletUtil.java rename to dotCMS/src/main/java/com/dotmarketing/business/ajax/DwrUtil.java index b57a6d09e10d..93297b0dc292 100644 --- a/dotCMS/src/main/java/com/liferay/portlet/PortletUtil.java +++ b/dotCMS/src/main/java/com/dotmarketing/business/ajax/DwrUtil.java @@ -1,4 +1,4 @@ -package com.liferay.portlet; +package com.dotmarketing.business.ajax; import com.dotcms.repackage.org.directwebremoting.WebContext; import com.dotcms.repackage.org.directwebremoting.WebContextFactory; @@ -6,7 +6,6 @@ import com.dotmarketing.business.web.WebAPILocator; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotSecurityException; -import com.dotmarketing.portlets.user.ajax.UserAjax; import com.dotmarketing.util.SecurityLogger; import com.liferay.portal.PortalException; import com.liferay.portal.SystemException; @@ -16,9 +15,9 @@ /** * @author Jonathan Gamba 11/29/17 */ -public class PortletUtil { +public class DwrUtil { - private PortletUtil() { + private DwrUtil() { throw new IllegalStateException("Utility class"); } @@ -64,7 +63,7 @@ public static void validatePortletPermissions(final String portletId, final User "User [%s] does not have access to the [%s] Portlet", loggedInUser.getEmailAddress(), portletId); - SecurityLogger.logInfo(PortletUtil.class, errorMessage); + SecurityLogger.logInfo(DwrUtil.class, errorMessage); throw new DotSecurityException(errorMessage); } } @@ -87,7 +86,7 @@ public static User getLoggedInUser() userId = loggedInUser.getUserId(); } if (loggedInUser == null) { - SecurityLogger.logInfo(UserAjax.class, + SecurityLogger.logInfo(DwrUtil.class, "unauthorized attempt to call getUserById by user " + userId + " from " + remoteIp); throw new DotSecurityException("not authorized"); diff --git a/dotCMS/src/main/java/com/dotmarketing/business/ajax/RoleAjax.java b/dotCMS/src/main/java/com/dotmarketing/business/ajax/RoleAjax.java index 84a54864c5a0..ff73f74f02e7 100644 --- a/dotCMS/src/main/java/com/dotmarketing/business/ajax/RoleAjax.java +++ b/dotCMS/src/main/java/com/dotmarketing/business/ajax/RoleAjax.java @@ -1,7 +1,7 @@ package com.dotmarketing.business.ajax; -import static com.liferay.portlet.PortletUtil.getLoggedInUser; -import static com.liferay.portlet.PortletUtil.validateRolesPortletPermissions; +import static com.dotmarketing.business.ajax.DwrUtil.getLoggedInUser; +import static com.dotmarketing.business.ajax.DwrUtil.validateRolesPortletPermissions; import com.dotcms.api.system.event.Payload; import com.dotcms.api.system.event.SystemEventType; diff --git a/dotCMS/src/main/java/com/dotmarketing/common/db/DotConnect.java b/dotCMS/src/main/java/com/dotmarketing/common/db/DotConnect.java index cf15278126f2..b8a65097589f 100644 --- a/dotCMS/src/main/java/com/dotmarketing/common/db/DotConnect.java +++ b/dotCMS/src/main/java/com/dotmarketing/common/db/DotConnect.java @@ -1096,11 +1096,25 @@ private void setParams(final PreparedStatement preparedStatement, * Executes an update operation for a preparedStatement, returns the number of affected rows. * If the connection is get from a transaction context, will used it. Otherwise will create and handle an atomic transaction. * @param preparedStatement String + * @param logException when an exception occurs, whether or not to log the exception as Error in log file * @param parameters Object array of parameters for the preparedStatement (if it does not have any, can be null). Not any checking of them * @return int rows affected * @throws DotDataException */ public int executeUpdate (final String preparedStatement, + final Object... parameters) throws DotDataException { + return executeUpdate(preparedStatement, true, parameters); + } + + /** + * Executes an update operation for a preparedStatement, returns the number of affected rows. + * If the connection is get from a transaction context, will used it. Otherwise will create and handle an atomic transaction. + * @param preparedStatement String + * @param parameters Object array of parameters for the preparedStatement (if it does not have any, can be null). Not any checking of them + * @return int rows affected + * @throws DotDataException + */ + public int executeUpdate (final String preparedStatement, Boolean logException, final Object... parameters) throws DotDataException { final boolean isNewTransaction = DbConnectionFactory.startTransactionIfNeeded(); @@ -1111,7 +1125,7 @@ public int executeUpdate (final String preparedStatement, connection = DbConnectionFactory.getConnection(); rowsAffected = this.executeUpdate(connection, - preparedStatement, parameters); + preparedStatement, logException, parameters); if (isNewTransaction) { connection.commit(); @@ -1124,7 +1138,9 @@ public int executeUpdate (final String preparedStatement, throw e; } catch (Exception e) { - Logger.error(DotConnect.class, e.getMessage(), e); + if (logException) { + Logger.error(DotConnect.class, e.getMessage(), e); + } throw new DotDataException(e.getMessage(), e); } finally { @@ -1157,6 +1173,20 @@ protected void rollback(final Connection connection) throws DotDataException { * @throws DotDataException */ public int executeUpdate (final Connection connection, final String preparedStatementString, + final Object... parameters) throws DotDataException { + return executeUpdate(connection, preparedStatementString, true, parameters); + } + + /** + * Executes an update operation for a preparedStatement + * @param connection {@link Connection} + * @param preparedStatementString String + * @param logException when an exception occurs, whether or not to log the exception as Error in log file + * @param parameters Object array of parameters for the preparedStatement (if it does not have any, can be null). Not any checking of them + * @return int rows affected + * @throws DotDataException + */ + public int executeUpdate (final Connection connection, final String preparedStatementString, Boolean logException, final Object... parameters) throws DotDataException { @@ -1169,8 +1199,9 @@ public int executeUpdate (final Connection connection, final String preparedStat this.setParams(preparedStatement, parameters); rowsAffected = preparedStatement.executeUpdate(); } catch (SQLException e) { - - Logger.error(DotConnect.class, e.getMessage(), e); + if (logException) { + Logger.error(DotConnect.class, e.getMessage(), e); + } throw new DotDataException(e.getMessage(), e); } finally { diff --git a/dotCMS/src/main/java/com/dotmarketing/common/util/SQLUtil.java b/dotCMS/src/main/java/com/dotmarketing/common/util/SQLUtil.java index ad4a2507b4e3..54629eb0ee15 100644 --- a/dotCMS/src/main/java/com/dotmarketing/common/util/SQLUtil.java +++ b/dotCMS/src/main/java/com/dotmarketing/common/util/SQLUtil.java @@ -7,12 +7,14 @@ import com.dotmarketing.business.APILocator; import com.dotmarketing.business.DotStateException; import com.dotmarketing.db.DbConnectionFactory; +import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotRuntimeException; import com.dotmarketing.util.Logger; import com.dotmarketing.util.SecurityLogger; import com.dotmarketing.util.UtilMethods; import com.liferay.util.StringPool; import com.liferay.util.StringUtil; +import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -37,6 +39,9 @@ public class SQLUtil { public static final String DESC = "desc"; public static final String _ASC = " " + ASC ; public static final String _DESC = " " + DESC; + public static final String PARAMETER = "?"; + + private static final String SQL_STATE_UNIQUE_CONSTRAINT = "23000"; private static final Set EVIL_SQL_CONDITION_WORDS = ImmutableSet.of( "insert", "delete", "update", "replace", "create", "drop", "alter", "truncate", "declare", "exec", "--", "procedure", "pg_", "lock", @@ -310,4 +315,11 @@ private static boolean isValidSQLCharacter (final char c) { return Character.isLetterOrDigit(c) || '-' == c || '_' == c; } // isValidSQLCharacter. + public static boolean isUniqueConstraintException (DotDataException ex) { + if (ex != null && ex.getCause() instanceof SQLException) { + return ((SQLException) ex.getCause()).getSQLState().equals(SQL_STATE_UNIQUE_CONSTRAINT); + } + return false; + } + } // E:O:F:SQLUtil. diff --git a/dotCMS/src/main/java/com/dotmarketing/db/DbType.java b/dotCMS/src/main/java/com/dotmarketing/db/DbType.java new file mode 100644 index 000000000000..bc78436e9aa2 --- /dev/null +++ b/dotCMS/src/main/java/com/dotmarketing/db/DbType.java @@ -0,0 +1,51 @@ +package com.dotmarketing.db; + +/** + * Enum for the Database Types available + * @author Andre Curione + */ +public enum DbType { + + MYSQL("MySQL"), + POSTGRESQL("PostgreSQL"), + ORACLE("Oracle"), + MSSQL("Microsoft SQL Server"), + H2("H2"); + + private String type; + + DbType(final String type) { + this.type = type; + } + + public String getDbType() { + return type; + } + + public static DbType getDbType(final String dbType) { + DbType type; + switch (dbType) { + case "PostgreSQL": + type = DbType.POSTGRESQL; + break; + case "MySQL": + type = DbType.MYSQL; + break; + case "Microsoft SQL Server": + type = DbType.MSSQL; + break; + case "Oracle": + type = DbType.ORACLE; + break; + default: + type = DbType.H2; + break; + } + return type; + } + + @Override + public String toString() { + return getDbType(); + } +} diff --git a/dotCMS/src/main/java/com/dotmarketing/db/commands/DatabaseCommand.java b/dotCMS/src/main/java/com/dotmarketing/db/commands/DatabaseCommand.java new file mode 100644 index 000000000000..634667ab514c --- /dev/null +++ b/dotCMS/src/main/java/com/dotmarketing/db/commands/DatabaseCommand.java @@ -0,0 +1,33 @@ +package com.dotmarketing.db.commands; + +import com.dotcms.system.SimpleMapAppContext; +import com.dotmarketing.common.db.DotConnect; +import com.dotmarketing.exception.DotDataException; + +/** + * Database Command Interface to Execute database queries + * @author Andre Curione + */ +public interface DatabaseCommand { + + enum QueryReplacements { + TABLE, + ID_COLUMN, + ID_VALUE, + CONDITIONAL_COLUMN, + CONDITIONAL_VALUE, + EXTRA_COLUMNS, + } + + /** + * Generates the Native SQL Query to be executed + * @return + */ + String generateSQLQuery (SimpleMapAppContext replacements); + + /** + * Execute the query + * @throws DotDataException + */ + void execute (DotConnect dotConnect, String query, Object... parameters) throws DotDataException; +} diff --git a/dotCMS/src/main/java/com/dotmarketing/db/commands/UpsertCommand.java b/dotCMS/src/main/java/com/dotmarketing/db/commands/UpsertCommand.java new file mode 100644 index 000000000000..cbe0ad402038 --- /dev/null +++ b/dotCMS/src/main/java/com/dotmarketing/db/commands/UpsertCommand.java @@ -0,0 +1,283 @@ +package com.dotmarketing.db.commands; + +import com.dotcms.system.SimpleMapAppContext; +import com.dotmarketing.common.db.DotConnect; +import com.dotmarketing.common.util.SQLUtil; +import com.dotmarketing.exception.DotDataException; +import com.liferay.util.StringUtil; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; + +/** + * Generic UpsertCommand that can be used to Generate and execute Native SQL Upsert Queries + * @author Andre Curione + */ +public abstract class UpsertCommand implements DatabaseCommand { + + /** + * Method to execute The Upsert Query... This method works for most DBTypes, + * and its overriden for DBTypes with particularities + * @param dotConnect Connection + * @param query SQL String to be executed + * @param parameters or values + * @throws DotDataException + */ + public void execute(DotConnect dotConnect, String query, Object... parameters) + throws DotDataException { + DotConnect dc = (dotConnect != null) ? dotConnect : new DotConnect(); + ArrayList params = new ArrayList<>(); + Collections.addAll(params, parameters); //Update parameters + Collections.addAll(params, parameters); //Insert parameters + dc.executeUpdate(query, params.toArray()); + } + + // Misc Methods: + /** + * Generates the Update statement query part, with the format: + * column = ?, column = ?, etc. + */ + protected String getUpdateColumnValuePairs(SimpleMapAppContext replacements) { + StringBuilder builder = new StringBuilder(); + if (replacements.getAttribute(QueryReplacements.ID_COLUMN) != null) { + builder.append(replacements.getAttribute(QueryReplacements.ID_COLUMN).toString()); + builder.append("="); + builder.append(replacements.getAttribute(QueryReplacements.ID_VALUE).toString()); + builder.append(","); + } + if (replacements.getAttribute(QueryReplacements.CONDITIONAL_COLUMN) != null + && !(this instanceof OracleUpsertCommand)) { //Oracle does not allow to Update the Conditional Column + builder.append(replacements.getAttribute(QueryReplacements.CONDITIONAL_COLUMN).toString()); + builder.append("=?,"); + } + if (replacements.getAttribute(QueryReplacements.EXTRA_COLUMNS) != null) { + String[] extraColumns = replacements.getAttribute(QueryReplacements.EXTRA_COLUMNS); + for (String column : extraColumns) { + builder.append(column); + builder.append("=?,"); + } + } + String update = builder.toString(); + if (update.endsWith(",")) { + update = update.substring(0, update.length() - 1); + } + return update; + } + + /** + * Generates the Insert Columns string, in comma separated format + * @param replacements + * @return + */ + protected String getInsertColumnsString (SimpleMapAppContext replacements) { + ArrayList columns = new ArrayList<>(); + if (replacements.getAttribute(QueryReplacements.ID_COLUMN) != null) { + columns.add(replacements.getAttribute(QueryReplacements.ID_COLUMN)); + } + if (replacements.getAttribute(QueryReplacements.CONDITIONAL_COLUMN) != null) { + columns.add(replacements.getAttribute(QueryReplacements.CONDITIONAL_COLUMN)); + } + if (replacements.getAttribute(QueryReplacements.EXTRA_COLUMNS) != null) { + columns.addAll(Arrays.asList(replacements.getAttribute(QueryReplacements.EXTRA_COLUMNS))); + } + return StringUtil.merge(columns.toArray(new String[0])); + } + + /** + * Generates the Insert Values parameter string, in comma separated format + * @param replacements + * @return + */ + protected String getInsertValuesString(SimpleMapAppContext replacements) { + ArrayList values = new ArrayList<>(); + if (replacements.getAttribute(QueryReplacements.ID_COLUMN) != null) { + values.add(replacements.getAttribute(QueryReplacements.ID_VALUE)); + } + if (replacements.getAttribute(QueryReplacements.CONDITIONAL_COLUMN) != null) { + values.add(SQLUtil.PARAMETER); + } + if (replacements.getAttribute(QueryReplacements.EXTRA_COLUMNS) != null) { + String[] extraColumns = replacements.getAttribute(QueryReplacements.EXTRA_COLUMNS); + for (int i=0; i params = new ArrayList<>(); + + //Update parameters, skip the Conditional parameter (assumed first) because Oracle cannot Update the conditional column + for (int i=1; i< parameters.length; i++) { + params.add(parameters[i]); + } + //Insert parameters + Collections.addAll(params, parameters); + + try { + //In Oracle the Upsert (Merge) is not thread safe. Attempt to insert first: + dc.executeUpdate(query, false, params.toArray()); + + } catch (DotDataException ex) { + if (SQLUtil.isUniqueConstraintException(ex)) { + //On Unique constraint exception, attempt again... to update: + dc.executeUpdate(query, params.toArray()); + } else { + throw ex; + } + } + } +} \ No newline at end of file diff --git a/dotCMS/src/main/java/com/dotmarketing/db/commands/UpsertCommandFactory.java b/dotCMS/src/main/java/com/dotmarketing/db/commands/UpsertCommandFactory.java new file mode 100644 index 000000000000..f74b9198f704 --- /dev/null +++ b/dotCMS/src/main/java/com/dotmarketing/db/commands/UpsertCommandFactory.java @@ -0,0 +1,33 @@ +package com.dotmarketing.db.commands; + +import com.dotmarketing.db.DbConnectionFactory; +import com.dotmarketing.db.DbType; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Factory class for the UpsertCommand + * @author andrecurione + */ +public class UpsertCommandFactory { + + /** + * Map that contains Upsert Command implementations + */ + private static Map commandMap = new ConcurrentHashMap<>(); + + static { + commandMap.put(DbType.H2, new H2UpsertCommand()); + commandMap.put(DbType.POSTGRESQL, new PostgreUpsertCommand()); + commandMap.put(DbType.MYSQL, new MySQLUpsertCommand()); + commandMap.put(DbType.MSSQL, new MSSQLUpsertCommand()); + commandMap.put(DbType.ORACLE, new OracleUpsertCommand()); + } + + //Hide the constructor + private UpsertCommandFactory() { } + + public static UpsertCommand getUpsertCommand() { + return commandMap.get(DbType.getDbType(DbConnectionFactory.getDBType())); + } +} diff --git a/dotCMS/src/main/java/com/dotmarketing/factories/EmailFactory.java b/dotCMS/src/main/java/com/dotmarketing/factories/EmailFactory.java index c8b0d506a311..fdf7dd2bb7aa 100644 --- a/dotCMS/src/main/java/com/dotmarketing/factories/EmailFactory.java +++ b/dotCMS/src/main/java/com/dotmarketing/factories/EmailFactory.java @@ -1,5 +1,6 @@ package com.dotmarketing.factories; +import com.dotcms.rendering.velocity.services.VelocityType; import com.dotcms.repackage.org.apache.commons.beanutils.BeanUtils; import com.dotmarketing.beans.Host; import com.dotmarketing.beans.Identifier; @@ -227,7 +228,9 @@ public static boolean sendForgotPassword(User user, String newPassword, String h try { String message = ""; try { - Template t = UtilMethods.getVelocityTemplate( PageMode.LIVE.name() +"/"+ idInode+ languageStr + "."+ Config.getStringProperty("VELOCITY_HTMLPAGE_EXTENSION")); + Template t = UtilMethods.getVelocityTemplate( + PageMode.LIVE.name() + File.separator + idInode + languageStr + "." + + VelocityType.HTMLPAGE.fileExtension); t.merge(context, writer); Logger .debug(EmailFactory.class, "writer:" @@ -588,7 +591,9 @@ public static Map buildEmail(String templatePath, Host host, Map try { if(InodeUtils.isSet(idInode)) { - t = UtilMethods.getVelocityTemplate(PageMode.LIVE.name() +File.separator+ idInode + languageStr + "."+ Config.getStringProperty("VELOCITY_HTMLPAGE_EXTENSION")); + t = UtilMethods.getVelocityTemplate( + PageMode.LIVE.name() + File.separator + idInode + languageStr + "." + + VelocityType.HTMLPAGE.fileExtension); } else { t = UtilMethods.getVelocityTemplate(templatePath); } diff --git a/dotCMS/src/main/java/com/dotmarketing/factories/MultiTreeAPI.java b/dotCMS/src/main/java/com/dotmarketing/factories/MultiTreeAPI.java index eca795473dd4..219729b1b3b8 100644 --- a/dotCMS/src/main/java/com/dotmarketing/factories/MultiTreeAPI.java +++ b/dotCMS/src/main/java/com/dotmarketing/factories/MultiTreeAPI.java @@ -1,84 +1,22 @@ package com.dotmarketing.factories; import com.dotmarketing.beans.MultiTree; -import com.dotmarketing.business.APILocator; -import com.dotmarketing.business.DotStateException; -import com.dotmarketing.business.VersionableAPI; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotSecurityException; -import com.dotmarketing.portlets.containers.model.Container; -import com.dotmarketing.portlets.contentlet.business.ContentletAPI; -import com.dotmarketing.portlets.contentlet.model.Contentlet; -import com.dotmarketing.portlets.htmlpageasset.model.HTMLPageAsset; import com.dotmarketing.portlets.htmlpageasset.model.IHTMLPage; -import com.dotmarketing.portlets.templates.model.Template; -import com.dotmarketing.util.Logger; +import com.google.common.collect.Table; -import java.util.ArrayList; -import java.util.LinkedHashSet; import java.util.List; import java.util.Set; -import com.google.common.collect.HashBasedTable; -import com.google.common.collect.Table; -import com.liferay.portal.model.User; - -public class MultiTreeAPI { - - VersionableAPI vers = APILocator.getVersionableAPI(); - ContentletAPI conAPI = APILocator.getContentletAPI(); - User sys = APILocator.systemUser(); - - - - public Table> getPageMultiTrees(final IHTMLPage page, final boolean liveMode) throws DotDataException, DotSecurityException { - - Table> pageContents = HashBasedTable.create(); - List multis = MultiTreeFactory.getMultiTrees(page.getIdentifier()); - for (MultiTree t : multis) { - Container container = (liveMode) ? (Container) vers.findLiveVersion(t.getContainer(), sys, false) - : (Container) vers.findWorkingVersion(t.getContainer(), sys, false); - if(container==null && ! liveMode) { - // MultiTreeFactory.deleteMultiTree(t); - continue; - } - Contentlet contentlet = null; - try { - contentlet = conAPI.findContentletByIdentifier(t.getContentlet(), liveMode, -1, sys, false); - }catch(Exception e){ - Logger.warn(this.getClass(), "invalid contentlet on multitree:" + t); - } - if(contentlet==null ) { - // MultiTreeFactory.deleteMultiTree(t); - continue; - }; - Set myContents = pageContents.contains(t.getContainer(), t.getRelationType()) - ? pageContents.get(t.getContainer(), t.getRelationType()) - : new LinkedHashSet<>(); - if(myContents.size()< container.getMaxContentlets()) { - myContents.add(t.getContentlet()); - } - else { - // MultiTreeFactory.deleteMultiTree(t); - } +/** + * API for {@link com.dotmarketing.beans.MultiTree} + */ +public interface MultiTreeAPI { + void saveMultiTrees(String pageId, List mTrees) throws DotDataException; - pageContents.put(t.getContainer(), t.getRelationType(), myContents); + void saveMultiTree(MultiTree multiTree) throws DotDataException; - } - - return pageContents; - } - - - - - - - - - - - - - + Table> getPageMultiTrees(final IHTMLPage page, final boolean liveMode) + throws DotDataException, DotSecurityException; } diff --git a/dotCMS/src/main/java/com/dotmarketing/factories/MultiTreeAPIImpl.java b/dotCMS/src/main/java/com/dotmarketing/factories/MultiTreeAPIImpl.java new file mode 100644 index 000000000000..64fc3598d3b8 --- /dev/null +++ b/dotCMS/src/main/java/com/dotmarketing/factories/MultiTreeAPIImpl.java @@ -0,0 +1,89 @@ +package com.dotmarketing.factories; + +import com.dotmarketing.beans.MultiTree; +import com.dotmarketing.business.APILocator; +import com.dotmarketing.business.VersionableAPI; +import com.dotmarketing.exception.DotDataException; +import com.dotmarketing.exception.DotSecurityException; +import com.dotmarketing.portlets.containers.model.Container; +import com.dotmarketing.portlets.contentlet.business.ContentletAPI; +import com.dotmarketing.portlets.contentlet.business.DotContentletStateException; +import com.dotmarketing.portlets.contentlet.model.Contentlet; +import com.dotmarketing.portlets.htmlpageasset.model.IHTMLPage; +import com.dotmarketing.util.Logger; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Table; +import com.liferay.portal.model.User; + +public class MultiTreeAPIImpl implements MultiTreeAPI { + + final VersionableAPI versionableAPI = APILocator.getVersionableAPI(); + final ContentletAPI contentletAPI = APILocator.getContentletAPI(); + final User systemUser = APILocator.systemUser(); + + + public void saveMultiTrees(final String pageId, final List multiTrees) throws DotDataException { + Logger.info(this, String.format("Saving MutiTrees: pageId -> %s multiTrees-> %s", pageId, multiTrees)); + MultiTreeFactory.saveMultiTrees(pageId, multiTrees); + } + + public void saveMultiTree(final MultiTree multiTree) throws DotDataException { + Logger.info(this, String.format("Saving MutiTree: %s", multiTree)); + MultiTreeFactory.saveMultiTree(multiTree); + } + + public Table> getPageMultiTrees(final IHTMLPage page, final boolean liveMode) + throws DotDataException, DotSecurityException { + + final Table> pageContents = HashBasedTable.create(); + final List multiTres = MultiTreeFactory.getMultiTrees(page.getIdentifier()); + + for (final MultiTree multiTree : multiTres) { + final Container container = (liveMode) ? (Container) versionableAPI.findLiveVersion(multiTree.getContainer(), + systemUser, false) + : (Container) versionableAPI.findWorkingVersion(multiTree.getContainer(), systemUser, false); + if(container==null && ! liveMode) { + continue; + } + + Contentlet contentlet = null; + try { + contentlet = contentletAPI.findContentletByIdentifier(multiTree.getContentlet(), liveMode, -1, + systemUser, false); + }catch(DotDataException | DotSecurityException | DotContentletStateException e){ + Logger.warn(this.getClass(), "invalid contentlet on multitree:" + multiTree); + } + if(contentlet!=null ) { + final Set myContents = pageContents.contains(multiTree.getContainer(), multiTree.getRelationType()) + ? pageContents.get(multiTree.getContainer(), multiTree.getRelationType()) + : new LinkedHashSet<>(); + if(container != null && myContents.size() < container.getMaxContentlets()) { + myContents.add(multiTree.getContentlet()); + } + + pageContents.put(multiTree.getContainer(), multiTree.getRelationType(), myContents); + }; + + } + + return pageContents; + } + + + + + + + + + + + + + +} diff --git a/dotCMS/src/main/java/com/dotmarketing/factories/MultiTreeFactory.java b/dotCMS/src/main/java/com/dotmarketing/factories/MultiTreeFactory.java index 896838775944..eb7f312a5754 100644 --- a/dotCMS/src/main/java/com/dotmarketing/factories/MultiTreeFactory.java +++ b/dotCMS/src/main/java/com/dotmarketing/factories/MultiTreeFactory.java @@ -9,6 +9,7 @@ import com.dotmarketing.business.APILocator; import com.dotmarketing.business.DotStateException; import com.dotmarketing.common.db.DotConnect; +import com.dotmarketing.common.db.Params; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotRuntimeException; import com.dotmarketing.exception.DotSecurityException; @@ -28,6 +29,8 @@ import com.google.common.collect.Lists; +import static com.dotcms.util.CollectionsUtils.list; + /** * This class provides utility routines to interact with the Multi-Tree structures in the system. A * Multi-Tree represents the relationship between a Legacy or Content Page, a container, and a @@ -43,18 +46,19 @@ public class MultiTreeFactory { - final static String DELETE_SQL = "delete from multi_tree where parent1=? and parent2=? and child=? and relation_type = ?"; - final static String SELECT_SQL = + static final String DELETE_SQL = "delete from multi_tree where parent1=? and parent2=? and child=? and relation_type = ?"; + static final String DELETE_ALL_MULTI_TREE_SQL = "delete from multi_tree where parent1=?"; + static final String SELECT_SQL = "select * from multi_tree where parent1 = ? and parent2 = ? and child = ? and relation_type = ?"; - final static String INSERT_SQL = + static final String INSERT_SQL = "insert into multi_tree (parent1, parent2, child, relation_type, tree_order ) values (?,?,?,?,?) "; - final static String SELECT_BY_ONE_PARENT = "select * from multi_tree where parent1 = ? or parent2 = ? "; - final static String SELECT_BY_TWO_PARENTS = "select * from multi_tree where parent1 = ? and parent2 = ? order by tree_order"; - final static String SELECT_ALL = "select * from multi_tree "; - final static String SELECT_BY_CHILD = "select * from multi_tree where child = ? order by parent1, parent2, relation_type "; - final static String SELECT_BY_PARENTS_AND_RELATIONS = + static final String SELECT_BY_ONE_PARENT = "select * from multi_tree where parent1 = ? or parent2 = ? "; + static final String SELECT_BY_TWO_PARENTS = "select * from multi_tree where parent1 = ? and parent2 = ? order by tree_order"; + static final String SELECT_ALL = "select * from multi_tree "; + static final String SELECT_BY_CHILD = "select * from multi_tree where child = ? order by parent1, parent2, relation_type "; + static final String SELECT_BY_PARENTS_AND_RELATIONS = " select * from multi_tree where parent1 = ? and parent2 = ? and relation_type = ? order by tree_order"; @@ -246,7 +250,7 @@ public static void saveMultiTree(MultiTree mTree) throws DotDataException { * @throws DotSecurityException */ @WrapInTransaction - public static void saveMultiTrees(List mTrees) throws DotDataException { + public static void saveMultiTrees(final List mTrees) throws DotDataException { if (mTrees == null || mTrees.isEmpty()) throw new DotDataException("empty list passed in"); int i = 0; @@ -254,13 +258,44 @@ public static void saveMultiTrees(List mTrees) throws DotDataExceptio _dbUpsert(tree.setTreeOrder(i++)); } - MultiTree mTree = mTrees.get(0); + final MultiTree mTree = mTrees.get(0); updateHTMLPageVersionTS(mTree.getHtmlPage()); refreshPageInCache(mTree.getHtmlPage()); } + /** + * Save a collection of {@link MultiTree} and link them with a page, Also delete all the {@link MultiTree} linked + * previously with the page. + * + * @param pageId Page's identifier + * @param mTrees + * @throws DotDataException + */ + @WrapInTransaction + public static void saveMultiTrees(final String pageId, final List mTrees) throws DotDataException { + if (mTrees == null || mTrees.isEmpty()) { + throw new DotDataException("empty list passed in"); + } + + Logger.debug(MultiTreeFactory.class, String.format("Saving page's content: %s", mTrees)); + final DotConnect db = new DotConnect().setSQL(DELETE_ALL_MULTI_TREE_SQL) + .addParam(pageId); + db.loadResult(); + + final List params = list(); + for (final MultiTree tree : mTrees) { + params.add(new Params(pageId, tree.getContainer(), tree.getContentlet(), tree.getRelationType(), tree.getTreeOrder())); + } + + db.executeBatch(INSERT_SQL, params); + + final MultiTree mTree = mTrees.get(0); + updateHTMLPageVersionTS(mTree.getHtmlPage()); + refreshPageInCache(mTree.getHtmlPage()); + + } private static void _dbUpsert(final MultiTree mtree) throws DotDataException { diff --git a/dotCMS/src/main/java/com/dotmarketing/filters/CMSFilter.java b/dotCMS/src/main/java/com/dotmarketing/filters/CMSFilter.java index df51a780acba..cd03d801b89e 100644 --- a/dotCMS/src/main/java/com/dotmarketing/filters/CMSFilter.java +++ b/dotCMS/src/main/java/com/dotmarketing/filters/CMSFilter.java @@ -131,7 +131,24 @@ private void doFilterInternal(ServletRequest req, ServletResponse res, FilterCha } } - else if (iAm == IAm.FILE) { + if (iAm == IAm.PAGE) { + countPageVisit(request); + countSiteVisit(request, response); + request.setAttribute(Constants.CMS_FILTER_URI_OVERRIDE, + this.urlUtil.getUriWithoutQueryString(uri)); + queryString = (null == queryString)? + this.urlUtil.getQueryStringFromUri (uri):queryString; + } + + // run rules engine for all requests + RulesEngine.fireRules(request, response, Rule.FireOn.EVERY_REQUEST); + + //if we have committed the response, die + if (response.isCommitted()) { + return; + } + + if (iAm == IAm.FILE) { Identifier ident; try { // Serving the file through the /dotAsset servlet @@ -155,18 +172,6 @@ else if (iAm == IAm.FILE) { if (iAm == IAm.PAGE) { - countPageVisit(request); - countSiteVisit(request, response); - request.setAttribute(Constants.CMS_FILTER_URI_OVERRIDE, this.urlUtil.getUriWithoutQueryString(uri)); - - // run rules engine for all requests - RulesEngine.fireRules(request, response, Rule.FireOn.EVERY_REQUEST); - - // if we have committed the response, die - if (response.isCommitted()) { - return; - } - // Serving a page through the velocity servlet StringWriter forward = new StringWriter().append("/servlets/VelocityServlet"); diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/cmsmaintenance/util/AssetFileNameFilter.java b/dotCMS/src/main/java/com/dotmarketing/portlets/cmsmaintenance/util/AssetFileNameFilter.java index 8f4bba954f38..6517430b4216 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/cmsmaintenance/util/AssetFileNameFilter.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/cmsmaintenance/util/AssetFileNameFilter.java @@ -1,62 +1,55 @@ package com.dotmarketing.portlets.cmsmaintenance.util; +import com.google.common.collect.ImmutableSet; import java.io.File; import java.io.FileFilter; import com.dotmarketing.util.Config; import com.dotmarketing.util.Logger; import com.liferay.util.FileUtil; +import java.util.Set; public class AssetFileNameFilter implements FileFilter { + private static final Set EXCLUDE_FOLDERS_LIST = ImmutableSet + .of("license", "bundles", "tmp_upload", + "timemachine", "integrity", "server", "dotGenerated"); + @Override public boolean accept(File dir) { if(dir ==null){ return false; } - if(dir.getAbsolutePath().contains("dotGenerated") ){ return false; } + String name = dir.getName(); - String osname = System.getProperty("os.name"); - String[] path = null; + final String osName = System.getProperty("os.name"); - if (osname.startsWith("Windows")) + String[] path; + + if (osName.startsWith("Windows")) { path = dir.getAbsolutePath().split("\\\\"); - else + } + else { path = dir.getAbsolutePath().split(File.separator); - + } String[] test = new String[0]; - String assetPath=null; + + String assetPath; + try { assetPath = Config.getStringProperty("ASSET_REAL_PATH", FileUtil.getRealPath(Config.getStringProperty("ASSET_PATH"))); test = new File(assetPath).getAbsolutePath().split(File.separator); } catch (Exception e) { Logger.debug(this.getClass(), e.getMessage()); } - if(test.length +1 == path.length){ - - if( "license".equals(name)){ - return false; - } - else if( "bundles".equals(name)){ - return false; - } - else if( "tmp_upload".equals(name)){ - return false; - } - else if( name.startsWith(".")){ - return false; - } - else if(name.equals("timemachine")) { - return false; - } - } - return true; + return test.length + 1 != path.length || (name.charAt(0) != '.' && !EXCLUDE_FOLDERS_LIST.contains(name)); + } } diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/model/Contentlet.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/model/Contentlet.java index 37672f65937a..0f0f45be2b67 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/model/Contentlet.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/model/Contentlet.java @@ -72,6 +72,11 @@ public class Contentlet implements Serializable, Permissionable, Categorizable, public static final String DONT_VALIDATE_ME = "_dont_validate_me"; public static final String DISABLE_WORKFLOW = "__disable_workflow__"; + /** + * Flag to avoid to trigger the workflow again on the checkin when it is already in progress. + */ + public static final String WORKFLOW_IN_PROGRESS = "__workflow_in_progress__"; + public static final String WORKFLOW_PUBLISH_DATE = "wfPublishDate"; public static final String WORKFLOW_PUBLISH_TIME = "wfPublishTime"; public static final String WORKFLOW_EXPIRE_DATE = "wfExpireDate"; @@ -948,6 +953,24 @@ public boolean isHost() { return getStructure().getInode().equals(hostStructure.getInode()); } + /** + * If the inode is set, means it has at least one version + * @return boolean true if has a version + */ + public boolean hasVersion () { + + return InodeUtils.isSet(this.getInode()); + } + + /** + * If does not has a version, means is new. + * @return boolean true if it is new + */ + public boolean isNew () { + + return !this.hasVersion(); + } + /** * * @return diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java new file mode 100644 index 000000000000..30b9b648c3b3 --- /dev/null +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java @@ -0,0 +1,78 @@ +package com.dotmarketing.portlets.contentlet.transform; + +import com.dotcms.util.ConversionUtils; +import com.dotcms.util.transform.DBTransformer; +import com.dotmarketing.portlets.contentlet.model.Contentlet; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import org.jetbrains.annotations.NotNull; + +/** + * DBTransformer that converts DB objects into Contentlet instances + */ +public class ContentletTransformer implements DBTransformer { + final List list; + + + public ContentletTransformer(final List> initList){ + final List newList = new ArrayList<>(); + if (initList != null){ + for(final Map map : initList){ + newList.add(transform(map)); + } + } + + this.list = newList; + } + + @Override + public List asList() { + return this.list; + } + + @NotNull + private static Contentlet transform(final Map map) { + final Contentlet contentlet; + contentlet = new Contentlet(); + contentlet.setInode((String) map.get("inode")); + contentlet.setModDate((Date) map.get("mod_date")); + contentlet.setModUser((String) map.get("mod_user")); + contentlet.setSortOrder(ConversionUtils.toInt(map.get("sort_order"),0)); + contentlet.setContentTypeId((String) map.get("structure_inode")); + contentlet.setLastReview((Date) map.get("last_review")); + contentlet.setNextReview((Date) map.get("next_review")); + contentlet.setReviewInterval((String) map.get("review_interval")); + + final List disabledWysiwyg = new ArrayList(); + disabledWysiwyg.add(map.get("disabled_wysiwyg")); + contentlet.setDisabledWysiwyg(disabledWysiwyg); + contentlet.setIdentifier((String) map.get("identifier")); + contentlet.setLanguageId((Long) map.get("language_id")); + + String key; + List ignoredFields = new ArrayList<>(); + ignoredFields.add("inode"); + ignoredFields.add("mod_date"); + ignoredFields.add("mod_user"); + ignoredFields.add("sort_order"); + ignoredFields.add("structure_inode"); + ignoredFields.add("last_review"); + ignoredFields.add("next_review"); + ignoredFields.add("review_interval"); + ignoredFields.add("disabled_wysiwyg"); + + for (Entry property: map.entrySet()){ + + key = property.getKey(); + if (!ignoredFields.contains(key)) { + contentlet.setProperty(property.getKey(), property.getValue()); + } + + } + return contentlet; + } +} + diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/fileassets/business/FileAsset.java b/dotCMS/src/main/java/com/dotmarketing/portlets/fileassets/business/FileAsset.java index 775599f2b281..3def903baba3 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/fileassets/business/FileAsset.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/fileassets/business/FileAsset.java @@ -166,7 +166,7 @@ public String getURI(Folder folder) { } public boolean isShowOnMenu() { - String isShowOnMenu = super.getStringProperty("showOnMenu");//DOTCMS-6968 + String isShowOnMenu = super.getStringProperty(FileAssetAPI.SHOW_ON_MENU);//DOTCMS-6968 if(UtilMethods.isSet(isShowOnMenu) && isShowOnMenu.contains("true")){ return true; }else{ @@ -175,7 +175,7 @@ public boolean isShowOnMenu() { } public void setShowOnMenu(boolean showOnMenu) { - super.setStringProperty("showOnMenu", Boolean.toString(showOnMenu)); + super.setStringProperty(FileAssetAPI.SHOW_ON_MENU, Boolean.toString(showOnMenu)); } @@ -184,13 +184,13 @@ public void setSortOrder(int sortOrder) { } - public void setTitle(String title) { - super.setStringProperty(title, title); + public void setTitle(final String title) { + super.setStringProperty(FileAssetAPI.TITLE_FIELD, title); } public String getFriendlyName() { - return super.getStringProperty("title"); + return super.getStringProperty(FileAssetAPI.TITLE_FIELD); } public void setFriendlyName(String friendlyName) { @@ -263,7 +263,7 @@ public Map getMap() throws DotRuntimeException { User modUser = null; try { modUser = APILocator.getUserAPI().loadUserById(this.getModUser(),APILocator.getUserAPI().getSystemUser(),false); - } catch (NoSuchUserException e) { + } catch (NoSuchUserException | DotDataException e) { Logger.debug(this, e.getMessage()); } catch (Exception e) { Logger.error(this, e.getMessage(), e); diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/folders/business/FolderAPI.java b/dotCMS/src/main/java/com/dotmarketing/portlets/folders/business/FolderAPI.java index 525c0f524118..8154d737bbb5 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/folders/business/FolderAPI.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/folders/business/FolderAPI.java @@ -235,13 +235,10 @@ public List getLinks ( Host host, boolean working, boolean deleted, User u /** * Gets a list of 'working' Contentlet under given folder * - * @param parent - * @param user - * @param respectFrontEndPermissions - * @return - * @throws DotStateException - * @throws DotDataException + * @deprecated use {@link com.dotmarketing.portlets.contentlet.business.ContentletAPI#findContentletsByFolder(Folder, + * User, boolean)} instead */ + @Deprecated public abstract List getContent(Folder parent, User user, boolean respectFrontEndPermissions) throws DotStateException, DotDataException, DotSecurityException; diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/folders/business/FolderFactoryImpl.java b/dotCMS/src/main/java/com/dotmarketing/portlets/folders/business/FolderFactoryImpl.java index 45174af6afae..3a654697486a 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/folders/business/FolderFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/folders/business/FolderFactoryImpl.java @@ -100,9 +100,9 @@ protected Folder find(String folderInode) throws DotDataException { if (folder == null) { try{ DotConnect dc = new DotConnect() - .setSQL("SELECT folder.*, folder_1_.* from folder folder, inode folder_1_ where folder.inode = ? ") + .setSQL("SELECT folder.*, folder_1_.* from folder folder, inode folder_1_ where folder.inode = ? or folder.identifier=?") + .addParam(folderInode) .addParam(folderInode); - folder = TransformerLocator.createFolderTransformer(dc.loadObjectResults()).asList().get(0); Identifier id = APILocator.getIdentifierAPI().find(folder.getIdentifier()); fc.addFolder(folder, id); diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/structure/action/EditStructureAction.java b/dotCMS/src/main/java/com/dotmarketing/portlets/structure/action/EditStructureAction.java index c40cdf3b3212..7795033755cd 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/structure/action/EditStructureAction.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/structure/action/EditStructureAction.java @@ -179,14 +179,15 @@ private Structure _loadStructure(ActionForm form, ActionRequest req, ActionRespo ContentType type; Structure struc = new Structure(); try{ - type= APILocator.getContentTypeAPI(user).find(inodeString); - struc = new StructureTransformer(type).asStructure(); - } - catch(NotFoundInDbException nodb){ + if(!UtilMethods.isSet(inodeString)) { + type= ContentTypeBuilder.instanceOf(SimpleContentType.class); + } else { + type = APILocator.getContentTypeAPI(user).find(inodeString); + struc = new StructureTransformer(type).asStructure(); + } + } catch(NotFoundInDbException nodb){ type= ContentTypeBuilder.instanceOf(SimpleContentType.class); - } - if(!type.fixed()){//GIT-780 if(type.baseType() == BaseContentType.WIDGET diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/templates/business/TemplateAPI.java b/dotCMS/src/main/java/com/dotmarketing/portlets/templates/business/TemplateAPI.java index 903b54913b3a..fafddc9972e2 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/templates/business/TemplateAPI.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/templates/business/TemplateAPI.java @@ -113,13 +113,6 @@ Template copy(Template sourceTemplate, Host destinationHost, boolean forceOverwr List getContainersInTemplate(Template template, User user, boolean respectFrontendRoles) throws DotDataException, DotSecurityException; - /** - * Update template body code to use the new parse container syntax - * - * @param template - */ - void updateParseContainerSyntax(Template template); - /** * Retrieves the template associated to a host * @param template diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/templates/business/TemplateAPIImpl.java b/dotCMS/src/main/java/com/dotmarketing/portlets/templates/business/TemplateAPIImpl.java index a9df01f2fcd8..cc561b78cc3f 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/templates/business/TemplateAPIImpl.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/templates/business/TemplateAPIImpl.java @@ -2,21 +2,25 @@ import com.dotcms.business.CloseDBIfOpened; import com.dotcms.business.WrapInTransaction; -import com.dotcms.repackage.org.apache.oro.text.regex.MalformedPatternException; -import com.dotcms.repackage.org.apache.oro.text.regex.MatchResult; -import com.dotcms.repackage.org.apache.oro.text.regex.Perl5Compiler; -import com.dotcms.repackage.org.apache.oro.text.regex.Perl5Matcher; + import com.dotmarketing.beans.Host; import com.dotmarketing.beans.Identifier; +import com.dotmarketing.beans.MultiTree; import com.dotmarketing.beans.VersionInfo; import com.dotmarketing.beans.WebAsset; -import com.dotmarketing.business.*; +import com.dotmarketing.business.APILocator; +import com.dotmarketing.business.BaseWebAssetAPI; +import com.dotmarketing.business.DotStateException; +import com.dotmarketing.business.FactoryLocator; +import com.dotmarketing.business.IdentifierAPI; +import com.dotmarketing.business.PermissionAPI; import com.dotmarketing.business.PermissionAPI.PermissionableType; +import com.dotmarketing.business.UserAPI; import com.dotmarketing.db.HibernateUtil; import com.dotmarketing.exception.DotDataException; -import com.dotmarketing.exception.DotHibernateException; import com.dotmarketing.exception.DotRuntimeException; import com.dotmarketing.exception.DotSecurityException; +import com.dotmarketing.factories.MultiTreeFactory; import com.dotmarketing.portlets.containers.business.ContainerAPI; import com.dotmarketing.portlets.containers.model.Container; import com.dotmarketing.portlets.contentlet.business.HostAPI; @@ -28,16 +32,18 @@ import com.dotmarketing.util.Logger; import com.dotmarketing.util.UtilMethods; import com.dotmarketing.util.WebKeys; -import com.liferay.portal.model.User; -import com.liferay.util.StringPool; -import com.liferay.util.StringUtil; +import java.util.ArrayList; import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import com.liferay.portal.model.User; public class TemplateAPIImpl extends BaseWebAssetAPI implements TemplateAPI { @@ -49,25 +55,7 @@ public class TemplateAPIImpl extends BaseWebAssetAPI implements TemplateAPI { static HostAPI hostAPI = APILocator.getHostAPI(); static UserAPI userAPI = APILocator.getUserAPI(); - private static ThreadLocal localP5Matcher = new ThreadLocal(){ - protected Perl5Matcher initialValue() { - return new Perl5Matcher(); - } - }; - - private static com.dotcms.repackage.org.apache.oro.text.regex.Pattern parseContainerPattern; - private static com.dotcms.repackage.org.apache.oro.text.regex.Pattern oldContainerPattern; - - static { - Perl5Compiler c = new Perl5Compiler(); - try{ - parseContainerPattern = c.compile("#parse\\( \\$container.* \\)",Perl5Compiler.READ_ONLY_MASK); - oldContainerPattern = c.compile("[0-9]+",Perl5Compiler.READ_ONLY_MASK); - }catch (MalformedPatternException mfe) { - Logger.fatal(TemplateAPIImpl.class, "Unable to instaniate dotCMS Velocity Cache", mfe); - Logger.error(TemplateAPIImpl.class, mfe.getMessage(), mfe); - } - } + @CloseDBIfOpened public List