예제 #1
0
    def stats(self, request: request.Request) -> response.Response:
        filter = Filter(request=request)
        team = request.user.team
        assert team is not None

        date_from, date_to = parse_timestamps(filter)

        prop_filters, prop_filter_params = parse_prop_clauses(
            filter.properties, team.pk)
        result = sync_execute(
            GET_ELEMENTS.format(date_from=date_from,
                                date_to=date_to,
                                query=prop_filters),
            {
                "team_id": team.id,
                **prop_filter_params
            },
        )
        return response.Response([{
            "count":
            elements[1],
            "hash":
            None,
            "elements": [
                ElementSerializer(element).data
                for element in chain_to_elements(elements[0])
            ],
        } for elements in result])
예제 #2
0
    def test_broken_class_names(self):
        elements = chain_to_elements("a........small")
        self.assertEqual(elements[0].tag_name, "a")
        self.assertEqual(elements[0].attr_class, ["small"])

        elements_string = elements_to_string(elements=[
            Element(tag_name="a",
                    href="/a-url",
                    attr_class=['small"', "xy:z"],
                    attributes={"attr_class": 'xyz small"'})
        ])

        elements = chain_to_elements(elements_string)
        self.assertEqual(elements[0].tag_name, "a")
        self.assertEqual(elements[0].href, "/a-url")
        self.assertEqual(elements[0].attr_class, ["small", "xy:z"])
예제 #3
0
파일: element.py 프로젝트: PostHog/posthog
    def stats(self, request: request.Request, **kwargs) -> response.Response:
        filter = Filter(request=request, team=self.team)

        date_from, date_to, date_params = parse_timestamps(
            filter, team_id=self.team.pk)

        prop_filters, prop_filter_params = parse_prop_grouped_clauses(
            team_id=self.team.pk, property_group=filter.property_groups)
        result = sync_execute(
            GET_ELEMENTS.format(date_from=date_from,
                                date_to=date_to,
                                query=prop_filters),
            {
                "team_id": self.team.pk,
                **prop_filter_params,
                **date_params
            },
        )
        return response.Response([{
            "count":
            elements[1],
            "hash":
            None,
            "elements": [
                ElementSerializer(element).data
                for element in chain_to_elements(elements[0])
            ],
        } for elements in result])
예제 #4
0
    def test_elements_to_string(self) -> None:
        self.maxDiff = None
        elements_string = elements_to_string(elements=[
            Element(
                tag_name="a",
                href="/a-url",
                attr_class=["small"],
                text="bla bla",
                attributes={
                    "prop": "value",
                    "number": 33,
                    "data-attr": 'something " that; could mess up',
                    "style": "min-height: 100vh;",
                },
                nth_child=1,
                nth_of_type=0,
            ),
            Element(tag_name="button",
                    attr_class=["btn", "btn-primary"],
                    nth_child=0,
                    nth_of_type=0),
            Element(tag_name="div", nth_child=0, nth_of_type=0),
            Element(
                tag_name="div",
                nth_child=0,
                nth_of_type=0,
                attr_id="nested",
            ),
        ], )

        self.assertEqual(
            elements_string,
            ";".join([
                r'a.small:data-attr="something \" that; could mess up"href="/a-url"nth-child="1"nth-of-type="0"number="33"prop="value"style="min-height: 100vh;"text="bla bla"',
                'button.btn.btn-primary:nth-child="0"nth-of-type="0"',
                'div:nth-child="0"nth-of-type="0"',
                'div:attr_id="nested"nth-child="0"nth-of-type="0"',
            ]),
        )

        elements = chain_to_elements(elements_string)
        self.assertEqual(elements[0].tag_name, "a")
        self.assertEqual(elements[0].href, "/a-url")
        self.assertEqual(elements[0].attr_class, ["small"])
        self.assertDictEqual(
            elements[0].attributes,
            {
                "prop": "value",
                "number": "33",
                "data-attr": r"something \" that; could mess up",
                "style": "min-height: 100vh;",
            },
        )
        self.assertEqual(elements[0].nth_child, 1)
        self.assertEqual(elements[0].nth_of_type, 0)

        self.assertEqual(elements[1].attr_class, ["btn", "btn-primary"])
        self.assertEqual(elements[3].attr_id, "nested")
