From 7cc4d9ed1402e3eb0137a027ffb27df17660d920 Mon Sep 17 00:00:00 2001 From: jdotcms Date: Mon, 23 Sep 2024 15:58:25 -0600 Subject: [PATCH] #29866 adding first draft for the viewtool --- .../content/ContentAnalyticsAPI.java | 16 +- .../content/ContentAnalyticsAPIImpl.java | 8 + .../content/ContentAnalyticsFactory.java | 10 ++ .../content/ContentAnalyticsFactoryImpl.java | 14 ++ .../analytics/viewtool/AnalyticsTool.java | 155 ++++++++++++++++++ dotCMS/src/main/webapp/WEB-INF/toolbox.xml | 5 + 6 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 dotCMS/src/main/java/com/dotcms/analytics/viewtool/AnalyticsTool.java diff --git a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPI.java b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPI.java index b9727a2e26ae..7b297eb8e716 100644 --- a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPI.java +++ b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPI.java @@ -1,16 +1,30 @@ package com.dotcms.analytics.content; import com.dotcms.analytics.query.AnalyticsQuery; +import com.dotcms.cube.CubeJSQuery; import com.liferay.portal.model.User; /** - * + * This interface provides the methods to run reports on content analytics. * * @author Jose Castro * @since Sep 13th, 2024 */ public interface ContentAnalyticsAPI { + /** + * Run a report based on an analytics query + * @param query + * @param user + * @return ReportResponse + */ ReportResponse runReport(final AnalyticsQuery query, final User user); + /** + * Runs a raw report based on a cubeJS query + * @param cubeJSQuery + * @param user + * @return ReportResponse + */ + ReportResponse runRawReport(CubeJSQuery cubeJSQuery, User user); } diff --git a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPIImpl.java b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPIImpl.java index 9fff54bf4257..2417314de079 100644 --- a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPIImpl.java +++ b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPIImpl.java @@ -1,6 +1,7 @@ package com.dotcms.analytics.content; import com.dotcms.analytics.query.AnalyticsQuery; +import com.dotcms.cube.CubeJSQuery; import com.dotmarketing.util.Logger; import com.liferay.portal.model.User; @@ -31,4 +32,11 @@ public ReportResponse runReport(final AnalyticsQuery query, final User user) { return this.contentAnalyticsFactory.getReport(query, user); } + @Override + public ReportResponse runRawReport(CubeJSQuery cubeJSQuery, User user) { + Logger.debug(this, ()-> "Running the report for the raw query: " + cubeJSQuery); + // note: should check any permissions for an user. + return this.contentAnalyticsFactory.getRawReport(cubeJSQuery, user); + } + } diff --git a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactory.java b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactory.java index 9f2f771a48ae..2821e6de5009 100644 --- a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactory.java +++ b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactory.java @@ -1,6 +1,7 @@ package com.dotcms.analytics.content; import com.dotcms.analytics.query.AnalyticsQuery; +import com.dotcms.cube.CubeJSQuery; import com.liferay.portal.model.User; /** @@ -20,4 +21,13 @@ public interface ContentAnalyticsFactory { */ ReportResponse getReport(final AnalyticsQuery query, final User user); + /** + * Runs the raw report based on the cube js query and user. + * + * @param query the query to run the report. + * @param user the user to run the report. + * @return the report response. + */ + ReportResponse getRawReport(final CubeJSQuery query, final User user); + } diff --git a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactoryImpl.java b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactoryImpl.java index b7338db2329d..be1e7f999d5e 100644 --- a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactoryImpl.java @@ -41,6 +41,20 @@ public ReportResponse getReport(final AnalyticsQuery query, final User user) { Logger.debug(this, ()-> "Getting the report for the query: " + query); try { final CubeJSQuery cubeJSQuery = this.queryParser.parseQueryToCubeQuery(query); + return getRawReport(cubeJSQuery, user); + } catch (Exception e) { + + Logger.error(this, e.getMessage(), e); + throw new DotRuntimeException(e); + } + } + + @Override + public ReportResponse getRawReport(final CubeJSQuery cubeJSQuery, final User user) { + + try { + + Logger.debug(this, ()-> "Getting the report for the raw query: " + cubeJSQuery); final CubeJSClient cubeClient = cubeJSClientFactory.create(user); return toReportResponse(cubeClient.send(cubeJSQuery)); } catch (DotDataException| DotSecurityException e) { diff --git a/dotCMS/src/main/java/com/dotcms/analytics/viewtool/AnalyticsTool.java b/dotCMS/src/main/java/com/dotcms/analytics/viewtool/AnalyticsTool.java new file mode 100644 index 000000000000..4efd255c30cd --- /dev/null +++ b/dotCMS/src/main/java/com/dotcms/analytics/viewtool/AnalyticsTool.java @@ -0,0 +1,155 @@ +package com.dotcms.analytics.viewtool; + +import com.dotcms.analytics.content.ContentAnalyticsAPI; +import com.dotcms.analytics.content.ReportResponse; +import com.dotcms.analytics.query.AnalyticsQuery; +import com.dotcms.analytics.query.AnalyticsQueryParser; +import com.dotcms.cdi.CDIUtils; +import com.dotcms.cube.CubeJSQuery; +import com.dotcms.rest.api.v1.DotObjectMapperProvider; +import com.dotmarketing.business.web.WebAPILocator; +import com.dotmarketing.exception.DotRuntimeException; +import com.dotmarketing.util.Logger; +import com.liferay.portal.model.User; +import org.apache.velocity.tools.view.context.ViewContext; +import org.apache.velocity.tools.view.tools.ViewTool; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import java.util.Map; + +/** + * This class is a ViewTool that can be used to access the analytics data. + * @author jsanca + */ +public class AnalyticsTool implements ViewTool { + + private final ContentAnalyticsAPI contentAnalyticsAPI; + private final AnalyticsQueryParser analyticsQueryParser; + + private User user = null; + + public AnalyticsTool() { + this(CDIUtils.getBean(ContentAnalyticsAPI.class).get(), + CDIUtils.getBean(AnalyticsQueryParser.class).get()); + } + + + public AnalyticsTool(final ContentAnalyticsAPI contentAnalyticsAPI, + final AnalyticsQueryParser analyticsQueryParser) { + + this.contentAnalyticsAPI = contentAnalyticsAPI; + this.analyticsQueryParser = analyticsQueryParser; + } + + @Override + public void init(final Object initData) { + + if (initData instanceof ViewContext) { + + final HttpServletRequest request = ((ViewContext) initData).getRequest(); + final HttpSession session = request.getSession(false); + + if (session != null) { + try { + user = WebAPILocator.getUserWebAPI().getLoggedInUser(request); + } catch (DotRuntimeException e) { + Logger.error(this.getClass(), e.getMessage()); + } + } + } + } + + /** + * Runs an analytics report based on the string json query. + * example: + * + * #set($query = "{ + * "dimensions": ["Events.referer", "Events.experiment", "Events.variant", "Events.utcTime", "Events.url", "Events.lookBackWindow", "Events.eventType"], + * "measures": ["Events.count", "Events.uniqueCount"], + * "filters": "Events.variant = ['B'] or Events.experiments = ['B']", + * "limit":100, + * "offset":1, + * "timeDimensions":"Events.day day", + * "orders":"Events.day ASC" + * }") + * + * $dotanalytics.runReportFromJson($query) + * + * @param query + * @return + */ + public ReportResponse runReportFromJson(final String query) { + + Logger.debug(this, () -> "Running report from json: " + query); + return contentAnalyticsAPI.runReport(this.analyticsQueryParser.parseJsonToQuery(query), user); + } + + /** + * Runs an analytics report based on Map query. + * example: + * + * #set ($myQuery = {}) + * $myMap.put('dimensions', ["Events.referer", "Events.experiment", "Events.variant", "Events.utcTime", "Events.url", "Events.lookBackWindow", "Events.eventType"]) + * $myMap.put('measures', ["Events.count", "Events.uniqueCount"]) + * $myMap.put('filters', "Events.variant = ['B'] or Events.experiments = ['B']") + * $myMap.put('limit', 100) + * $myMap.put('offset', 1) + * $myMap.put('timeDimensions', "Events.day day") + * $myMap.put('orders', "Events.day ASC") + * + * $dotanalytics.runReportFromMap($myQuery) + * + * @param query + * @return + */ + public ReportResponse runReportFromMap(final Map query) { + + Logger.debug(this, () -> "Running report from map: " + query); + final AnalyticsQuery analyticsQuery = DotObjectMapperProvider.getInstance() + .getDefaultObjectMapper().convertValue(query, AnalyticsQuery.class); + return contentAnalyticsAPI.runReport(analyticsQuery, user); + } + + /** + * Runs an analytics report based cube js raw json string query + * + * example: + * + * #set($query = "{ + * + * }") + * + * $dotanalytics.runRawReportFromJson($query) + * + * @param query + * @return + */ + public ReportResponse runRawReportFromJson(final Map query) { + + Logger.debug(this, () -> "Running report from raw query: " + query); + final CubeJSQuery cubeJSQuery = DotObjectMapperProvider.getInstance() + .getDefaultObjectMapper().convertValue(query, CubeJSQuery.class); + return contentAnalyticsAPI.runRawReport(cubeJSQuery, user); + } + + /** + * Runs an analytics report based on Map query. + * example: + * + * #set ($myQuery = {}) + * + * + * $dotanalytics.runRawReportFromMap($myQuery) + * + * @param query + * @return + */ + public ReportResponse runRawReportFromMap(final Map query) { + + Logger.debug(this, () -> "Running report from raw query map: " + query); + final CubeJSQuery cubeJSQuery = DotObjectMapperProvider.getInstance() + .getDefaultObjectMapper().convertValue(query, CubeJSQuery.class); + return contentAnalyticsAPI.runRawReport(cubeJSQuery, user); + } +} diff --git a/dotCMS/src/main/webapp/WEB-INF/toolbox.xml b/dotCMS/src/main/webapp/WEB-INF/toolbox.xml index dbc7172ebbaa..2371ca535fdb 100644 --- a/dotCMS/src/main/webapp/WEB-INF/toolbox.xml +++ b/dotCMS/src/main/webapp/WEB-INF/toolbox.xml @@ -322,4 +322,9 @@ request com.dotcms.ai.viewtool.AIViewTool + + analytics + request + com.dotcms.analytics.viewtool.AnalyticsTool +