diff --git a/api/chalicelib/core/heatmaps.py b/api/chalicelib/core/heatmaps.py index 1b93c3010f..5dcbb9fb0b 100644 --- a/api/chalicelib/core/heatmaps.py +++ b/api/chalicelib/core/heatmaps.py @@ -80,7 +80,7 @@ def get_by_url(project_id, data: schemas.GetHeatmapPayloadSchema): return helper.list_to_camel_case(rows) -def get_by_url_and_session_id(project_id, session_id, data: schemas.GetHeatmapBasePayloadSchema): +def get_x_y_by_url_and_session_id(project_id, session_id, data: schemas.GetHeatmapBasePayloadSchema): args = {"session_id": session_id, "url": data.url} constraints = ["session_id = %(session_id)s", "(url = %(url)s OR path= %(url)s)", @@ -108,6 +108,35 @@ def get_by_url_and_session_id(project_id, session_id, data: schemas.GetHeatmapBa return helper.list_to_camel_case(rows) +def get_selectors_by_url_and_session_id(project_id, session_id, data: schemas.GetHeatmapBasePayloadSchema): + args = {"session_id": session_id, "url": data.url} + constraints = ["session_id = %(session_id)s", + "(url = %(url)s OR path= %(url)s)"] + query_from = "events.clicks" + + with pg_client.PostgresClient() as cur: + query = cur.mogrify(f"""SELECT selector, COUNT(1) AS count + FROM {query_from} + WHERE {" AND ".join(constraints)} + GROUP BY 1 + ORDER BY count DESC;""", args) + logger.debug("---------") + logger.debug(query.decode('UTF-8')) + logger.debug("---------") + try: + cur.execute(query) + except Exception as err: + logger.warning("--------- HEATMAP-selector-session_id SEARCH QUERY EXCEPTION -----------") + logger.warning(query.decode('UTF-8')) + logger.warning("--------- PAYLOAD -----------") + logger.warning(data) + logger.warning("--------------------") + raise err + rows = cur.fetchall() + + return helper.list_to_camel_case(rows) + + SESSION_PROJECTION_COLS = """s.project_id, s.session_id::text AS session_id, s.user_uuid, diff --git a/api/routers/core_dynamic.py b/api/routers/core_dynamic.py index 1fd8551926..577a982b79 100644 --- a/api/routers/core_dynamic.py +++ b/api/routers/core_dynamic.py @@ -417,11 +417,18 @@ def get_heatmaps_by_url(projectId: int, data: schemas.GetHeatmapPayloadSchema = return {"data": heatmaps.get_by_url(project_id=projectId, data=data)} -@app.post('/{projectId}/sessions/{sessionId}/heatmaps/url', tags=["heatmaps"]) +@app.post('/{projectId}/sessions/{sessionId}/heatmaps', tags=["heatmaps"]) def get_heatmaps_by_session_id_url(projectId: int, sessionId: int, data: schemas.GetHeatmapBasePayloadSchema = Body(...), context: schemas.CurrentContext = Depends(OR_context)): - return {"data": heatmaps.get_by_url_and_session_id(project_id=projectId, session_id=sessionId, data=data)} + return {"data": heatmaps.get_x_y_by_url_and_session_id(project_id=projectId, session_id=sessionId, data=data)} + + +@app.post('/{projectId}/sessions/{sessionId}/clickmaps', tags=["heatmaps"]) +def get_clickmaps_by_session_id_url(projectId: int, sessionId: int, + data: schemas.GetHeatmapBasePayloadSchema = Body(...), + context: schemas.CurrentContext = Depends(OR_context)): + return {"data": heatmaps.get_selectors_by_url_and_session_id(project_id=projectId, session_id=sessionId, data=data)} @app.get('/{projectId}/sessions/{sessionId}/favorite', tags=["sessions"]) diff --git a/ee/api/chalicelib/core/heatmaps.py b/ee/api/chalicelib/core/heatmaps.py index d415c9aae0..bb92a369ac 100644 --- a/ee/api/chalicelib/core/heatmaps.py +++ b/ee/api/chalicelib/core/heatmaps.py @@ -90,7 +90,7 @@ def get_by_url(project_id, data: schemas.GetHeatmapPayloadSchema): return helper.list_to_camel_case(rows) -def get_by_url_and_session_id(project_id, session_id, data: schemas.GetHeatmapBasePayloadSchema): +def get_x_y_by_url_and_session_id(project_id, session_id, data: schemas.GetHeatmapBasePayloadSchema): args = {"project_id": project_id, "session_id": session_id, "url": data.url} constraints = ["main_events.project_id = toUInt16(%(project_id)s)", "main_events.session_id = %(session_id)s", @@ -120,6 +120,37 @@ def get_by_url_and_session_id(project_id, session_id, data: schemas.GetHeatmapBa return helper.list_to_camel_case(rows) +def get_selectors_by_url_and_session_id(project_id, session_id, data: schemas.GetHeatmapBasePayloadSchema): + args = {"project_id": project_id, "session_id": session_id, "url": data.url} + constraints = ["main_events.project_id = toUInt16(%(project_id)s)", + "main_events.session_id = %(session_id)s", + "(main_events.url_hostpath = %(url)s OR main_events.url_path = %(url)s)", + "main_events.event_type='CLICK'"] + query_from = f"{exp_ch_helper.get_main_events_table(0)} AS main_events" + + with ch_client.ClickHouseClient() as cur: + query = cur.format(f"""SELECT main_events.selector AS selector, + COUNT(1) AS count + FROM {query_from} + WHERE {" AND ".join(constraints)} + GROUP BY 1 + ORDER BY count DESC;""", args) + logger.debug("---------") + logger.debug(query) + logger.debug("---------") + try: + rows = cur.execute(query) + except Exception as err: + logger.warning("--------- HEATMAP-session_id SEARCH QUERY EXCEPTION CH -----------") + logger.warning(query) + logger.warning("--------- PAYLOAD -----------") + logger.warning(data) + logger.warning("--------------------") + raise err + + return helper.list_to_camel_case(rows) + + if not config("EXP_SESSIONS_SEARCH", cast=bool, default=False): # this part is identical to FOSS SESSION_PROJECTION_COLS = """s.project_id, diff --git a/ee/api/routers/core_dynamic.py b/ee/api/routers/core_dynamic.py index efd23986b2..cb6f353d1f 100644 --- a/ee/api/routers/core_dynamic.py +++ b/ee/api/routers/core_dynamic.py @@ -446,12 +446,20 @@ def get_heatmaps_by_url(projectId: int, data: schemas.GetHeatmapPayloadSchema = return {"data": heatmaps.get_by_url(project_id=projectId, data=data)} -@app.post('/{projectId}/sessions/{sessionId}/heatmaps/url', tags=["heatmaps"], +@app.post('/{projectId}/sessions/{sessionId}/heatmaps', tags=["heatmaps"], dependencies=[OR_scope(Permissions.session_replay)]) def get_heatmaps_by_session_id_url(projectId: int, sessionId: int, data: schemas.GetHeatmapBasePayloadSchema = Body(...), context: schemas.CurrentContext = Depends(OR_context)): - return {"data": heatmaps.get_by_url_and_session_id(project_id=projectId, session_id=sessionId, data=data)} + return {"data": heatmaps.get_x_y_by_url_and_session_id(project_id=projectId, session_id=sessionId, data=data)} + + +@app.post('/{projectId}/sessions/{sessionId}/clickmaps', tags=["heatmaps"], + dependencies=[OR_scope(Permissions.session_replay)]) +def get_clickmaps_by_session_id_url(projectId: int, sessionId: int, + data: schemas.GetHeatmapBasePayloadSchema = Body(...), + context: schemas.CurrentContext = Depends(OR_context)): + return {"data": heatmaps.get_selectors_by_url_and_session_id(project_id=projectId, session_id=sessionId, data=data)} @app.get('/{projectId}/sessions/{sessionId}/favorite', tags=["sessions"],