Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Mixpanel #306

Merged
merged 10 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ jobs:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: police_data
MIXPANEL_TOKEN: mixpanel_token
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ POSTGRES_DB=police_data
POSTGRES_HOST=db
POSTGRES_PORT=5432
PDT_API_PORT=5000
MIXPANEL_TOKEN=your_mixpanel_token
```

> **Note**
Expand Down
5 changes: 5 additions & 0 deletions backend/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ def SQLALCHEMY_DATABASE_URI(self):
self.POSTGRES_DB,
)

@property
def MIXPANEL_TOKEN(self):
return os.environ.get("MIXPANEL_TOKEN", None)

SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = False

Expand Down Expand Up @@ -90,6 +94,7 @@ class TestingConfig(Config):
POSTGRES_DB = "police_data_test"
SECRET_KEY = "my-secret-key"
JWT_SECRET_KEY = "my-jwt-secret-key"
MIXPANEL_TOKEN = "mixpanel-token"


def get_config_from_env(env: str) -> Config:
Expand Down
Empty file added backend/mixpanel/__init__.py
Empty file.
31 changes: 31 additions & 0 deletions backend/mixpanel/mix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from mixpanel import Mixpanel
from backend.config import Config
from ua_parser import user_agent_parser
from flask_jwt_extended import get_jwt

# Path: backend/mixpanel/mix.py

config = Config()

# Mixpanel connection
mp = Mixpanel(config.MIXPANEL_TOKEN)


def track_to_mp(request, event_name, properties):
parsed = user_agent_parser.Parse(request.headers["User-Agent"])

# Set parsed values as properties.
# You can also parse out the browser/device/os versions.
properties.update({
"$browser": parsed["user_agent"]["family"],
"$device": parsed["device"]["family"],
"$os": parsed["os"]["family"],
})

if "user_id" not in properties:
user_id = get_jwt()["sub"]
else:
user_id = properties["user_id"]

properties["ip"] = request.remote_addr
mp.track(user_id, event_name, properties)
6 changes: 6 additions & 0 deletions backend/routes/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
)
from pydantic.main import BaseModel
from ..auth import min_role_required, user_manager
from ..mixpanel.mix import track_to_mp
from ..database import User, UserRole, db
from ..dto import LoginUserDTO, RegisterUserDTO
from ..schemas import UserSchema, validate
Expand Down Expand Up @@ -94,6 +95,11 @@ def register():
}
)
set_access_cookies(resp, token)

track_to_mp(request, "register", {
'user_id': user.id,
'success': True,
})
return resp, 200
# In case of missing fields, return error message indicating
# required fields.
Expand Down
16 changes: 16 additions & 0 deletions backend/routes/incidents.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import logging
from datetime import datetime
from typing import Optional

from backend.auth.jwt import min_role_required, contributor_has_partner
from backend.mixpanel.mix import track_to_mp
from mixpanel import MixpanelException
from backend.database.models.user import UserRole
from flask import Blueprint, abort, current_app, request
from flask_jwt_extended.view_decorators import jwt_required
Expand Down Expand Up @@ -47,6 +50,8 @@ def create_incident():
abort(400)

created = incident.create()
track_to_mp(request, "create_incident", {
"source_id": incident.source_id})
return incident_orm_to_json(created)


Expand Down Expand Up @@ -78,6 +83,7 @@ def search_incidents():
"""Search Incidents."""
body: SearchIncidentsSchema = request.context.json
query = db.session.query(Incident)
logger = logging.getLogger('incidents')

try:
if body.location:
Expand Down Expand Up @@ -106,6 +112,16 @@ def search_incidents():
page=body.page, per_page=body.perPage, max_per_page=100
)

try:
track_to_mp(request, "search_incidents", {
"description": body.description,
"location": body.location,
"dateStart": body.dateStart,
"dateEnd": body.dateEnd,
})
except MixpanelException as e:
logger.error(e)

try:
return {
"results": [
Expand Down
12 changes: 11 additions & 1 deletion backend/routes/partners.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from backend.auth.jwt import min_role_required
from backend.mixpanel.mix import track_to_mp
from backend.database.models.user import User, UserRole
from flask import Blueprint, abort, current_app, request
from flask_jwt_extended import get_jwt
Expand Down Expand Up @@ -48,11 +49,15 @@ def create_partner():
created = partner.create()
make_admin = PartnerMember(
partner_id=created.id,
user_id=User.get(get_jwt()["sub"]).id,
user_id=get_jwt()["sub"],
role=MemberRole.ADMIN,
)
make_admin.create()

track_to_mp(request, "create_partner", {
"partner_name": partner.name,
"partner_contact": partner.contact_email
})
return partner_orm_to_json(created)


Expand Down Expand Up @@ -182,4 +187,9 @@ def add_member_to_partner(partner_id: int):

created = partner_member.create()

track_to_mp(request, "add_partner_member", {
"partner_id": partner_id,
"user_id": partner_member.user_id,
"role": partner_member.role,
})
return partner_member_orm_to_json(created)
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ services:
POSTGRES_HOST: db
FLASK_ENV: ${FLASK_ENV:-development}
WAIT_HOSTS: db:${POSTGRES_PORT:-5432}
MIXPANEL_TOKEN: ${MIXPANEL_TOKEN:-notset}
ports:
- ${PDT_API_PORT:-5000}:${PDT_API_PORT:-5000}

Expand Down
18 changes: 18 additions & 0 deletions frontend/next.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
module.exports = {
headers() {
return [
{
// matching all API routes
source: "/api/:path*",
headers: [
{ key: "Access-Control-Allow-Credentials", value: "true" },
{ key: "Access-Control-Allow-Origin", value: "*" }, // replace this your actual origin
{ key: "Access-Control-Allow-Methods", value: "GET,DELETE,PATCH,POST,PUT" },
{
key: "Access-Control-Allow-Headers",
value:
"X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version"
}
]
}
]
},
eslint: {
dirs: ["tests", "shared-components", "pages", "models", "helpers", "compositions"]
}
Expand Down
4 changes: 3 additions & 1 deletion requirements/_core.in
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ openpyxl
xlsxwriter
numpy
spectree
jupyter
jupyter
mixpanel
ua-parser
17 changes: 13 additions & 4 deletions requirements/dev_unix.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#
# This file is autogenerated by pip-compile with python 3.8
# To update, run:
# This file is autogenerated by pip-compile with Python 3.8
# by the following command:
#
# pip-compile requirements/dev_unix.in
#
Expand Down Expand Up @@ -205,6 +205,8 @@ mirakuru==2.4.1
# via pytest-postgresql
mistune==0.8.4
# via nbconvert
mixpanel==4.10.0
# via -r requirements/_core.in
mypy-extensions==0.4.3
# via black
nbclient==0.5.13
Expand Down Expand Up @@ -362,7 +364,9 @@ qtpy==2.0.1
regex==2021.4.4
# via black
requests==2.25.1
# via -r requirements/_core.in
# via
# -r requirements/_core.in
# mixpanel
send2trash==1.8.0
# via notebook
six==1.16.0
Expand All @@ -372,6 +376,7 @@ six==1.16.0
# bleach
# click-repl
# flask-cors
# mixpanel
# python-dateutil
# sqlalchemy-utils
soupsieve==2.3.1
Expand Down Expand Up @@ -424,8 +429,12 @@ traitlets==5.1.1
# qtconsole
typing-extensions==3.10.0.0
# via pydantic
ua-parser==0.18.0
# via -r requirements/_core.in
urllib3==1.26.5
# via requests
# via
# mixpanel
# requests
vine==5.0.0
# via
# amqp
Expand Down
17 changes: 13 additions & 4 deletions requirements/dev_windows.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#
# This file is autogenerated by pip-compile with python 3.8
# To update, run:
# This file is autogenerated by pip-compile with Python 3.8
# by the following command:
#
# pip-compile requirements/dev_windows.in
#
Expand Down Expand Up @@ -205,6 +205,8 @@ mirakuru==2.4.1
# via pytest-postgresql
mistune==0.8.4
# via nbconvert
mixpanel==4.10.0
# via -r requirements/_core.in
mypy-extensions==0.4.3
# via black
nbclient==0.5.13
Expand Down Expand Up @@ -362,7 +364,9 @@ qtpy==2.0.1
regex==2021.4.4
# via black
requests==2.25.1
# via -r requirements/_core.in
# via
# -r requirements/_core.in
# mixpanel
send2trash==1.8.0
# via notebook
six==1.16.0
Expand All @@ -372,6 +376,7 @@ six==1.16.0
# bleach
# click-repl
# flask-cors
# mixpanel
# python-dateutil
# sqlalchemy-utils
soupsieve==2.3.1
Expand Down Expand Up @@ -424,8 +429,12 @@ traitlets==5.1.1
# qtconsole
typing-extensions==3.10.0.0
# via pydantic
ua-parser==0.18.0
# via -r requirements/_core.in
urllib3==1.26.5
# via requests
# via
# mixpanel
# requests
vine==5.0.0
# via
# amqp
Expand Down
4 changes: 2 additions & 2 deletions requirements/docs.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#
# This file is autogenerated by pip-compile with python 3.8
# To update, run:
# This file is autogenerated by pip-compile with Python 3.8
# by the following command:
#
# pip-compile requirements/docs.in
#
Expand Down
17 changes: 13 additions & 4 deletions requirements/prod.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#
# This file is autogenerated by pip-compile with python 3.8
# To update, run:
# This file is autogenerated by pip-compile with Python 3.8
# by the following command:
#
# pip-compile requirements/prod.in
#
Expand Down Expand Up @@ -205,6 +205,8 @@ mirakuru==2.4.1
# via pytest-postgresql
mistune==0.8.4
# via nbconvert
mixpanel==4.10.0
# via -r requirements/_core.in
mypy-extensions==0.4.3
# via black
nbclient==0.5.13
Expand Down Expand Up @@ -362,7 +364,9 @@ qtpy==2.0.1
regex==2021.4.4
# via black
requests==2.25.1
# via -r requirements/_core.in
# via
# -r requirements/_core.in
# mixpanel
send2trash==1.8.0
# via notebook
six==1.16.0
Expand All @@ -372,6 +376,7 @@ six==1.16.0
# bleach
# click-repl
# flask-cors
# mixpanel
# python-dateutil
# sqlalchemy-utils
soupsieve==2.3.1
Expand Down Expand Up @@ -424,8 +429,12 @@ traitlets==5.1.1
# qtconsole
typing-extensions==3.10.0.0
# via pydantic
ua-parser==0.18.0
# via -r requirements/_core.in
urllib3==1.26.5
# via requests
# via
# mixpanel
# requests
vine==5.0.0
# via
# amqp
Expand Down
Loading