module
pretalx.mail.domain.context
Functions 4
base_placeholders(sender, **kwargs)source
@receiver(register_mail_placeholders, dispatch_uid="pretalx_register_base_placeholders")
def base_placeholders(sender, **kwargs):
# sender may be None for eventless mail rendering (e.g.
# ``person.domain.user.reset_password`` outside an event context).
# override(None) activates the default language.
with override(sender.locale if sender is not None else None):
date_format = get_notification_date_format()
time = _date(now().replace(hour=9, minute=0), date_format)
time2 = _date(now().replace(hour=11, minute=0), date_format)
placeholders = [
*placeholder_aliases(
["event_name", "event"],
["event"],
lambda event: event.name,
lambda event: event.name,
_("The event’s full name"),
cls=TrustedPlainMailTextPlaceholder,
),
TrustedPlainMailTextPlaceholder(
"event_slug",
["event"],
lambda event: event.slug,
lambda event: event.slug,
_("The event’s short form, used in URLs"),
),
LinkMailTextPlaceholder(
"event_url",
["event"],
lambda event: event.urls.base.full(),
lambda event: f"https://pretalx.com/{event.slug}/",
_("The event’s public base URL"),
),
LinkMailTextPlaceholder(
"event_schedule_url",
["event"],
lambda event: event.urls.schedule.full(),
lambda event: f"https://pretalx.com/{event.slug}/schedule/",
_("The event’s public schedule URL"),
),
LinkMailTextPlaceholder(
"event_cfp_url",
["event"],
lambda event: event.cfp.urls.base.full(),
lambda event: f"https://pretalx.com/{event.slug}/cfp",
_("The event’s public CfP URL"),
),
LinkMailTextPlaceholder(
"all_submissions_url",
["event", "user"],
lambda event, user: event.urls.user_submissions.full(),
"https://pretalx.example.com/democon/me/submissions/",
_("URL to a user’s list of proposals"),
account_required=True,
),
LinkMailTextPlaceholder(
"profile_page_url",
["event", "user"],
lambda event, user: event.urls.user.full(),
"https://pretalx.example.com/democon/me/",
_("URL to a user’s private profile page."),
account_required=True,
),
TrustedPlainMailTextPlaceholder(
"deadline",
["event"],
lambda event: (
_date(event.cfp.deadline.astimezone(event.tz), "SHORT_DATETIME_FORMAT")
if event.cfp.deadline
else ""
),
lambda event: (
_date(event.cfp.deadline.astimezone(event.tz), "SHORT_DATETIME_FORMAT")
if event.cfp.deadline
else ""
),
_("The general CfP deadline"),
),
*placeholder_aliases(
["proposal_code", "session_code", "code"],
["submission"],
lambda submission: submission.code,
"F8VVL",
_("The proposal’s unique ID"),
cls=TrustedPlainMailTextPlaceholder,
),
LinkMailTextPlaceholder(
"talk_url",
["slot"],
lambda slot: slot.submission.urls.public.full(),
"https://pretalx.example.com/democon/schedule/F8VVL/",
_("The proposal’s public URL"),
),
*placeholder_aliases(
["proposal_url", "edit_url", "submission_url"],
["submission"],
lambda submission: submission.urls.user_base.full(),
"https://pretalx.example.com/democon/me/submissions/F8VVL/",
_("The speaker’s edit page for the proposal"),
cls=LinkMailTextPlaceholder,
account_required=True,
),
LinkMailTextPlaceholder(
"confirmation_link",
["submission"],
lambda submission: submission.urls.confirm.full(),
"https://pretalx.example.com/democon/me/submissions/F8VVL/confirm",
_("Link to confirm a proposal after it has been accepted."),
account_required=True,
),
LinkMailTextPlaceholder(
"withdraw_link",
["submission"],
lambda submission: submission.urls.withdraw.full(),
"https://pretalx.example.com/democon/me/submissions/F8VVL/withdraw",
_("Link to withdraw the proposal"),
account_required=True,
),
*placeholder_aliases(
["proposal_title", "submission_title"],
["submission"],
lambda submission: submission.title,
_("This Is a Proposal Title"),
_("The proposal’s title"),
cls=UntrustedPlainMailTextPlaceholder,
),
UntrustedPlainMailTextPlaceholder(
"speakers",
["submission"],
lambda submission: submission.display_speaker_names,
"Jane Smith, Fred Jones",
_("The name(s) of all speakers in this proposal."),
),
*placeholder_aliases(
["session_type", "submission_type"],
["submission"],
lambda submission: str(submission.submission_type.name),
_("Session Type A"),
_("The proposal’s session type"),
cls=TrustedPlainMailTextPlaceholder,
),
TrustedPlainMailTextPlaceholder(
"track_name",
["submission"],
lambda submission: str(submission.track.name) if submission.track else "",
_("Track A"),
_("The track the proposal belongs to"),
),
TrustedPlainMailTextPlaceholder(
"session_duration_minutes",
["submission"],
lambda submission: submission.get_duration(),
"30",
_("Duration in minutes"),
),
UntrustedMarkdownMailTextPlaceholder(
"all_reviews",
["submission"],
get_all_reviews,
_(
"First review, agreeing with the proposal.\n\n--------- \n\nSecond review, containing heavy criticism!"
),
_("All review texts for this proposal"),
),
TrustedPlainMailTextPlaceholder(
"session_start_date",
["slot"],
lambda slot: _date(slot.local_start, "SHORT_DATE_FORMAT"),
_date(now(), "SHORT_DATE_FORMAT"),
_("The session’s start date"),
),
TrustedPlainMailTextPlaceholder(
"session_start_time",
["slot"],
lambda slot: _date(slot.local_start, "TIME_FORMAT"),
_date(now(), "TIME_FORMAT"),
_("The session’s start time"),
),
TrustedPlainMailTextPlaceholder(
"session_end_date",
["slot"],
lambda slot: _date(slot.local_end, "SHORT_DATE_FORMAT"),
_date(now(), "SHORT_DATE_FORMAT"),
_("The session’s end date"),
),
TrustedPlainMailTextPlaceholder(
"session_end_time",
["slot"],
lambda slot: _date(slot.local_end, "TIME_FORMAT"),
_date(now(), "TIME_FORMAT"),
_("The session’s end time"),
),
TrustedPlainMailTextPlaceholder(
"session_room",
["slot"],
lambda slot: str(slot.room),
_("Room 101"),
_("The session’s room"),
),
UntrustedSpeakerNameMailTextPlaceholder(
"name",
["user", "event"],
lambda user, event=None: Recipient(user).get_display_name(
event, allow_empty=True
),
_("Jane Doe"),
_("The addressed user’s full name"),
),
UntrustedPlainMailTextPlaceholder(
"inviting_speaker",
["inviting_user"],
lambda inviting_user: inviting_user.get_display_name(),
_("Jane Doe"),
),
UntrustedPlainMailTextPlaceholder(
"email",
["user"],
lambda user: user.email,
"jane@example.org",
_("The addressed user’s email address"),
),
UntrustedMarkdownMailTextPlaceholder(
"speaker_schedule_new",
["user", "event"],
lambda user, event: render_notifications(
get_current_notifications(recipient_speaker(user, event), event), event
),
_(
"- Your session “Title” will take place at {time} in Room 101.\n"
"- Your session “Other Title” has been moved to {time2} in Room 102."
).format(time=time, time2=time2),
_(
"A list of all changes to the user’s schedule in the current schedule version."
),
),
UntrustedMarkdownMailTextPlaceholder(
"speaker_schedule_full",
["user", "event"],
lambda user, event: render_notifications(
get_full_notifications(recipient_speaker(user, event), event), event
),
_(
"- Your session “Title” will take place at {time} in Room 101.\n"
"- Your session “Other Title” will take place at {time2} in Room 102."
).format(time=time, time2=time2),
_("Times and locations for this user\u2019s publicly visible sessions."),
),
]
return placeholders # noqa: RET504 -- explicit return aids debugger breakpoints
get_all_reviews(submission)source
def get_all_reviews(submission):
reviews = submission.reviews.filter(text__isnull=False)
if not reviews:
return ""
texts = [review.text.strip() for review in reviews if review.text.strip()]
if not texts:
return ""
return "\n\n--------------\n\n".join(texts)
get_mail_context(*, safe_extra_context=None, **kwargs)sourceResolve registered mail placeholders satisfied by kwargs and return a {identifier: value} dict, merged with safe_extra_context.
safe_extra_context values must be pre-sanitised. Only SafeString, EmailAlternativeString, UrlString, and numeric types are permitted.
def get_mail_context(*, safe_extra_context=None, **kwargs):
"""Resolve registered mail placeholders satisfied by ``kwargs`` and return
a ``{identifier: value}`` dict, merged with ``safe_extra_context``.
``safe_extra_context`` values must be pre-sanitised. Only ``SafeString``,
``EmailAlternativeString``, ``UrlString``, and numeric types are permitted.
"""
_validate_safe_extra_context(safe_extra_context)
if safe_extra_context:
safe_extra_context = {
key: (
mark_safe(value.full()) # noqa: S308 -- urlman-built internal URL
if isinstance(value, UrlString)
else value
)
for key, value in safe_extra_context.items()
}
kwargs = {key: value for key, value in kwargs.items() if value is not None}
event = kwargs.get("event")
if "submission" in kwargs and "slot" not in kwargs:
slot = kwargs["submission"].slot
if slot and slot.start and slot.room:
kwargs["slot"] = kwargs["submission"].slot
degrade_account_links = "user" in kwargs and not recipient_account(kwargs["user"])
context = {}
for _recv, placeholders in register_mail_placeholders.send(sender=event):
placeholder_list = (
placeholders if isinstance(placeholders, (list, tuple)) else [placeholders]
)
for placeholder in placeholder_list:
if all(required in kwargs for required in placeholder.required_context):
if placeholder.account_required and degrade_account_links:
context[placeholder.identifier] = ""
else:
context[placeholder.identifier] = placeholder.render(kwargs)
if safe_extra_context:
context.update(safe_extra_context)
return context
placeholder_aliases(identifiers, args, func, sample, explanation=None, *, cls, **kwargs)source
def placeholder_aliases(
identifiers, args, func, sample, explanation=None, *, cls, **kwargs
):
result = []
is_visible = True
for identifier in identifiers:
result.append(
cls(
identifier,
args,
func,
sample,
explanation=explanation,
is_visible=is_visible,
**kwargs,
)
)
is_visible = False
return result