We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Weekly stats shows 0 downloads for some users
### Context

A lot of changes has gone into prod recently. One of them is the EngagementBot weekly stats updates.

### Problem or idea

The most recent summary contains lines like "0 downloads from " indicating some (potential) stats inaccuracy.

### Solution or next step

Figure out why the value is empty and fix the issue. If everything is right then just hide those 0 downloads items.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `api/data_refinery_api/management/commands/post_downloads_summary.py`
Content:
```
1 import datetime
2 from collections import Counter
3 
4 from django.conf import settings
5 from django.core.management.base import BaseCommand
6 from django.template.defaultfilters import pluralize
7 from django.utils import timezone
8 
9 import requests
10 
11 from data_refinery_common.models import Dataset, DatasetAnnotation
12 
13 
14 class Command(BaseCommand):
15     help = "Post downloads summary to Slack"
16 
17     def add_arguments(self, parser):
18         parser.add_argument(
19             "--channel",
20             type=str,
21             default="ccdl-general",
22             help=("Optional parameter to choose the channel where the message will be posted."),
23         )
24         parser.add_argument(
25             "--days",
26             type=int,
27             default=7,  # Default to a week.
28             help=("Number of days in the past for which to build the stats."),
29         )
30         parser.add_argument(
31             "--top-countries",
32             type=int,
33             default=5,
34             help=("Number of countries to show in the per country downloads summary."),
35         )
36 
37     def handle(self, *args, **options):
38         post_downloads_summary(options["days"], options["channel"], options["top_countries"])
39 
40 
41 def format_user_data(header, data):
42     """
43     Formats user email, downloads count, location information sorted
44     by downloads count.
45     """
46     # Allowed overhead for 2 column sorting: downloads count, email.
47     lines = sorted(data, key=lambda u: u[0].lower())
48     lines = [
49         f"{email.lower()} | {downloads} download{pluralize(downloads)} from {location}"
50         for email, downloads, location in sorted(lines, key=lambda u: u[1], reverse=True)
51     ]
52     lines.insert(0, header)
53 
54     return "\n".join(lines)
55 
56 
57 def get_user_location(ip_address):
58     """Gets user location information based on their IP address."""
59     try:
60         data = requests.get(f"https://ipapi.co/{ip_address}/json/", timeout=10).json()
61         # The list of available fields https://ipapi.co/api/#complete-location
62         return ", ".join((data["city"], data["country_name"]))
63     except (requests.exceptions.RequestException, KeyError, ValueError):
64         return ip_address
65 
66 
67 def post_downloads_summary(days, channel, top_countries=5):
68     """Posts downloads summary to Slack channel."""
69 
70     start_time = timezone.now() - datetime.timedelta(days=days)
71     datasets = Dataset.processed_filtered_objects.filter(
72         created_at__gt=start_time
73     ).prefetch_related("datasetannotation_set")
74     annotations = DatasetAnnotation.objects.filter(dataset__in=datasets)
75     users_emails = set(dataset.email_address for dataset in datasets)
76 
77     locations = set()
78     locations_cache = dict()
79     for annotation in annotations:
80         if "location" not in annotation.data:
81             ip_address = annotation.data["ip"]
82             if ip_address not in locations_cache:
83                 locations_cache[ip_address] = get_user_location(ip_address)
84 
85             # Save the locations permanently, since IP addresses can cycle over time.
86             annotation.data["location"] = locations_cache[ip_address]
87             annotation.save()
88         locations.add(annotation.data["location"])
89 
90     downloads_per_country = Counter()
91     downloads_total = 0
92     new_users = []
93     returning_users = []
94     for user_email in users_emails:
95         user_annotations = annotations.filter(dataset__email_address=user_email)
96         user_downloads = user_annotations.count()
97         downloads_total += user_downloads
98 
99         user_locations = set()
100         for user_annotation in user_annotations:
101             user_locations.add(user_annotation.data["location"])
102             try:
103                 country = user_annotation.data["location"].split(", ")[1]
104                 downloads_per_country.update({country: 1})
105             except (IndexError, TypeError):
106                 pass
107 
108         user_locations = "; ".join(sorted(user_locations))
109         user_data = (user_email, user_downloads, user_locations)
110 
111         is_returning_user = Dataset.processed_filtered_objects.filter(
112             created_at__lt=start_time, email_address=user_email
113         )
114         if is_returning_user:
115             returning_users.append(user_data)
116         else:
117             new_users.append(user_data)
118 
119     if downloads_total:
120         locations_count = len(locations)
121         users_emails_count = len(users_emails)
122         fallback_text = (
123             f"In the last {days} day{pluralize(days)}, {users_emails_count} "
124             f"user{pluralize(users_emails_count)} downloaded {downloads_total} "
125             f"dataset{pluralize(downloads_total)} from {locations_count} "
126             f"location{pluralize(locations_count)}."
127         )
128     else:
129         fallback_text = f"There were no downloads in the last {days} day{pluralize(days)}."
130 
131     blocks = [
132         {"type": "section", "text": {"type": "plain_text", "emoji": True, "text": fallback_text}}
133     ]
134 
135     if new_users:
136         blocks.append(
137             {
138                 "type": "section",
139                 "text": {"type": "mrkdwn", "text": format_user_data("*New users*", new_users)},
140             }
141         )
142 
143     if returning_users:
144         blocks.append(
145             {
146                 "type": "section",
147                 "text": {
148                     "type": "mrkdwn",
149                     "text": format_user_data("*Returning users*", returning_users),
150                 },
151             }
152         )
153 
154     if top_countries and downloads_per_country:
155         countries_count = downloads_per_country.most_common(top_countries)
156         top_countries = min(top_countries, len(countries_count))
157         lines = [f"*Top {top_countries} countr{pluralize(top_countries, 'y,ies')}*"]
158         # Allowed overhead for 2 column sorting: downloads count, country.
159         countries_count = sorted(countries_count, key=lambda cc: cc[0])
160         countries_count = sorted(countries_count, key=lambda cc: cc[1], reverse=True)
161         for country, count in countries_count:
162             lines.append(f"{country}: {count} download{pluralize(count)}")
163 
164         blocks.append(
165             {
166                 "type": "section",
167                 "text": {"type": "mrkdwn", "text": "\n".join(lines)},
168             }
169         )
170 
171     # Post to Slack.
172     requests.post(
173         settings.ENGAGEMENTBOT_WEBHOOK,
174         json={
175             "username": "EngagementBot",
176             "icon_emoji": ":halal:",
177             "channel": f"#{channel}",
178             "text": fallback_text,
179             "blocks": blocks,
180         },
181         headers={"Content-Type": "application/json"},
182         timeout=10,
183     )
184
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/api/data_refinery_api/management/commands/post_downloads_summary.py b/api/data_refinery_api/management/commands/post_downloads_summary.py
--- a/api/data_refinery_api/management/commands/post_downloads_summary.py
+++ b/api/data_refinery_api/management/commands/post_downloads_summary.py
@@ -66,7 +66,6 @@
 
 def post_downloads_summary(days, channel, top_countries=5):
     """Posts downloads summary to Slack channel."""
-
     start_time = timezone.now() - datetime.timedelta(days=days)
     datasets = Dataset.processed_filtered_objects.filter(
         created_at__gt=start_time
@@ -75,7 +74,7 @@
     users_emails = set(dataset.email_address for dataset in datasets)
 
     locations = set()
-    locations_cache = dict()
+    locations_cache = {}
     for annotation in annotations:
         if "location" not in annotation.data:
             ip_address = annotation.data["ip"]
@@ -94,8 +93,10 @@
     for user_email in users_emails:
         user_annotations = annotations.filter(dataset__email_address=user_email)
         user_downloads = user_annotations.count()
-        downloads_total += user_downloads
+        if user_downloads == 0:
+            continue
 
+        downloads_total += user_downloads
         user_locations = set()
         for user_annotation in user_annotations:
             user_locations.add(user_annotation.data["location"])
@@ -110,18 +111,18 @@
 
         is_returning_user = Dataset.processed_filtered_objects.filter(
             created_at__lt=start_time, email_address=user_email
-        )
+        ).exists()
         if is_returning_user:
             returning_users.append(user_data)
         else:
             new_users.append(user_data)
 
-    if downloads_total:
+    if downloads_total > 0:
         locations_count = len(locations)
-        users_emails_count = len(users_emails)
+        users_count = len(new_users) + len(returning_users)
         fallback_text = (
-            f"In the last {days} day{pluralize(days)}, {users_emails_count} "
-            f"user{pluralize(users_emails_count)} downloaded {downloads_total} "
+            f"In the last {days} day{pluralize(days)}, {users_count} "
+            f"user{pluralize(users_count)} downloaded {downloads_total} "
             f"dataset{pluralize(downloads_total)} from {locations_count} "
             f"location{pluralize(locations_count)}."
         )
@@ -129,14 +130,20 @@
         fallback_text = f"There were no downloads in the last {days} day{pluralize(days)}."
 
     blocks = [
-        {"type": "section", "text": {"type": "plain_text", "emoji": True, "text": fallback_text}}
+        {
+            "type": "section",
+            "text": {"type": "plain_text", "emoji": True, "text": fallback_text},
+        }
     ]
 
     if new_users:
         blocks.append(
             {
                 "type": "section",
-                "text": {"type": "mrkdwn", "text": format_user_data("*New users*", new_users)},
+                "text": {
+                    "type": "mrkdwn",
+                    "text": format_user_data("*New users*", new_users),
+                },
             }
         )

{"golden_diff": "diff --git a/api/data_refinery_api/management/commands/post_downloads_summary.py b/api/data_refinery_api/management/commands/post_downloads_summary.py\n--- a/api/data_refinery_api/management/commands/post_downloads_summary.py\n+++ b/api/data_refinery_api/management/commands/post_downloads_summary.py\n@@ -66,7 +66,6 @@\n \n def post_downloads_summary(days, channel, top_countries=5):\n     \"\"\"Posts downloads summary to Slack channel.\"\"\"\n-\n     start_time = timezone.now() - datetime.timedelta(days=days)\n     datasets = Dataset.processed_filtered_objects.filter(\n         created_at__gt=start_time\n@@ -75,7 +74,7 @@\n     users_emails = set(dataset.email_address for dataset in datasets)\n \n     locations = set()\n-    locations_cache = dict()\n+    locations_cache = {}\n     for annotation in annotations:\n         if \"location\" not in annotation.data:\n             ip_address = annotation.data[\"ip\"]\n@@ -94,8 +93,10 @@\n     for user_email in users_emails:\n         user_annotations = annotations.filter(dataset__email_address=user_email)\n         user_downloads = user_annotations.count()\n-        downloads_total += user_downloads\n+        if user_downloads == 0:\n+            continue\n \n+        downloads_total += user_downloads\n         user_locations = set()\n         for user_annotation in user_annotations:\n             user_locations.add(user_annotation.data[\"location\"])\n@@ -110,18 +111,18 @@\n \n         is_returning_user = Dataset.processed_filtered_objects.filter(\n             created_at__lt=start_time, email_address=user_email\n-        )\n+        ).exists()\n         if is_returning_user:\n             returning_users.append(user_data)\n         else:\n             new_users.append(user_data)\n \n-    if downloads_total:\n+    if downloads_total > 0:\n         locations_count = len(locations)\n-        users_emails_count = len(users_emails)\n+        users_count = len(new_users) + len(returning_users)\n         fallback_text = (\n-            f\"In the last {days} day{pluralize(days)}, {users_emails_count} \"\n-            f\"user{pluralize(users_emails_count)} downloaded {downloads_total} \"\n+            f\"In the last {days} day{pluralize(days)}, {users_count} \"\n+            f\"user{pluralize(users_count)} downloaded {downloads_total} \"\n             f\"dataset{pluralize(downloads_total)} from {locations_count} \"\n             f\"location{pluralize(locations_count)}.\"\n         )\n@@ -129,14 +130,20 @@\n         fallback_text = f\"There were no downloads in the last {days} day{pluralize(days)}.\"\n \n     blocks = [\n-        {\"type\": \"section\", \"text\": {\"type\": \"plain_text\", \"emoji\": True, \"text\": fallback_text}}\n+        {\n+            \"type\": \"section\",\n+            \"text\": {\"type\": \"plain_text\", \"emoji\": True, \"text\": fallback_text},\n+        }\n     ]\n \n     if new_users:\n         blocks.append(\n             {\n                 \"type\": \"section\",\n-                \"text\": {\"type\": \"mrkdwn\", \"text\": format_user_data(\"*New users*\", new_users)},\n+                \"text\": {\n+                    \"type\": \"mrkdwn\",\n+                    \"text\": format_user_data(\"*New users*\", new_users),\n+                },\n             }\n         )\n", "issue": "Weekly stats shows 0 downloads for some users\n### Context\r\n\r\nA lot of changes has gone into prod recently. One of them is the EngagementBot weekly stats updates.\r\n\r\n### Problem or idea\r\n\r\nThe most recent summary contains lines like \"0 downloads from \" indicating some (potential) stats inaccuracy.\r\n\r\n### Solution or next step\r\n\r\nFigure out why the value is empty and fix the issue. If everything is right then just hide those 0 downloads items.\r\n\n", "before_files": [{"content": "import datetime\nfrom collections import Counter\n\nfrom django.conf import settings\nfrom django.core.management.base import BaseCommand\nfrom django.template.defaultfilters import pluralize\nfrom django.utils import timezone\n\nimport requests\n\nfrom data_refinery_common.models import Dataset, DatasetAnnotation\n\n\nclass Command(BaseCommand):\n    help = \"Post downloads summary to Slack\"\n\n    def add_arguments(self, parser):\n        parser.add_argument(\n            \"--channel\",\n            type=str,\n            default=\"ccdl-general\",\n            help=(\"Optional parameter to choose the channel where the message will be posted.\"),\n        )\n        parser.add_argument(\n            \"--days\",\n            type=int,\n            default=7,  # Default to a week.\n            help=(\"Number of days in the past for which to build the stats.\"),\n        )\n        parser.add_argument(\n            \"--top-countries\",\n            type=int,\n            default=5,\n            help=(\"Number of countries to show in the per country downloads summary.\"),\n        )\n\n    def handle(self, *args, **options):\n        post_downloads_summary(options[\"days\"], options[\"channel\"], options[\"top_countries\"])\n\n\ndef format_user_data(header, data):\n    \"\"\"\n    Formats user email, downloads count, location information sorted\n    by downloads count.\n    \"\"\"\n    # Allowed overhead for 2 column sorting: downloads count, email.\n    lines = sorted(data, key=lambda u: u[0].lower())\n    lines = [\n        f\"{email.lower()} | {downloads} download{pluralize(downloads)} from {location}\"\n        for email, downloads, location in sorted(lines, key=lambda u: u[1], reverse=True)\n    ]\n    lines.insert(0, header)\n\n    return \"\\n\".join(lines)\n\n\ndef get_user_location(ip_address):\n    \"\"\"Gets user location information based on their IP address.\"\"\"\n    try:\n        data = requests.get(f\"https://ipapi.co/{ip_address}/json/\", timeout=10).json()\n        # The list of available fields https://ipapi.co/api/#complete-location\n        return \", \".join((data[\"city\"], data[\"country_name\"]))\n    except (requests.exceptions.RequestException, KeyError, ValueError):\n        return ip_address\n\n\ndef post_downloads_summary(days, channel, top_countries=5):\n    \"\"\"Posts downloads summary to Slack channel.\"\"\"\n\n    start_time = timezone.now() - datetime.timedelta(days=days)\n    datasets = Dataset.processed_filtered_objects.filter(\n        created_at__gt=start_time\n    ).prefetch_related(\"datasetannotation_set\")\n    annotations = DatasetAnnotation.objects.filter(dataset__in=datasets)\n    users_emails = set(dataset.email_address for dataset in datasets)\n\n    locations = set()\n    locations_cache = dict()\n    for annotation in annotations:\n        if \"location\" not in annotation.data:\n            ip_address = annotation.data[\"ip\"]\n            if ip_address not in locations_cache:\n                locations_cache[ip_address] = get_user_location(ip_address)\n\n            # Save the locations permanently, since IP addresses can cycle over time.\n            annotation.data[\"location\"] = locations_cache[ip_address]\n            annotation.save()\n        locations.add(annotation.data[\"location\"])\n\n    downloads_per_country = Counter()\n    downloads_total = 0\n    new_users = []\n    returning_users = []\n    for user_email in users_emails:\n        user_annotations = annotations.filter(dataset__email_address=user_email)\n        user_downloads = user_annotations.count()\n        downloads_total += user_downloads\n\n        user_locations = set()\n        for user_annotation in user_annotations:\n            user_locations.add(user_annotation.data[\"location\"])\n            try:\n                country = user_annotation.data[\"location\"].split(\", \")[1]\n                downloads_per_country.update({country: 1})\n            except (IndexError, TypeError):\n                pass\n\n        user_locations = \"; \".join(sorted(user_locations))\n        user_data = (user_email, user_downloads, user_locations)\n\n        is_returning_user = Dataset.processed_filtered_objects.filter(\n            created_at__lt=start_time, email_address=user_email\n        )\n        if is_returning_user:\n            returning_users.append(user_data)\n        else:\n            new_users.append(user_data)\n\n    if downloads_total:\n        locations_count = len(locations)\n        users_emails_count = len(users_emails)\n        fallback_text = (\n            f\"In the last {days} day{pluralize(days)}, {users_emails_count} \"\n            f\"user{pluralize(users_emails_count)} downloaded {downloads_total} \"\n            f\"dataset{pluralize(downloads_total)} from {locations_count} \"\n            f\"location{pluralize(locations_count)}.\"\n        )\n    else:\n        fallback_text = f\"There were no downloads in the last {days} day{pluralize(days)}.\"\n\n    blocks = [\n        {\"type\": \"section\", \"text\": {\"type\": \"plain_text\", \"emoji\": True, \"text\": fallback_text}}\n    ]\n\n    if new_users:\n        blocks.append(\n            {\n                \"type\": \"section\",\n                \"text\": {\"type\": \"mrkdwn\", \"text\": format_user_data(\"*New users*\", new_users)},\n            }\n        )\n\n    if returning_users:\n        blocks.append(\n            {\n                \"type\": \"section\",\n                \"text\": {\n                    \"type\": \"mrkdwn\",\n                    \"text\": format_user_data(\"*Returning users*\", returning_users),\n                },\n            }\n        )\n\n    if top_countries and downloads_per_country:\n        countries_count = downloads_per_country.most_common(top_countries)\n        top_countries = min(top_countries, len(countries_count))\n        lines = [f\"*Top {top_countries} countr{pluralize(top_countries, 'y,ies')}*\"]\n        # Allowed overhead for 2 column sorting: downloads count, country.\n        countries_count = sorted(countries_count, key=lambda cc: cc[0])\n        countries_count = sorted(countries_count, key=lambda cc: cc[1], reverse=True)\n        for country, count in countries_count:\n            lines.append(f\"{country}: {count} download{pluralize(count)}\")\n\n        blocks.append(\n            {\n                \"type\": \"section\",\n                \"text\": {\"type\": \"mrkdwn\", \"text\": \"\\n\".join(lines)},\n            }\n        )\n\n    # Post to Slack.\n    requests.post(\n        settings.ENGAGEMENTBOT_WEBHOOK,\n        json={\n            \"username\": \"EngagementBot\",\n            \"icon_emoji\": \":halal:\",\n            \"channel\": f\"#{channel}\",\n            \"text\": fallback_text,\n            \"blocks\": blocks,\n        },\n        headers={\"Content-Type\": \"application/json\"},\n        timeout=10,\n    )\n", "path": "api/data_refinery_api/management/commands/post_downloads_summary.py"}], "after_files": [{"content": "import datetime\nfrom collections import Counter\n\nfrom django.conf import settings\nfrom django.core.management.base import BaseCommand\nfrom django.template.defaultfilters import pluralize\nfrom django.utils import timezone\n\nimport requests\n\nfrom data_refinery_common.models import Dataset, DatasetAnnotation\n\n\nclass Command(BaseCommand):\n    help = \"Post downloads summary to Slack\"\n\n    def add_arguments(self, parser):\n        parser.add_argument(\n            \"--channel\",\n            type=str,\n            default=\"ccdl-general\",\n            help=(\"Optional parameter to choose the channel where the message will be posted.\"),\n        )\n        parser.add_argument(\n            \"--days\",\n            type=int,\n            default=7,  # Default to a week.\n            help=(\"Number of days in the past for which to build the stats.\"),\n        )\n        parser.add_argument(\n            \"--top-countries\",\n            type=int,\n            default=5,\n            help=(\"Number of countries to show in the per country downloads summary.\"),\n        )\n\n    def handle(self, *args, **options):\n        post_downloads_summary(options[\"days\"], options[\"channel\"], options[\"top_countries\"])\n\n\ndef format_user_data(header, data):\n    \"\"\"\n    Formats user email, downloads count, location information sorted\n    by downloads count.\n    \"\"\"\n    # Allowed overhead for 2 column sorting: downloads count, email.\n    lines = sorted(data, key=lambda u: u[0].lower())\n    lines = [\n        f\"{email.lower()} | {downloads} download{pluralize(downloads)} from {location}\"\n        for email, downloads, location in sorted(lines, key=lambda u: u[1], reverse=True)\n    ]\n    lines.insert(0, header)\n\n    return \"\\n\".join(lines)\n\n\ndef get_user_location(ip_address):\n    \"\"\"Gets user location information based on their IP address.\"\"\"\n    try:\n        data = requests.get(f\"https://ipapi.co/{ip_address}/json/\", timeout=10).json()\n        # The list of available fields https://ipapi.co/api/#complete-location\n        return \", \".join((data[\"city\"], data[\"country_name\"]))\n    except (requests.exceptions.RequestException, KeyError, ValueError):\n        return ip_address\n\n\ndef post_downloads_summary(days, channel, top_countries=5):\n    \"\"\"Posts downloads summary to Slack channel.\"\"\"\n    start_time = timezone.now() - datetime.timedelta(days=days)\n    datasets = Dataset.processed_filtered_objects.filter(\n        created_at__gt=start_time\n    ).prefetch_related(\"datasetannotation_set\")\n    annotations = DatasetAnnotation.objects.filter(dataset__in=datasets)\n    users_emails = set(dataset.email_address for dataset in datasets)\n\n    locations = set()\n    locations_cache = {}\n    for annotation in annotations:\n        if \"location\" not in annotation.data:\n            ip_address = annotation.data[\"ip\"]\n            if ip_address not in locations_cache:\n                locations_cache[ip_address] = get_user_location(ip_address)\n\n            # Save the locations permanently, since IP addresses can cycle over time.\n            annotation.data[\"location\"] = locations_cache[ip_address]\n            annotation.save()\n        locations.add(annotation.data[\"location\"])\n\n    downloads_per_country = Counter()\n    downloads_total = 0\n    new_users = []\n    returning_users = []\n    for user_email in users_emails:\n        user_annotations = annotations.filter(dataset__email_address=user_email)\n        user_downloads = user_annotations.count()\n        if user_downloads == 0:\n            continue\n\n        downloads_total += user_downloads\n        user_locations = set()\n        for user_annotation in user_annotations:\n            user_locations.add(user_annotation.data[\"location\"])\n            try:\n                country = user_annotation.data[\"location\"].split(\", \")[1]\n                downloads_per_country.update({country: 1})\n            except (IndexError, TypeError):\n                pass\n\n        user_locations = \"; \".join(sorted(user_locations))\n        user_data = (user_email, user_downloads, user_locations)\n\n        is_returning_user = Dataset.processed_filtered_objects.filter(\n            created_at__lt=start_time, email_address=user_email\n        ).exists()\n        if is_returning_user:\n            returning_users.append(user_data)\n        else:\n            new_users.append(user_data)\n\n    if downloads_total > 0:\n        locations_count = len(locations)\n        users_count = len(new_users) + len(returning_users)\n        fallback_text = (\n            f\"In the last {days} day{pluralize(days)}, {users_count} \"\n            f\"user{pluralize(users_count)} downloaded {downloads_total} \"\n            f\"dataset{pluralize(downloads_total)} from {locations_count} \"\n            f\"location{pluralize(locations_count)}.\"\n        )\n    else:\n        fallback_text = f\"There were no downloads in the last {days} day{pluralize(days)}.\"\n\n    blocks = [\n        {\n            \"type\": \"section\",\n            \"text\": {\"type\": \"plain_text\", \"emoji\": True, \"text\": fallback_text},\n        }\n    ]\n\n    if new_users:\n        blocks.append(\n            {\n                \"type\": \"section\",\n                \"text\": {\n                    \"type\": \"mrkdwn\",\n                    \"text\": format_user_data(\"*New users*\", new_users),\n                },\n            }\n        )\n\n    if returning_users:\n        blocks.append(\n            {\n                \"type\": \"section\",\n                \"text\": {\n                    \"type\": \"mrkdwn\",\n                    \"text\": format_user_data(\"*Returning users*\", returning_users),\n                },\n            }\n        )\n\n    if top_countries and downloads_per_country:\n        countries_count = downloads_per_country.most_common(top_countries)\n        top_countries = min(top_countries, len(countries_count))\n        lines = [f\"*Top {top_countries} countr{pluralize(top_countries, 'y,ies')}*\"]\n        # Allowed overhead for 2 column sorting: downloads count, country.\n        countries_count = sorted(countries_count, key=lambda cc: cc[0])\n        countries_count = sorted(countries_count, key=lambda cc: cc[1], reverse=True)\n        for country, count in countries_count:\n            lines.append(f\"{country}: {count} download{pluralize(count)}\")\n\n        blocks.append(\n            {\n                \"type\": \"section\",\n                \"text\": {\"type\": \"mrkdwn\", \"text\": \"\\n\".join(lines)},\n            }\n        )\n\n    # Post to Slack.\n    requests.post(\n        settings.ENGAGEMENTBOT_WEBHOOK,\n        json={\n            \"username\": \"EngagementBot\",\n            \"icon_emoji\": \":halal:\",\n            \"channel\": f\"#{channel}\",\n            \"text\": fallback_text,\n            \"blocks\": blocks,\n        },\n        headers={\"Content-Type\": \"application/json\"},\n        timeout=10,\n    )\n", "path": "api/data_refinery_api/management/commands/post_downloads_summary.py"}]}