Skip to content

Commit

Permalink
feat: fix "All User Stats" download link
Browse files Browse the repository at this point in the history
This commit brings in a new route, /data/all_user_stats.csv.

TODO: Simplify other CSV views.

Signed-off-by: Kevin Morris <kevr@0cost.org>
  • Loading branch information
kevr committed Oct 13, 2022
1 parent b0201d4 commit 7fd4720
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 4 deletions.
2 changes: 1 addition & 1 deletion home/templates/home/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
Download
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="/data/users_agg.csv">All User Stats</a>
<a class="dropdown-item" href="/data/all_user_stats.csv">All User Stats</a>
<a class="dropdown-item" href="/data/users.csv">All User Account Info</a>
<a class="dropdown-item" href="/data/daily_walks.csv">All Walks</a>
<a class="dropdown-item" href="/data/intentional_walks.csv">All Recorded Walks</a>
Expand Down
71 changes: 68 additions & 3 deletions home/tests/integration/views/web/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@ def setUpTestData(cls):
Login()

# Generate fake accounts
accounts = list(AccountGenerator().generate(2))
cls.accounts = list(AccountGenerator().generate(2))

# Device associated with accounts[0]
device0 = list(DeviceGenerator(accounts[0:1]).generate(1))
device0 = list(DeviceGenerator(cls.accounts[0:1]).generate(1))
# Device associated with accounts[1]
device1 = list(DeviceGenerator(accounts[1:2]).generate(1))
device1 = list(DeviceGenerator(cls.accounts[1:2]).generate(1))

# Generate daily walks (10 per device)
dwalks0 = DailyWalkGenerator(device0)
Expand Down Expand Up @@ -77,6 +78,70 @@ def group_by(rows: List[Dict], key: str) -> Dict[str, List]:
grouped[row[key]].append(row)
return grouped

def test_all_user_stats_csv_view(self):
client = Client()
self.assertTrue(self.login(client))

params = {
"start_baseline": date(3000, 2, 28),
"start_promo": date(3000, 3, 1),
"start": date(3000, 3, 7),
"end": date(3000, 3, 14),
}
next(ContestGenerator().generate(1, **params)).pk

response = client.get("/data/all_user_stats.csv")
self.assertEqual(200, response.status_code)
self.assertEqual("text/csv", response["Content-Type"])
content = response.content.decode("utf-8")
reader = csv.DictReader(io.StringIO(content))

headers = reader.fieldnames
self.assertEqual(
headers,
[
"Participant Name",
"Date Enrolled",
"Email",
"Zip Code",
"Sexual Orientation",
"Sexual Orientation Other",
"Gender Identity",
"Gender Identity Other",
"Race",
"Race Other",
"Is Latino",
"Age",
"Total Daily Walks",
"Total Daily Steps",
"Total Recorded Walks",
"Total Recorded Steps",
],
)

rows = list(reader)
# Order accounts in ascending order based on the name, to match
# the backend's production, which orders records by
# ascending order (created, name).
for i, account in enumerate(
sorted(self.accounts, key=lambda a: a.name)
):
row = rows[i]
self.assertEqual(account.name, row.get("Participant Name"))
self.assertEqual(account.email, row.get("Email"))
self.assertEqual(account.zip, row.get("Zip Code"))
self.assertEqual(
account.sexual_orien, row.get("Sexual Orientation")
)
self.assertEqual(account.gender, row.get("Gender Identity"))
self.assertEqual(account.is_latino, row.get("Is Latino"))
self.assertEqual(account.age, int(row.get("Age")))
self.assertEqual(set(account.race), eval(row.get("Race")))
self.assertGreater(int(row.get("Total Daily Walks")), 0)
self.assertGreater(int(row.get("Total Daily Steps")), 0)
self.assertGreater(int(row.get("Total Recorded Walks")), 0)
self.assertGreater(int(row.get("Total Recorded Steps")), 0)

def test_user_agg_csv_view(self):
c = Client()
self.assertTrue(self.login(c))
Expand Down
5 changes: 5 additions & 0 deletions home/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
views.user_agg_csv_view,
name="users_agg_csv_view",
),
path(
"data/all_user_stats.csv",
views.all_user_stats_csv_view,
name="all_user_stats_csv_view",
),
path("data/users.csv", views.users_csv_view, name="users_csv_view"),
path(
"data/daily_walks.csv",
Expand Down
1 change: 1 addition & 0 deletions home/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .web.home import HomeView
from .web.intentionalwalk import IntentionalWalkWebView
from .web.user import UserListView
from .web.data import all_user_stats_csv_view
from .web.data import user_agg_csv_view
from .web.data import users_csv_view
from .web.data import daily_walks_csv_view
Expand Down
64 changes: 64 additions & 0 deletions home/views/web/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,70 @@ def _get_user_daily_step_counts(
return daily_step_counts_by_user


def all_user_stats_csv_view(request) -> HttpResponse:
columns = [
"Participant Name",
"Date Enrolled",
"Email",
"Zip Code",
"Sexual Orientation",
"Sexual Orientation Other",
"Gender Identity",
"Gender Identity Other",
"Race",
"Race Other",
"Is Latino",
"Age",
"Total Daily Walks",
"Total Daily Steps",
"Total Recorded Walks",
"Total Recorded Steps",
]

users = Account.objects.order_by("created").order_by("name").all()
output = []
for user in users:
daily_walks = user.dailywalk_set.values("steps")
cnt_daily = len(daily_walks)
daily_steps = sum([w.get("steps") for w in daily_walks])

rec_walks = user.intentionalwalk_set.values("steps")
cnt_recorded = len(rec_walks)
rec_steps = sum([w.get("steps") for w in rec_walks])

output.append(
{
"Participant Name": user.name,
"Date Enrolled": user.created,
"Email": user.email,
"Zip Code": user.zip,
"Sexual Orientation": user.sexual_orien,
"Sexual Orientation Other": user.sexual_orien_other,
"Gender Identity": user.gender,
"Gender Identity Other": user.gender_other,
"Race": user.race,
"Race Other": user.race_other,
"Is Latino": user.is_latino,
"Age": user.age,
"Total Daily Walks": cnt_daily,
"Total Daily Steps": daily_steps,
"Total Recorded Walks": cnt_recorded,
"Total Recorded Steps": rec_steps,
}
)

response = HttpResponse(content_type="text/csv")
response[
"Content-Disposition"
] = 'attachment; filename="all_users_stats.csv"'

writer = csv.DictWriter(response, fieldnames=columns)
writer.writeheader()
writer.writerows(output)

return response


def user_agg_csv_view(request) -> HttpResponse:
if not request.user.is_authenticated:
return HttpResponse("You are not authorized to view this!")
Expand Down

0 comments on commit 7fd4720

Please sign in to comment.