diff --git a/.github/workflows/issue_comp_release-labeling.yml b/.github/workflows/issue_comp_release-labeling.yml new file mode 100644 index 000000000000..0ac34b46cab3 --- /dev/null +++ b/.github/workflows/issue_comp_release-labeling.yml @@ -0,0 +1,119 @@ +name: 'Release Labeling' +on: + workflow_call: + secrets: + CI_MACHINE_TOKEN: + description: 'CI machine token' + required: true + inputs: + rename_label: + description: 'Rename label' + type: string + required: false + default: 'Next Release' + new_label: + description: 'New label' + type: string + required: true + workflow_dispatch: + inputs: + rename_label: + description: 'Rename label' + type: string + required: false + default: 'Next Release' + new_label: + description: 'New label' + type: string + required: true + +jobs: + release-labeling: + runs-on: ubuntu-20.04 + env: + REPO: core + steps: + - run: echo 'GitHub context' + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + - name: Rename label + if: success() + id: validate-inputs + uses: actions/github-script@v7 + with: + result-encoding: string + retries: 3 + retry-exempt-status-codes: 400,401 + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + async function getLabel(name) { + console.log(`Getting label [${name}]`); + try { + const response = await github.rest.issues.getLabel({ + owner: '${{ github.repository_owner }}', + repo: '${{ env.REPO }}', + name, + }); + return response.data; + } catch(error) { + console.log(`Error getting label: ${error}`); + return undefined; + } + } + + const renameLabel = await getLabel('${{ inputs.rename_label }}'); + if (!renameLabel) { + console.log(`Label [${{ inputs.rename_label }}] not found, skipping rename`); + return; + } + + const newLabel = await getLabel('${{ inputs.new_label }}'); + if (newLabel) { + console.log(`Label [${newLabel.name}] already exists, skipping rename`); + return; + } + + console.log(`Renaming label [${renameLabel.name}] for owner [${{ github.repository_owner }}] repo [${{ env.REPO }}] with new label [${{ inputs.new_label }}]`); + await github.rest.issues.updateLabel({ + owner: '${{ github.repository_owner }}', + repo: '${{ env.REPO }}', + name: renameLabel.name, + new_name: '${{ inputs.new_label }}' + }); + + - name: Re-Create New Label + if: success() + uses: actions/github-script@v7 + with: + result-encoding: string + retries: 3 + retry-exempt-status-codes: 400,401 + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + async function getLabel(name) { + console.log(`Getting label [${name}]`); + try { + const response = await github.rest.issues.getLabel({ + owner: '${{ github.repository_owner }}', + repo: '${{ env.REPO }}', + name, + }); + return response.data; + } catch(error) { + console.log(`Error getting label: ${error}`); + return undefined; + } + } + + const renameLabel = await getLabel('${{ inputs.rename_label }}'); + if (renameLabel) { + console.log(`Label [${renameLabel.name}] already exists, skipping re-creation`); + return; + } + + console.log(`Recreating label [${{ inputs.rename_label }}] for owner [${{ github.repository_owner }}] repo [${{ env.REPO }}]`); + await github.rest.issues.createLabel({ + owner: '${{ github.repository_owner }}', + repo: '${{ env.REPO }}', + name: '${{ inputs.rename_label }}' + }); diff --git a/.github/workflows/legacy-release_maven-release-process.yml b/.github/workflows/legacy-release_maven-release-process.yml index 9959dbcdfc33..7cec4210f243 100644 --- a/.github/workflows/legacy-release_maven-release-process.yml +++ b/.github/workflows/legacy-release_maven-release-process.yml @@ -395,32 +395,13 @@ jobs: - uses: ./.github/actions/core-cicd/cleanup-runner - # - name: Fetch `Next Release` issues - # id: fetch-next-release-issues - # uses: ./.github/actions/issues/issue-fetcher - # with: - # fetch_operation: 'WITH_LABELS' - # fetch_value: ${{ env.FETCH_VALUE }} - # github_token: ${{ secrets.GITHUB_TOKEN }} - # if: github.event.inputs.update_github_labels == 'true' - # - # - name: Clear next release issues - # uses: ./.github/actions/issues/issue-labeler - # with: - # issues_json: ${{ steps.fetch-next-release-issues.outputs.issues }} - # labels: ${{ env.FETCH_VALUE }} - # operation: 'REMOVE' - # github_token: ${{ secrets.GITHUB_TOKEN }} - # if: github.event.inputs.update_github_labels == 'true' - # - # - name: Label current release issues - # uses: ./.github/actions/issues/issue-labeler - # with: - # issues_json: ${{ steps.fetch-next-release-issues.outputs.issues }} - # labels: 'Release ${{ needs.prepare-release.outputs.release_version }}' - # operation: 'ADD' - # github_token: ${{ secrets.GITHUB_TOKEN }} - # if: github.event.inputs.update_github_labels == 'true' + - name: Release Labeling + if: success() && github.event.inputs.update_github_labels == 'true' + uses: ./.github/workflows/issue_comp_release-labeling.yml + with: + new_label: 'Release ${{ github.event.inputs.release_version }}'' + secrets: + CI_MACHINE_TOKEN: ${{ secrets.CI_MACHINE_TOKEN }} - name: Slack Notification uses: rtCamp/action-slack-notify@v2 diff --git a/dotCMS/src/main/java/com/dotcms/api/web/HttpServletRequestImpersonator.java b/dotCMS/src/main/java/com/dotcms/api/web/HttpServletRequestImpersonator.java new file mode 100644 index 000000000000..236eeb88ea63 --- /dev/null +++ b/dotCMS/src/main/java/com/dotcms/api/web/HttpServletRequestImpersonator.java @@ -0,0 +1,67 @@ +package com.dotcms.api.web; + +import com.dotcms.mock.request.FakeHttpRequest; +import com.dotcms.mock.request.MockAttributeRequest; +import com.dotcms.mock.request.MockHeaderRequest; +import com.dotcms.mock.request.MockParameterRequest; +import com.dotcms.mock.request.MockSessionRequest; +import com.dotcms.mock.response.MockHttpResponse; +import java.util.regex.Pattern; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/* + * The Request impersonator is a class that will return a Mock instance of a request object. + * We use this to block the real request object from being used to perform operations that could break certain flows + * Sometimes we want to block a session invalidation for example or a redirect, so we use this class to return a fake request object. + */ +public class HttpServletRequestImpersonator { + + private static final Pattern MOCK_OR_FAKE_PATTERN = Pattern.compile("(^|\\b|\\.)mock|fake($|\\b|\\.)", Pattern.CASE_INSENSITIVE); + + /** + * new instance of {@link HttpServletRequestImpersonator} + * @return {@link HttpServletRequestImpersonator} + */ + public static HttpServletRequestImpersonator newInstance() { + return new HttpServletRequestImpersonator(); + } + + /** + * Returns a fake request object + * @return {@link HttpServletRequest} + */ + public HttpServletRequest request() { + final HttpServletRequest request = HttpServletRequestThreadLocal.INSTANCE.getRequest(); + if (isMockRequest(request)) { + // no use in mocking a mock this could actually break tests + return request; + } + return request == null + ? new FakeHttpRequest("localhost", "/").request() + : new MockHeaderRequest(new MockAttributeRequest(new MockSessionRequest(new MockParameterRequest(request)))); + } + + /** + * Returns a fake response object + * @return {@link HttpServletResponse} + */ + public HttpServletResponse response() { + return new MockHttpResponse(); + } + + /** + * Check if the request is a mock request + * as We have so many different types of mock requests this is probably the best way to check + * @param request {@link HttpServletRequest} + * @return boolean + */ + boolean isMockRequest(final HttpServletRequest request) { + if (request == null) { + return false; + } + final String clazzName = request.getClass().getName(); + return MOCK_OR_FAKE_PATTERN.matcher(clazzName).find(); + } + +} diff --git a/dotCMS/src/main/java/com/dotcms/mock/request/MockSession.java b/dotCMS/src/main/java/com/dotcms/mock/request/MockSession.java index 29aabd4fd1d8..d4c29a3ce2d4 100644 --- a/dotCMS/src/main/java/com/dotcms/mock/request/MockSession.java +++ b/dotCMS/src/main/java/com/dotcms/mock/request/MockSession.java @@ -1,123 +1,136 @@ package com.dotcms.mock.request; +import com.dotmarketing.util.UUIDGenerator; +import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Vector; - import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionContext; -@SuppressWarnings("deprecation") -public class MockSession implements HttpSession { - - final String id; - final long createionTime; - public MockSession(final String id) { - super(); - this.id=id; - createionTime = System.currentTimeMillis(); - } - Map valmap = new HashMap<>(); +public class MockSession implements HttpSession { + + String id; + long creationTime; + final Map valmap = new HashMap<>(); - @Override - public void setMaxInactiveInterval(int arg0) { + public MockSession(final String id) { + this(null, id); + } + public MockSession(final HttpSession sessionIn) { + this(sessionIn, UUIDGenerator.generateUuid()); + } - } + public MockSession(final HttpSession sessionIn, final String id) { + super(); + this.id = id; + this.creationTime = System.currentTimeMillis(); + if (sessionIn != null && sessionIn.getAttributeNames() != null) { + Collections.list(sessionIn.getAttributeNames()) + .forEach(k -> valmap.put(k, sessionIn.getAttribute(k))); + } + } - @Override - public void setAttribute(String arg0, Object arg1) { - valmap.put(arg0, arg1); + @Override + public void setMaxInactiveInterval(int arg0) { + // has no effect + } - } + @Override + public void setAttribute(String arg0, Object arg1) { + valmap.put(arg0, arg1); + } - @Override - public void removeValue(String arg0) { - valmap.remove(arg0); + @Override + public void removeValue(String arg0) { + valmap.remove(arg0); - } + } - @Override - public void removeAttribute(String arg0) { - valmap.remove(arg0); + @Override + public void removeAttribute(String arg0) { + valmap.remove(arg0); - } + } - @Override - public void putValue(String arg0, Object arg1) { - valmap.put(arg0, arg1); + @Override + public void putValue(String arg0, Object arg1) { + valmap.put(arg0, arg1); - } + } - @Override - public boolean isNew() { + @Override + public boolean isNew() { - return (valmap.isEmpty()); - } + return (valmap.isEmpty()); + } - @Override - public void invalidate() { - valmap = new HashMap<>(); + @Override + public void invalidate() { + valmap.clear(); + this.id = UUIDGenerator.generateUuid(); + this.creationTime = System.currentTimeMillis(); - } + } - @Override - public String[] getValueNames() { + @Override + public String[] getValueNames() { - return valmap.keySet().toArray(new String[valmap.size()]); - } + return valmap.keySet().toArray(new String[valmap.size()]); + } - @Override - public Object getValue(String arg0) { - return valmap.get(arg0); - } + @Override + public Object getValue(String arg0) { + return valmap.get(arg0); + } - @Override - public ServletContext getServletContext() { + @Override + public ServletContext getServletContext() { - return null; - } + return null; + } - @Override - public int getMaxInactiveInterval() { + @Override + public int getMaxInactiveInterval() { - return 0; - } + return 0; + } - @Override - public long getLastAccessedTime() { + @Override + public long getLastAccessedTime() { - return 0; - } + return 0; + } - @Override - public String getId() { + @Override + public String getId() { - return id; - } + return id; + } - @Override - public long getCreationTime() { + @Override + public long getCreationTime() { - return createionTime; - } + return creationTime; + } - @Override - public Enumeration getAttributeNames() { - return new Vector(valmap.keySet()).elements(); - } + @Override + public Enumeration getAttributeNames() { + return new Vector<>(valmap.keySet()).elements(); + } - @Override - public Object getAttribute(String arg0) { - return valmap.get(arg0); - } + @Override + public Object getAttribute(String arg0) { + return valmap.get(arg0); + } - @Override - public HttpSessionContext getSessionContext() { - // TODO Auto-generated method stub - return null; - } + @Override + public HttpSessionContext getSessionContext() { + // Not implemented + return null; + } } \ No newline at end of file diff --git a/dotCMS/src/main/java/com/dotcms/mock/request/MockSessionRequest.java b/dotCMS/src/main/java/com/dotcms/mock/request/MockSessionRequest.java index a16220a58154..fc25b688270e 100644 --- a/dotCMS/src/main/java/com/dotcms/mock/request/MockSessionRequest.java +++ b/dotCMS/src/main/java/com/dotcms/mock/request/MockSessionRequest.java @@ -19,13 +19,13 @@ */ public class MockSessionRequest extends HttpServletRequestWrapper implements MockRequest { - HttpSession session = null; + HttpSession session = null; public MockSessionRequest(HttpServletRequest request) { - super(request); - if (request.getSession(false)!= null) { - session = request.getSession(); - } + super(request); + if (request.getSession(false) != null) { + session = new MockSession(request.getSession()); + } } @@ -48,11 +48,9 @@ public HttpSession getSession() { @Override public HttpSession getSession(boolean create) { - return (create) - ? getSession() - : session!=null - ? session - : null; + return (create) + ? getSession() + : session; } @@ -61,6 +59,6 @@ public HttpSession setSession(final HttpSession session) { this.session = session; return this.session; } - - -} + + +} \ No newline at end of file diff --git a/dotCMS/src/main/java/com/dotcms/rest/ContentResource.java b/dotCMS/src/main/java/com/dotcms/rest/ContentResource.java index 29b12fd24c3c..b23595a8122a 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/ContentResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/ContentResource.java @@ -1,5 +1,9 @@ package com.dotcms.rest; +import static com.dotmarketing.util.NumberUtil.toInt; +import static com.dotmarketing.util.NumberUtil.toLong; + +import com.dotcms.api.web.HttpServletRequestImpersonator; import com.dotcms.contenttype.model.field.CategoryField; import com.dotcms.contenttype.model.field.RelationshipField; import com.dotcms.contenttype.model.field.StoryBlockField; @@ -63,28 +67,6 @@ import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import io.swagger.v3.oas.annotations.tags.Tag; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.glassfish.jersey.media.multipart.BodyPart; -import org.glassfish.jersey.media.multipart.ContentDisposition; -import org.glassfish.jersey.media.multipart.FormDataMultiPart; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.Part; -import javax.ws.rs.Consumes; -import javax.ws.rs.DefaultValue; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -108,9 +90,27 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static com.dotmarketing.util.NumberUtil.toInt; -import static com.dotmarketing.util.NumberUtil.toLong; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.Part; +import javax.ws.rs.Consumes; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.glassfish.jersey.media.multipart.BodyPart; +import org.glassfish.jersey.media.multipart.ContentDisposition; +import org.glassfish.jersey.media.multipart.FormDataMultiPart; /** * This REST Endpoint provides access to Contentlet data, fields, and different actions that can be @@ -576,7 +576,10 @@ public Response getContent(@Context HttpServletRequest request, @Context final H final ResourceResponse responseResource = new ResourceResponse(initData.getParamsMap()); final Map paramsMap = initData.getParamsMap(); final User user = initData.getUser(); - final String render = paramsMap.get(RESTParams.RENDER.getValue()); + //Try the render url parameter first, then the query parameter + final String render = UtilMethods.isSet(paramsMap.get(RESTParams.RENDER.getValue())) ? + paramsMap.get(RESTParams.RENDER.getValue()) : + request.getParameter(RESTParams.RENDER.getValue()); final String query = paramsMap.get(RESTParams.QUERY.getValue()); final String related = paramsMap.get(RESTParams.RELATED.getValue()); final String id = paramsMap.get(RESTParams.ID.getValue()); @@ -835,8 +838,9 @@ private Map getContentXML(final Contentlet contentlet, final Map m = new HashMap<>(); final ContentType type = contentlet.getContentType(); - m.putAll(ContentletUtil.getContentPrintableMap(user, contentlet, allCategoriesInfo)); - + final boolean doRender = (BaseContentType.WIDGET.equals(type.baseType()) && "true".equalsIgnoreCase(render)); + //Render code + m.putAll(ContentletUtil.getContentPrintableMap(user, contentlet, allCategoriesInfo, doRender)); if (BaseContentType.WIDGET.equals(type.baseType()) && Boolean.toString(true) .equalsIgnoreCase(render)) { m.put("parsedCode", WidgetResource.parseWidget(request, response, contentlet)); @@ -1426,7 +1430,11 @@ public static JSONObject contentletToJSON(Contentlet contentlet, final HttpServl contentlet = myTransformer.hydrate().get(0); } - final Map map = ContentletUtil.getContentPrintableMap(user, contentlet, allCategoriesInfo); + final boolean doRender = (BaseContentType.WIDGET.equals(type.baseType()) && Boolean.TRUE.toString().equalsIgnoreCase(render)); + //By default, all underlying transformer strategies that are triggered by the Widget ContentType or the option RENDER_FIELDS are enabled + //Therefore, we need to disable them in case the render option is not enabled to avoid undesired rendering when no explicitly requested + // Render field "code" + final Map map = ContentletUtil.getContentPrintableMap(user, contentlet, allCategoriesInfo, doRender); final Set jsonFields = getJSONFields(type); for (final String key : map.keySet()) { @@ -1458,10 +1466,9 @@ public static JSONObject contentletToJSON(Contentlet contentlet, final HttpServl } } } - - if (BaseContentType.WIDGET.equals(type.baseType()) && Boolean.toString(true) - .equalsIgnoreCase(render)) { - jsonObject.put("parsedCode", WidgetResource.parseWidget(request, response, contentlet)); + if (BaseContentType.WIDGET.equals(type.baseType()) && "true".equalsIgnoreCase(render)) { + final HttpServletRequestImpersonator impersonator = HttpServletRequestImpersonator.newInstance(); + jsonObject.put("parsedCode", WidgetResource.parseWidget(impersonator.request(), response, contentlet)); } if (BaseContentType.HTMLPAGE.equals(type.baseType())) { diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/DotTransformerBuilder.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/DotTransformerBuilder.java index e5aff67f5822..01f3acfcf2de 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/DotTransformerBuilder.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/DotTransformerBuilder.java @@ -194,7 +194,7 @@ public DotTransformerBuilder dotAssetOptions(){ } /** - * Fine Tuned to be consumed from ContentResource + * Fine-Tuned to be consumed from ContentResource * @return */ public DotTransformerBuilder contentResourceOptions(final boolean allCategoriesInfo){ @@ -209,7 +209,7 @@ public DotTransformerBuilder contentResourceOptions(final boolean allCategoriesI } /** - * Fine Tuned to be consumed from ContentResource + * Fine-Tuned to be consumed from ContentResource * @return */ public DotTransformerBuilder allOptions(final boolean allCategoriesInfo){ @@ -234,7 +234,7 @@ public DotTransformerBuilder graphQLDataFetchOptions(){ } /** - * Dont know where? to go land here. + * Don't know where? to go land here. * @return */ public DotTransformerBuilder defaultOptions(){ @@ -243,6 +243,22 @@ public DotTransformerBuilder defaultOptions(){ return this; } + /** + * This opens the door to say we want to skip rendering code + * @param renderFields boolean true if we want to render the fields, otherwise false + * @return the builder + */ + public DotTransformerBuilder renderFields(final boolean renderFields){ + if (renderFields) { + optionsHolder.add(TransformOptions.RENDER_FIELDS); + } else { + optionsHolder.remove(TransformOptions.RENDER_FIELDS); + //By default, Widget Strategy render widget code. If we want to skip it, we need to add this option + optionsHolder.add(TransformOptions.SKIP_WIDGET_CODE_RENDERING); + } + return this; + } + /** * Once every option has been selected get the instance here * @return diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/strategy/RenderFieldStrategy.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/strategy/RenderFieldStrategy.java index f0f892c94039..80b86108b0b7 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/strategy/RenderFieldStrategy.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/strategy/RenderFieldStrategy.java @@ -2,6 +2,7 @@ import com.dotcms.api.APIProvider; import com.dotcms.api.vtl.model.DotJSON; +import com.dotcms.api.web.HttpServletRequestImpersonator; import com.dotcms.api.web.HttpServletRequestThreadLocal; import com.dotcms.api.web.HttpServletResponseThreadLocal; import com.dotcms.contenttype.model.field.ConstantField; @@ -66,11 +67,12 @@ protected Map transform(final Contentlet contentlet, final List rederableFields = contentType.fields().stream() .filter(RenderFieldStrategy::isFieldRenderable).collect(Collectors.toList()); + final HttpServletRequestImpersonator impersonator = HttpServletRequestImpersonator.newInstance(); if (UtilMethods.isSet(rederableFields)) { rederableFields.forEach(field -> map.put(field.variable(), - renderFieldValue(HttpServletRequestThreadLocal.INSTANCE.getRequest(), + renderFieldValue(impersonator.request(), HttpServletResponseThreadLocal.INSTANCE.getResponse(), RenderFieldStrategy.getFieldValue(contentlet, field), contentlet, field.variable()))); @@ -136,14 +138,9 @@ public static Object parseAsJSON(HttpServletRequest request, Logger.warn(ContainerRenderedBuilder.class, e.getMessage()); } - final String code = (String) context.get(fieldVar); - final DotJSON dotJSON = (DotJSON) context.get("dotJSON"); - return UtilMethods.isSet(code) - ? dotJSON.size() > 0 - ? dotJSON.getMap() : Collections.emptyMap() - : Collections.emptyMap(); + return UtilMethods.isSet(dotJSON) ? dotJSON.getMap() : Collections.emptyMap(); } public static Object renderFieldValue(final HttpServletRequest request, diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/strategy/TransformOptions.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/strategy/TransformOptions.java index 38d2e7f9a2f9..4fcde8191b70 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/strategy/TransformOptions.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/strategy/TransformOptions.java @@ -95,9 +95,16 @@ public enum TransformOptions { /** * Instructs the Strategy to velocity-render the render-able fields */ - RENDER_FIELDS, + RENDER_FIELDS, //This triggers a Strategy that will render the fields explicitly JSON_VIEW, - DATETIME_FIELDS_TO_TIMESTAMP; + DATETIME_FIELDS_TO_TIMESTAMP, + + /** + * Instructs the Strategy to skip the rendering of the widget code + * I hate to introduce this but seems like the safest way to avoid breaking backward compatibility + * This options controls the Strategy that gets fired by the Widget Content Type which by default will render the widget code + */ + SKIP_WIDGET_CODE_RENDERING; // ----------------------------------------------------------------------------------------- // Plug additional Transform Options to manipulate the outcome as a particular type of view diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/strategy/WidgetViewStrategy.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/strategy/WidgetViewStrategy.java index 86cdaf03c85c..93c8c74fa8e2 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/strategy/WidgetViewStrategy.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/strategy/WidgetViewStrategy.java @@ -1,13 +1,17 @@ package com.dotmarketing.portlets.contentlet.transform.strategy; import com.dotcms.api.APIProvider; +import com.dotcms.api.web.HttpServletRequestImpersonator; import com.dotcms.contenttype.model.type.WidgetContentType; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotSecurityException; import com.dotmarketing.portlets.contentlet.model.Contentlet; +import com.dotmarketing.util.Logger; import com.liferay.portal.model.User; import java.util.Map; import java.util.Set; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; /** * Strategy to handle Contentlets of type Widget. It simply adds a new field to the map called @@ -38,13 +42,19 @@ protected Map transform(final Contentlet widget, final Map options, final User user) throws DotSecurityException, DotDataException { - final String fieldValue = (String) map.get(WidgetContentType.WIDGET_CODE_FIELD_VAR); - - final Object parsedValue = RenderFieldStrategy.parseAsJSON(null, null, - fieldValue, widget, WidgetContentType.WIDGET_CODE_FIELD_VAR); + if (options.contains(TransformOptions.SKIP_WIDGET_CODE_RENDERING)) { + Logger.debug(this, "Skipping widget code rendering"); + return map; + } + final HttpServletRequestImpersonator impersonator = HttpServletRequestImpersonator.newInstance(); + // do not allow the real request/response to be modified here. + final HttpServletRequest request = impersonator.request(); + final HttpServletResponse response = impersonator.response(); + final String fieldValue = (String) map.get(WidgetContentType.WIDGET_CODE_FIELD_VAR); + final Object parsedValue = RenderFieldStrategy.parseAsJSON(request, response, fieldValue, widget, + WidgetContentType.WIDGET_CODE_FIELD_VAR); map.put(WidgetContentType.WIDGET_CODE_JSON_FIELD_VAR, parsedValue); - return map; } } diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/util/ContentletUtil.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/util/ContentletUtil.java index 1f0c5851a2d7..edc31d48ccf8 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/util/ContentletUtil.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/util/ContentletUtil.java @@ -138,14 +138,33 @@ public static Map getContentPrintableMap( * * @return Contentlet with the values in place. * - * @throws DotDataException - * @throws IOException - */ + */ public static Map getContentPrintableMap( - final User user, final Contentlet sourceContentlet, final boolean allCategoriesInfo) - throws DotDataException, IOException { + final User user, final Contentlet sourceContentlet, final boolean allCategoriesInfo) { + return getContentPrintableMap(user, sourceContentlet, allCategoriesInfo, false); + } + + /** + * Returns a {@link Map} that includes original content's map entries and also special entries for string + * representation of the values of binary and category field. It also set the tags to the contentlet's map for them + * to be included in the resulting map. This map can be used to return a string representation of the given content + * (e.g. REST, ES portlet) + * + * @param user User from Front End with permission to read Special Fields. + * @param sourceContentlet the contentlet to generate the printable map from + * @param allCategoriesInfo {@code "true"} to return all fields for + * the categories associated to the content (key, name, description),{@code "false"} + * to return only categories names. + * @param renderFields {@code "true"} to render the fields, {@code "false"} to not render the fields. + * @return Contentlet with the values in place. + * + */ + public static Map getContentPrintableMap( + final User user, final Contentlet sourceContentlet, final boolean allCategoriesInfo, final boolean renderFields) { return new DotTransformerBuilder().contentResourceOptions(allCategoriesInfo) .siteToMapTransformer(false) + .renderFields(renderFields) + .forUser(user) .content(sourceContentlet).build().toMaps().get(0); } diff --git a/dotcms-integration/src/test/java/com/dotcms/MainSuite2a.java b/dotcms-integration/src/test/java/com/dotcms/MainSuite2a.java index 97385a00f65f..eef0ca11106e 100644 --- a/dotcms-integration/src/test/java/com/dotcms/MainSuite2a.java +++ b/dotcms-integration/src/test/java/com/dotcms/MainSuite2a.java @@ -79,6 +79,7 @@ com.dotmarketing.portlets.contentlet.model.ContentletIntegrationTest.class, com.dotmarketing.portlets.contentlet.transform.BinaryToMapTransformerTest.class, com.dotmarketing.portlets.contentlet.transform.ContentletTransformerTest.class, + com.dotmarketing.portlets.contentlet.transform.WidgetViewStrategyTest.class, com.dotmarketing.portlets.contentlet.ajax.ContentletAjaxTest.class, com.dotmarketing.portlets.workflows.business.SaveContentDraftActionletTest.class, com.dotmarketing.portlets.workflows.business.WorkflowFactoryTest.class, diff --git a/dotcms-integration/src/test/java/com/dotcms/MainSuite2b.java b/dotcms-integration/src/test/java/com/dotcms/MainSuite2b.java index 4b716d43c119..da6b48b34deb 100644 --- a/dotcms-integration/src/test/java/com/dotcms/MainSuite2b.java +++ b/dotcms-integration/src/test/java/com/dotcms/MainSuite2b.java @@ -17,6 +17,7 @@ import com.dotcms.analytics.track.collectors.PagesCollectorTest; import com.dotcms.analytics.track.collectors.SyncVanitiesCollectorTest; import com.dotcms.analytics.track.collectors.WebEventsCollectorServiceImplTest; +import com.dotcms.api.web.HttpServletRequestImpersonatorTest; import com.dotcms.auth.providers.saml.v1.DotSamlResourceTest; import com.dotcms.auth.providers.saml.v1.SAMLHelperTest; import com.dotcms.bayesian.BayesianAPIImplIT; @@ -412,7 +413,8 @@ PageDetailCollectorTest.class, FilesCollectorTest.class, SyncVanitiesCollectorTest.class, - AsyncVanitiesCollectorTest.class + AsyncVanitiesCollectorTest.class, + HttpServletRequestImpersonatorTest.class }) public class MainSuite2b { diff --git a/dotcms-integration/src/test/java/com/dotcms/api/web/HttpServletRequestImpersonatorTest.java b/dotcms-integration/src/test/java/com/dotcms/api/web/HttpServletRequestImpersonatorTest.java new file mode 100644 index 000000000000..d90e80326a98 --- /dev/null +++ b/dotcms-integration/src/test/java/com/dotcms/api/web/HttpServletRequestImpersonatorTest.java @@ -0,0 +1,39 @@ +package com.dotcms.api.web; + +import static org.mockito.Mockito.mock; + +import com.dotcms.mock.request.FakeHttpRequest; +import com.dotcms.mock.request.MockHeaderRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import org.junit.Assert; +import org.junit.Test; + +/** + * Test class for {@link HttpServletRequestImpersonator} + */ +public class HttpServletRequestImpersonatorTest { + + static final HttpServletRequestImpersonator test = new HttpServletRequestImpersonator(); + + /** + * Test method for {@link HttpServletRequestImpersonator#isMockRequest(HttpServletRequest)}. + * Given Scenario: A request is passed to the method. + * Expected: The method should return true if the request is a mock request. Only the + */ + @Test + public void testIsMockRequest_identifiesMockRequests() { + + final HttpServletRequest mockHeaderRequest = new MockHeaderRequest(new FakeHttpRequest("localhost", "/").request()); + final HttpServletRequest mockSessionRequest = mock(HttpServletRequest.class); + final HttpServletRequest localRequest = new FakeHttpRequest("localhost", "/").request(); + + Assert.assertTrue(test.isMockRequest(mockHeaderRequest)); + Assert.assertTrue(test.isMockRequest(mockSessionRequest)); + Assert.assertTrue(test.isMockRequest(localRequest)); + + final HttpServletRequest wrapper = new HttpServletRequestWrapper(mockHeaderRequest); + Assert.assertFalse(test.isMockRequest(wrapper)); + } + +} diff --git a/dotcms-integration/src/test/java/com/dotcms/contenttype/test/ContentResourceTest.java b/dotcms-integration/src/test/java/com/dotcms/contenttype/test/ContentResourceTest.java index e0f5ca683f79..1a1a4d021783 100644 --- a/dotcms-integration/src/test/java/com/dotcms/contenttype/test/ContentResourceTest.java +++ b/dotcms-integration/src/test/java/com/dotcms/contenttype/test/ContentResourceTest.java @@ -39,6 +39,8 @@ import com.dotmarketing.util.json.JSONArray; import com.dotmarketing.util.json.JSONException; import com.dotmarketing.util.json.JSONObject; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Sets; import com.liferay.portal.model.Company; import com.liferay.portal.model.User; @@ -49,6 +51,7 @@ import io.vavr.Tuple2; import org.glassfish.jersey.internal.util.Base64; import org.junit.AfterClass; +import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -1690,4 +1693,82 @@ public static ContentType getWidgetLikeContentTypeUrlField(final String contentT return simpleWidgetContentType; } + + /** + * Method to test: {@link ContentResource#getContent(HttpServletRequest, HttpServletResponse, String)} + * Given scenario: The method is invoked for a widget with a code field and a widget code field with the same value + * Expected result: The response should return the rendered widget code when the render parameter is set to true + * @throws Exception + */ + @Test + public void testRenderWidgetCode() throws Exception { + + //We're going to use this as code and widget code to test the endpoint + final String code = "#set($a = 10)\n" + + "#set($b = 5) \n" + + "#set($sum = $a + $b) \n" + + "$sum"; + // When rendering the widget code, the result should be the sum of a and b (10 + 5 = 15) + + final ContentType type = getWidgetLikeContentTypeUrlField("CodeWidgetType", null, ()->code); + + ContentletDataGen contentletDataGen = new ContentletDataGen(type.id()) + .languageId(1L) + .host(APILocator.getHostAPI().findDefaultHost(APILocator.systemUser(), false)) + .setProperty("widgetTitle", "myWidgetTitle") + .setProperty("code", code) + .setProperty("url", "somevalue"); + + final Contentlet contentlet = contentletDataGen.nextPersisted(); + ContentletDataGen.publish(contentlet); + + // Build request and response + final HttpServletRequest request = createHttpRequest(null, null); + final HttpServletResponse response = Mockito.mock(HttpServletResponse.class); + + // Send request + final ContentResource contentResource = new ContentResource(); + + final Map resp = callEndpoint(contentResource, request, response, contentlet, false); + final String codeValue = resp.get("code").toString(); + final String widgetCodeValue = resp.get("widgetCode").toString(); + + final String raw = removeSpecialCharacters(code); + + assertEquals(raw, removeSpecialCharacters(codeValue)); + assertEquals(raw, removeSpecialCharacters(widgetCodeValue)); + + final Map resp2 = callEndpoint(contentResource, request, response, contentlet, true); + final String parsedCode = resp2.get("code").toString(); + final String parsedWidgetCode = resp2.get("widgetCode").toString(); + Assert.assertEquals(15,Integer.parseInt(parsedCode)); + Assert.assertEquals(15,Integer.parseInt(parsedWidgetCode)); + + } + + public static String removeSpecialCharacters(String input) { + return input.replaceAll("[^a-zA-Z0-9\\s]", ""); + } + + /** + * Method to test: {@link ContentResource#getContent(HttpServletRequest, HttpServletResponse, String)} + * @param contentResource The content resource + * @param request The request + * @param response The response + * @param contentlet The contentlet + * @param render If the contentlet should be rendered + * @return The map with the contentlet + * @throws JsonProcessingException + */ + private static Map callEndpoint(final ContentResource contentResource, final HttpServletRequest request, + final HttpServletResponse response, final Contentlet contentlet, final boolean render) throws JsonProcessingException { + Response endpointResponse = contentResource.getContent(request, response, + "/id/" + contentlet.getIdentifier() + "/render/"+render); + + final String out = endpointResponse.getEntity().toString(); + final Map map = new ObjectMapper().readValue(out, Map.class); + final List contentlets = (List)map.get("contentlets"); + Assert.assertFalse(contentlets.isEmpty()); + return (Map)contentlets.get(0); + } } diff --git a/dotcms-integration/src/test/java/com/dotcms/rest/api/v1/page/PageResourceTest.java b/dotcms-integration/src/test/java/com/dotcms/rest/api/v1/page/PageResourceTest.java index 7f627605c5ba..22307ffb4401 100644 --- a/dotcms-integration/src/test/java/com/dotcms/rest/api/v1/page/PageResourceTest.java +++ b/dotcms-integration/src/test/java/com/dotcms/rest/api/v1/page/PageResourceTest.java @@ -16,6 +16,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.dotcms.JUnit4WeldRunner; import com.dotcms.api.web.HttpServletRequestThreadLocal; import com.dotcms.api.web.HttpServletResponseThreadLocal; import com.dotcms.content.elasticsearch.business.ESSearchResults; @@ -108,6 +109,7 @@ import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; +import javax.enterprise.context.ApplicationScoped; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -116,12 +118,15 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; /** * {@link PageResource} test */ +@ApplicationScoped +@RunWith(JUnit4WeldRunner.class) public class PageResourceTest { private ContentletAPI esapi; private PageResource pageResource; @@ -131,10 +136,10 @@ public class PageResourceTest { private HttpServletResponse response; private HttpSession session; private Host host; - private final String pageName = "index" + System.currentTimeMillis(); - private final String folderName = "about-us" + System.currentTimeMillis(); - private final String hostName = "my.host.com" + System.currentTimeMillis(); - private final String pagePath = String.format("/%s/%s",folderName,pageName); + private String pageName = "index" + System.currentTimeMillis(); + private String folderName = "about-us" + System.currentTimeMillis(); + private String hostName = "my.host.com" + System.currentTimeMillis(); + private String pagePath = String.format("/%s/%s",folderName,pageName); private HTMLPageAsset pageAsset; private Template template; private Container container1; @@ -157,6 +162,11 @@ public static void prepare() throws Exception { public void init() throws DotSecurityException, DotDataException, SystemException, PortalException { + pageName = "index" + System.currentTimeMillis(); + folderName = "about-us" + System.currentTimeMillis(); + hostName = "my.host.com" + System.currentTimeMillis(); + pagePath = String.format("/%s/%s", folderName, pageName); + // Collection to store attributes keys/values final Map attributes = new ConcurrentHashMap<>(); session = mock(HttpSession.class); diff --git a/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformerTest.java b/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformerTest.java index 19129d16b479..e808d1d531b9 100644 --- a/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformerTest.java +++ b/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformerTest.java @@ -1,5 +1,7 @@ package com.dotmarketing.portlets.contentlet.transform; +import com.dotcms.DataProviderWeldRunner; +import com.dotcms.IntegrationTestBase; import com.dotcms.api.APIProvider; import com.dotcms.api.APIProvider.Builder; import com.dotcms.contenttype.model.field.BinaryField; @@ -56,6 +58,7 @@ import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; import io.vavr.control.Try; +import javax.enterprise.context.ApplicationScoped; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -101,8 +104,9 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -@RunWith(DataProviderRunner.class) -public class ContentletTransformerTest extends BaseWorkflowIntegrationTest { +@ApplicationScoped +@RunWith(DataProviderWeldRunner.class) +public class ContentletTransformerTest extends IntegrationTestBase { static String serializePath; static long langId; diff --git a/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/transform/WidgetViewStrategyTest.java b/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/transform/WidgetViewStrategyTest.java new file mode 100644 index 000000000000..038736fd17ca --- /dev/null +++ b/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/transform/WidgetViewStrategyTest.java @@ -0,0 +1,191 @@ +package com.dotmarketing.portlets.contentlet.transform; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.dotcms.DataProviderWeldRunner; +import com.dotcms.IntegrationTestBase; +import com.dotcms.api.web.HttpServletRequestThreadLocal; +import com.dotcms.contenttype.model.field.Field; +import com.dotcms.contenttype.model.field.FieldBuilder; +import com.dotcms.contenttype.model.type.BaseContentType; +import com.dotcms.contenttype.model.type.ContentType; +import com.dotcms.contenttype.model.type.WidgetContentType; +import com.dotcms.datagen.ContentTypeDataGen; +import com.dotcms.datagen.ContentletDataGen; +import com.dotcms.datagen.FieldDataGen; +import com.dotcms.datagen.SiteDataGen; +import com.dotcms.mock.request.FakeHttpRequest; +import com.dotcms.mock.request.MockHeaderRequest; +import com.dotcms.mock.request.MockSessionRequest; +import com.dotcms.util.IntegrationTestInitService; +import com.dotmarketing.beans.Host; +import com.dotmarketing.business.APILocator; +import com.dotmarketing.exception.DotDataException; +import com.dotmarketing.exception.DotSecurityException; +import com.dotmarketing.portlets.contentlet.model.Contentlet; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import javax.enterprise.context.ApplicationScoped; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +@ApplicationScoped +@RunWith(DataProviderWeldRunner.class) +public class WidgetViewStrategyTest extends IntegrationTestBase { + + static final String VELOCITY_MESSAGE = "Hello World"; + static final String DONT_RENDER_THIS_CODE = "Message from velocity $date"; + static final String YES_RENDER_THIS_CODE = "My value: #set($message=\"" + VELOCITY_MESSAGE + + "\") $dotJSON.put(\"message\", $message)"; + static final String DESTROY_USER_SESSION = "kill session ${session.invalidate()}"; + static Host site; + static Contentlet widgetWithJson; + static Contentlet widgetWithoutJson; + static Contentlet widgetSessionKiller; + + @BeforeClass + public static void prepare() throws Exception { + + IntegrationTestInitService.getInstance().init(); + + List fields = new ArrayList<>(); + fields.add( + new FieldDataGen() + .name("Code") + .velocityVarName("code") + .required(true) + .sortOrder(10) + .next() + ); + + ContentType simpleWidgetContentType = new ContentTypeDataGen() + .baseContentType(BaseContentType.WIDGET) + .name("SimpleWidget" + System.currentTimeMillis()) + .velocityVarName("SimpleWidget" + System.currentTimeMillis()) + .fields(fields) + .nextPersisted(); + + Field codeField = simpleWidgetContentType.fieldMap().get("widgetCode"); + + APILocator.getContentTypeFieldAPI() + .save(FieldBuilder.builder(codeField).values("$code").sortOrder(100).build(), + APILocator.systemUser()); + + site = new SiteDataGen().nextPersisted(); + + Contentlet con = new Contentlet(); + con.setContentType(simpleWidgetContentType); + con.setStringProperty("code", DONT_RENDER_THIS_CODE); + con.setStringProperty("widgetTitle", "NoRender"); + widgetWithoutJson = ContentletDataGen.checkin(con); + ContentletDataGen.publish(widgetWithoutJson); + + con = new Contentlet(); + con.setContentType(simpleWidgetContentType); + con.setStringProperty("code", YES_RENDER_THIS_CODE); + con.setStringProperty("widgetTitle", "Yes Render"); + widgetWithJson = ContentletDataGen.checkin(con); + + ContentletDataGen.publish(widgetWithJson); + + con = new Contentlet(); + con.setContentType(simpleWidgetContentType); + con.setStringProperty("code", DESTROY_USER_SESSION); + con.setStringProperty("widgetTitle", "Die Session"); + widgetSessionKiller = ContentletDataGen.checkin(con); + ContentletDataGen.publish(widgetSessionKiller); + + HttpServletRequestThreadLocal.INSTANCE.setRequest(null); + + } + + /** + * Validates that a widget without JSON code does not produce a JSON response. + * + *

