We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[notifications] Notify project Translators when suggestions are submitted
*This issue was created automatically by a [script](https://github.com/mathjazz/bugzilla2github/).*
## [Bug 1398861](https://bugzilla.mozilla.org/show_bug.cgi?id=1398861)
Bug Reporter: @mathjazz
CC:   @MikkCZ, mvasicek@mozilla.cz
See also:     https://bugzilla.mozilla.org/show_bug.cgi?id=1625102

We should probably do that periodically and aggregate notifications.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pontoon/projects/management/commands/send_suggestion_notifications.py`
Content:
```
1 import calendar
2 
3 from collections import defaultdict
4 from datetime import timedelta
5 from functools import cached_property
6 
7 from django.conf import settings
8 from django.contrib.auth.models import User
9 from django.core.management.base import BaseCommand, CommandError
10 from django.db.models import Prefetch, Q
11 from django.template.loader import render_to_string
12 from django.utils import timezone
13 from notifications.signals import notify
14 
15 from pontoon.base.models import Comment, Locale, ProjectLocale, Translation
16 
17 
18 class Command(BaseCommand):
19     help = "Notify contributors about newly added unreviewed suggestions"
20 
21     def add_arguments(self, parser):
22         parser.add_argument(
23             "--force",
24             action="store_true",
25             dest="force",
26             default=False,
27             help="Force run command, regardless of what day of the week it is",
28         )
29 
30     @cached_property
31     def locale_reviewers(self):
32         locales = Locale.objects.prefetch_related(
33             Prefetch("managers_group__user_set", to_attr="fetched_managers"),
34             Prefetch("translators_group__user_set", to_attr="fetched_translators"),
35         )
36 
37         locale_reviewers = {}
38 
39         for locale in locales:
40             managers = locale.managers_group.fetched_managers
41             translators = locale.translators_group.fetched_translators
42             locale_reviewers[locale] = managers + translators
43 
44         return locale_reviewers
45 
46     def extract_notifications_data(self, data, suggestion):
47         locale = suggestion.locale
48         entity = suggestion.entity
49         project = entity.resource.project
50         project_locale = ProjectLocale.objects.get(project=project, locale=locale)
51 
52         translations = Translation.objects.filter(entity=entity, locale=locale)
53         recipients = set()
54 
55         # Users with permission to review suggestions
56         recipients = recipients.union(self.locale_reviewers[locale])
57 
58         # Authors of previous translations of the same string
59         recipients = recipients.union(User.objects.filter(translation__in=translations))
60 
61         # Authors of comments of previous translations
62         translations_comments = Comment.objects.filter(translation__in=translations)
63         recipients = recipients.union(
64             User.objects.filter(comment__in=translations_comments)
65         )
66 
67         # Authors of team comments of the same string
68         team_comments = Comment.objects.filter(entity=entity, locale=locale)
69         recipients = recipients.union(User.objects.filter(comment__in=team_comments))
70 
71         for recipient in recipients:
72             data[recipient].add(project_locale)
73 
74     def get_suggestions(self):
75         start = timezone.now() - timedelta(days=7)
76 
77         return Translation.objects.filter(
78             approved=False, rejected=False, fuzzy=False
79         ).filter(
80             Q(date__gt=start)
81             | Q(unapproved_date__gt=start)
82             | Q(unrejected_date__gt=start)
83         )
84 
85     def handle(self, *args, **options):
86         """
87         This command sends notifications about newly created unreviewed suggestions that
88         were submitted, unapproved or unrejected in the last 7 days. Recipients of
89         notifications are users with permission to review them, as well as authors of
90         previous translations or comments of the same string.
91 
92         The command is designed to run on a weekly basis.
93         """
94         self.stdout.write("Sending suggestion notifications.")
95 
96         today = calendar.day_name[timezone.datetime.today().weekday()]
97         day = calendar.day_name[settings.SUGGESTION_NOTIFICATIONS_DAY]
98 
99         if today != day and not options["force"]:
100             raise CommandError(f"Skipping. Command runs every {day}. Today is {today}.")
101 
102         suggestions = self.get_suggestions()
103 
104         data = defaultdict(set)
105 
106         for suggestion in suggestions:
107             self.extract_notifications_data(data, suggestion)
108 
109         for recipient, project_locales in data.items():
110             verb = render_to_string(
111                 "projects/suggestion_notification.jinja",
112                 {"project_locales": project_locales},
113             )
114 
115             notify.send(recipient, recipient=recipient, verb=verb)
116 
117         self.stdout.write("Suggestion notifications sent.")
118
```
--- 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/pontoon/projects/management/commands/send_suggestion_notifications.py b/pontoon/projects/management/commands/send_suggestion_notifications.py
--- a/pontoon/projects/management/commands/send_suggestion_notifications.py
+++ b/pontoon/projects/management/commands/send_suggestion_notifications.py
@@ -107,11 +107,13 @@
             self.extract_notifications_data(data, suggestion)
 
         for recipient, project_locales in data.items():
-            verb = render_to_string(
+            description = render_to_string(
                 "projects/suggestion_notification.jinja",
                 {"project_locales": project_locales},
             )
 
-            notify.send(recipient, recipient=recipient, verb=verb)
+            notify.send(
+                recipient, recipient=recipient, verb="", description=description
+            )
 
-        self.stdout.write("Suggestion notifications sent.")
+        self.stdout.write(f"Suggestion notifications sent to {len(data)} users.")

{"golden_diff": "diff --git a/pontoon/projects/management/commands/send_suggestion_notifications.py b/pontoon/projects/management/commands/send_suggestion_notifications.py\n--- a/pontoon/projects/management/commands/send_suggestion_notifications.py\n+++ b/pontoon/projects/management/commands/send_suggestion_notifications.py\n@@ -107,11 +107,13 @@\n             self.extract_notifications_data(data, suggestion)\n \n         for recipient, project_locales in data.items():\n-            verb = render_to_string(\n+            description = render_to_string(\n                 \"projects/suggestion_notification.jinja\",\n                 {\"project_locales\": project_locales},\n             )\n \n-            notify.send(recipient, recipient=recipient, verb=verb)\n+            notify.send(\n+                recipient, recipient=recipient, verb=\"\", description=description\n+            )\n \n-        self.stdout.write(\"Suggestion notifications sent.\")\n+        self.stdout.write(f\"Suggestion notifications sent to {len(data)} users.\")\n", "issue": "[notifications] Notify project Translators when suggestions are submitted\n*This issue was created automatically by a [script](https://github.com/mathjazz/bugzilla2github/).*\n## [Bug 1398861](https://bugzilla.mozilla.org/show_bug.cgi?id=1398861)\nBug Reporter: @mathjazz\nCC:   @MikkCZ, mvasicek@mozilla.cz\nSee also:     https://bugzilla.mozilla.org/show_bug.cgi?id=1625102\n\nWe should probably do that periodically and aggregate notifications.\n", "before_files": [{"content": "import calendar\n\nfrom collections import defaultdict\nfrom datetime import timedelta\nfrom functools import cached_property\n\nfrom django.conf import settings\nfrom django.contrib.auth.models import User\nfrom django.core.management.base import BaseCommand, CommandError\nfrom django.db.models import Prefetch, Q\nfrom django.template.loader import render_to_string\nfrom django.utils import timezone\nfrom notifications.signals import notify\n\nfrom pontoon.base.models import Comment, Locale, ProjectLocale, Translation\n\n\nclass Command(BaseCommand):\n    help = \"Notify contributors about newly added unreviewed suggestions\"\n\n    def add_arguments(self, parser):\n        parser.add_argument(\n            \"--force\",\n            action=\"store_true\",\n            dest=\"force\",\n            default=False,\n            help=\"Force run command, regardless of what day of the week it is\",\n        )\n\n    @cached_property\n    def locale_reviewers(self):\n        locales = Locale.objects.prefetch_related(\n            Prefetch(\"managers_group__user_set\", to_attr=\"fetched_managers\"),\n            Prefetch(\"translators_group__user_set\", to_attr=\"fetched_translators\"),\n        )\n\n        locale_reviewers = {}\n\n        for locale in locales:\n            managers = locale.managers_group.fetched_managers\n            translators = locale.translators_group.fetched_translators\n            locale_reviewers[locale] = managers + translators\n\n        return locale_reviewers\n\n    def extract_notifications_data(self, data, suggestion):\n        locale = suggestion.locale\n        entity = suggestion.entity\n        project = entity.resource.project\n        project_locale = ProjectLocale.objects.get(project=project, locale=locale)\n\n        translations = Translation.objects.filter(entity=entity, locale=locale)\n        recipients = set()\n\n        # Users with permission to review suggestions\n        recipients = recipients.union(self.locale_reviewers[locale])\n\n        # Authors of previous translations of the same string\n        recipients = recipients.union(User.objects.filter(translation__in=translations))\n\n        # Authors of comments of previous translations\n        translations_comments = Comment.objects.filter(translation__in=translations)\n        recipients = recipients.union(\n            User.objects.filter(comment__in=translations_comments)\n        )\n\n        # Authors of team comments of the same string\n        team_comments = Comment.objects.filter(entity=entity, locale=locale)\n        recipients = recipients.union(User.objects.filter(comment__in=team_comments))\n\n        for recipient in recipients:\n            data[recipient].add(project_locale)\n\n    def get_suggestions(self):\n        start = timezone.now() - timedelta(days=7)\n\n        return Translation.objects.filter(\n            approved=False, rejected=False, fuzzy=False\n        ).filter(\n            Q(date__gt=start)\n            | Q(unapproved_date__gt=start)\n            | Q(unrejected_date__gt=start)\n        )\n\n    def handle(self, *args, **options):\n        \"\"\"\n        This command sends notifications about newly created unreviewed suggestions that\n        were submitted, unapproved or unrejected in the last 7 days. Recipients of\n        notifications are users with permission to review them, as well as authors of\n        previous translations or comments of the same string.\n\n        The command is designed to run on a weekly basis.\n        \"\"\"\n        self.stdout.write(\"Sending suggestion notifications.\")\n\n        today = calendar.day_name[timezone.datetime.today().weekday()]\n        day = calendar.day_name[settings.SUGGESTION_NOTIFICATIONS_DAY]\n\n        if today != day and not options[\"force\"]:\n            raise CommandError(f\"Skipping. Command runs every {day}. Today is {today}.\")\n\n        suggestions = self.get_suggestions()\n\n        data = defaultdict(set)\n\n        for suggestion in suggestions:\n            self.extract_notifications_data(data, suggestion)\n\n        for recipient, project_locales in data.items():\n            verb = render_to_string(\n                \"projects/suggestion_notification.jinja\",\n                {\"project_locales\": project_locales},\n            )\n\n            notify.send(recipient, recipient=recipient, verb=verb)\n\n        self.stdout.write(\"Suggestion notifications sent.\")\n", "path": "pontoon/projects/management/commands/send_suggestion_notifications.py"}], "after_files": [{"content": "import calendar\n\nfrom collections import defaultdict\nfrom datetime import timedelta\nfrom functools import cached_property\n\nfrom django.conf import settings\nfrom django.contrib.auth.models import User\nfrom django.core.management.base import BaseCommand, CommandError\nfrom django.db.models import Prefetch, Q\nfrom django.template.loader import render_to_string\nfrom django.utils import timezone\nfrom notifications.signals import notify\n\nfrom pontoon.base.models import Comment, Locale, ProjectLocale, Translation\n\n\nclass Command(BaseCommand):\n    help = \"Notify contributors about newly added unreviewed suggestions\"\n\n    def add_arguments(self, parser):\n        parser.add_argument(\n            \"--force\",\n            action=\"store_true\",\n            dest=\"force\",\n            default=False,\n            help=\"Force run command, regardless of what day of the week it is\",\n        )\n\n    @cached_property\n    def locale_reviewers(self):\n        locales = Locale.objects.prefetch_related(\n            Prefetch(\"managers_group__user_set\", to_attr=\"fetched_managers\"),\n            Prefetch(\"translators_group__user_set\", to_attr=\"fetched_translators\"),\n        )\n\n        locale_reviewers = {}\n\n        for locale in locales:\n            managers = locale.managers_group.fetched_managers\n            translators = locale.translators_group.fetched_translators\n            locale_reviewers[locale] = managers + translators\n\n        return locale_reviewers\n\n    def extract_notifications_data(self, data, suggestion):\n        locale = suggestion.locale\n        entity = suggestion.entity\n        project = entity.resource.project\n        project_locale = ProjectLocale.objects.get(project=project, locale=locale)\n\n        translations = Translation.objects.filter(entity=entity, locale=locale)\n        recipients = set()\n\n        # Users with permission to review suggestions\n        recipients = recipients.union(self.locale_reviewers[locale])\n\n        # Authors of previous translations of the same string\n        recipients = recipients.union(User.objects.filter(translation__in=translations))\n\n        # Authors of comments of previous translations\n        translations_comments = Comment.objects.filter(translation__in=translations)\n        recipients = recipients.union(\n            User.objects.filter(comment__in=translations_comments)\n        )\n\n        # Authors of team comments of the same string\n        team_comments = Comment.objects.filter(entity=entity, locale=locale)\n        recipients = recipients.union(User.objects.filter(comment__in=team_comments))\n\n        for recipient in recipients:\n            data[recipient].add(project_locale)\n\n    def get_suggestions(self):\n        start = timezone.now() - timedelta(days=7)\n\n        return Translation.objects.filter(\n            approved=False, rejected=False, fuzzy=False\n        ).filter(\n            Q(date__gt=start)\n            | Q(unapproved_date__gt=start)\n            | Q(unrejected_date__gt=start)\n        )\n\n    def handle(self, *args, **options):\n        \"\"\"\n        This command sends notifications about newly created unreviewed suggestions that\n        were submitted, unapproved or unrejected in the last 7 days. Recipients of\n        notifications are users with permission to review them, as well as authors of\n        previous translations or comments of the same string.\n\n        The command is designed to run on a weekly basis.\n        \"\"\"\n        self.stdout.write(\"Sending suggestion notifications.\")\n\n        today = calendar.day_name[timezone.datetime.today().weekday()]\n        day = calendar.day_name[settings.SUGGESTION_NOTIFICATIONS_DAY]\n\n        if today != day and not options[\"force\"]:\n            raise CommandError(f\"Skipping. Command runs every {day}. Today is {today}.\")\n\n        suggestions = self.get_suggestions()\n\n        data = defaultdict(set)\n\n        for suggestion in suggestions:\n            self.extract_notifications_data(data, suggestion)\n\n        for recipient, project_locales in data.items():\n            description = render_to_string(\n                \"projects/suggestion_notification.jinja\",\n                {\"project_locales\": project_locales},\n            )\n\n            notify.send(\n                recipient, recipient=recipient, verb=\"\", description=description\n            )\n\n        self.stdout.write(f\"Suggestion notifications sent to {len(data)} users.\")\n", "path": "pontoon/projects/management/commands/send_suggestion_notifications.py"}]}