We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Email to admins when a user is reported has the wrong link


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bookwyrm/models/report.py`
Content:
```
1 """ flagged for moderation """
2 from django.db import models
3 from .base_model import BookWyrmModel
4 
5 
6 class Report(BookWyrmModel):
7     """reported status or user"""
8 
9     reporter = models.ForeignKey(
10         "User", related_name="reporter", on_delete=models.PROTECT
11     )
12     note = models.TextField(null=True, blank=True)
13     user = models.ForeignKey("User", on_delete=models.PROTECT)
14     statuses = models.ManyToManyField("Status", blank=True)
15     links = models.ManyToManyField("Link", blank=True)
16     resolved = models.BooleanField(default=False)
17 
18     class Meta:
19         """set order by default"""
20 
21         ordering = ("-created_date",)
22 
23 
24 class ReportComment(BookWyrmModel):
25     """updates on a report"""
26 
27     user = models.ForeignKey("User", on_delete=models.PROTECT)
28     note = models.TextField()
29     report = models.ForeignKey(Report, on_delete=models.PROTECT)
30 
31     class Meta:
32         """sort comments"""
33 
34         ordering = ("-created_date",)
35
```

Path: `bookwyrm/views/admin/reports.py`
Content:
```
1 """ moderation via flagged posts and users """
2 from django.contrib.auth.decorators import login_required, permission_required
3 from django.core.exceptions import PermissionDenied
4 from django.shortcuts import get_object_or_404, redirect
5 from django.template.response import TemplateResponse
6 from django.utils.decorators import method_decorator
7 from django.views import View
8 
9 from bookwyrm import forms, models
10 
11 
12 # pylint: disable=no-self-use
13 @method_decorator(login_required, name="dispatch")
14 @method_decorator(
15     permission_required("bookwyrm.moderate_user", raise_exception=True),
16     name="dispatch",
17 )
18 @method_decorator(
19     permission_required("bookwyrm.moderate_post", raise_exception=True),
20     name="dispatch",
21 )
22 class ReportsAdmin(View):
23     """list of reports"""
24 
25     def get(self, request):
26         """view current reports"""
27         filters = {}
28 
29         resolved = request.GET.get("resolved") == "true"
30         server = request.GET.get("server")
31         if server:
32             filters["user__federated_server__server_name"] = server
33         username = request.GET.get("username")
34         if username:
35             filters["user__username__icontains"] = username
36         filters["resolved"] = resolved
37         data = {
38             "resolved": resolved,
39             "server": server,
40             "reports": models.Report.objects.filter(**filters),
41         }
42         return TemplateResponse(request, "settings/reports/reports.html", data)
43 
44 
45 @method_decorator(login_required, name="dispatch")
46 @method_decorator(
47     permission_required("bookwyrm.moderate_user", raise_exception=True),
48     name="dispatch",
49 )
50 @method_decorator(
51     permission_required("bookwyrm.moderate_post", raise_exception=True),
52     name="dispatch",
53 )
54 class ReportAdmin(View):
55     """view a specific report"""
56 
57     def get(self, request, report_id):
58         """load a report"""
59         data = {
60             "report": get_object_or_404(models.Report, id=report_id),
61         }
62         return TemplateResponse(request, "settings/reports/report.html", data)
63 
64     def post(self, request, report_id):
65         """comment on a report"""
66         report = get_object_or_404(models.Report, id=report_id)
67         models.ReportComment.objects.create(
68             user=request.user,
69             report=report,
70             note=request.POST.get("note"),
71         )
72         return redirect("settings-report", report.id)
73 
74 
75 @login_required
76 @permission_required("bookwyrm_moderate_user")
77 def suspend_user(_, user_id):
78     """mark an account as inactive"""
79     user = get_object_or_404(models.User, id=user_id)
80     user.is_active = False
81     user.deactivation_reason = "moderator_suspension"
82     # this isn't a full deletion, so we don't want to tell the world
83     user.save(broadcast=False)
84     return redirect("settings-user", user.id)
85 
86 
87 @login_required
88 @permission_required("bookwyrm_moderate_user")
89 def unsuspend_user(_, user_id):
90     """mark an account as inactive"""
91     user = get_object_or_404(models.User, id=user_id)
92     user.is_active = True
93     user.deactivation_reason = None
94     # this isn't a full deletion, so we don't want to tell the world
95     user.save(broadcast=False)
96     return redirect("settings-user", user.id)
97 
98 
99 @login_required
100 @permission_required("bookwyrm_moderate_user")
101 def moderator_delete_user(request, user_id):
102     """permanently delete a user"""
103     user = get_object_or_404(models.User, id=user_id)
104 
105     # we can't delete users on other instances
106     if not user.local:
107         raise PermissionDenied()
108 
109     form = forms.DeleteUserForm(request.POST, instance=user)
110 
111     moderator = models.User.objects.get(id=request.user.id)
112     # check the moderator's password
113     if form.is_valid() and moderator.check_password(form.cleaned_data["password"]):
114         user.deactivation_reason = "moderator_deletion"
115         user.delete()
116         return redirect("settings-user", user.id)
117 
118     form.errors["password"] = ["Invalid password"]
119 
120     data = {"user": user, "group_form": forms.UserGroupForm(), "form": form}
121     return TemplateResponse(request, "user_admin/user.html", data)
122 
123 
124 @login_required
125 @permission_required("bookwyrm_moderate_post")
126 def resolve_report(_, report_id):
127     """mark a report as (un)resolved"""
128     report = get_object_or_404(models.Report, id=report_id)
129     report.resolved = not report.resolved
130     report.save()
131     if not report.resolved:
132         return redirect("settings-report", report.id)
133     return redirect("settings-reports")
134
```

Path: `bookwyrm/emailing.py`
Content:
```
1 """ send emails """
2 from django.core.mail import EmailMultiAlternatives
3 from django.template.loader import get_template
4 
5 from bookwyrm import models, settings
6 from bookwyrm.tasks import app
7 from bookwyrm.settings import DOMAIN
8 
9 
10 def email_data():
11     """fields every email needs"""
12     site = models.SiteSettings.objects.get()
13     return {
14         "site_name": site.name,
15         "logo": site.logo_small_url,
16         "domain": DOMAIN,
17         "user": None,
18     }
19 
20 
21 def email_confirmation_email(user):
22     """newly registered users confirm email address"""
23     data = email_data()
24     data["confirmation_code"] = user.confirmation_code
25     data["confirmation_link"] = user.confirmation_link
26     send_email.delay(user.email, *format_email("confirm", data))
27 
28 
29 def invite_email(invite_request):
30     """send out an invite code"""
31     data = email_data()
32     data["invite_link"] = invite_request.invite.link
33     send_email.delay(invite_request.email, *format_email("invite", data))
34 
35 
36 def password_reset_email(reset_code):
37     """generate a password reset email"""
38     data = email_data()
39     data["reset_link"] = reset_code.link
40     data["user"] = reset_code.user.display_name
41     send_email.delay(reset_code.user.email, *format_email("password_reset", data))
42 
43 
44 def moderation_report_email(report):
45     """a report was created"""
46     data = email_data()
47     data["reporter"] = report.reporter.localname or report.reporter.username
48     data["reportee"] = report.user.localname or report.user.username
49     data["report_link"] = report.remote_id
50 
51     for admin in models.User.objects.filter(groups__name__in=["admin", "moderator"]):
52         data["user"] = admin.display_name
53         send_email.delay(admin.email, *format_email("moderation_report", data))
54 
55 
56 def format_email(email_name, data):
57     """render the email templates"""
58     subject = get_template(f"email/{email_name}/subject.html").render(data).strip()
59     html_content = (
60         get_template(f"email/{email_name}/html_content.html").render(data).strip()
61     )
62     text_content = (
63         get_template(f"email/{email_name}/text_content.html").render(data).strip()
64     )
65     return (subject, html_content, text_content)
66 
67 
68 @app.task(queue="high_priority")
69 def send_email(recipient, subject, html_content, text_content):
70     """use a task to send the email"""
71     email = EmailMultiAlternatives(
72         subject, text_content, settings.EMAIL_SENDER, [recipient]
73     )
74     email.attach_alternative(html_content, "text/html")
75     email.send()
76
```
--- 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/bookwyrm/emailing.py b/bookwyrm/emailing.py
--- a/bookwyrm/emailing.py
+++ b/bookwyrm/emailing.py
@@ -48,7 +48,9 @@
     data["reportee"] = report.user.localname or report.user.username
     data["report_link"] = report.remote_id
 
-    for admin in models.User.objects.filter(groups__name__in=["admin", "moderator"]):
+    for admin in models.User.objects.filter(
+        groups__name__in=["admin", "moderator"]
+    ).distinct():
         data["user"] = admin.display_name
         send_email.delay(admin.email, *format_email("moderation_report", data))
 
diff --git a/bookwyrm/models/report.py b/bookwyrm/models/report.py
--- a/bookwyrm/models/report.py
+++ b/bookwyrm/models/report.py
@@ -1,5 +1,6 @@
 """ flagged for moderation """
 from django.db import models
+from bookwyrm.settings import DOMAIN
 from .base_model import BookWyrmModel
 
 
@@ -15,6 +16,9 @@
     links = models.ManyToManyField("Link", blank=True)
     resolved = models.BooleanField(default=False)
 
+    def get_remote_id(self):
+        return f"https://{DOMAIN}/settings/reports/{self.id}"
+
     class Meta:
         """set order by default"""
 
diff --git a/bookwyrm/views/admin/reports.py b/bookwyrm/views/admin/reports.py
--- a/bookwyrm/views/admin/reports.py
+++ b/bookwyrm/views/admin/reports.py
@@ -58,6 +58,7 @@
         """load a report"""
         data = {
             "report": get_object_or_404(models.Report, id=report_id),
+            "group_form": forms.UserGroupForm(),
         }
         return TemplateResponse(request, "settings/reports/report.html", data)

{"golden_diff": "diff --git a/bookwyrm/emailing.py b/bookwyrm/emailing.py\n--- a/bookwyrm/emailing.py\n+++ b/bookwyrm/emailing.py\n@@ -48,7 +48,9 @@\n     data[\"reportee\"] = report.user.localname or report.user.username\n     data[\"report_link\"] = report.remote_id\n \n-    for admin in models.User.objects.filter(groups__name__in=[\"admin\", \"moderator\"]):\n+    for admin in models.User.objects.filter(\n+        groups__name__in=[\"admin\", \"moderator\"]\n+    ).distinct():\n         data[\"user\"] = admin.display_name\n         send_email.delay(admin.email, *format_email(\"moderation_report\", data))\n \ndiff --git a/bookwyrm/models/report.py b/bookwyrm/models/report.py\n--- a/bookwyrm/models/report.py\n+++ b/bookwyrm/models/report.py\n@@ -1,5 +1,6 @@\n \"\"\" flagged for moderation \"\"\"\n from django.db import models\n+from bookwyrm.settings import DOMAIN\n from .base_model import BookWyrmModel\n \n \n@@ -15,6 +16,9 @@\n     links = models.ManyToManyField(\"Link\", blank=True)\n     resolved = models.BooleanField(default=False)\n \n+    def get_remote_id(self):\n+        return f\"https://{DOMAIN}/settings/reports/{self.id}\"\n+\n     class Meta:\n         \"\"\"set order by default\"\"\"\n \ndiff --git a/bookwyrm/views/admin/reports.py b/bookwyrm/views/admin/reports.py\n--- a/bookwyrm/views/admin/reports.py\n+++ b/bookwyrm/views/admin/reports.py\n@@ -58,6 +58,7 @@\n         \"\"\"load a report\"\"\"\n         data = {\n             \"report\": get_object_or_404(models.Report, id=report_id),\n+            \"group_form\": forms.UserGroupForm(),\n         }\n         return TemplateResponse(request, \"settings/reports/report.html\", data)\n", "issue": "Email to admins when a user is reported has the wrong link\n\n", "before_files": [{"content": "\"\"\" flagged for moderation \"\"\"\nfrom django.db import models\nfrom .base_model import BookWyrmModel\n\n\nclass Report(BookWyrmModel):\n    \"\"\"reported status or user\"\"\"\n\n    reporter = models.ForeignKey(\n        \"User\", related_name=\"reporter\", on_delete=models.PROTECT\n    )\n    note = models.TextField(null=True, blank=True)\n    user = models.ForeignKey(\"User\", on_delete=models.PROTECT)\n    statuses = models.ManyToManyField(\"Status\", blank=True)\n    links = models.ManyToManyField(\"Link\", blank=True)\n    resolved = models.BooleanField(default=False)\n\n    class Meta:\n        \"\"\"set order by default\"\"\"\n\n        ordering = (\"-created_date\",)\n\n\nclass ReportComment(BookWyrmModel):\n    \"\"\"updates on a report\"\"\"\n\n    user = models.ForeignKey(\"User\", on_delete=models.PROTECT)\n    note = models.TextField()\n    report = models.ForeignKey(Report, on_delete=models.PROTECT)\n\n    class Meta:\n        \"\"\"sort comments\"\"\"\n\n        ordering = (\"-created_date\",)\n", "path": "bookwyrm/models/report.py"}, {"content": "\"\"\" moderation via flagged posts and users \"\"\"\nfrom django.contrib.auth.decorators import login_required, permission_required\nfrom django.core.exceptions import PermissionDenied\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.template.response import TemplateResponse\nfrom django.utils.decorators import method_decorator\nfrom django.views import View\n\nfrom bookwyrm import forms, models\n\n\n# pylint: disable=no-self-use\n@method_decorator(login_required, name=\"dispatch\")\n@method_decorator(\n    permission_required(\"bookwyrm.moderate_user\", raise_exception=True),\n    name=\"dispatch\",\n)\n@method_decorator(\n    permission_required(\"bookwyrm.moderate_post\", raise_exception=True),\n    name=\"dispatch\",\n)\nclass ReportsAdmin(View):\n    \"\"\"list of reports\"\"\"\n\n    def get(self, request):\n        \"\"\"view current reports\"\"\"\n        filters = {}\n\n        resolved = request.GET.get(\"resolved\") == \"true\"\n        server = request.GET.get(\"server\")\n        if server:\n            filters[\"user__federated_server__server_name\"] = server\n        username = request.GET.get(\"username\")\n        if username:\n            filters[\"user__username__icontains\"] = username\n        filters[\"resolved\"] = resolved\n        data = {\n            \"resolved\": resolved,\n            \"server\": server,\n            \"reports\": models.Report.objects.filter(**filters),\n        }\n        return TemplateResponse(request, \"settings/reports/reports.html\", data)\n\n\n@method_decorator(login_required, name=\"dispatch\")\n@method_decorator(\n    permission_required(\"bookwyrm.moderate_user\", raise_exception=True),\n    name=\"dispatch\",\n)\n@method_decorator(\n    permission_required(\"bookwyrm.moderate_post\", raise_exception=True),\n    name=\"dispatch\",\n)\nclass ReportAdmin(View):\n    \"\"\"view a specific report\"\"\"\n\n    def get(self, request, report_id):\n        \"\"\"load a report\"\"\"\n        data = {\n            \"report\": get_object_or_404(models.Report, id=report_id),\n        }\n        return TemplateResponse(request, \"settings/reports/report.html\", data)\n\n    def post(self, request, report_id):\n        \"\"\"comment on a report\"\"\"\n        report = get_object_or_404(models.Report, id=report_id)\n        models.ReportComment.objects.create(\n            user=request.user,\n            report=report,\n            note=request.POST.get(\"note\"),\n        )\n        return redirect(\"settings-report\", report.id)\n\n\n@login_required\n@permission_required(\"bookwyrm_moderate_user\")\ndef suspend_user(_, user_id):\n    \"\"\"mark an account as inactive\"\"\"\n    user = get_object_or_404(models.User, id=user_id)\n    user.is_active = False\n    user.deactivation_reason = \"moderator_suspension\"\n    # this isn't a full deletion, so we don't want to tell the world\n    user.save(broadcast=False)\n    return redirect(\"settings-user\", user.id)\n\n\n@login_required\n@permission_required(\"bookwyrm_moderate_user\")\ndef unsuspend_user(_, user_id):\n    \"\"\"mark an account as inactive\"\"\"\n    user = get_object_or_404(models.User, id=user_id)\n    user.is_active = True\n    user.deactivation_reason = None\n    # this isn't a full deletion, so we don't want to tell the world\n    user.save(broadcast=False)\n    return redirect(\"settings-user\", user.id)\n\n\n@login_required\n@permission_required(\"bookwyrm_moderate_user\")\ndef moderator_delete_user(request, user_id):\n    \"\"\"permanently delete a user\"\"\"\n    user = get_object_or_404(models.User, id=user_id)\n\n    # we can't delete users on other instances\n    if not user.local:\n        raise PermissionDenied()\n\n    form = forms.DeleteUserForm(request.POST, instance=user)\n\n    moderator = models.User.objects.get(id=request.user.id)\n    # check the moderator's password\n    if form.is_valid() and moderator.check_password(form.cleaned_data[\"password\"]):\n        user.deactivation_reason = \"moderator_deletion\"\n        user.delete()\n        return redirect(\"settings-user\", user.id)\n\n    form.errors[\"password\"] = [\"Invalid password\"]\n\n    data = {\"user\": user, \"group_form\": forms.UserGroupForm(), \"form\": form}\n    return TemplateResponse(request, \"user_admin/user.html\", data)\n\n\n@login_required\n@permission_required(\"bookwyrm_moderate_post\")\ndef resolve_report(_, report_id):\n    \"\"\"mark a report as (un)resolved\"\"\"\n    report = get_object_or_404(models.Report, id=report_id)\n    report.resolved = not report.resolved\n    report.save()\n    if not report.resolved:\n        return redirect(\"settings-report\", report.id)\n    return redirect(\"settings-reports\")\n", "path": "bookwyrm/views/admin/reports.py"}, {"content": "\"\"\" send emails \"\"\"\nfrom django.core.mail import EmailMultiAlternatives\nfrom django.template.loader import get_template\n\nfrom bookwyrm import models, settings\nfrom bookwyrm.tasks import app\nfrom bookwyrm.settings import DOMAIN\n\n\ndef email_data():\n    \"\"\"fields every email needs\"\"\"\n    site = models.SiteSettings.objects.get()\n    return {\n        \"site_name\": site.name,\n        \"logo\": site.logo_small_url,\n        \"domain\": DOMAIN,\n        \"user\": None,\n    }\n\n\ndef email_confirmation_email(user):\n    \"\"\"newly registered users confirm email address\"\"\"\n    data = email_data()\n    data[\"confirmation_code\"] = user.confirmation_code\n    data[\"confirmation_link\"] = user.confirmation_link\n    send_email.delay(user.email, *format_email(\"confirm\", data))\n\n\ndef invite_email(invite_request):\n    \"\"\"send out an invite code\"\"\"\n    data = email_data()\n    data[\"invite_link\"] = invite_request.invite.link\n    send_email.delay(invite_request.email, *format_email(\"invite\", data))\n\n\ndef password_reset_email(reset_code):\n    \"\"\"generate a password reset email\"\"\"\n    data = email_data()\n    data[\"reset_link\"] = reset_code.link\n    data[\"user\"] = reset_code.user.display_name\n    send_email.delay(reset_code.user.email, *format_email(\"password_reset\", data))\n\n\ndef moderation_report_email(report):\n    \"\"\"a report was created\"\"\"\n    data = email_data()\n    data[\"reporter\"] = report.reporter.localname or report.reporter.username\n    data[\"reportee\"] = report.user.localname or report.user.username\n    data[\"report_link\"] = report.remote_id\n\n    for admin in models.User.objects.filter(groups__name__in=[\"admin\", \"moderator\"]):\n        data[\"user\"] = admin.display_name\n        send_email.delay(admin.email, *format_email(\"moderation_report\", data))\n\n\ndef format_email(email_name, data):\n    \"\"\"render the email templates\"\"\"\n    subject = get_template(f\"email/{email_name}/subject.html\").render(data).strip()\n    html_content = (\n        get_template(f\"email/{email_name}/html_content.html\").render(data).strip()\n    )\n    text_content = (\n        get_template(f\"email/{email_name}/text_content.html\").render(data).strip()\n    )\n    return (subject, html_content, text_content)\n\n\n@app.task(queue=\"high_priority\")\ndef send_email(recipient, subject, html_content, text_content):\n    \"\"\"use a task to send the email\"\"\"\n    email = EmailMultiAlternatives(\n        subject, text_content, settings.EMAIL_SENDER, [recipient]\n    )\n    email.attach_alternative(html_content, \"text/html\")\n    email.send()\n", "path": "bookwyrm/emailing.py"}], "after_files": [{"content": "\"\"\" flagged for moderation \"\"\"\nfrom django.db import models\nfrom bookwyrm.settings import DOMAIN\nfrom .base_model import BookWyrmModel\n\n\nclass Report(BookWyrmModel):\n    \"\"\"reported status or user\"\"\"\n\n    reporter = models.ForeignKey(\n        \"User\", related_name=\"reporter\", on_delete=models.PROTECT\n    )\n    note = models.TextField(null=True, blank=True)\n    user = models.ForeignKey(\"User\", on_delete=models.PROTECT)\n    statuses = models.ManyToManyField(\"Status\", blank=True)\n    links = models.ManyToManyField(\"Link\", blank=True)\n    resolved = models.BooleanField(default=False)\n\n    def get_remote_id(self):\n        return f\"https://{DOMAIN}/settings/reports/{self.id}\"\n\n    class Meta:\n        \"\"\"set order by default\"\"\"\n\n        ordering = (\"-created_date\",)\n\n\nclass ReportComment(BookWyrmModel):\n    \"\"\"updates on a report\"\"\"\n\n    user = models.ForeignKey(\"User\", on_delete=models.PROTECT)\n    note = models.TextField()\n    report = models.ForeignKey(Report, on_delete=models.PROTECT)\n\n    class Meta:\n        \"\"\"sort comments\"\"\"\n\n        ordering = (\"-created_date\",)\n", "path": "bookwyrm/models/report.py"}, {"content": "\"\"\" moderation via flagged posts and users \"\"\"\nfrom django.contrib.auth.decorators import login_required, permission_required\nfrom django.core.exceptions import PermissionDenied\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.template.response import TemplateResponse\nfrom django.utils.decorators import method_decorator\nfrom django.views import View\n\nfrom bookwyrm import forms, models\n\n\n# pylint: disable=no-self-use\n@method_decorator(login_required, name=\"dispatch\")\n@method_decorator(\n    permission_required(\"bookwyrm.moderate_user\", raise_exception=True),\n    name=\"dispatch\",\n)\n@method_decorator(\n    permission_required(\"bookwyrm.moderate_post\", raise_exception=True),\n    name=\"dispatch\",\n)\nclass ReportsAdmin(View):\n    \"\"\"list of reports\"\"\"\n\n    def get(self, request):\n        \"\"\"view current reports\"\"\"\n        filters = {}\n\n        resolved = request.GET.get(\"resolved\") == \"true\"\n        server = request.GET.get(\"server\")\n        if server:\n            filters[\"user__federated_server__server_name\"] = server\n        username = request.GET.get(\"username\")\n        if username:\n            filters[\"user__username__icontains\"] = username\n        filters[\"resolved\"] = resolved\n        data = {\n            \"resolved\": resolved,\n            \"server\": server,\n            \"reports\": models.Report.objects.filter(**filters),\n        }\n        return TemplateResponse(request, \"settings/reports/reports.html\", data)\n\n\n@method_decorator(login_required, name=\"dispatch\")\n@method_decorator(\n    permission_required(\"bookwyrm.moderate_user\", raise_exception=True),\n    name=\"dispatch\",\n)\n@method_decorator(\n    permission_required(\"bookwyrm.moderate_post\", raise_exception=True),\n    name=\"dispatch\",\n)\nclass ReportAdmin(View):\n    \"\"\"view a specific report\"\"\"\n\n    def get(self, request, report_id):\n        \"\"\"load a report\"\"\"\n        data = {\n            \"report\": get_object_or_404(models.Report, id=report_id),\n            \"group_form\": forms.UserGroupForm(),\n        }\n        return TemplateResponse(request, \"settings/reports/report.html\", data)\n\n    def post(self, request, report_id):\n        \"\"\"comment on a report\"\"\"\n        report = get_object_or_404(models.Report, id=report_id)\n        models.ReportComment.objects.create(\n            user=request.user,\n            report=report,\n            note=request.POST.get(\"note\"),\n        )\n        return redirect(\"settings-report\", report.id)\n\n\n@login_required\n@permission_required(\"bookwyrm_moderate_user\")\ndef suspend_user(_, user_id):\n    \"\"\"mark an account as inactive\"\"\"\n    user = get_object_or_404(models.User, id=user_id)\n    user.is_active = False\n    user.deactivation_reason = \"moderator_suspension\"\n    # this isn't a full deletion, so we don't want to tell the world\n    user.save(broadcast=False)\n    return redirect(\"settings-user\", user.id)\n\n\n@login_required\n@permission_required(\"bookwyrm_moderate_user\")\ndef unsuspend_user(_, user_id):\n    \"\"\"mark an account as inactive\"\"\"\n    user = get_object_or_404(models.User, id=user_id)\n    user.is_active = True\n    user.deactivation_reason = None\n    # this isn't a full deletion, so we don't want to tell the world\n    user.save(broadcast=False)\n    return redirect(\"settings-user\", user.id)\n\n\n@login_required\n@permission_required(\"bookwyrm_moderate_user\")\ndef moderator_delete_user(request, user_id):\n    \"\"\"permanently delete a user\"\"\"\n    user = get_object_or_404(models.User, id=user_id)\n\n    # we can't delete users on other instances\n    if not user.local:\n        raise PermissionDenied()\n\n    form = forms.DeleteUserForm(request.POST, instance=user)\n\n    moderator = models.User.objects.get(id=request.user.id)\n    # check the moderator's password\n    if form.is_valid() and moderator.check_password(form.cleaned_data[\"password\"]):\n        user.deactivation_reason = \"moderator_deletion\"\n        user.delete()\n        return redirect(\"settings-user\", user.id)\n\n    form.errors[\"password\"] = [\"Invalid password\"]\n\n    data = {\"user\": user, \"group_form\": forms.UserGroupForm(), \"form\": form}\n    return TemplateResponse(request, \"user_admin/user.html\", data)\n\n\n@login_required\n@permission_required(\"bookwyrm_moderate_post\")\ndef resolve_report(_, report_id):\n    \"\"\"mark a report as (un)resolved\"\"\"\n    report = get_object_or_404(models.Report, id=report_id)\n    report.resolved = not report.resolved\n    report.save()\n    if not report.resolved:\n        return redirect(\"settings-report\", report.id)\n    return redirect(\"settings-reports\")\n", "path": "bookwyrm/views/admin/reports.py"}, {"content": "\"\"\" send emails \"\"\"\nfrom django.core.mail import EmailMultiAlternatives\nfrom django.template.loader import get_template\n\nfrom bookwyrm import models, settings\nfrom bookwyrm.tasks import app\nfrom bookwyrm.settings import DOMAIN\n\n\ndef email_data():\n    \"\"\"fields every email needs\"\"\"\n    site = models.SiteSettings.objects.get()\n    return {\n        \"site_name\": site.name,\n        \"logo\": site.logo_small_url,\n        \"domain\": DOMAIN,\n        \"user\": None,\n    }\n\n\ndef email_confirmation_email(user):\n    \"\"\"newly registered users confirm email address\"\"\"\n    data = email_data()\n    data[\"confirmation_code\"] = user.confirmation_code\n    data[\"confirmation_link\"] = user.confirmation_link\n    send_email.delay(user.email, *format_email(\"confirm\", data))\n\n\ndef invite_email(invite_request):\n    \"\"\"send out an invite code\"\"\"\n    data = email_data()\n    data[\"invite_link\"] = invite_request.invite.link\n    send_email.delay(invite_request.email, *format_email(\"invite\", data))\n\n\ndef password_reset_email(reset_code):\n    \"\"\"generate a password reset email\"\"\"\n    data = email_data()\n    data[\"reset_link\"] = reset_code.link\n    data[\"user\"] = reset_code.user.display_name\n    send_email.delay(reset_code.user.email, *format_email(\"password_reset\", data))\n\n\ndef moderation_report_email(report):\n    \"\"\"a report was created\"\"\"\n    data = email_data()\n    data[\"reporter\"] = report.reporter.localname or report.reporter.username\n    data[\"reportee\"] = report.user.localname or report.user.username\n    data[\"report_link\"] = report.remote_id\n\n    for admin in models.User.objects.filter(\n        groups__name__in=[\"admin\", \"moderator\"]\n    ).distinct():\n        data[\"user\"] = admin.display_name\n        send_email.delay(admin.email, *format_email(\"moderation_report\", data))\n\n\ndef format_email(email_name, data):\n    \"\"\"render the email templates\"\"\"\n    subject = get_template(f\"email/{email_name}/subject.html\").render(data).strip()\n    html_content = (\n        get_template(f\"email/{email_name}/html_content.html\").render(data).strip()\n    )\n    text_content = (\n        get_template(f\"email/{email_name}/text_content.html\").render(data).strip()\n    )\n    return (subject, html_content, text_content)\n\n\n@app.task(queue=\"high_priority\")\ndef send_email(recipient, subject, html_content, text_content):\n    \"\"\"use a task to send the email\"\"\"\n    email = EmailMultiAlternatives(\n        subject, text_content, settings.EMAIL_SENDER, [recipient]\n    )\n    email.attach_alternative(html_content, \"text/html\")\n    email.send()\n", "path": "bookwyrm/emailing.py"}]}