*** Wartungsfenster jeden ersten Mittwoch vormittag im Monat ***

Skip to content
Snippets Groups Projects
Commit 5ce7d546 authored by Moser, Maximilian's avatar Moser, Maximilian
Browse files

Add secondary email to notification preferences

* this enables users to set an alternative email address to which
  notifications will be sent, in case they don't like to use their
  institutional email address
parent ad21f638
No related branches found
No related tags found
1 merge request!82Add support for "secondary email" address for notifications
......@@ -45,6 +45,7 @@ from .users import (
tuw_registration_form,
)
from .users.utils import check_user_email_for_tuwien, current_user_as_creator
from .users.views import notification_settings
# Invenio-Config-TUW
# ==================
......@@ -386,3 +387,5 @@ NOTIFICATIONS_BACKENDS = {
**NOTIFICATIONS_BACKENDS,
TUWEmailNotificationBackend.id: TUWEmailNotificationBackend(),
}
NOTIFICATIONS_SETTINGS_VIEW_FUNCTION = notification_settings
......@@ -32,6 +32,12 @@ class TUWEmailNotificationBackend(EmailNotificationBackend):
if site_id:
subject = f"[{site_id}] {subject}"
secondary_email = (
recipient.data.get("preferences", {})
.get("notifications", {})
.get("secondary_email", None)
)
resp = send_email(
{
"subject": subject,
......@@ -40,6 +46,7 @@ class TUWEmailNotificationBackend(EmailNotificationBackend):
"recipients": [
recipient.data.get("email") or recipient.data.get("email_hidden")
],
"cc": [secondary_email] if secondary_email else [],
"sender": current_app.config["MAIL_DEFAULT_SENDER"],
"reply_to": current_app.config["MAIL_DEFAULT_REPLY_TO"],
"extra_headers": {
......
......@@ -8,7 +8,8 @@
"""Form for curation-related user settings, inspired by the notifications settings."""
from flask_wtf import FlaskForm
from wtforms import BooleanField
from invenio_users_resources.forms import NotificationsForm
from wtforms import BooleanField, EmailField
class CurationPreferencesProxy:
......@@ -62,3 +63,15 @@ class CurationPreferencesForm(FlaskForm):
"""Populate the object."""
user = self.proxy_cls(user)
return super().populate_obj(user)
class TUWNotificationsForm(NotificationsForm):
"""Form for editing user notification preferences."""
secondary_email = EmailField(
label="Secondary email",
description=(
"Secondary email address for notifications. "
"If set, this email address will be added in CC."
),
)
......@@ -11,7 +11,10 @@ from invenio_app_rdm.users.schemas import NotificationsUserSchema as UserSchema
from invenio_app_rdm.users.schemas import (
UserPreferencesNotificationsSchema as UserPreferencesSchema,
)
from invenio_users_resources.services.schemas import UserProfileSchema
from invenio_users_resources.services.schemas import (
NotificationPreferences,
UserProfileSchema,
)
from marshmallow import fields
......@@ -25,10 +28,17 @@ class TUWUserProfileSchema(UserProfileSchema):
# preferences
class TUWNotificationPreferencesSchema(NotificationPreferences):
"""Schema for notification preferences."""
secondary_email = fields.Email()
class TUWUserPreferencesSchema(UserPreferencesSchema):
"""User preferences schema with TU Wien extensions."""
curation_consent = fields.Boolean(default=False)
notifications = fields.Nested(TUWNotificationPreferencesSchema)
# complete user schema
......
{# -*- coding: utf-8 -*-
This file is part of Invenio.
Copyright (C) 2023 Graz University of Technology.
Copyright (C) 2025 TU Wien.
Invenio-Config-TUW is free software; you can redistribute it and/or
modify it under the terms of the MIT License; see LICENSE file for more
details.
#}
{#- base: invenio_users_resources v5.2.0 -#}
{#- file: invenio_users_resources/templates/semantic-ui/invenio_users_resources/settings/notifications.html -#}
{#- changes: rewording & mild restructuring, adding input for secondary email; see "change:" comments in the code #}
{%- extends config.USERPROFILES_SETTINGS_TEMPLATE %}
{% from "invenio_userprofiles/settings/_macros.html" import render_field, form_errors %}
{%- block settings_content scoped %}
<section aria-label="{{ _('Notifications') }}" class="ui segments">
<div class="ui segment secondary">
<i class="bell icon" aria-hidden="true"></i>
<h2 class="ui tiny header inline-block m-0">{{ _("Notifications") }}</h2>
</div>
<div class="ui segment">
<form {% if not read_only %}method="POST" {% endif %} name="notifications_form" class="ui form">
<div class="ui four column grid">
<div class="two column stackable tablet-mobile row">
<div class="column">
{%- set form = notifications_form %}
{%- for field in form %}
{%- if field.widget.input_type == 'hidden' %}
{{ field() }}
{%- endif %}
{%- endfor %}
{#- change: create vars for other fields -#}
{%- set enabled_field = form.enabled %}
{%- set secondary_email_field = form.secondary_email %}
{%- set matrix_user_id_field = form.matrix_user_id %}
{%- set notif_enabled = current_user.preferences.get("notifications", {}).get("enabled", True) %}
<div class="field">
<label for="{{ enabled_field.id }}">{{ enabled_field.label }}</label>
{#- change: add contextual text, and restructure input #}
<p>
<small>
Note that this setting only affects <strong>automatic notifications</strong>.
Contact requests will still be sent to both primary and secondary email address, regardless of this setting.
</small>
</p>
<div class="ui toggle on-off checkbox">
<input type="checkbox" name="{{ enabled_field.id }}" id="{{ enabled_field.id }}" {{ "checked" if notif_enabled else "" }}>
<label>
<small class="ml-10">{{ enabled_field.description }}</small>
</label>
</div>
</div>
</div>
<div class="column">
{#- change: remove use of url_for() #}
<div class="field">
<label>{{ _("Primary email") }}</label>
<p>
<small>
{#- change: remove mention of changing email address #}
{% trans %}
We use your primary email address for sending notifications.
{% endtrans %}
</small>
</p>
<div class="ui basic label large ml-0">{{ current_user.email }}</div>
</div>
{#- change: add input for secondary email address #}
<div class="field">
<label for="{{ secondary_email_field.id }}">{{ secondary_email_field.label }}</label>
<p>
<small>
{{ secondary_email_field.description }}
</small>
</p>
<div class="ui">
<input
type="email" name="{{ secondary_email_field.id }}" id="{{ secondary_email_field.id }}"
value={{ current_user.preferences.get("notifications", {}).get("secondary_email", "") }}>
</div>
</div>
</div>
{{ form.id }}
<div class="one column row">
<div class="form-actions">
<a href="./" class="ui labeled icon button mt-5">
<i class="close icon" aria-hidden="true"></i> {{ _('Cancel') }}
</a>
<button type="submit" name="submit" value="{{ form._prefix }}" class="ui primary labeled icon button mt-5">
<i class="check icon" aria-hidden="true"></i>
{{ _('Update notification preferences') }}
</button>
</div>
</div>
</div>
</div>
</form>
</div>
</section>
{% endblock settings_content%}
......@@ -9,9 +9,11 @@
from flask import Blueprint, current_app, flash, render_template, request
from flask_login import current_user, login_required
from invenio_app_rdm.theme.views import handle_notifications_form
from invenio_db import db
from invenio_i18n import lazy_gettext as _
from .preferences import CurationPreferencesForm
from .preferences import CurationPreferencesForm, TUWNotificationsForm
user_settings_blueprint = Blueprint(
"invenio_config_tuw_settings",
......@@ -44,3 +46,29 @@ def curation_settings_view():
["invenio_theme_tuw/settings/curation.html", "curation_settings.html"],
preferences_curation_form=preferences_curation_form,
)
def notification_settings():
"""View for notification settings."""
preferences_notifications_form = TUWNotificationsForm(
formdata=None, obj=current_user, prefix="preferences-notifications"
)
# Pick form
form_name = request.form.get("submit", None)
form = preferences_notifications_form if form_name else None
# Process form
if form:
form.process(formdata=request.form)
if form.validate_on_submit():
handle_notifications_form(form)
flash(_("Notification preferences were updated."), category="success")
return render_template(
[
"invenio_theme_tuw/notifications_settings.html",
"notifications_settings.html",
],
notifications_form=preferences_notifications_form,
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment