diff --git a/funnel/templates/notifications/layout_email.html.jinja2 b/funnel/templates/notifications/layout_email.html.jinja2 index 1c5a92003..aa0937d6d 100644 --- a/funnel/templates/notifications/layout_email.html.jinja2 +++ b/funnel/templates/notifications/layout_email.html.jinja2 @@ -323,6 +323,67 @@ font-weight: bold; text-align: center; } + + .schedule { + margin: 32px 0 !important; + } + .schedule__date { + font-size: 16px !important; + margin: 0 !important; + text-align: left; + line-height: 1.5; + padding-left: 0 !important; + } + .schedule__table { + margin: 16px 0; + background-color: #fff !important; + overflow: auto; + } + .schedule__row { + overflow: auto; + border-bottom: 1pt solid rgba(132, 146, 166, 0.3) !important; + } + .schedule__row__column--header { + outline: 1px solid rgba(132, 146, 166, 0.3) + border: none !important; + background-color: #fff; + font-size: 16px; + line-height: 1.5; + align: left; + padding: 4px 16px; + width: calc(100% - 150px); + } + .schedule__row__column--time--header { + outline: 1px solid rgba(132, 146, 166, 0.3) + border: none !important; + background-color: #fff; + width: 150px; + padding: 4px 16px; + align: left; + } + .schedule__row__column { + position: relative !important; + outline: 1px solid rgba(132, 146, 166, 0.3) + } + .schedule__row__column__content__title { + width: 100% !important; + } + .schedule__row__column__content__title__duration { + position: relative !important; + background-color: transparent !important; + font-size: 16px !important; + padding: 0 !important; + margin: 0 0 4px !important; + line-height: 1.5 !important; + } + .schedule__row__column__content__title__heading, + .schedule__row__column__content__title__speaker { + font-size: 16px !important; + font-weight: normal !important; + line-height: 1.5 !important; + margin: 0 0 4px; + color: #4d5763; + } .unsubscribe { color: #4d5763; text-decoration: underline; diff --git a/funnel/templates/notifications/macros_email.html.jinja2 b/funnel/templates/notifications/macros_email.html.jinja2 index 6245c1444..fcf24a13a 100644 --- a/funnel/templates/notifications/macros_email.html.jinja2 +++ b/funnel/templates/notifications/macros_email.html.jinja2 @@ -29,29 +29,61 @@ {%- endmacro -%} {% macro cta_button(btn_url, btn_text) %} - - -
- - - - - - + + + +{% endmacro %} + +{% macro schedule_tables(schedule) %} + + {% for day, rooms in schedule.items() %} +
- -
+
+ + + + + + +
+ +
+ +
+
+

+ {% trans %}{{ day }}{% endtrans %} +

+ {% for room, slots in rooms.items() %} + + + + + + {% for slot, sessions in slots.items() %} + {% for session in sessions %} + + + + + {% endfor %} + {% endfor %} + + {% endfor %}
{% trans %}Time{% endtrans %}{% trans %}{{ room }}{% endtrans %}
{% trans start_time=session.startTime, end_time=session.endTime %}{{ start_time }}–{{ end_time }}{% endtrans %} + {% if session.title %}

{% trans title=session.title %}{{ title }}{% endtrans %}

{% endif %} + {% if session.speaker %}

{% trans speaker=session.speaker %}{{ speaker }}{% endtrans %}

{% endif %} +
- -
- + {% endfor %} +
{% endmacro %} {% macro rsvp_footer(view, rsvp_linktext) %} diff --git a/funnel/templates/notifications/update_new_email.html.jinja2 b/funnel/templates/notifications/update_new_email.html.jinja2 index b33cd1e91..006ea6bad 100644 --- a/funnel/templates/notifications/update_new_email.html.jinja2 +++ b/funnel/templates/notifications/update_new_email.html.jinja2 @@ -1,5 +1,5 @@ {%- extends "notifications/layout_email.html.jinja2" -%} -{%- from "notifications/macros_email.html.jinja2" import cta_button -%} +{%- from "notifications/macros_email.html.jinja2" import cta_button, schedule_tables -%} {%- block content -%} @@ -17,7 +17,10 @@ {% trans update_body=view.update.body %}{{ update_body }}{% endtrans %} -
+ + {# Schedule : BEGIN #} + {{ schedule_tables(schedules) }} + {# Schedule: END #} {# Button : BEGIN #} {{ cta_button(view.update.url_for(_external=true, **view.tracking_tags()), gettext("Read on the website") )}} diff --git a/funnel/views/notifications/update_notification.py b/funnel/views/notifications/update_notification.py index 388bb6f46..376145d79 100644 --- a/funnel/views/notifications/update_notification.py +++ b/funnel/views/notifications/update_notification.py @@ -6,10 +6,11 @@ from baseframe import _, __ -from ...models import Account, NewUpdateNotification, Update +from ...models import Account, NewUpdateNotification, Project, Update from ...transports.sms import SmsPriority, SmsTemplate from ..helpers import shortlink from ..notification import RenderNotification +from ..schedule import upcoming_schedule_data_with_room from .mixins import TemplateVarMixin @@ -33,6 +34,7 @@ class RenderNewUpdateNotification(RenderNotification): """Notify crew and participants when the project has a new update.""" update: Update + project: Project aliases = {'document': 'update'} emoji_prefix = "📰 " reason = __( @@ -62,7 +64,12 @@ def email_subject(self) -> str: ) def email_content(self) -> str: - return render_template('notifications/update_new_email.html.jinja2', view=self) + schedules = upcoming_schedule_data_with_room(self.project) + return render_template( + 'notifications/update_new_email.html.jinja2', + view=self, + schedules=schedules, + ) def sms(self) -> UpdateTemplate: return UpdateTemplate( diff --git a/funnel/views/schedule.py b/funnel/views/schedule.py index cc3058801..14506bcf4 100644 --- a/funnel/views/schedule.py +++ b/funnel/views/schedule.py @@ -3,7 +3,7 @@ from __future__ import annotations from collections import defaultdict -from datetime import timedelta +from datetime import datetime, timedelta from types import SimpleNamespace from typing import TYPE_CHECKING, Any, cast @@ -115,6 +115,22 @@ def schedule_data( return schedule +def upcoming_schedule_data_with_room(project: Project) -> list[dict]: + schedule = schedule_data(project) + schedule_with_room = [] + for key, day in schedule: + if datetime.strptime(key, '%y-%m-%d') >= datetime.today(): + daydata_with_room: dict[str, dict[str, list]] = defaultdict( + lambda: defaultdict(list) + ) + for slots in schedule[day]: + roomdata: dict[str, Any] = {'date': day, 'rooms': defaultdict(list)} + roomdata[slots.sessions.room_scoped_name].append(slots) + daydata_with_room[day]['rooms'].append(roomdata) + schedule_with_room.append(daydata_with_room) + return schedule_with_room + + def schedule_ical( project: Project, rsvp: Rsvp | None = None, future_only: bool = False ) -> bytes: diff --git a/sample.env b/sample.env index 159905cbc..08c528399 100644 --- a/sample.env +++ b/sample.env @@ -107,9 +107,9 @@ FLASK_CACHE_REDIS_URL=redis://${REDIS_HOST}:6379/0 # --- Database configuration DB_HOST=localhost # Main app database -FLASK_SQLALCHEMY_DATABASE_URI='postgresql+psycopg:///funnel' +FLASK_SQLALCHEMY_DATABASE_URI='postgresql+psycopg:///funnel_test' # Geoname database (the use of `__` creates a dict and sets a key in the dict) -FLASK_SQLALCHEMY_BINDS__geoname='postgresql+psycopg:///geoname' +FLASK_SQLALCHEMY_BINDS__geoname='postgresql+psycopg:///geoname_testing' # --- Email configuration # SMTP mail server ('localhost' if Postfix is configured as a relay email server)