diff --git a/frontend/src/scenes/trends/PeopleModal.js b/frontend/src/scenes/trends/PeopleModal.js
index ef63a7bc633..ca6fe15b86f 100644
--- a/frontend/src/scenes/trends/PeopleModal.js
+++ b/frontend/src/scenes/trends/PeopleModal.js
@@ -2,12 +2,12 @@ import React from 'react'
import { useActions, useValues } from 'kea'
import moment from 'moment'
import { trendsLogic } from 'scenes/trends/trendsLogic'
-import { Modal, Button } from 'antd'
+import { Modal, Button, Spin } from 'antd'
import { PeopleTable } from 'scenes/users/PeopleTable'
export function PeopleModal({ visible }) {
const { people, filters } = useValues(trendsLogic({ id: null }))
- const { setShowingPeople } = useActions(trendsLogic({ dashboardItemId: null }))
+ const { setShowingPeople, loadMorePeople } = useActions(trendsLogic({ dashboardItemId: null }))
const title =
filters.shown_as === 'Stickiness'
@@ -26,13 +26,24 @@ export function PeopleModal({ visible }) {
{people ? (
Found {people.count} {people.count === 1 ? 'user' : 'users'}
- {people.count > 100 ? '. Showing the first 100 below.' : ''}
) : (
Loading users...
)}
+
+ {people?.next && (
+
+ )}
+
)
}
diff --git a/frontend/src/scenes/trends/trendsLogic.js b/frontend/src/scenes/trends/trendsLogic.js
index 7a8e14be832..c0c286bc09e 100644
--- a/frontend/src/scenes/trends/trendsLogic.js
+++ b/frontend/src/scenes/trends/trendsLogic.js
@@ -81,6 +81,32 @@ function autocorrectInterval({ date_from, interval }) {
}
}
+function parsePeopleParams(peopleParams, filters) {
+ const { action, day, breakdown_value } = peopleParams
+ const params = filterClientSideParams({
+ ...filters,
+ entityId: action.id,
+ type: action.type,
+ breakdown_value,
+ })
+
+ if (filters.shown_as === STICKINESS) {
+ params.stickiness_days = day
+ } else if (params.display === ACTIONS_LINE_GRAPH_CUMULATIVE) {
+ params.date_to = day
+ } else {
+ params.date_from = day
+ params.date_to = day
+ }
+ // If breakdown type is cohort, we use breakdown_value
+ // If breakdown type is event, we just set another filter
+ if (breakdown_value && filters.breakdown_type != 'cohort') {
+ params.properties = [...params.properties, { key: params.breakdown, value: breakdown_value, type: 'event' }]
+ }
+
+ return toAPIParams(params)
+}
+
// props:
// - dashboardItemId
// - filters
@@ -121,14 +147,17 @@ export const trendsLogic = kea({
setDisplay: display => ({ display }),
loadPeople: (action, label, day, breakdown_value) => ({ action, label, day, breakdown_value }),
+ loadMorePeople: true,
+ setLoadingMorePeople: status => ({ status }),
setShowingPeople: isShowing => ({ isShowing }),
- setPeople: (people, count, action, label, day, breakdown_value) => ({
+ setPeople: (people, count, action, label, day, breakdown_value, next) => ({
people,
count,
action,
label,
day,
breakdown_value,
+ next,
}),
setActiveView: type => ({ type }),
setCachedUrl: (type, url) => ({ type, url }),
@@ -151,6 +180,7 @@ export const trendsLogic = kea({
{
[actions.setFilters]: () => null,
[actions.setPeople]: (_, people) => people,
+ [actions.setLoadingMorePeople]: (state, { status }) => ({ ...state, loadingMore: status }),
},
],
cachedUrls: [
@@ -183,35 +213,35 @@ export const trendsLogic = kea({
actions.setFilters({ display })
},
[actions.loadPeople]: async ({ label, action, day, breakdown_value }, breakpoint) => {
- const params = filterClientSideParams({
- ...values.filters,
- entityId: action.id,
- type: action.type,
- breakdown_value,
- })
-
- if (values.filters.shown_as === STICKINESS) {
- params.stickiness_days = day
- } else if (params.display === ACTIONS_LINE_GRAPH_CUMULATIVE) {
- params.date_to = day
- } else {
- params.date_from = day
- params.date_to = day
- }
- // If breakdown type is cohort, we use breakdown_value
- // If breakdown type is event, we just set another filter
- if (breakdown_value && values.filters.breakdown_type != 'cohort') {
- params.properties = [
- ...params.properties,
- { key: params.breakdown, value: breakdown_value, type: 'event' },
- ]
- }
-
- const filterParams = toAPIParams(params)
- actions.setPeople(null, null, action, label, day, breakdown_value)
+ const filterParams = parsePeopleParams({ label, action, day, breakdown_value }, values.filters)
+ actions.setPeople(null, null, action, label, day, breakdown_value, null)
const people = await api.get(`api/action/people/?include_last_event=1&${filterParams}`)
breakpoint()
- actions.setPeople(people[0]?.people, people[0]?.count, action, label, day, breakdown_value)
+ actions.setPeople(
+ people.results[0]?.people,
+ people.results[0]?.count,
+ action,
+ label,
+ day,
+ breakdown_value,
+ people.next
+ )
+ },
+ [actions.loadMorePeople]: async (_, breakpoint) => {
+ const { people: currPeople, count, action, label, day, breakdown_value, next } = values.people
+ actions.setLoadingMorePeople(true)
+ const people = await api.get(next)
+ actions.setLoadingMorePeople(false)
+ breakpoint()
+ actions.setPeople(
+ [...currPeople, ...people.results[0]?.people],
+ count + people.results[0]?.count,
+ action,
+ label,
+ day,
+ breakdown_value,
+ people.next
+ )
},
}),
diff --git a/frontend/src/scenes/users/PeopleTable.js b/frontend/src/scenes/users/PeopleTable.js
index b7bdc17e6a2..2028bdd9e9d 100644
--- a/frontend/src/scenes/users/PeopleTable.js
+++ b/frontend/src/scenes/users/PeopleTable.js
@@ -38,7 +38,7 @@ export function PeopleTable({ people, loading, actions, onChange }) {
columns={columns}
loading={loading}
rowKey={person => person.id}
- pagination={{ pageSize: 100, hideOnSinglePage: true }}
+ pagination={{ pageSize: 99999, hideOnSinglePage: true }}
expandable={{
expandedRowRender: function RenderPropertiesTable({ properties }) {
return
diff --git a/posthog/api/action.py b/posthog/api/action.py
index b0bb1550197..8bdd87219e5 100644
--- a/posthog/api/action.py
+++ b/posthog/api/action.py
@@ -105,7 +105,9 @@ def get_actions(queryset: QuerySet, params: dict, team_id: int) -> QuerySet:
queryset = queryset.filter(
pk__in=[
action.id
- for action in Filter({"actions": json.loads(params.get("actions", "[]"))}).actions
+ for action in Filter(
+ {"actions": json.loads(params.get("actions", "[]"))}
+ ).actions
]
)
@@ -131,7 +133,9 @@ class ActionViewSet(viewsets.ModelViewSet):
queryset = super().get_queryset()
if self.action == "list": # type: ignore
queryset = queryset.filter(deleted=False)
- return get_actions(queryset, self.request.GET.dict(), self.request.user.team_set.get().pk)
+ return get_actions(
+ queryset, self.request.GET.dict(), self.request.user.team_set.get().pk
+ )
def create(self, request: request.Request, *args: Any, **kwargs: Any) -> Response:
action, created = Action.objects.get_or_create(
@@ -144,7 +148,9 @@ class ActionViewSet(viewsets.ModelViewSet):
},
)
if not created:
- return Response(data={"detail": "action-exists", "id": action.pk}, status=400)
+ return Response(
+ data={"detail": "action-exists", "id": action.pk}, status=400
+ )
if request.data.get("steps"):
for step in request.data["steps"]:
@@ -195,7 +201,9 @@ class ActionViewSet(viewsets.ModelViewSet):
actions = self.get_queryset()
actions_list: List[Dict[Any, Any]] = ActionSerializer(actions, many=True, context={"request": request}).data # type: ignore
if request.GET.get("include_count", False):
- actions_list.sort(key=lambda action: action.get("count", action["id"]), reverse=True)
+ actions_list.sort(
+ key=lambda action: action.get("count", action["id"]), reverse=True
+ )
return Response({"results": actions_list})
@action(methods=["GET"], detail=False)
@@ -223,14 +231,17 @@ class ActionViewSet(viewsets.ModelViewSet):
def people(self, request: request.Request, *args: Any, **kwargs: Any) -> Response:
team = request.user.team_set.get()
filter = Filter(request=request)
+ offset = int(request.GET.get("offset", 0))
- def _calculate_people(events: QuerySet):
+ def _calculate_people(events: QuerySet, offset: int):
shown_as = request.GET.get("shown_as")
if shown_as is not None and shown_as == "Stickiness":
stickiness_days = int(request.GET["stickiness_days"])
events = (
events.values("person_id")
- .annotate(day_count=Count(functions.TruncDay("timestamp"), distinct=True))
+ .annotate(
+ day_count=Count(functions.TruncDay("timestamp"), distinct=True)
+ )
.filter(day_count=stickiness_days)
)
else:
@@ -250,7 +261,8 @@ class ActionViewSet(viewsets.ModelViewSet):
)
people = Person.objects.filter(
- team=team, id__in=[p["person_id"] for p in events[0:100]]
+ team=team,
+ id__in=[p["person_id"] for p in events[offset : offset + 100]],
)
people = people.prefetch_related(
@@ -270,7 +282,9 @@ class ActionViewSet(viewsets.ModelViewSet):
if len(filter.entities) >= 1:
entity = filter.entities[0]
else:
- entity = Entity({"id": request.GET["entityId"], "type": request.GET["type"]})
+ entity = Entity(
+ {"id": request.GET["entityId"], "type": request.GET["type"]}
+ )
if entity.type == TREND_FILTER_TYPE_EVENTS:
filtered_events = process_entity_for_events(
@@ -287,8 +301,28 @@ class ActionViewSet(viewsets.ModelViewSet):
entity, team_id=team.pk, order_by=None
).filter(filter_events(team.pk, filter, entity))
- people = _calculate_people(events=filtered_events)
- return Response([people])
+ people = _calculate_people(events=filtered_events, offset=offset)
+
+ current_url = request.get_full_path()
+ next_url: Optional[str] = request.get_full_path()
+ if people["count"] > 99 and next_url:
+ if "offset" in next_url:
+ next_url = next_url[1:]
+ next_url = next_url.replace(
+ "offset=" + str(offset), "offset=" + str(offset + 100)
+ )
+ else:
+ next_url = request.build_absolute_uri(
+ "{}{}offset={}".format(
+ next_url, "&" if "?" in next_url else "?", offset + 100
+ )
+ )
+ else:
+ next_url = None
+
+ return Response(
+ {"results": [people], "next": next_url, "previous": current_url[1:]}
+ )
def calculate_trends(
@@ -301,7 +335,13 @@ def calculate_trends(
if len(filter.entities) == 0:
# If no filters, automatically grab all actions and show those instead
filter.entities = [
- Entity({"id": action.id, "name": action.name, "type": TREND_FILTER_TYPE_ACTIONS,})
+ Entity(
+ {
+ "id": action.id,
+ "name": action.name,
+ "type": TREND_FILTER_TYPE_ACTIONS,
+ }
+ )
for action in actions
]
@@ -340,7 +380,9 @@ def calculate_trends(
)
compared_trend_entity = convert_to_comparison(
- compared_trend_entity, compared_filter, "{} - {}".format(entity.name, "previous"),
+ compared_trend_entity,
+ compared_filter,
+ "{} - {}".format(entity.name, "previous"),
)
entities_list.extend(compared_trend_entity)
else:
@@ -378,9 +420,13 @@ def build_dataframe(
]
)
if interval == "week":
- dataframe["date"] = dataframe["date"].apply(lambda x: x - pd.offsets.Week(weekday=6))
+ dataframe["date"] = dataframe["date"].apply(
+ lambda x: x - pd.offsets.Week(weekday=6)
+ )
elif interval == "month":
- dataframe["date"] = dataframe["date"].apply(lambda x: x - pd.offsets.MonthEnd(n=1))
+ dataframe["date"] = dataframe["date"].apply(
+ lambda x: x - pd.offsets.MonthEnd(n=1)
+ )
return dataframe
@@ -415,13 +461,15 @@ def group_events_to_date(
df_dates = pd.DataFrame(filtered.groupby("date").mean(), index=time_index)
df_dates = df_dates.fillna(0)
response[value] = {
- key: value[0] if len(value) > 0 else 0 for key, value in df_dates.iterrows()
+ key: value[0] if len(value) > 0 else 0
+ for key, value in df_dates.iterrows()
}
else:
dataframe = pd.DataFrame([], index=time_index)
dataframe = dataframe.fillna(0)
response["total"] = {
- key: value[0] if len(value) > 0 else 0 for key, value in dataframe.iterrows()
+ key: value[0] if len(value) > 0 else 0
+ for key, value in dataframe.iterrows()
}
return response
@@ -444,13 +492,15 @@ def get_interval_annotation(key: str) -> Dict[str, Any]:
def add_cohort_annotations(
team_id: int, breakdown: List[Union[int, str]]
) -> Dict[str, Union[Value, Exists]]:
- cohorts = Cohort.objects.filter(team_id=team_id, pk__in=[b for b in breakdown if b != "all"])
+ cohorts = Cohort.objects.filter(
+ team_id=team_id, pk__in=[b for b in breakdown if b != "all"]
+ )
annotations: Dict[str, Union[Value, Exists]] = {}
for cohort in cohorts:
annotations["cohort_{}".format(cohort.pk)] = Exists(
- CohortPeople.objects.filter(cohort=cohort.pk, person_id=OuterRef("person_id")).only(
- "id"
- )
+ CohortPeople.objects.filter(
+ cohort=cohort.pk, person_id=OuterRef("person_id")
+ ).only("id")
)
if "all" in breakdown:
annotations["cohort_all"] = Value(True, output_field=BooleanField())
@@ -470,7 +520,9 @@ def aggregate_by_interval(
values = [interval]
if breakdown:
if params.get("breakdown_type") == "cohort":
- annotations = add_cohort_annotations(team_id, json.loads(params.get("breakdown", "[]")))
+ annotations = add_cohort_annotations(
+ team_id, json.loads(params.get("breakdown", "[]"))
+ )
values.extend(annotations.keys())
filtered_events = filtered_events.annotate(**annotations)
breakdown = "cohorts"
@@ -551,11 +603,14 @@ def stickiness(
}
-def breakdown_label(entity: Entity, value: Union[str, int]) -> Dict[str, Optional[Union[str, int]]]:
+def breakdown_label(
+ entity: Entity, value: Union[str, int]
+) -> Dict[str, Optional[Union[str, int]]]:
ret_dict: Dict[str, Optional[Union[str, int]]] = {}
if not value or not isinstance(value, str) or "cohort_" not in value:
ret_dict["label"] = "{} - {}".format(
- entity.name, value if value and value != "None" and value != "nan" else "Other",
+ entity.name,
+ value if value and value != "None" and value != "nan" else "Other",
)
ret_dict["breakdown_value"] = value if value and not pd.isna(value) else None
else:
@@ -607,14 +662,18 @@ def serialize_entity(
new_dict = copy.deepcopy(serialized)
if value != "Total":
new_dict.update(breakdown_label(entity, value))
- new_dict.update(append_data(dates_filled=list(item.items()), interval=interval))
+ new_dict.update(
+ append_data(dates_filled=list(item.items()), interval=interval)
+ )
if filter.display == TRENDS_CUMULATIVE:
new_dict["data"] = np.cumsum(new_dict["data"])
response.append(new_dict)
elif params.get("shown_as") == TRENDS_STICKINESS:
new_dict = copy.deepcopy(serialized)
new_dict.update(
- stickiness(filtered_events=events, entity=entity, filter=filter, team_id=team_id)
+ stickiness(
+ filtered_events=events, entity=entity, filter=filter, team_id=team_id
+ )
)
response.append(new_dict)
@@ -622,7 +681,9 @@ def serialize_entity(
def serialize_people(people: QuerySet, request: request.Request) -> Dict:
- people_dict = [PersonSerializer(person, context={"request": request}).data for person in people]
+ people_dict = [
+ PersonSerializer(person, context={"request": request}).data for person in people
+ ]
return {"people": people_dict, "count": len(people_dict)}
diff --git a/posthog/api/test/test_action.py b/posthog/api/test/test_action.py
index 8020245814f..866f8a1c7ea 100644
--- a/posthog/api/test/test_action.py
+++ b/posthog/api/test/test_action.py
@@ -7,75 +7,101 @@ from posthog.models import Action, ActionStep, Element, Event, Person, Team, Coh
from .base import BaseTest, TransactionBaseTest
-@patch('posthog.tasks.calculate_action.calculate_action.delay')
+@patch("posthog.tasks.calculate_action.calculate_action.delay")
class TestCreateAction(BaseTest):
TESTS_API = True
def test_create_and_update_action(self, patch_delay):
- Event.objects.create(team=self.team, event='$autocapture', elements=[
- Element(tag_name='button', order=0, text='sign up NOW'),
- Element(tag_name='div', order=1),
- ])
- response = self.client.post('/api/action/', data={
- 'name': 'user signed up',
- 'steps': [{
- "text": "sign up",
- "selector": "div > button",
- "url": "/signup",
- "isNew": 'asdf',
- }],
- }, content_type='application/json', HTTP_ORIGIN='http://testserver').json()
+ Event.objects.create(
+ team=self.team,
+ event="$autocapture",
+ elements=[
+ Element(tag_name="button", order=0, text="sign up NOW"),
+ Element(tag_name="div", order=1),
+ ],
+ )
+ response = self.client.post(
+ "/api/action/",
+ data={
+ "name": "user signed up",
+ "steps": [
+ {
+ "text": "sign up",
+ "selector": "div > button",
+ "url": "/signup",
+ "isNew": "asdf",
+ }
+ ],
+ },
+ content_type="application/json",
+ HTTP_ORIGIN="http://testserver",
+ ).json()
action = Action.objects.get()
- self.assertEqual(action.name, 'user signed up')
+ self.assertEqual(action.name, "user signed up")
self.assertEqual(action.team, self.team)
- self.assertEqual(action.steps.get().selector, 'div > button')
- self.assertEqual(response['steps'][0]['text'], 'sign up')
+ self.assertEqual(action.steps.get().selector, "div > button")
+ self.assertEqual(response["steps"][0]["text"], "sign up")
# test no actions with same name
- user2 = self._create_user('tim2')
+ user2 = self._create_user("tim2")
self.client.force_login(user2)
response = self.client.post(
- '/api/action/',
- data={'name': 'user signed up'},
- content_type='application/json',
- HTTP_ORIGIN='http://testserver',
+ "/api/action/",
+ data={"name": "user signed up"},
+ content_type="application/json",
+ HTTP_ORIGIN="http://testserver",
).json()
- self.assertEqual(response['detail'], 'action-exists')
+ self.assertEqual(response["detail"], "action-exists")
# test update
- event2 = Event.objects.create(team=self.team, event='$autocapture', properties={'$browser': 'Chrome'}, elements=[
- Element(tag_name='button', order=0, text='sign up NOW'),
- Element(tag_name='div', order=1),
- ])
- response = self.client.patch('/api/action/%s/' % action.pk, data={
- 'name': 'user signed up 2',
- 'steps': [{
- "id": action.steps.get().pk,
- "isNew": "asdf",
- "text": "sign up NOW",
- "selector": "div > button",
- "properties": [{'key': '$browser', 'value': 'Chrome'}],
- "url": None,
- }, {'href': '/a-new-link'}],
- }, content_type='application/json', HTTP_ORIGIN='http://testserver').json()
+ event2 = Event.objects.create(
+ team=self.team,
+ event="$autocapture",
+ properties={"$browser": "Chrome"},
+ elements=[
+ Element(tag_name="button", order=0, text="sign up NOW"),
+ Element(tag_name="div", order=1),
+ ],
+ )
+ response = self.client.patch(
+ "/api/action/%s/" % action.pk,
+ data={
+ "name": "user signed up 2",
+ "steps": [
+ {
+ "id": action.steps.get().pk,
+ "isNew": "asdf",
+ "text": "sign up NOW",
+ "selector": "div > button",
+ "properties": [{"key": "$browser", "value": "Chrome"}],
+ "url": None,
+ },
+ {"href": "/a-new-link"},
+ ],
+ },
+ content_type="application/json",
+ HTTP_ORIGIN="http://testserver",
+ ).json()
action = Action.objects.get()
action.calculate_events()
- steps = action.steps.all().order_by('id')
- self.assertEqual(action.name, 'user signed up 2')
- self.assertEqual(steps[0].text, 'sign up NOW')
- self.assertEqual(steps[1].href, '/a-new-link')
+ steps = action.steps.all().order_by("id")
+ self.assertEqual(action.name, "user signed up 2")
+ self.assertEqual(steps[0].text, "sign up NOW")
+ self.assertEqual(steps[1].href, "/a-new-link")
self.assertEqual(action.events.get(), event2)
self.assertEqual(action.events.count(), 1)
# test queries
with self.assertNumQueries(5):
- response = self.client.get('/api/action/')
+ response = self.client.get("/api/action/")
# test remove steps
- response = self.client.patch('/api/action/%s/' % action.pk, data={
- 'name': 'user signed up 2',
- 'steps': [],
- }, content_type='application/json', HTTP_ORIGIN='http://testserver').json()
+ response = self.client.patch(
+ "/api/action/%s/" % action.pk,
+ data={"name": "user signed up 2", "steps": [],},
+ content_type="application/json",
+ HTTP_ORIGIN="http://testserver",
+ ).json()
self.assertEqual(ActionStep.objects.count(), 0)
# When we send a user to their own site, we give them a token.
@@ -85,57 +111,73 @@ class TestCreateAction(BaseTest):
def test_create_from_other_domain(self, patch_delay):
# FIXME: BaseTest is using Django client to performe calls to a DRF endpoint.
# Django HttpResponse does not have an attribute `data`. Better use rest_framework.test.APIClient.
- response = self.client.post('/api/action/', data={
- 'name': 'user signed up',
- }, content_type='application/json', HTTP_ORIGIN='https://evilwebsite.com')
+ response = self.client.post(
+ "/api/action/",
+ data={"name": "user signed up",},
+ content_type="application/json",
+ HTTP_ORIGIN="https://evilwebsite.com",
+ )
self.assertEqual(response.status_code, 403)
- self.user.temporary_token = 'token123'
+ self.user.temporary_token = "token123"
self.user.save()
- response = self.client.post('/api/action/?temporary_token=token123', data={
- 'name': 'user signed up',
- }, content_type='application/json', HTTP_ORIGIN='https://somewebsite.com')
+ response = self.client.post(
+ "/api/action/?temporary_token=token123",
+ data={"name": "user signed up",},
+ content_type="application/json",
+ HTTP_ORIGIN="https://somewebsite.com",
+ )
self.assertEqual(response.status_code, 200)
- response = self.client.post('/api/action/?temporary_token=token123', data={
- 'name': 'user signed up and post to slack',
- 'post_to_slack': True,
- }, content_type='application/json', HTTP_ORIGIN='https://somewebsite.com')
+ response = self.client.post(
+ "/api/action/?temporary_token=token123",
+ data={"name": "user signed up and post to slack", "post_to_slack": True,},
+ content_type="application/json",
+ HTTP_ORIGIN="https://somewebsite.com",
+ )
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.json()['post_to_slack'], True)
+ self.assertEqual(response.json()["post_to_slack"], True)
- list_response = self.client.get('/api/action/', content_type='application/json', HTTP_ORIGIN='https://evilwebsite.com')
+ list_response = self.client.get(
+ "/api/action/",
+ content_type="application/json",
+ HTTP_ORIGIN="https://evilwebsite.com",
+ )
self.assertEqual(list_response.status_code, 403)
detail_response = self.client.get(
f"/api/action/{response.json()['id']}/",
- content_type='application/json',
- HTTP_ORIGIN='https://evilwebsite.com',
+ content_type="application/json",
+ HTTP_ORIGIN="https://evilwebsite.com",
)
self.assertEqual(detail_response.status_code, 403)
self.client.logout()
list_response = self.client.get(
- '/api/action/',
- data={
- 'temporary_token': 'token123',
- },
- content_type='application/json',
- HTTP_ORIGIN='https://somewebsite.com',
+ "/api/action/",
+ data={"temporary_token": "token123",},
+ content_type="application/json",
+ HTTP_ORIGIN="https://somewebsite.com",
)
self.assertEqual(list_response.status_code, 200)
- response = self.client.post('/api/action/?temporary_token=token123', data={
- 'name': 'user signed up 22',
- }, content_type='application/json', HTTP_ORIGIN='https://somewebsite.com')
+ response = self.client.post(
+ "/api/action/?temporary_token=token123",
+ data={"name": "user signed up 22",},
+ content_type="application/json",
+ HTTP_ORIGIN="https://somewebsite.com",
+ )
self.assertEqual(response.status_code, 200, response.json())
# This case happens when someone is running behind a proxy, but hasn't set `IS_BEHIND_PROXY`
def test_http_to_https(self, patch_delay):
- response = self.client.post('/api/action/', data={
- 'name': 'user signed up again',
- }, content_type='application/json', HTTP_ORIGIN='https://testserver/')
+ response = self.client.post(
+ "/api/action/",
+ data={"name": "user signed up again",},
+ content_type="application/json",
+ HTTP_ORIGIN="https://testserver/",
+ )
self.assertEqual(response.status_code, 200, response.json())
@@ -143,58 +185,88 @@ class TestTrends(TransactionBaseTest):
TESTS_API = True
def _create_events(self, use_time=False):
- no_events = Action.objects.create(team=self.team, name='no events')
- ActionStep.objects.create(action=no_events, event='no events')
+ no_events = Action.objects.create(team=self.team, name="no events")
+ ActionStep.objects.create(action=no_events, event="no events")
- sign_up_action = Action.objects.create(team=self.team, name='sign up')
- ActionStep.objects.create(action=sign_up_action, event='sign up')
+ sign_up_action = Action.objects.create(team=self.team, name="sign up")
+ ActionStep.objects.create(action=sign_up_action, event="sign up")
- person = Person.objects.create(team=self.team, distinct_ids=['blabla', 'anonymous_id'])
- secondTeam = Team.objects.create(api_token='token123')
+ person = Person.objects.create(
+ team=self.team, distinct_ids=["blabla", "anonymous_id"]
+ )
+ secondTeam = Team.objects.create(api_token="token123")
- freeze_without_time = ['2019-12-24', '2020-01-01', '2020-01-02']
- freeze_with_time = ['2019-12-24 03:45:34', '2020-01-01 00:06:34', '2020-01-02 16:34:34']
+ freeze_without_time = ["2019-12-24", "2020-01-01", "2020-01-02"]
+ freeze_with_time = [
+ "2019-12-24 03:45:34",
+ "2020-01-01 00:06:34",
+ "2020-01-02 16:34:34",
+ ]
freeze_args = freeze_without_time
if use_time:
freeze_args = freeze_with_time
with freeze_time(freeze_args[0]):
- Event.objects.create(team=self.team, event='sign up', distinct_id='blabla', properties={"$some_property": "value"})
+ Event.objects.create(
+ team=self.team,
+ event="sign up",
+ distinct_id="blabla",
+ properties={"$some_property": "value"},
+ )
with freeze_time(freeze_args[1]):
- Event.objects.create(team=self.team, event='sign up', distinct_id='blabla', properties={"$some_property": "value"})
- Event.objects.create(team=self.team, event='sign up', distinct_id='anonymous_id')
- Event.objects.create(team=self.team, event='sign up', distinct_id='blabla')
+ Event.objects.create(
+ team=self.team,
+ event="sign up",
+ distinct_id="blabla",
+ properties={"$some_property": "value"},
+ )
+ Event.objects.create(
+ team=self.team, event="sign up", distinct_id="anonymous_id"
+ )
+ Event.objects.create(team=self.team, event="sign up", distinct_id="blabla")
with freeze_time(freeze_args[2]):
Event.objects.create(
team=self.team,
- event='sign up',
- distinct_id='blabla',
- properties={"$some_property": "other_value", "$some_numerical_prop": 80},
+ event="sign up",
+ distinct_id="blabla",
+ properties={
+ "$some_property": "other_value",
+ "$some_numerical_prop": 80,
+ },
+ )
+ Event.objects.create(
+ team=self.team, event="no events", distinct_id="blabla"
)
- Event.objects.create(team=self.team, event='no events', distinct_id='blabla')
# second team should have no effect
Event.objects.create(
team=secondTeam,
- event='sign up',
- distinct_id='blabla',
+ event="sign up",
+ distinct_id="blabla",
properties={"$some_property": "other_value"},
)
return sign_up_action, person
def _create_breakdown_events(self):
- freeze_without_time = ['2020-01-02']
+ freeze_without_time = ["2020-01-02"]
- sign_up_action = Action.objects.create(team=self.team, name='sign up')
- ActionStep.objects.create(action=sign_up_action, event='sign up')
+ sign_up_action = Action.objects.create(team=self.team, name="sign up")
+ ActionStep.objects.create(action=sign_up_action, event="sign up")
with freeze_time(freeze_without_time[0]):
for i in range(25):
- Event.objects.create(team=self.team, event='sign up', distinct_id='blabla', properties={"$some_property": i})
+ Event.objects.create(
+ team=self.team,
+ event="sign up",
+ distinct_id="blabla",
+ properties={"$some_property": i},
+ )
- def _compare_entity_response(self, response1, response2, remove=('action', 'label')):
+ def _compare_entity_response(
+ self, response1, response2, remove=("action", "label")
+ ):
if len(response1):
for attr in remove:
response1[0].pop(attr)
@@ -209,115 +281,120 @@ class TestTrends(TransactionBaseTest):
def test_trends_per_day(self):
self._create_events()
- with freeze_time('2020-01-04T13:00:01Z'):
+ with freeze_time("2020-01-04T13:00:01Z"):
with self.assertNumQueries(16):
- action_response = self.client.get('/api/action/trends/?date_from=-7d').json()
+ action_response = self.client.get(
+ "/api/action/trends/?date_from=-7d"
+ ).json()
event_response = self.client.get(
- '/api/action/trends/',
+ "/api/action/trends/",
data={
- 'date_from': '-7d',
- 'events': jdumps([{'id': "sign up"}, {'id': "no events"}]),
+ "date_from": "-7d",
+ "events": jdumps([{"id": "sign up"}, {"id": "no events"}]),
},
).json()
- self.assertEqual(action_response[0]['label'], 'sign up')
- self.assertEqual(action_response[0]['labels'][4], 'Wed. 1 January')
- self.assertEqual(action_response[0]['data'][4], 3.0)
- self.assertEqual(action_response[0]['labels'][5], 'Thu. 2 January')
- self.assertEqual(action_response[0]['data'][5], 1.0)
- self.assertEqual(event_response[0]['label'], 'sign up')
+ self.assertEqual(action_response[0]["label"], "sign up")
+ self.assertEqual(action_response[0]["labels"][4], "Wed. 1 January")
+ self.assertEqual(action_response[0]["data"][4], 3.0)
+ self.assertEqual(action_response[0]["labels"][5], "Thu. 2 January")
+ self.assertEqual(action_response[0]["data"][5], 1.0)
+ self.assertEqual(event_response[0]["label"], "sign up")
self.assertTrue(self._compare_entity_response(action_response, event_response))
def test_trends_per_day_cumulative(self):
self._create_events()
- with freeze_time('2020-01-04T13:00:01Z'):
+ with freeze_time("2020-01-04T13:00:01Z"):
with self.assertNumQueries(16):
- action_response = self.client.get('/api/action/trends/?date_from=-7d&display=ActionsLineGraphCumulative').json()
+ action_response = self.client.get(
+ "/api/action/trends/?date_from=-7d&display=ActionsLineGraphCumulative"
+ ).json()
event_response = self.client.get(
- '/api/action/trends/',
+ "/api/action/trends/",
data={
- 'date_from': '-7d',
- 'events': jdumps([{'id': "sign up"}, {'id': "no events"}]),
- 'display': 'ActionsLineGraphCumulative'
+ "date_from": "-7d",
+ "events": jdumps([{"id": "sign up"}, {"id": "no events"}]),
+ "display": "ActionsLineGraphCumulative",
},
).json()
- self.assertEqual(action_response[0]['label'], 'sign up')
- self.assertEqual(action_response[0]['labels'][4], 'Wed. 1 January')
- self.assertEqual(action_response[0]['data'][4], 3.0)
- self.assertEqual(action_response[0]['labels'][5], 'Thu. 2 January')
- self.assertEqual(action_response[0]['data'][5], 4.0)
- self.assertEqual(event_response[0]['label'], 'sign up')
+ self.assertEqual(action_response[0]["label"], "sign up")
+ self.assertEqual(action_response[0]["labels"][4], "Wed. 1 January")
+ self.assertEqual(action_response[0]["data"][4], 3.0)
+ self.assertEqual(action_response[0]["labels"][5], "Thu. 2 January")
+ self.assertEqual(action_response[0]["data"][5], 4.0)
+ self.assertEqual(event_response[0]["label"], "sign up")
self.assertTrue(self._compare_entity_response(action_response, event_response))
def test_trends_compare(self):
self._create_events()
- with freeze_time('2020-01-04T13:00:01Z'):
- action_response = self.client.get('/api/action/trends/?date_from=-7d&compare=true').json()
+ with freeze_time("2020-01-04T13:00:01Z"):
+ action_response = self.client.get(
+ "/api/action/trends/?date_from=-7d&compare=true"
+ ).json()
event_response = self.client.get(
- '/api/action/trends/',
+ "/api/action/trends/",
data={
- 'date_from': '-7d',
- 'events': jdumps([{'id': "sign up"}, {'id': "no events"}]),
- 'compare': 'true'
+ "date_from": "-7d",
+ "events": jdumps([{"id": "sign up"}, {"id": "no events"}]),
+ "compare": "true",
},
).json()
- self.assertEqual(action_response[0]['label'], 'sign up - current')
- self.assertEqual(action_response[0]['labels'][4], 'day 4')
- self.assertEqual(action_response[0]['data'][4], 3.0)
- self.assertEqual(action_response[0]['labels'][5], 'day 5')
- self.assertEqual(action_response[0]['data'][5], 1.0)
+ self.assertEqual(action_response[0]["label"], "sign up - current")
+ self.assertEqual(action_response[0]["labels"][4], "day 4")
+ self.assertEqual(action_response[0]["data"][4], 3.0)
+ self.assertEqual(action_response[0]["labels"][5], "day 5")
+ self.assertEqual(action_response[0]["data"][5], 1.0)
- self.assertEqual(action_response[1]['label'], 'sign up - previous')
- self.assertEqual(action_response[1]['labels'][4], 'day 4')
- self.assertEqual(action_response[1]['data'][4], 1.0)
- self.assertEqual(action_response[1]['labels'][5], 'day 5')
- self.assertEqual(action_response[1]['data'][5], 0.0)
+ self.assertEqual(action_response[1]["label"], "sign up - previous")
+ self.assertEqual(action_response[1]["labels"][4], "day 4")
+ self.assertEqual(action_response[1]["data"][4], 1.0)
+ self.assertEqual(action_response[1]["labels"][5], "day 5")
+ self.assertEqual(action_response[1]["data"][5], 0.0)
self.assertTrue(self._compare_entity_response(action_response, event_response))
-
def test_property_filtering(self):
self._create_events()
- with freeze_time('2020-01-04'):
+ with freeze_time("2020-01-04"):
action_response = self.client.get(
- '/api/action/trends/',
- data={
- 'properties': jdumps({'$some_property': 'value'}),
- },
+ "/api/action/trends/",
+ data={"properties": jdumps({"$some_property": "value"}),},
).json()
event_response = self.client.get(
- '/api/action/trends/',
+ "/api/action/trends/",
data={
- 'events': jdumps([{'id': "sign up"}, {'id': "no events"}]),
- 'properties': jdumps({'$some_property': 'value'}),
+ "events": jdumps([{"id": "sign up"}, {"id": "no events"}]),
+ "properties": jdumps({"$some_property": "value"}),
},
).json()
- self.assertEqual(action_response[0]['labels'][4], 'Wed. 1 January')
- self.assertEqual(action_response[0]['data'][4], 1.0)
- self.assertEqual(action_response[0]['labels'][5], 'Thu. 2 January')
- self.assertEqual(action_response[0]['data'][5], 0)
- self.assertEqual(action_response[1]['count'], 0)
+ self.assertEqual(action_response[0]["labels"][4], "Wed. 1 January")
+ self.assertEqual(action_response[0]["data"][4], 1.0)
+ self.assertEqual(action_response[0]["labels"][5], "Thu. 2 January")
+ self.assertEqual(action_response[0]["data"][5], 0)
+ self.assertEqual(action_response[1]["count"], 0)
self.assertTrue(self._compare_entity_response(action_response, event_response))
def test_date_filtering(self):
self._create_events()
- with freeze_time('2020-01-02'):
- action_response = self.client.get('/api/action/trends/?date_from=2019-12-21').json()
+ with freeze_time("2020-01-02"):
+ action_response = self.client.get(
+ "/api/action/trends/?date_from=2019-12-21"
+ ).json()
event_response = self.client.get(
- '/api/action/trends/',
+ "/api/action/trends/",
data={
- 'date_from': '2019-12-21',
- 'events': jdumps([{'id': "sign up"}, {'id': "no events"}]),
+ "date_from": "2019-12-21",
+ "events": jdumps([{"id": "sign up"}, {"id": "no events"}]),
},
).json()
- self.assertEqual(action_response[0]['labels'][3], 'Tue. 24 December')
- self.assertEqual(action_response[0]['data'][3], 1.0)
- self.assertEqual(action_response[0]['data'][12], 1.0)
+ self.assertEqual(action_response[0]["labels"][3], "Tue. 24 December")
+ self.assertEqual(action_response[0]["data"][3], 1.0)
+ self.assertEqual(action_response[0]["data"][12], 1.0)
self.assertTrue(self._compare_entity_response(action_response, event_response))
@@ -325,553 +402,782 @@ class TestTrends(TransactionBaseTest):
self._create_events(use_time=True)
# test minute
- with freeze_time('2020-01-02'):
- action_response = self.client.get('/api/action/trends/?date_from=2020-01-01&interval=minute').json()
- self.assertEqual(action_response[0]['labels'][6], 'Wed. 1 January, 00:06')
- self.assertEqual(action_response[0]['data'][6], 3.0)
+ with freeze_time("2020-01-02"):
+ action_response = self.client.get(
+ "/api/action/trends/?date_from=2020-01-01&interval=minute"
+ ).json()
+ self.assertEqual(action_response[0]["labels"][6], "Wed. 1 January, 00:06")
+ self.assertEqual(action_response[0]["data"][6], 3.0)
# test hour
- with freeze_time('2020-01-02'):
- action_response = self.client.get('/api/action/trends/?date_from=2019-12-24&interval=hour').json()
- self.assertEqual(action_response[0]['labels'][3], 'Tue. 24 December, 03:00')
- self.assertEqual(action_response[0]['data'][3], 1.0)
+ with freeze_time("2020-01-02"):
+ action_response = self.client.get(
+ "/api/action/trends/?date_from=2019-12-24&interval=hour"
+ ).json()
+ self.assertEqual(action_response[0]["labels"][3], "Tue. 24 December, 03:00")
+ self.assertEqual(action_response[0]["data"][3], 1.0)
# 217 - 24 - 1
- self.assertEqual(action_response[0]['data'][192], 3.0)
+ self.assertEqual(action_response[0]["data"][192], 3.0)
# test week
- with freeze_time('2020-01-02'):
- action_response = self.client.get('/api/action/trends/?date_from=2019-11-24&interval=week').json()
- self.assertEqual(action_response[0]['labels'][4], 'Sun. 22 December')
- self.assertEqual(action_response[0]['data'][4], 1.0)
- self.assertEqual(action_response[0]['labels'][5], 'Sun. 29 December')
- self.assertEqual(action_response[0]['data'][5], 4.0)
+ with freeze_time("2020-01-02"):
+ action_response = self.client.get(
+ "/api/action/trends/?date_from=2019-11-24&interval=week"
+ ).json()
+ self.assertEqual(action_response[0]["labels"][4], "Sun. 22 December")
+ self.assertEqual(action_response[0]["data"][4], 1.0)
+ self.assertEqual(action_response[0]["labels"][5], "Sun. 29 December")
+ self.assertEqual(action_response[0]["data"][5], 4.0)
# test month
- with freeze_time('2020-01-02'):
- action_response = self.client.get('/api/action/trends/?date_from=2019-9-24&interval=month').json()
- self.assertEqual(action_response[0]['labels'][2], 'Sat. 30 November')
- self.assertEqual(action_response[0]['data'][2], 1.0)
- self.assertEqual(action_response[0]['labels'][3], 'Tue. 31 December')
- self.assertEqual(action_response[0]['data'][3], 4.0)
+ with freeze_time("2020-01-02"):
+ action_response = self.client.get(
+ "/api/action/trends/?date_from=2019-9-24&interval=month"
+ ).json()
+ self.assertEqual(action_response[0]["labels"][2], "Sat. 30 November")
+ self.assertEqual(action_response[0]["data"][2], 1.0)
+ self.assertEqual(action_response[0]["labels"][3], "Tue. 31 December")
+ self.assertEqual(action_response[0]["data"][3], 4.0)
- with freeze_time('2020-01-02 23:30'):
- Event.objects.create(team=self.team, event='sign up', distinct_id='blabla')
+ with freeze_time("2020-01-02 23:30"):
+ Event.objects.create(team=self.team, event="sign up", distinct_id="blabla")
# test today + hourly
- with freeze_time('2020-01-02T23:31:00Z'):
+ with freeze_time("2020-01-02T23:31:00Z"):
action_response = self.client.get(
- '/api/action/trends/',
- data={
- 'date_from': 'dStart',
- 'interval': 'hour',
- },
+ "/api/action/trends/",
+ data={"date_from": "dStart", "interval": "hour",},
).json()
- self.assertEqual(action_response[0]['labels'][23], 'Thu. 2 January, 23:00')
- self.assertEqual(action_response[0]['data'][23], 1.0)
+ self.assertEqual(action_response[0]["labels"][23], "Thu. 2 January, 23:00")
+ self.assertEqual(action_response[0]["data"][23], 1.0)
def test_all_dates_filtering(self):
self._create_events(use_time=True)
# automatically sets first day as first day of any events
- with freeze_time('2020-01-04T15:01:01Z'):
- action_response = self.client.get('/api/action/trends/?date_from=all').json()
+ with freeze_time("2020-01-04T15:01:01Z"):
+ action_response = self.client.get(
+ "/api/action/trends/?date_from=all"
+ ).json()
event_response = self.client.get(
- '/api/action/trends/',
+ "/api/action/trends/",
data={
- 'date_from': 'all',
- 'events': jdumps([{'id': "sign up"}, {'id': "no events"}]),
+ "date_from": "all",
+ "events": jdumps([{"id": "sign up"}, {"id": "no events"}]),
},
).json()
- self.assertEqual(action_response[0]['labels'][0], 'Tue. 24 December')
- self.assertEqual(action_response[0]['data'][0], 1.0)
+ self.assertEqual(action_response[0]["labels"][0], "Tue. 24 December")
+ self.assertEqual(action_response[0]["data"][0], 1.0)
self.assertTrue(self._compare_entity_response(action_response, event_response))
-
# test empty response
- with freeze_time('2020-01-04'):
- empty = self.client.get('/api/action/trends/?date_from=all&events=%s' % jdumps([{'id': 'blabla'}, {'id': 'sign up'}])).json()
- self.assertEqual(empty[0]['data'][0], 0)
+ with freeze_time("2020-01-04"):
+ empty = self.client.get(
+ "/api/action/trends/?date_from=all&events=%s"
+ % jdumps([{"id": "blabla"}, {"id": "sign up"}])
+ ).json()
+ self.assertEqual(empty[0]["data"][0], 0)
def test_breakdown_filtering(self):
self._create_events()
# test breakdown filtering
- with freeze_time('2020-01-04T13:01:01Z'):
- action_response = self.client.get('/api/action/trends/?date_from=-14d&breakdown=$some_property').json()
- event_response = self.client.get('/api/action/trends/?date_from=-14d&properties={}&actions=[]&display=ActionsTable&interval=day&breakdown=$some_property&events=%s' % jdumps([{'id': "sign up", "name": "sign up", "type": "events", "order": 0}, {'id': "no events"}])).json()
+ with freeze_time("2020-01-04T13:01:01Z"):
+ action_response = self.client.get(
+ "/api/action/trends/?date_from=-14d&breakdown=$some_property"
+ ).json()
+ event_response = self.client.get(
+ "/api/action/trends/?date_from=-14d&properties={}&actions=[]&display=ActionsTable&interval=day&breakdown=$some_property&events=%s"
+ % jdumps(
+ [
+ {
+ "id": "sign up",
+ "name": "sign up",
+ "type": "events",
+ "order": 0,
+ },
+ {"id": "no events"},
+ ]
+ )
+ ).json()
- self.assertEqual(event_response[0]['label'], 'sign up - Other')
- self.assertEqual(event_response[1]['label'], 'sign up - other_value')
- self.assertEqual(event_response[2]['label'], 'sign up - value')
- self.assertEqual(event_response[3]['label'], 'no events - Other')
+ self.assertEqual(event_response[0]["label"], "sign up - Other")
+ self.assertEqual(event_response[1]["label"], "sign up - other_value")
+ self.assertEqual(event_response[2]["label"], "sign up - value")
+ self.assertEqual(event_response[3]["label"], "no events - Other")
- self.assertEqual(sum(event_response[0]['data']), 2)
- self.assertEqual(event_response[0]['data'][4+7], 2)
- self.assertEqual(event_response[0]['breakdown_value'], 'None')
+ self.assertEqual(sum(event_response[0]["data"]), 2)
+ self.assertEqual(event_response[0]["data"][4 + 7], 2)
+ self.assertEqual(event_response[0]["breakdown_value"], "None")
- self.assertEqual(sum(event_response[1]['data']), 1)
- self.assertEqual(event_response[1]['data'][5+7], 1)
- self.assertEqual(event_response[1]['breakdown_value'], 'other_value')
+ self.assertEqual(sum(event_response[1]["data"]), 1)
+ self.assertEqual(event_response[1]["data"][5 + 7], 1)
+ self.assertEqual(event_response[1]["breakdown_value"], "other_value")
self.assertTrue(self._compare_entity_response(action_response, event_response))
# check numerical breakdown
- with freeze_time('2020-01-04T13:01:01Z'):
- action_response = self.client.get('/api/action/trends/?date_from=-14d&breakdown=$some_numerical_prop').json()
- event_response = self.client.get('/api/action/trends/?date_from=-14d&properties={}&actions=[]&display=ActionsTable&interval=day&breakdown=$some_numerical_prop&events=%s' % jdumps([{'id': "sign up", "name": "sign up", "type": "events", "order": 0}, {'id': "no events"}])).json()
- self.assertEqual(event_response[0]['label'], 'sign up - Other')
- self.assertEqual(event_response[0]['count'], 4.0)
- self.assertEqual(event_response[1]['label'], 'sign up - 80.0')
- self.assertEqual(event_response[1]['count'], 1.0)
+ with freeze_time("2020-01-04T13:01:01Z"):
+ action_response = self.client.get(
+ "/api/action/trends/?date_from=-14d&breakdown=$some_numerical_prop"
+ ).json()
+ event_response = self.client.get(
+ "/api/action/trends/?date_from=-14d&properties={}&actions=[]&display=ActionsTable&interval=day&breakdown=$some_numerical_prop&events=%s"
+ % jdumps(
+ [
+ {
+ "id": "sign up",
+ "name": "sign up",
+ "type": "events",
+ "order": 0,
+ },
+ {"id": "no events"},
+ ]
+ )
+ ).json()
+ self.assertEqual(event_response[0]["label"], "sign up - Other")
+ self.assertEqual(event_response[0]["count"], 4.0)
+ self.assertEqual(event_response[1]["label"], "sign up - 80.0")
+ self.assertEqual(event_response[1]["count"], 1.0)
self.assertTrue(self._compare_entity_response(action_response, event_response))
def test_breakdown_filtering_limit(self):
self._create_breakdown_events()
- with freeze_time('2020-01-04T13:01:01Z'):
- action_response = self.client.get('/api/action/trends/?date_from=-14d&breakdown=$some_property').json()
- event_response = self.client.get('/api/action/trends/?date_from=-14d&properties={}&actions=[]&display=ActionsTable&interval=day&breakdown=$some_property&events=%s' % jdumps([{'id': "sign up", "name": "sign up", "type": "events", "order": 0}])).json()
+ with freeze_time("2020-01-04T13:01:01Z"):
+ action_response = self.client.get(
+ "/api/action/trends/?date_from=-14d&breakdown=$some_property"
+ ).json()
+ event_response = self.client.get(
+ "/api/action/trends/?date_from=-14d&properties={}&actions=[]&display=ActionsTable&interval=day&breakdown=$some_property&events=%s"
+ % jdumps(
+ [{"id": "sign up", "name": "sign up", "type": "events", "order": 0}]
+ )
+ ).json()
self.assertEqual(len(action_response), 20)
self.assertTrue(self._compare_entity_response(action_response, event_response))
def test_action_filtering(self):
sign_up_action, person = self._create_events()
- with freeze_time('2020-01-04'):
+ with freeze_time("2020-01-04"):
action_response = self.client.get(
- '/api/action/trends/',
- data={
- 'actions': jdumps([{'id': sign_up_action.id}]),
- },
+ "/api/action/trends/",
+ data={"actions": jdumps([{"id": sign_up_action.id}]),},
).json()
event_response = self.client.get(
- '/api/action/trends/',
- data={
- 'events': jdumps([{'id': "sign up"}]),
- },
+ "/api/action/trends/", data={"events": jdumps([{"id": "sign up"}]),},
).json()
self.assertEqual(len(action_response), 1)
self.assertTrue(self._compare_entity_response(action_response, event_response))
def test_trends_for_non_existing_action(self):
- with freeze_time('2020-01-04'):
- response = self.client.get('/api/action/trends/', {'actions': jdumps([{'id': 4000000}])}).json()
+ with freeze_time("2020-01-04"):
+ response = self.client.get(
+ "/api/action/trends/", {"actions": jdumps([{"id": 4000000}])}
+ ).json()
self.assertEqual(len(response), 0)
- with freeze_time('2020-01-04'):
- response = self.client.get('/api/action/trends/', {'events': jdumps([{'id': "DNE"}])}).json()
+ with freeze_time("2020-01-04"):
+ response = self.client.get(
+ "/api/action/trends/", {"events": jdumps([{"id": "DNE"}])}
+ ).json()
- self.assertEqual(response[0]['data'], [0, 0, 0, 0, 0, 0, 0, 0])
+ self.assertEqual(response[0]["data"], [0, 0, 0, 0, 0, 0, 0, 0])
def test_dau_filtering(self):
sign_up_action, person = self._create_events()
- with freeze_time('2020-01-02'):
- Person.objects.create(team=self.team, distinct_ids=['someone_else'])
- Event.objects.create(team=self.team, event='sign up', distinct_id='someone_else')
- with freeze_time('2020-01-04'):
+ with freeze_time("2020-01-02"):
+ Person.objects.create(team=self.team, distinct_ids=["someone_else"])
+ Event.objects.create(
+ team=self.team, event="sign up", distinct_id="someone_else"
+ )
+ with freeze_time("2020-01-04"):
action_response = self.client.get(
- '/api/action/trends/',
- data={
- 'actions': jdumps([{'id': sign_up_action.id, 'math': 'dau'}]),
- },
+ "/api/action/trends/",
+ data={"actions": jdumps([{"id": sign_up_action.id, "math": "dau"}]),},
).json()
event_response = self.client.get(
- '/api/action/trends/',
- data={
- 'events': jdumps([{'id': "sign up", 'math': 'dau'}]),
- },
+ "/api/action/trends/",
+ data={"events": jdumps([{"id": "sign up", "math": "dau"}]),},
).json()
- self.assertEqual(action_response[0]['data'][4], 1)
- self.assertEqual(action_response[0]['data'][5], 2)
+ self.assertEqual(action_response[0]["data"][4], 1)
+ self.assertEqual(action_response[0]["data"][5], 2)
self.assertTrue(self._compare_entity_response(action_response, event_response))
def test_dau_with_breakdown_filtering(self):
sign_up_action, _ = self._create_events()
- with freeze_time('2020-01-02'):
- Event.objects.create(team=self.team, event='sign up', distinct_id='blabla', properties={"$some_property": "other_value"})
- with freeze_time('2020-01-04'):
- action_response = self.client.get('/api/action/trends/?breakdown=$some_property&actions=%s' % jdumps([{'id': sign_up_action.id, 'math': 'dau'}])).json()
- event_response = self.client.get('/api/action/trends/?breakdown=$some_property&events=%s' % jdumps([{'id': "sign up", 'math': 'dau'}])).json()
+ with freeze_time("2020-01-02"):
+ Event.objects.create(
+ team=self.team,
+ event="sign up",
+ distinct_id="blabla",
+ properties={"$some_property": "other_value"},
+ )
+ with freeze_time("2020-01-04"):
+ action_response = self.client.get(
+ "/api/action/trends/?breakdown=$some_property&actions=%s"
+ % jdumps([{"id": sign_up_action.id, "math": "dau"}])
+ ).json()
+ event_response = self.client.get(
+ "/api/action/trends/?breakdown=$some_property&events=%s"
+ % jdumps([{"id": "sign up", "math": "dau"}])
+ ).json()
- self.assertEqual(event_response[0]['label'], 'sign up - other_value')
- self.assertEqual(event_response[1]['label'], 'sign up - value')
- self.assertEqual(event_response[2]['label'], 'sign up - Other')
+ self.assertEqual(event_response[0]["label"], "sign up - other_value")
+ self.assertEqual(event_response[1]["label"], "sign up - value")
+ self.assertEqual(event_response[2]["label"], "sign up - Other")
- self.assertEqual(sum(event_response[0]['data']), 1)
- self.assertEqual(event_response[0]['data'][5], 1)
+ self.assertEqual(sum(event_response[0]["data"]), 1)
+ self.assertEqual(event_response[0]["data"][5], 1)
+
+ self.assertEqual(sum(event_response[2]["data"]), 1)
+ self.assertEqual(event_response[2]["data"][4], 1) # property not defined
- self.assertEqual(sum(event_response[2]['data']), 1)
- self.assertEqual(event_response[2]['data'][4], 1) # property not defined
-
self.assertTrue(self._compare_entity_response(action_response, event_response))
def test_people_endpoint(self):
sign_up_action, person = self._create_events()
- person1 = Person.objects.create(team=self.team, distinct_ids=['person1'])
- Person.objects.create(team=self.team, distinct_ids=['person2'])
- Event.objects.create(team=self.team, event='sign up', distinct_id='person1', timestamp='2020-01-04T12:00:00Z')
- Event.objects.create(team=self.team, event='sign up', distinct_id='person2', timestamp='2020-01-05T12:00:00Z')
+ person1 = Person.objects.create(team=self.team, distinct_ids=["person1"])
+ Person.objects.create(team=self.team, distinct_ids=["person2"])
+ Event.objects.create(
+ team=self.team,
+ event="sign up",
+ distinct_id="person1",
+ timestamp="2020-01-04T12:00:00Z",
+ )
+ Event.objects.create(
+ team=self.team,
+ event="sign up",
+ distinct_id="person2",
+ timestamp="2020-01-05T12:00:00Z",
+ )
# test people
action_response = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'date_from': '2020-01-04',
- 'date_to': '2020-01-04',
- 'type': 'actions',
- 'entityId': sign_up_action.id,
+ "date_from": "2020-01-04",
+ "date_to": "2020-01-04",
+ "type": "actions",
+ "entityId": sign_up_action.id,
},
).json()
event_response = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'date_from': '2020-01-04',
- 'date_to': '2020-01-04',
- 'type': 'events',
- 'entityId': 'sign up',
+ "date_from": "2020-01-04",
+ "date_to": "2020-01-04",
+ "type": "events",
+ "entityId": "sign up",
},
).json()
- self.assertEqual(action_response[0]['people'][0]['id'], person1.pk)
- self.assertTrue(self._compare_entity_response(action_response, event_response, remove=[]))
+ self.assertEqual(action_response["results"][0]["people"][0]["id"], person1.pk)
+ self.assertTrue(
+ self._compare_entity_response(
+ action_response["results"], event_response["results"], remove=[]
+ )
+ )
+
+ def test_people_endpoint_paginated(self):
+
+ for index in range(0, 150):
+ Person.objects.create(team=self.team, distinct_ids=["person" + str(index)])
+ Event.objects.create(
+ team=self.team,
+ event="sign up",
+ distinct_id="person" + str(index),
+ timestamp="2020-01-04T12:00:00Z",
+ )
+
+ event_response = self.client.get(
+ "/api/action/people/",
+ data={
+ "date_from": "2020-01-04",
+ "date_to": "2020-01-04",
+ "type": "events",
+ "entityId": "sign up",
+ },
+ ).json()
+ self.assertEqual(len(event_response["results"][0]["people"]), 100)
+ event_response_next = self.client.get(event_response["next"]).json()
+ self.assertEqual(len(event_response_next["results"][0]["people"]), 50)
def test_people_endpoint_with_intervals(self):
sign_up_action, person = self._create_events()
- person1 = Person.objects.create(team=self.team, distinct_ids=['person1'])
- person2 = Person.objects.create(team=self.team, distinct_ids=['person2'])
- person3 = Person.objects.create(team=self.team, distinct_ids=['person3'])
- person4 = Person.objects.create(team=self.team, distinct_ids=['person4'])
- person5 = Person.objects.create(team=self.team, distinct_ids=['person5'])
- person6 = Person.objects.create(team=self.team, distinct_ids=['person6'])
- person7 = Person.objects.create(team=self.team, distinct_ids=['person7'])
+ person1 = Person.objects.create(team=self.team, distinct_ids=["person1"])
+ person2 = Person.objects.create(team=self.team, distinct_ids=["person2"])
+ person3 = Person.objects.create(team=self.team, distinct_ids=["person3"])
+ person4 = Person.objects.create(team=self.team, distinct_ids=["person4"])
+ person5 = Person.objects.create(team=self.team, distinct_ids=["person5"])
+ person6 = Person.objects.create(team=self.team, distinct_ids=["person6"])
+ person7 = Person.objects.create(team=self.team, distinct_ids=["person7"])
# solo
- Event.objects.create(team=self.team, event='sign up', distinct_id='person1', timestamp='2020-01-04T14:10:00Z')
+ Event.objects.create(
+ team=self.team,
+ event="sign up",
+ distinct_id="person1",
+ timestamp="2020-01-04T14:10:00Z",
+ )
# group by hour
- Event.objects.create(team=self.team, event='sign up', distinct_id='person2', timestamp='2020-01-04T16:30:00Z')
+ Event.objects.create(
+ team=self.team,
+ event="sign up",
+ distinct_id="person2",
+ timestamp="2020-01-04T16:30:00Z",
+ )
# group by hour
- Event.objects.create(team=self.team, event='sign up', distinct_id='person3', timestamp='2020-01-04T16:50:00Z')
+ Event.objects.create(
+ team=self.team,
+ event="sign up",
+ distinct_id="person3",
+ timestamp="2020-01-04T16:50:00Z",
+ )
# group by min
- Event.objects.create(team=self.team, event='sign up', distinct_id='person4', timestamp='2020-01-04T19:20:00Z')
+ Event.objects.create(
+ team=self.team,
+ event="sign up",
+ distinct_id="person4",
+ timestamp="2020-01-04T19:20:00Z",
+ )
# group by min
- Event.objects.create(team=self.team, event='sign up', distinct_id='person5', timestamp='2020-01-04T19:20:00Z')
+ Event.objects.create(
+ team=self.team,
+ event="sign up",
+ distinct_id="person5",
+ timestamp="2020-01-04T19:20:00Z",
+ )
# group by week and month
- Event.objects.create(team=self.team, event='sign up', distinct_id='person6', timestamp='2019-11-05T16:30:00Z')
+ Event.objects.create(
+ team=self.team,
+ event="sign up",
+ distinct_id="person6",
+ timestamp="2019-11-05T16:30:00Z",
+ )
# group by week and month
- Event.objects.create(team=self.team, event='sign up', distinct_id='person7', timestamp='2019-11-07T16:50:00Z')
+ Event.objects.create(
+ team=self.team,
+ event="sign up",
+ distinct_id="person7",
+ timestamp="2019-11-07T16:50:00Z",
+ )
# check solo hour
action_response = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'interval': 'hour',
- 'date_from': '2020-01-04 14:00:00',
- 'date_to': '2020-01-04 14:00:00',
- 'type': 'actions',
- 'entityId': sign_up_action.id,
+ "interval": "hour",
+ "date_from": "2020-01-04 14:00:00",
+ "date_to": "2020-01-04 14:00:00",
+ "type": "actions",
+ "entityId": sign_up_action.id,
},
).json()
event_response = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'interval': 'hour',
- 'date_from': '2020-01-04 14:00:00',
- 'date_to': '2020-01-04 14:00:00',
- 'type': 'events',
- 'entityId': 'sign up',
+ "interval": "hour",
+ "date_from": "2020-01-04 14:00:00",
+ "date_to": "2020-01-04 14:00:00",
+ "type": "events",
+ "entityId": "sign up",
},
).json()
- self.assertEqual(action_response[0]['people'][0]['id'], person1.pk)
- self.assertEqual(len(action_response[0]['people']), 1)
- self.assertTrue(self._compare_entity_response(action_response, event_response, remove=[]))
+ self.assertEqual(action_response["results"][0]["people"][0]["id"], person1.pk)
+ self.assertEqual(len(action_response["results"][0]["people"]), 1)
+ self.assertTrue(
+ self._compare_entity_response(
+ action_response["results"], event_response["results"], remove=[]
+ )
+ )
# check grouped hour
hour_grouped_action_response = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'interval': 'hour',
- 'date_from': '2020-01-04 16:00:00',
- 'date_to': '2020-01-04 16:00:00',
- 'type': 'actions',
- 'entityId': sign_up_action.id,
+ "interval": "hour",
+ "date_from": "2020-01-04 16:00:00",
+ "date_to": "2020-01-04 16:00:00",
+ "type": "actions",
+ "entityId": sign_up_action.id,
},
).json()
hour_grouped_grevent_response = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'interval': 'hour',
- 'date_from': '2020-01-04 16:00:00',
- 'date_to': '2020-01-04 16:00:00',
- 'type': 'events',
- 'entityId': 'sign up',
+ "interval": "hour",
+ "date_from": "2020-01-04 16:00:00",
+ "date_to": "2020-01-04 16:00:00",
+ "type": "events",
+ "entityId": "sign up",
},
).json()
- self.assertEqual(hour_grouped_action_response[0]['people'][0]['id'], person2.pk)
- self.assertEqual(hour_grouped_action_response[0]['people'][1]['id'], person3.pk)
- self.assertEqual(len(hour_grouped_action_response[0]['people']), 2)
- self.assertTrue(self._compare_entity_response(
- hour_grouped_action_response,
- hour_grouped_grevent_response,
- remove=[],
- ))
+ self.assertEqual(
+ hour_grouped_action_response["results"][0]["people"][0]["id"], person2.pk
+ )
+ self.assertEqual(
+ hour_grouped_action_response["results"][0]["people"][1]["id"], person3.pk
+ )
+ self.assertEqual(len(hour_grouped_action_response["results"][0]["people"]), 2)
+ self.assertTrue(
+ self._compare_entity_response(
+ hour_grouped_action_response["results"],
+ hour_grouped_grevent_response["results"],
+ remove=[],
+ )
+ )
# check grouped minute
min_grouped_action_response = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'interval': 'hour',
- 'date_from': '2020-01-04 19:20:00',
- 'date_to': '2020-01-04 19:20:00',
- 'type': 'actions',
- 'entityId': sign_up_action.id,
+ "interval": "hour",
+ "date_from": "2020-01-04 19:20:00",
+ "date_to": "2020-01-04 19:20:00",
+ "type": "actions",
+ "entityId": sign_up_action.id,
},
).json()
min_grouped_grevent_response = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'interval': 'hour',
- 'date_from': '2020-01-04 19:20:00',
- 'date_to': '2020-01-04 19:20:00',
- 'type': 'events',
- 'entityId': 'sign up',
+ "interval": "hour",
+ "date_from": "2020-01-04 19:20:00",
+ "date_to": "2020-01-04 19:20:00",
+ "type": "events",
+ "entityId": "sign up",
},
).json()
- self.assertEqual(min_grouped_action_response[0]['people'][0]['id'], person4.pk)
- self.assertEqual(min_grouped_action_response[0]['people'][1]['id'], person5.pk)
- self.assertEqual(len(min_grouped_action_response[0]['people']), 2)
- self.assertTrue(self._compare_entity_response(
- min_grouped_action_response,
- min_grouped_grevent_response,
- remove=[],
- ))
+ self.assertEqual(
+ min_grouped_action_response["results"][0]["people"][0]["id"], person4.pk
+ )
+ self.assertEqual(
+ min_grouped_action_response["results"][0]["people"][1]["id"], person5.pk
+ )
+ self.assertEqual(len(min_grouped_action_response["results"][0]["people"]), 2)
+ self.assertTrue(
+ self._compare_entity_response(
+ min_grouped_action_response["results"],
+ min_grouped_grevent_response["results"],
+ remove=[],
+ )
+ )
# check grouped week
week_grouped_action_response = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'interval': 'week',
- 'date_from': '2019-11-01',
- 'date_to': '2019-11-01',
- 'type': 'actions',
- 'entityId': sign_up_action.id,
+ "interval": "week",
+ "date_from": "2019-11-01",
+ "date_to": "2019-11-01",
+ "type": "actions",
+ "entityId": sign_up_action.id,
},
).json()
week_grouped_grevent_response = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'interval': 'week',
- 'date_from': '2019-11-01',
- 'date_to': '2019-11-01',
- 'type': 'events',
- 'entityId': 'sign up',
+ "interval": "week",
+ "date_from": "2019-11-01",
+ "date_to": "2019-11-01",
+ "type": "events",
+ "entityId": "sign up",
},
).json()
- self.assertEqual(week_grouped_action_response[0]['people'][0]['id'], person6.pk)
- self.assertEqual(week_grouped_action_response[0]['people'][1]['id'], person7.pk)
- self.assertEqual(len(week_grouped_action_response[0]['people']), 2)
- self.assertTrue(self._compare_entity_response(
- week_grouped_action_response,
- week_grouped_grevent_response,
- remove=[],
- ))
+ self.assertEqual(
+ week_grouped_action_response["results"][0]["people"][0]["id"], person6.pk
+ )
+ self.assertEqual(
+ week_grouped_action_response["results"][0]["people"][1]["id"], person7.pk
+ )
+ self.assertEqual(len(week_grouped_action_response["results"][0]["people"]), 2)
+ self.assertTrue(
+ self._compare_entity_response(
+ week_grouped_action_response["results"],
+ week_grouped_grevent_response["results"],
+ remove=[],
+ )
+ )
# check grouped month
month_group_action_response = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'interval': 'month',
- 'date_from': '2019-11-01',
- 'date_to': '2019-11-01',
- 'type': 'actions',
- 'entityId': sign_up_action.id,
+ "interval": "month",
+ "date_from": "2019-11-01",
+ "date_to": "2019-11-01",
+ "type": "actions",
+ "entityId": sign_up_action.id,
},
).json()
month_group_grevent_response = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'interval': 'month',
- 'date_from': '2019-11-01',
- 'date_to': '2019-11-01',
- 'type': 'events',
- 'entityId': 'sign up',
+ "interval": "month",
+ "date_from": "2019-11-01",
+ "date_to": "2019-11-01",
+ "type": "events",
+ "entityId": "sign up",
},
).json()
- self.assertEqual(month_group_action_response[0]['people'][0]['id'], person6.pk)
- self.assertEqual(month_group_action_response[0]['people'][1]['id'], person7.pk)
- self.assertEqual(len(month_group_action_response[0]['people']), 2)
- self.assertTrue(self._compare_entity_response(
- month_group_action_response,
- month_group_grevent_response,
- remove=[],
- ))
+ self.assertEqual(
+ month_group_action_response["results"][0]["people"][0]["id"], person6.pk
+ )
+ self.assertEqual(
+ month_group_action_response["results"][0]["people"][1]["id"], person7.pk
+ )
+ self.assertEqual(len(month_group_action_response["results"][0]["people"]), 2)
+ self.assertTrue(
+ self._compare_entity_response(
+ month_group_action_response["results"],
+ month_group_grevent_response["results"],
+ remove=[],
+ )
+ )
def _create_multiple_people(self):
- person1 = Person.objects.create(team=self.team, distinct_ids=['person1'], properties={'name': 'person1'})
- Event.objects.create(team=self.team, event='watched movie', distinct_id='person1', timestamp='2020-01-01T12:00:00Z')
+ person1 = Person.objects.create(
+ team=self.team, distinct_ids=["person1"], properties={"name": "person1"}
+ )
+ Event.objects.create(
+ team=self.team,
+ event="watched movie",
+ distinct_id="person1",
+ timestamp="2020-01-01T12:00:00Z",
+ )
- person2 = Person.objects.create(team=self.team, distinct_ids=['person2'], properties={'name': 'person2'})
- Event.objects.create(team=self.team, event='watched movie', distinct_id='person2', timestamp='2020-01-01T12:00:00Z')
- Event.objects.create(team=self.team, event='watched movie', distinct_id='person2', timestamp='2020-01-02T12:00:00Z')
+ person2 = Person.objects.create(
+ team=self.team, distinct_ids=["person2"], properties={"name": "person2"}
+ )
+ Event.objects.create(
+ team=self.team,
+ event="watched movie",
+ distinct_id="person2",
+ timestamp="2020-01-01T12:00:00Z",
+ )
+ Event.objects.create(
+ team=self.team,
+ event="watched movie",
+ distinct_id="person2",
+ timestamp="2020-01-02T12:00:00Z",
+ )
# same day
- Event.objects.create(team=self.team, event='watched movie', distinct_id='person2', timestamp='2020-01-02T12:00:00Z')
+ Event.objects.create(
+ team=self.team,
+ event="watched movie",
+ distinct_id="person2",
+ timestamp="2020-01-02T12:00:00Z",
+ )
- person3 = Person.objects.create(team=self.team, distinct_ids=['person3'], properties={'name': 'person3'})
- Event.objects.create(team=self.team, event='watched movie', distinct_id='person3', timestamp='2020-01-01T12:00:00Z')
- Event.objects.create(team=self.team, event='watched movie', distinct_id='person3', timestamp='2020-01-02T12:00:00Z')
- Event.objects.create(team=self.team, event='watched movie', distinct_id='person3', timestamp='2020-01-03T12:00:00Z')
+ person3 = Person.objects.create(
+ team=self.team, distinct_ids=["person3"], properties={"name": "person3"}
+ )
+ Event.objects.create(
+ team=self.team,
+ event="watched movie",
+ distinct_id="person3",
+ timestamp="2020-01-01T12:00:00Z",
+ )
+ Event.objects.create(
+ team=self.team,
+ event="watched movie",
+ distinct_id="person3",
+ timestamp="2020-01-02T12:00:00Z",
+ )
+ Event.objects.create(
+ team=self.team,
+ event="watched movie",
+ distinct_id="person3",
+ timestamp="2020-01-03T12:00:00Z",
+ )
- person4 =Person.objects.create(team=self.team, distinct_ids=['person4'], properties={'name': 'person4'})
- Event.objects.create(team=self.team, event='watched movie', distinct_id='person4', timestamp='2020-01-05T12:00:00Z')
+ person4 = Person.objects.create(
+ team=self.team, distinct_ids=["person4"], properties={"name": "person4"}
+ )
+ Event.objects.create(
+ team=self.team,
+ event="watched movie",
+ distinct_id="person4",
+ timestamp="2020-01-05T12:00:00Z",
+ )
return (person1, person2, person3, person4)
def test_stickiness(self):
person1 = self._create_multiple_people()[0]
watched_movie = Action.objects.create(team=self.team)
- ActionStep.objects.create(action=watched_movie, event='watched movie')
+ ActionStep.objects.create(action=watched_movie, event="watched movie")
watched_movie.calculate_events()
- with freeze_time('2020-01-08T13:01:01Z'):
+ with freeze_time("2020-01-08T13:01:01Z"):
action_response = self.client.get(
- '/api/action/trends/',
+ "/api/action/trends/",
data={
- 'shown_as': 'Stickiness',
- 'actions': jdumps([{'id': watched_movie.id}]),
+ "shown_as": "Stickiness",
+ "actions": jdumps([{"id": watched_movie.id}]),
},
).json()
event_response = self.client.get(
- '/api/action/trends/',
+ "/api/action/trends/",
data={
- 'shown_as': 'Stickiness',
- 'date_from': '2020-01-01',
- 'date_to': '2020-01-08',
- 'events': jdumps([{'id': "watched movie"}]),
+ "shown_as": "Stickiness",
+ "date_from": "2020-01-01",
+ "date_to": "2020-01-08",
+ "events": jdumps([{"id": "watched movie"}]),
},
).json()
- self.assertEqual(action_response[0]['count'], 4)
- self.assertEqual(action_response[0]['labels'][0], '1 day')
- self.assertEqual(action_response[0]['data'][0], 2)
- self.assertEqual(action_response[0]['labels'][1], '2 days')
- self.assertEqual(action_response[0]['data'][1], 1)
- self.assertEqual(action_response[0]['labels'][2], '3 days')
- self.assertEqual(action_response[0]['data'][2], 1)
- self.assertEqual(action_response[0]['labels'][6], '7 days')
- self.assertEqual(action_response[0]['data'][6], 0)
+ self.assertEqual(action_response[0]["count"], 4)
+ self.assertEqual(action_response[0]["labels"][0], "1 day")
+ self.assertEqual(action_response[0]["data"][0], 2)
+ self.assertEqual(action_response[0]["labels"][1], "2 days")
+ self.assertEqual(action_response[0]["data"][1], 1)
+ self.assertEqual(action_response[0]["labels"][2], "3 days")
+ self.assertEqual(action_response[0]["data"][2], 1)
+ self.assertEqual(action_response[0]["labels"][6], "7 days")
+ self.assertEqual(action_response[0]["data"][6], 0)
self.assertTrue(self._compare_entity_response(action_response, event_response))
# test people
action_response = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'shown_as': 'Stickiness',
- 'stickiness_days': 1,
- 'date_from': '2020-01-01',
- 'date_to': '2020-01-07',
- 'type': 'actions',
- 'entityId': watched_movie.id,
+ "shown_as": "Stickiness",
+ "stickiness_days": 1,
+ "date_from": "2020-01-01",
+ "date_to": "2020-01-07",
+ "type": "actions",
+ "entityId": watched_movie.id,
},
).json()
event_response = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'shown_as': 'Stickiness',
- 'stickiness_days': 1,
- 'date_from': '2020-01-01',
- 'date_to': '2020-01-07',
- 'type': 'events',
- 'entityId': 'watched movie',
+ "shown_as": "Stickiness",
+ "stickiness_days": 1,
+ "date_from": "2020-01-01",
+ "date_to": "2020-01-07",
+ "type": "events",
+ "entityId": "watched movie",
},
).json()
- self.assertEqual(action_response[0]['people'][0]['id'], person1.pk)
+ self.assertEqual(action_response["results"][0]["people"][0]["id"], person1.pk)
- self.assertTrue(self._compare_entity_response(action_response, event_response, remove=[]))
+ self.assertTrue(
+ self._compare_entity_response(
+ action_response["results"], event_response["results"], remove=[]
+ )
+ )
# test all time
response = self.client.get(
- '/api/action/trends/',
+ "/api/action/trends/",
data={
- 'shown_as': 'Stickiness',
- 'date_from': 'all',
- 'date_to': '2020-01-07',
- 'events': jdumps([{'id': 'watched_movie'}]),
+ "shown_as": "Stickiness",
+ "date_from": "all",
+ "date_to": "2020-01-07",
+ "events": jdumps([{"id": "watched_movie"}]),
},
).json()
- self.assertEqual(len(response[0]['data']), 7)
+ self.assertEqual(len(response[0]["data"]), 7)
def test_breakdown_by_cohort(self):
- person1, person2, person3, person4 = self._create_multiple_people()
- cohort = Cohort.objects.create(name='cohort1', team=self.team, groups=[
- {'properties': {'name': 'person1'}}
- ])
- cohort2 = Cohort.objects.create(name='cohort2', team=self.team, groups=[
- {'properties': {'name': 'person2'}}
- ])
- cohort3 = Cohort.objects.create(name='cohort3', team=self.team, groups=[
- {'properties': {'name': 'person1'}},
- {'properties': {'name': 'person2'}},
- ])
+ person1, person2, person3, person4 = self._create_multiple_people()
+ cohort = Cohort.objects.create(
+ name="cohort1", team=self.team, groups=[{"properties": {"name": "person1"}}]
+ )
+ cohort2 = Cohort.objects.create(
+ name="cohort2", team=self.team, groups=[{"properties": {"name": "person2"}}]
+ )
+ cohort3 = Cohort.objects.create(
+ name="cohort3",
+ team=self.team,
+ groups=[
+ {"properties": {"name": "person1"}},
+ {"properties": {"name": "person2"}},
+ ],
+ )
cohort.calculate_people()
cohort2.calculate_people()
cohort3.calculate_people()
- action = Action.objects.create(name='watched movie', team=self.team)
- ActionStep.objects.create(action=action, event='watched movie')
+ action = Action.objects.create(name="watched movie", team=self.team)
+ ActionStep.objects.create(action=action, event="watched movie")
action.calculate_events()
- with freeze_time('2020-01-04T13:01:01Z'):
- event_response = self.client.get('/api/action/trends/?date_from=-14d&breakdown=%s&breakdown_type=cohort&events=%s' % (jdumps([cohort.pk, cohort2.pk, cohort3.pk, 'all']), jdumps([{'id': "watched movie", "name": "watched movie", "type": "events", "order": 0}]))).json()
- action_response = self.client.get('/api/action/trends/?date_from=-14d&breakdown=%s&breakdown_type=cohort&actions=%s' % (jdumps([cohort.pk, cohort2.pk, cohort3.pk, 'all']), jdumps([{'id': action.pk, "type": "actions", "order": 0}]))).json()
+ with freeze_time("2020-01-04T13:01:01Z"):
+ event_response = self.client.get(
+ "/api/action/trends/?date_from=-14d&breakdown=%s&breakdown_type=cohort&events=%s"
+ % (
+ jdumps([cohort.pk, cohort2.pk, cohort3.pk, "all"]),
+ jdumps(
+ [
+ {
+ "id": "watched movie",
+ "name": "watched movie",
+ "type": "events",
+ "order": 0,
+ }
+ ]
+ ),
+ )
+ ).json()
+ action_response = self.client.get(
+ "/api/action/trends/?date_from=-14d&breakdown=%s&breakdown_type=cohort&actions=%s"
+ % (
+ jdumps([cohort.pk, cohort2.pk, cohort3.pk, "all"]),
+ jdumps([{"id": action.pk, "type": "actions", "order": 0}]),
+ )
+ ).json()
- self.assertEqual(event_response[0]['label'], 'watched movie - cohort1')
- self.assertEqual(event_response[1]['label'], 'watched movie - cohort2')
- self.assertEqual(event_response[2]['label'], 'watched movie - cohort3')
- self.assertEqual(event_response[3]['label'], 'watched movie - all users')
+ self.assertEqual(event_response[0]["label"], "watched movie - cohort1")
+ self.assertEqual(event_response[1]["label"], "watched movie - cohort2")
+ self.assertEqual(event_response[2]["label"], "watched movie - cohort3")
+ self.assertEqual(event_response[3]["label"], "watched movie - all users")
- self.assertEqual(sum(event_response[0]['data']), 1)
- self.assertEqual(event_response[0]['breakdown_value'], cohort.pk)
+ self.assertEqual(sum(event_response[0]["data"]), 1)
+ self.assertEqual(event_response[0]["breakdown_value"], cohort.pk)
- self.assertEqual(sum(event_response[1]['data']), 3)
- self.assertEqual(event_response[1]['breakdown_value'], cohort2.pk)
+ self.assertEqual(sum(event_response[1]["data"]), 3)
+ self.assertEqual(event_response[1]["breakdown_value"], cohort2.pk)
- self.assertEqual(sum(event_response[2]['data']), 4)
- self.assertEqual(event_response[2]['breakdown_value'], cohort3.pk)
+ self.assertEqual(sum(event_response[2]["data"]), 4)
+ self.assertEqual(event_response[2]["breakdown_value"], cohort3.pk)
- self.assertEqual(sum(event_response[3]['data']), 7)
- self.assertEqual(event_response[3]['breakdown_value'], 'all')
+ self.assertEqual(sum(event_response[3]["data"]), 7)
+ self.assertEqual(event_response[3]["breakdown_value"], "all")
- self.assertTrue(self._compare_entity_response(
- event_response,
- action_response,
- ))
+ self.assertTrue(self._compare_entity_response(event_response, action_response,))
people = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'date_from': '2020-01-01',
- 'date_to': '2020-01-07',
- 'type': 'events',
- 'entityId': 'watched movie',
- 'breakdown_type': 'cohort',
- 'breakdown_value': cohort.pk,
- 'breakdown': [cohort.pk] # this shouldn't do anything
+ "date_from": "2020-01-01",
+ "date_to": "2020-01-07",
+ "type": "events",
+ "entityId": "watched movie",
+ "breakdown_type": "cohort",
+ "breakdown_value": cohort.pk,
+ "breakdown": [cohort.pk], # this shouldn't do anything
},
).json()
- self.assertEqual(len(people[0]['people']), 1)
- self.assertEqual(people[0]['people'][0]['id'], person1.pk)
+ self.assertEqual(len(people["results"][0]["people"]), 1)
+ self.assertEqual(people["results"][0]["people"][0]["id"], person1.pk)
# all people
people = self.client.get(
- '/api/action/people/',
+ "/api/action/people/",
data={
- 'date_from': '2020-01-01',
- 'date_to': '2020-01-07',
- 'type': 'events',
- 'entityId': 'watched movie',
- 'breakdown_type': 'cohort',
- 'breakdown_value': 'all',
- 'breakdown': [cohort.pk]
+ "date_from": "2020-01-01",
+ "date_to": "2020-01-07",
+ "type": "events",
+ "entityId": "watched movie",
+ "breakdown_type": "cohort",
+ "breakdown_value": "all",
+ "breakdown": [cohort.pk],
},
).json()
- self.assertEqual(len(people[0]['people']), 4)
- self.assertEqual(people[0]['people'][0]['id'], person1.pk)
\ No newline at end of file
+ self.assertEqual(len(people["results"][0]["people"]), 4)
+ self.assertEqual(people["results"][0]["people"][0]["id"], person1.pk)
diff --git a/posthog/decorators.py b/posthog/decorators.py
index bdd923b53bb..ec7641eeb65 100644
--- a/posthog/decorators.py
+++ b/posthog/decorators.py
@@ -6,18 +6,20 @@ import json
from posthog.celery import update_cache_item
from datetime import datetime
+
def generate_cache_key(obj):
stringified = json.dumps(obj)
return hashlib.md5(stringified.encode("utf-8")).hexdigest()
-TRENDS_ENDPOINT = 'Trends'
-FUNNEL_ENDPOINT = 'Funnel'
+TRENDS_ENDPOINT = "Trends"
+FUNNEL_ENDPOINT = "Funnel"
+
def cached_function(cache_type: str, expiry=30):
def inner_decorator(f):
def wrapper(*args, **kw):
- cache_key = ''
+ cache_key = ""
_expiry = expiry
# prepare caching params
@@ -30,28 +32,34 @@ def cached_function(cache_type: str, expiry=30):
if cache_type == TRENDS_ENDPOINT:
request = args[1]
- filter = Filter(request=request)
+ filter = Filter(request=request)
params = request.GET.dict()
- refresh = params.pop('refresh', None)
+ refresh = params.pop("refresh", None)
team = request.user.team_set.get()
- cache_key = generate_cache_key(json.dumps(params) + '_' + str(team.pk))
- payload = {'filter': filter.toJSON(), 'params': params, 'team_id': team.pk}
+ cache_key = generate_cache_key(json.dumps(params) + "_" + str(team.pk))
+ payload = {
+ "filter": filter.toJSON(),
+ "params": params,
+ "team_id": team.pk,
+ }
elif cache_type == FUNNEL_ENDPOINT:
request = args[1]
pk = args[2]
params = request.GET.dict()
- refresh = params.pop('refresh', None)
+ refresh = params.pop("refresh", None)
team = request.user.team_set.get()
- cache_key = generate_cache_key(str(pk) + '_' + str(team.pk))
- payload = {'pk': pk, 'params': params, 'team_id': team.pk}
+ cache_key = generate_cache_key(str(pk) + "_" + str(team.pk))
+ payload = {"pk": pk, "params": params, "team_id": team.pk}
- if params and payload and params.get('from_dashboard'): #cache for 30 minutes if dashboard item
- cache_key = cache_key + '_' + 'dashboard'
+ if (
+ params and payload and params.get("from_dashboard")
+ ): # cache for 30 minutes if dashboard item
+ cache_key = cache_key + "_" + "dashboard"
_expiry = 900
- dashboard_item_id = params.get('from_dashboard')
- payload.update({'dashboard_id': dashboard_item_id})
-
- cache_key = cache_key + '_' + cache_type
+ dashboard_item_id = params.get("from_dashboard")
+ payload.update({"dashboard_id": dashboard_item_id})
+
+ cache_key = cache_key + "_" + cache_type
if refresh and dashboard_item_id:
dashboard_item = DashboardItem.objects.filter(pk=dashboard_item_id)
@@ -62,16 +70,27 @@ def cached_function(cache_type: str, expiry=30):
# return result if cached
cached_result = cache.get(cache_key)
- if cached_result :
- return cached_result['result']
+ if cached_result:
+ return cached_result["result"]
# call wrapped function
result = f(*args, **kw)
# cache new data using
if result and payload:
- cache.set(cache_key, {'result':result, 'details': payload, 'type': cache_type, 'last_accessed': datetime.now()}, _expiry)
+ cache.set(
+ cache_key,
+ {
+ "result": result,
+ "details": payload,
+ "type": cache_type,
+ "last_accessed": datetime.now(),
+ },
+ _expiry,
+ )
return result
+
return wrapper
- return inner_decorator
\ No newline at end of file
+
+ return inner_decorator
diff --git a/webpack.config.js b/webpack.config.js
index d4053ef5e7d..07cb175df06 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -34,9 +34,11 @@ function createEntry(entry) {
filename: '[name].js',
chunkFilename: '[name].[contenthash].js',
publicPath:
- process.env.NODE_ENV === 'production' ? '/static/'
- : process.env.IS_PORTER ? `https://${process.env.PORTER_WEBPACK_HOST}/static/`
- : `http${process.env.LOCAL_HTTPS ? 's' : ''}://${webpackDevServerHost}:8234/static/`
+ process.env.NODE_ENV === 'production'
+ ? '/static/'
+ : process.env.IS_PORTER
+ ? `https://${process.env.PORTER_WEBPACK_HOST}/static/`
+ : `http${process.env.LOCAL_HTTPS ? 's' : ''}://${webpackDevServerHost}:8234/static/`,
},
resolve: {
alias: {
@@ -147,15 +149,12 @@ function createEntry(entry) {
hot: true,
host: webpackDevServerHost,
port: 8234,
- public: (process.env.IS_PORTER ?
- `https://${process.env.PORTER_WEBPACK_HOST}`
- : `http${process.env.LOCAL_HTTPS ? 's' : ''}://${webpackDevServerHost}:8234`),
- allowedHosts: (process.env.IS_PORTER ?
- [
- `${process.env.PORTER_WEBPACK_HOST}`,
- `${process.env.PORTER_SERVER_HOST}`
- ]
- : []),
+ public: process.env.IS_PORTER
+ ? `https://${process.env.PORTER_WEBPACK_HOST}`
+ : `http${process.env.LOCAL_HTTPS ? 's' : ''}://${webpackDevServerHost}:8234`,
+ allowedHosts: process.env.IS_PORTER
+ ? [`${process.env.PORTER_WEBPACK_HOST}`, `${process.env.PORTER_SERVER_HOST}`]
+ : [],
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*',