Given Scenario: A widget is created with content that does not include + * JSON-producing code.

+ *

Expected Result: The widget's JSON field is present but empty.

+ * + * @throws DotDataException if there is a data-related error. + * @throws DotSecurityException if there is a security-related error. + */ + @Test + public void test_widget_returns_NO_json() throws DotDataException, DotSecurityException { + Map map = new DotTransformerBuilder().defaultOptions() + .content(widgetWithoutJson).build().toMaps().get(0); + Map widgetCode = (Map) map.get( + WidgetContentType.WIDGET_CODE_JSON_FIELD_VAR); + assertNotNull(widgetCode); + assertTrue(widgetCode.isEmpty()); + } + + /** + * Validates that a widget with JSON code produces the correct JSON response. + * + *

Given Scenario: A widget is created with content that includes JSON-producing + * code.

+ *

Expected Result: The widget's JSON field contains the expected key-value pair.

+ * + * @throws DotDataException if there is a data-related error. + * @throws DotSecurityException if there is a security-related error. + */ + @Test + public void test_widget_returns_WITH_json() throws DotDataException, DotSecurityException { + + Map map = new DotTransformerBuilder().defaultOptions() + .content(widgetWithJson).build().toMaps().get(0); + Map widgetCode = (Map) map.get( + WidgetContentType.WIDGET_CODE_JSON_FIELD_VAR); + assertNotNull(widgetCode); + assertFalse(widgetCode.isEmpty()); + assertEquals(VELOCITY_MESSAGE, widgetCode.get("message")); + + } + + /** + * Validates that a widget with session-modifying code does not affect the actual HTTP session. + * + *

Given Scenario: A widget is created with content intended to invalidate the + * session.

+ *

Expected Result: The session remains unchanged, preserving its attributes and + * ID.

+ */ + @Test + public void test_widget_does_not_modify_real_request_session() { + + //This should pass as none mocked request + //Cause of we pass a mock the impersonator will not mock a mock + final HttpServletRequest request = new HttpServletRequestWrapper(new MockSessionRequest( + new MockHeaderRequest(new FakeHttpRequest("localhost", "/").request())).request()); + + request.getSession().setAttribute("testing", Boolean.TRUE); + String sessionId = request.getSession().getId(); + + try { + HttpServletRequestThreadLocal.INSTANCE.setRequest(request); + + Map map = new DotTransformerBuilder().defaultOptions() + .content(widgetSessionKiller).build().toMaps().get(0); + Map widgetCode = (Map) map.get( + WidgetContentType.WIDGET_CODE_JSON_FIELD_VAR); + assertNotNull(widgetCode); + assertTrue(widgetCode.isEmpty()); + + assertEquals(sessionId, request.getSession().getId()); + assertTrue((Boolean) request.getSession().getAttribute("testing")); + + + } finally { + HttpServletRequestThreadLocal.INSTANCE.setRequest(null); + } + + } + +} \ No newline at end of file diff --git a/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/util/ContentletUtilTest.java b/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/util/ContentletUtilTest.java index ebcf3af18631..a5e19afb6087 100644 --- a/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/util/ContentletUtilTest.java +++ b/dotcms-integration/src/test/java/com/dotmarketing/portlets/contentlet/util/ContentletUtilTest.java @@ -5,6 +5,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import com.dotcms.DataProviderWeldRunner; import com.dotcms.IntegrationTestBase; import com.dotcms.contenttype.model.field.CategoryField; import com.dotcms.contenttype.model.field.Field; @@ -44,6 +45,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import javax.enterprise.context.ApplicationScoped; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -51,7 +53,8 @@ /** * Created by Oscar Arrieta on 6/13/17. */ -@RunWith(DataProviderRunner.class) +@ApplicationScoped +@RunWith(DataProviderWeldRunner.class) public class ContentletUtilTest extends IntegrationTestBase { private static User user; diff --git a/dotcms-integration/src/test/java/com/dotmarketing/portlets/htmlpages/business/render/HTMLPageAssetRenderedAPIImplIntegrationTest.java b/dotcms-integration/src/test/java/com/dotmarketing/portlets/htmlpages/business/render/HTMLPageAssetRenderedAPIImplIntegrationTest.java index d75bc00b98d9..0b5f9769bd94 100644 --- a/dotcms-integration/src/test/java/com/dotmarketing/portlets/htmlpages/business/render/HTMLPageAssetRenderedAPIImplIntegrationTest.java +++ b/dotcms-integration/src/test/java/com/dotmarketing/portlets/htmlpages/business/render/HTMLPageAssetRenderedAPIImplIntegrationTest.java @@ -2,6 +2,7 @@ import com.dotcms.IntegrationTestBase; +import com.dotcms.JUnit4WeldRunner; import com.dotcms.api.web.HttpServletRequestThreadLocal; import com.dotcms.contenttype.model.field.Field; import com.dotcms.contenttype.model.field.TextField; @@ -59,6 +60,7 @@ import com.dotmarketing.util.WebKeys; import com.liferay.portal.model.User; import com.liferay.util.StringPool; +import javax.enterprise.context.ApplicationScoped; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Ignore; @@ -71,6 +73,7 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; +import org.junit.runner.RunWith; import static com.dotcms.rendering.velocity.directive.ParseContainer.getDotParserContainerUUID; import static com.dotcms.util.CollectionsUtils.list; @@ -79,6 +82,8 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +@ApplicationScoped +@RunWith(JUnit4WeldRunner.class) public class HTMLPageAssetRenderedAPIImplIntegrationTest extends IntegrationTestBase { private HttpServletRequest request;