Skip to content

Commit

Permalink
Merge pull request #306 from mikeyavorsky/dkmalone/analytics
Browse files Browse the repository at this point in the history
Add Mixpanel
  • Loading branch information
mikeyavorsky authored Nov 22, 2023
2 parents 8bf58f5 + 466d990 commit d7b3310
Show file tree
Hide file tree
Showing 15 changed files with 134 additions and 16 deletions.
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

0 comments on commit d7b3310

Please sign in to comment.