prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Broken link on weekly mails
  The link used to unsubscribe from the mail is broken, because `frontend_url` is undefined. Probably due to the weekly mails being handled differently than all other 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: `lego/apps/email/tasks.py`
  Content:
  ```
  1 from datetime import timedelta
  2 
  3 from django.conf import settings
  4 from django.template.loader import render_to_string
  5 from django.utils import timezone
  6 
  7 from premailer import transform
  8 from structlog import get_logger
  9 
  10 from lego import celery_app
  11 from lego.apps.events.constants import EVENT_TYPE_TRANSLATIONS
  12 from lego.apps.events.models import Event
  13 from lego.apps.joblistings.constants import JOB_TYPE_TRANSLATIONS
  14 from lego.apps.joblistings.models import Joblisting
  15 from lego.apps.notifications.constants import EMAIL, WEEKLY_MAIL
  16 from lego.apps.notifications.models import NotificationSetting
  17 from lego.apps.permissions.utils import get_permission_handler
  18 from lego.apps.restricted.message_processor import MessageProcessor
  19 from lego.apps.tags.models import Tag
  20 from lego.apps.users.models import AbakusGroup
  21 from lego.utils.tasks import AbakusTask
  22 
  23 log = get_logger()
  24 
  25 
  26 def create_weekly_mail(user):
  27     three_days_ago_timestamp = timezone.now() - timedelta(days=3)
  28     last_sunday_timestamp = timezone.now() - timedelta(days=7)
  29 
  30     weekly_tag = Tag.objects.filter(tag="weekly").first()
  31     # Check if weekly tag exists so it does not crash if some idiot deletes the weekly tag
  32     todays_weekly = (
  33         weekly_tag.article_set.filter(created_at__gt=three_days_ago_timestamp).first()
  34         if weekly_tag
  35         else None
  36     )
  37 
  38     events_next_week = Event.objects.filter(
  39         pools__activation_date__gt=timezone.now(),
  40         pools__activation_date__lt=timezone.now() + timedelta(days=7),
  41     ).distinct()
  42 
  43     permission_handler = get_permission_handler(events_next_week.model)
  44     filtered_events = permission_handler.filter_queryset(user, events_next_week)
  45 
  46     filtered_events = filter(
  47         lambda event: event.get_possible_pools(user, True) or event.is_admitted(user),
  48         filtered_events,
  49     )
  50 
  51     joblistings_last_week = Joblisting.objects.filter(
  52         created_at__gt=last_sunday_timestamp, visible_from__lt=timezone.now()
  53     )
  54 
  55     joblistings = []
  56     for joblisting in joblistings_last_week:
  57         joblistings.append(
  58             {
  59                 "id": joblisting.id,
  60                 "company_name": joblisting.company.name,
  61                 "type": JOB_TYPE_TRANSLATIONS[joblisting.job_type],
  62                 "title": joblisting.title,
  63             }
  64         )
  65 
  66     events = []
  67     for event in filtered_events:
  68         pools = []
  69         for pool in event.pools.all():
  70             pools.append(
  71                 {
  72                     "name": pool.name,
  73                     "activation_date": pool.activation_date.strftime("%d/%m kl. %H:%M"),
  74                 }
  75             )
  76 
  77         events.append(
  78             {
  79                 "title": event.title,
  80                 "id": event.id,
  81                 "pools": pools,
  82                 "start_time": event.start_time.strftime("%d/%m kl %H:%M"),
  83                 "url": event.get_absolute_url(),
  84                 "type": EVENT_TYPE_TRANSLATIONS[event.event_type],
  85             }
  86         )
  87 
  88     html_body = render_to_string(
  89         "email/email/weekly_mail.html",
  90         {
  91             "events": events,
  92             "todays_weekly": ""
  93             if todays_weekly is None
  94             else todays_weekly.get_absolute_url(),
  95             "joblistings": joblistings,
  96         },
  97     )
  98     if events or joblistings or todays_weekly:
  99         return html_body
  100     return None
  101 
  102 
  103 @celery_app.task(serializer="json", bind=True, base=AbakusTask)
  104 def send_weekly_email(self, logger_context=None):
  105     self.setup_logger(logger_context)
  106 
  107     week_number = timezone.now().isocalendar().week
  108 
  109     # Set to just PR and Webkom for testing purposes
  110     all_users = set(
  111         AbakusGroup.objects.get(name="Webkom").restricted_lookup()[0]
  112         + AbakusGroup.objects.get(name="PR").restricted_lookup()[0]
  113     )
  114     recipients = []
  115 
  116     for user in all_users:
  117         if not user.email_lists_enabled:
  118             # Don't send emails to users that don't want mail.
  119             continue
  120 
  121         if EMAIL not in NotificationSetting.active_channels(user, WEEKLY_MAIL):
  122             continue
  123         recipients.append(user)
  124 
  125     datatuple = (
  126         (
  127             f"Ukesmail uke {week_number}",
  128             transform(html) if (html := create_weekly_mail(user)) is not None else None,
  129             settings.DEFAULT_FROM_EMAIL,
  130             [user.email],
  131         )
  132         for user in recipients
  133     )
  134     datatuple = tuple(tuppel for tuppel in datatuple if tuppel[1] is not None)
  135     if datatuple:
  136         MessageProcessor.send_mass_mail_html(datatuple)
  137
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/lego/apps/email/tasks.py b/lego/apps/email/tasks.py
  --- a/lego/apps/email/tasks.py
  +++ b/lego/apps/email/tasks.py
  @@ -93,6 +93,7 @@
               if todays_weekly is None
               else todays_weekly.get_absolute_url(),
               "joblistings": joblistings,
  +            "frontend_url": settings.FRONTEND_URL,
           },
       )
       if events or joblistings or todays_weekly:
  
verification_info: {"golden_diff": "diff --git a/lego/apps/email/tasks.py b/lego/apps/email/tasks.py\n--- a/lego/apps/email/tasks.py\n+++ b/lego/apps/email/tasks.py\n@@ -93,6 +93,7 @@\n             if todays_weekly is None\n             else todays_weekly.get_absolute_url(),\n             \"joblistings\": joblistings,\n+            \"frontend_url\": settings.FRONTEND_URL,\n         },\n     )\n     if events or joblistings or todays_weekly:\n", "issue": "Broken link on weekly mails\nThe link used to unsubscribe from the mail is broken, because `frontend_url` is undefined. Probably due to the weekly mails being handled differently than all other notifications.\n", "before_files": [{"content": "from datetime import timedelta\n\nfrom django.conf import settings\nfrom django.template.loader import render_to_string\nfrom django.utils import timezone\n\nfrom premailer import transform\nfrom structlog import get_logger\n\nfrom lego import celery_app\nfrom lego.apps.events.constants import EVENT_TYPE_TRANSLATIONS\nfrom lego.apps.events.models import Event\nfrom lego.apps.joblistings.constants import JOB_TYPE_TRANSLATIONS\nfrom lego.apps.joblistings.models import Joblisting\nfrom lego.apps.notifications.constants import EMAIL, WEEKLY_MAIL\nfrom lego.apps.notifications.models import NotificationSetting\nfrom lego.apps.permissions.utils import get_permission_handler\nfrom lego.apps.restricted.message_processor import MessageProcessor\nfrom lego.apps.tags.models import Tag\nfrom lego.apps.users.models import AbakusGroup\nfrom lego.utils.tasks import AbakusTask\n\nlog = get_logger()\n\n\ndef create_weekly_mail(user):\n    three_days_ago_timestamp = timezone.now() - timedelta(days=3)\n    last_sunday_timestamp = timezone.now() - timedelta(days=7)\n\n    weekly_tag = Tag.objects.filter(tag=\"weekly\").first()\n    # Check if weekly tag exists so it does not crash if some idiot deletes the weekly tag\n    todays_weekly = (\n        weekly_tag.article_set.filter(created_at__gt=three_days_ago_timestamp).first()\n        if weekly_tag\n        else None\n    )\n\n    events_next_week = Event.objects.filter(\n        pools__activation_date__gt=timezone.now(),\n        pools__activation_date__lt=timezone.now() + timedelta(days=7),\n    ).distinct()\n\n    permission_handler = get_permission_handler(events_next_week.model)\n    filtered_events = permission_handler.filter_queryset(user, events_next_week)\n\n    filtered_events = filter(\n        lambda event: event.get_possible_pools(user, True) or event.is_admitted(user),\n        filtered_events,\n    )\n\n    joblistings_last_week = Joblisting.objects.filter(\n        created_at__gt=last_sunday_timestamp, visible_from__lt=timezone.now()\n    )\n\n    joblistings = []\n    for joblisting in joblistings_last_week:\n        joblistings.append(\n            {\n                \"id\": joblisting.id,\n                \"company_name\": joblisting.company.name,\n                \"type\": JOB_TYPE_TRANSLATIONS[joblisting.job_type],\n                \"title\": joblisting.title,\n            }\n        )\n\n    events = []\n    for event in filtered_events:\n        pools = []\n        for pool in event.pools.all():\n            pools.append(\n                {\n                    \"name\": pool.name,\n                    \"activation_date\": pool.activation_date.strftime(\"%d/%m kl. %H:%M\"),\n                }\n            )\n\n        events.append(\n            {\n                \"title\": event.title,\n                \"id\": event.id,\n                \"pools\": pools,\n                \"start_time\": event.start_time.strftime(\"%d/%m kl %H:%M\"),\n                \"url\": event.get_absolute_url(),\n                \"type\": EVENT_TYPE_TRANSLATIONS[event.event_type],\n            }\n        )\n\n    html_body = render_to_string(\n        \"email/email/weekly_mail.html\",\n        {\n            \"events\": events,\n            \"todays_weekly\": \"\"\n            if todays_weekly is None\n            else todays_weekly.get_absolute_url(),\n            \"joblistings\": joblistings,\n        },\n    )\n    if events or joblistings or todays_weekly:\n        return html_body\n    return None\n\n\n@celery_app.task(serializer=\"json\", bind=True, base=AbakusTask)\ndef send_weekly_email(self, logger_context=None):\n    self.setup_logger(logger_context)\n\n    week_number = timezone.now().isocalendar().week\n\n    # Set to just PR and Webkom for testing purposes\n    all_users = set(\n        AbakusGroup.objects.get(name=\"Webkom\").restricted_lookup()[0]\n        + AbakusGroup.objects.get(name=\"PR\").restricted_lookup()[0]\n    )\n    recipients = []\n\n    for user in all_users:\n        if not user.email_lists_enabled:\n            # Don't send emails to users that don't want mail.\n            continue\n\n        if EMAIL not in NotificationSetting.active_channels(user, WEEKLY_MAIL):\n            continue\n        recipients.append(user)\n\n    datatuple = (\n        (\n            f\"Ukesmail uke {week_number}\",\n            transform(html) if (html := create_weekly_mail(user)) is not None else None,\n            settings.DEFAULT_FROM_EMAIL,\n            [user.email],\n        )\n        for user in recipients\n    )\n    datatuple = tuple(tuppel for tuppel in datatuple if tuppel[1] is not None)\n    if datatuple:\n        MessageProcessor.send_mass_mail_html(datatuple)\n", "path": "lego/apps/email/tasks.py"}], "after_files": [{"content": "from datetime import timedelta\n\nfrom django.conf import settings\nfrom django.template.loader import render_to_string\nfrom django.utils import timezone\n\nfrom premailer import transform\nfrom structlog import get_logger\n\nfrom lego import celery_app\nfrom lego.apps.events.constants import EVENT_TYPE_TRANSLATIONS\nfrom lego.apps.events.models import Event\nfrom lego.apps.joblistings.constants import JOB_TYPE_TRANSLATIONS\nfrom lego.apps.joblistings.models import Joblisting\nfrom lego.apps.notifications.constants import EMAIL, WEEKLY_MAIL\nfrom lego.apps.notifications.models import NotificationSetting\nfrom lego.apps.permissions.utils import get_permission_handler\nfrom lego.apps.restricted.message_processor import MessageProcessor\nfrom lego.apps.tags.models import Tag\nfrom lego.apps.users.models import AbakusGroup\nfrom lego.utils.tasks import AbakusTask\n\nlog = get_logger()\n\n\ndef create_weekly_mail(user):\n    three_days_ago_timestamp = timezone.now() - timedelta(days=3)\n    last_sunday_timestamp = timezone.now() - timedelta(days=7)\n\n    weekly_tag = Tag.objects.filter(tag=\"weekly\").first()\n    # Check if weekly tag exists so it does not crash if some idiot deletes the weekly tag\n    todays_weekly = (\n        weekly_tag.article_set.filter(created_at__gt=three_days_ago_timestamp).first()\n        if weekly_tag\n        else None\n    )\n\n    events_next_week = Event.objects.filter(\n        pools__activation_date__gt=timezone.now(),\n        pools__activation_date__lt=timezone.now() + timedelta(days=7),\n    ).distinct()\n\n    permission_handler = get_permission_handler(events_next_week.model)\n    filtered_events = permission_handler.filter_queryset(user, events_next_week)\n\n    filtered_events = filter(\n        lambda event: event.get_possible_pools(user, True) or event.is_admitted(user),\n        filtered_events,\n    )\n\n    joblistings_last_week = Joblisting.objects.filter(\n        created_at__gt=last_sunday_timestamp, visible_from__lt=timezone.now()\n    )\n\n    joblistings = []\n    for joblisting in joblistings_last_week:\n        joblistings.append(\n            {\n                \"id\": joblisting.id,\n                \"company_name\": joblisting.company.name,\n                \"type\": JOB_TYPE_TRANSLATIONS[joblisting.job_type],\n                \"title\": joblisting.title,\n            }\n        )\n\n    events = []\n    for event in filtered_events:\n        pools = []\n        for pool in event.pools.all():\n            pools.append(\n                {\n                    \"name\": pool.name,\n                    \"activation_date\": pool.activation_date.strftime(\"%d/%m kl. %H:%M\"),\n                }\n            )\n\n        events.append(\n            {\n                \"title\": event.title,\n                \"id\": event.id,\n                \"pools\": pools,\n                \"start_time\": event.start_time.strftime(\"%d/%m kl %H:%M\"),\n                \"url\": event.get_absolute_url(),\n                \"type\": EVENT_TYPE_TRANSLATIONS[event.event_type],\n            }\n        )\n\n    html_body = render_to_string(\n        \"email/email/weekly_mail.html\",\n        {\n            \"events\": events,\n            \"todays_weekly\": \"\"\n            if todays_weekly is None\n            else todays_weekly.get_absolute_url(),\n            \"joblistings\": joblistings,\n            \"frontend_url\": settings.FRONTEND_URL,\n        },\n    )\n    if events or joblistings or todays_weekly:\n        return html_body\n    return None\n\n\n@celery_app.task(serializer=\"json\", bind=True, base=AbakusTask)\ndef send_weekly_email(self, logger_context=None):\n    self.setup_logger(logger_context)\n\n    week_number = timezone.now().isocalendar().week\n\n    # Set to just PR and Webkom for testing purposes\n    all_users = set(\n        AbakusGroup.objects.get(name=\"Webkom\").restricted_lookup()[0]\n        + AbakusGroup.objects.get(name=\"PR\").restricted_lookup()[0]\n    )\n    recipients = []\n\n    for user in all_users:\n        if not user.email_lists_enabled:\n            # Don't send emails to users that don't want mail.\n            continue\n\n        if EMAIL not in NotificationSetting.active_channels(user, WEEKLY_MAIL):\n            continue\n        recipients.append(user)\n\n    datatuple = (\n        (\n            f\"Ukesmail uke {week_number}\",\n            transform(html) if (html := create_weekly_mail(user)) is not None else None,\n            settings.DEFAULT_FROM_EMAIL,\n            [user.email],\n        )\n        for user in recipients\n    )\n    datatuple = tuple(tuppel for tuppel in datatuple if tuppel[1] is not None)\n    if datatuple:\n        MessageProcessor.send_mass_mail_html(datatuple)\n", "path": "lego/apps/email/tasks.py"}]}