예제 #5
0
def post_event_to_webhook_ee(self: Task, event: Dict[str, Any], team_id: int,
                             site_url: str) -> None:
    team = Team.objects.get(pk=team_id)
    elements_list = chain_to_elements(event.get("elements_chain", ""))
    _event = Event.objects.create(event=event["event"],
                                  distinct_id=event["distinct_id"],
                                  properties=event["properties"],
                                  team=team,
                                  site_url=site_url,
                                  **({
                                      "timestamp": event["timestamp"]
                                  } if event["timestamp"] else {}),
                                  **({
                                      "elements": elements_list
                                  }))

    actions = cast(
        Sequence[Action],
        Action.objects.filter(team_id=team_id, post_to_slack=True).all())

    if not site_url:
        site_url = settings.SITE_URL

    for action in actions:
        qs = Event.objects.filter(pk=_event.pk).query_db_by_action(action)
        if not qs:
            continue
        # REST hooks
        action.on_perform(_event)
        # webhooks
        if not team.slack_incoming_webhook:
            continue
        message_text, message_markdown = get_formatted_message(
            action,
            _event,
            site_url,
        )
        if determine_webhook_type(team) == "slack":
            message = {
                "text":
                message_text,
                "blocks": [
                    {
                        "type": "section",
                        "text": {
                            "type": "mrkdwn",
                            "text": message_markdown
                        },
                    },
                ],
            }
        else:
            message = {
                "text": message_markdown,
            }
        requests.post(team.slack_incoming_webhook, verify=False, json=message)

    _event.delete()
예제 #6
0
def post_event_to_webhook_ee(self: Task, event: Dict[str, Any], team_id: int, site_url: str) -> None:
    if not site_url:
        site_url = settings.SITE_URL

    timer = statsd.Timer("%s_posthog_cloud" % (settings.STATSD_PREFIX,))
    timer.start()

    team = Team.objects.select_related("organization").get(pk=team_id)

    elements_list = chain_to_elements(event.get("elements_chain", ""))
    ephemeral_postgres_event = Event.objects.create(
        event=event["event"],
        distinct_id=event["distinct_id"],
        properties=event["properties"],
        team=team,
        site_url=site_url,
        **({"timestamp": event["timestamp"]} if event["timestamp"] else {}),
        **({"elements": elements_list})
    )

    try:
        is_zapier_available = team.organization.is_feature_available("zapier")

        actionFilters = {"team_id": team_id}
        if not is_zapier_available:
            if not team.slack_incoming_webhook:
                return  # Exit this task if neither Zapier nor webhook URL are available
            else:
                actionFilters["post_to_slack"] = True  # We only need to fire for actions that are posted to webhook URL

        for action in cast(Sequence[Action], Action.objects.filter(**actionFilters).all()):
            qs = Event.objects.filter(pk=ephemeral_postgres_event.pk).query_db_by_action(action)
            if not qs:
                continue
            # REST hooks
            if is_zapier_available:
                action.on_perform(ephemeral_postgres_event)
            # webhooks
            if team.slack_incoming_webhook and action.post_to_slack:
                message_text, message_markdown = get_formatted_message(action, ephemeral_postgres_event, site_url)
                if determine_webhook_type(team) == "slack":
                    message = {
                        "text": message_text,
                        "blocks": [{"type": "section", "text": {"type": "mrkdwn", "text": message_markdown}}],
                    }
                else:
                    message = {
                        "text": message_markdown,
                    }
                statsd.Counter("%s_posthog_cloud_hooks_web_fired" % (settings.STATSD_PREFIX)).increment()
                requests.post(team.slack_incoming_webhook, verify=False, json=message)
    except:
        raise
    finally:
        timer.stop("hooks_processed_for_event")
        ephemeral_postgres_event.delete()
예제 #7
0
    def serialize_event_with_property(self, event: str) -> EventDefinition:
        """
        Format the event name for display.
        """
        if not self.support_autocapture_elements():
            return EventDefinition(event=event, properties={}, elements=[])

        event_name, property_name, property_value = event.split("::")
        if event_name == AUTOCAPTURE_EVENT and property_name == "elements_chain":

            event_type, elements_chain = property_value.split(self.ELEMENTS_DIVIDER)
            return EventDefinition(
                event=event,
                properties={self.AUTOCAPTURE_EVENT_TYPE: event_type},
                elements=cast(list, ElementSerializer(chain_to_elements(elements_chain), many=True).data),
            )

        return EventDefinition(event=event, properties={}, elements=[])
예제 #8
0
 def get_elements(self, event):
     if not event[6]:
         return []
     return ElementSerializer(chain_to_elements(event[6]), many=True).data
예제 #9
0
def get_elements(event_id: Union[int, UUID]) -> List[Element]:
    return chain_to_elements(
        sync_execute("select elements_chain from events where uuid = %(id)s",
                     {"id": event_id})[0][0])