diff --git a/docs/references/signals.md b/docs/references/signals.md new file mode 100644 index 0000000000..7fb8cd5ad6 --- /dev/null +++ b/docs/references/signals.md @@ -0,0 +1,27 @@ +Hypha uses django signals to enable extensions to modify behavior, as well as execute their own code when certain things happen in hypha. This page servers as a reference to implemented signals in hypha. + +#### hypha.apply.activity.signals.message_hook + +Gives a chance to override messages that go out from hypha, and whether those messages should go out. + +Function definition to receive signal: + +``` +@receiver(message_hook, sender=sender) +def handle_message_hook(sender, message_type, **kwargs) +``` + +With the following parameters: + +* `sender`: one of the adapters defined in `hypha/apply/activity/messaging.py`, such as EmailAdapter +* `message_type`: one of the `MESSAGES` defined in `hypha/apply/activity/options.py` +* `kwargs`: all the additional information present for generating the message. The information changes per call, so should be treated as unreliable. That said, normally there are a few items available + * `"request"` - the django request + * `"source"` - the item that caused the message to be fired, such as the submission, invoice, or project + +The response from the hook should be a dictionary including any or all of the following attributes: + +* `"should_send"` - A boolean about whether this message should be sent. If any hook handlers have this set to false, the message will not be sent. +* `"extra_kwargs"` - a dictionary of extra kwargs that are used by the adapters to send. For instance, "subject" is used by the email adapater for the subject line of the message +* `"message"` - The message that should be sent instead of the one generated by hypha +* `"priority"` - When multiple hooks are fired that define new messages or extra kwargs, the one with the highest priority will be used. If no priorities are defined, then the first one will be used. diff --git a/extensions/ots/message_configuration/__init__.py b/extensions/ots/message_configuration/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/extensions/ots/message_configuration/apps.py b/extensions/ots/message_configuration/apps.py new file mode 100644 index 0000000000..baf7047893 --- /dev/null +++ b/extensions/ots/message_configuration/apps.py @@ -0,0 +1,11 @@ +from django.apps import AppConfig + + +class MessageConfigurationConfig(AppConfig): + name = "extensions.ots.message_configuration" + label = "extension_message_configuration" + + def ready(self): + from . import signals # noqa + + pass diff --git a/extensions/ots/message_configuration/migrations/0001_initial.py b/extensions/ots/message_configuration/migrations/0001_initial.py new file mode 100644 index 0000000000..8892a25403 --- /dev/null +++ b/extensions/ots/message_configuration/migrations/0001_initial.py @@ -0,0 +1,160 @@ +# Generated by Django 4.2.11 on 2024-04-30 19:58 + +from django.db import migrations, models +import django.db.models.deletion +import modelcluster.fields + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + ("wagtailcore", "0089_log_entry_data_json_null_to_object"), + ] + + operations = [ + migrations.CreateModel( + name="MessagingSetting", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("email_default_send", models.BooleanField(default=True)), + ("slack_default_send", models.BooleanField(default=True)), + ("email_footer", models.TextField(blank=True, null=True)), + ("email_header", models.TextField(blank=True, null=True)), + ( + "site", + models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + to="wagtailcore.site", + ), + ), + ], + options={ + "verbose_name": "Messaging Settings", + }, + ), + migrations.CreateModel( + name="MessagingSettings", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "sort_order", + models.IntegerField(blank=True, editable=False, null=True), + ), + ( + "message_type", + models.CharField( + choices=[ + ("UPDATE_LEAD", "updated lead"), + ("BATCH_UPDATE_LEAD", "batch updated lead"), + ("EDIT_SUBMISSION", "edited submission"), + ("APPLICANT_EDIT", "edited applicant"), + ("NEW_SUBMISSION", "submitted new submission"), + ("DRAFT_SUBMISSION", "submitted new draft submission"), + ("SCREENING", "screened"), + ("TRANSITION", "transitioned"), + ("BATCH_TRANSITION", "batch transitioned"), + ("DETERMINATION_OUTCOME", "sent determination outcome"), + ( + "BATCH_DETERMINATION_OUTCOME", + "sent batch determination outcome", + ), + ("INVITED_TO_PROPOSAL", "invited to proposal"), + ("REVIEWERS_UPDATED", "updated reviewers"), + ("BATCH_REVIEWERS_UPDATED", "batch updated reviewers"), + ("PARTNERS_UPDATED", "updated partners"), + ("PARTNERS_UPDATED_PARTNER", "partners updated partner"), + ("READY_FOR_REVIEW", "marked ready for review"), + ("BATCH_READY_FOR_REVIEW", "marked batch ready for review"), + ("NEW_REVIEW", "added new review"), + ("COMMENT", "added comment"), + ("PROPOSAL_SUBMITTED", "submitted proposal"), + ("OPENED_SEALED", "opened sealed submission"), + ("REVIEW_OPINION", "reviewed opinion"), + ("DELETE_SUBMISSION", "deleted submission"), + ("DELETE_REVIEW", "deleted review"), + ("DELETE_REVIEW_OPINION", "deleted review opinion"), + ("CREATED_PROJECT", "created project"), + ("UPDATED_VENDOR", "updated contracting information"), + ("UPDATE_PROJECT_LEAD", "updated project lead"), + ("EDIT_REVIEW", "edited review"), + ("SEND_FOR_APPROVAL", "sent for approval"), + ("APPROVE_PROJECT", "approved project"), + ("ASSIGN_PAF_APPROVER", "assign paf approver"), + ("APPROVE_PAF", "approved paf"), + ("PROJECT_TRANSITION", "transitioned project"), + ("REQUEST_PROJECT_CHANGE", "requested project change"), + ( + "SUBMIT_CONTRACT_DOCUMENTS", + "submitted contract documents", + ), + ("UPLOAD_DOCUMENT", "uploaded document to project"), + ("REMOVE_DOCUMENT", "removed document from project"), + ("UPLOAD_CONTRACT", "uploaded contract to project"), + ("APPROVE_CONTRACT", "approved contract"), + ("CREATE_INVOICE", "created invoice for project"), + ("UPDATE_INVOICE_STATUS", "updated invoice status"), + ("APPROVE_INVOICE", "approve invoice"), + ("DELETE_INVOICE", "deleted invoice"), + ("SENT_TO_COMPLIANCE", "sent project to compliance"), + ("UPDATE_INVOICE", "updated invoice"), + ("SUBMIT_REPORT", "submitted report"), + ("SKIPPED_REPORT", "skipped report"), + ("REPORT_FREQUENCY_CHANGED", "changed report frequency"), + ("DISABLED_REPORTING", "disabled reporting"), + ("REPORT_NOTIFY", "notified report"), + ("CREATE_REMINDER", "created reminder"), + ("DELETE_REMINDER", "deleted reminder"), + ("REVIEW_REMINDER", "reminder to review"), + ("BATCH_DELETE_SUBMISSION", "batch deleted submissions"), + ("BATCH_ARCHIVE_SUBMISSION", "batch archive submissions"), + ("STAFF_ACCOUNT_CREATED", "created new account"), + ("STAFF_ACCOUNT_EDITED", "edited account"), + ("ARCHIVE_SUBMISSION", "archived submission"), + ("UNARCHIVE_SUBMISSION", "unarchived submission"), + ], + max_length=50, + ), + ), + ("email_subject", models.TextField(blank=True, null=True)), + ("email_message", models.TextField(blank=True, null=True)), + ("slack_message", models.TextField(blank=True, null=True)), + ("email_enabled", models.BooleanField()), + ("slack_enabled", models.BooleanField()), + ( + "setting", + modelcluster.fields.ParentalKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="messaging_settings", + to="extension_message_configuration.messagingsetting", + ), + ), + ], + options={ + "verbose_name": "Messaging Settings Page", + }, + ), + migrations.AddConstraint( + model_name="messagingsettings", + constraint=models.UniqueConstraint( + fields=("setting", "message_type"), name="unique_site_type" + ), + ), + ] diff --git a/extensions/ots/message_configuration/migrations/__init__.py b/extensions/ots/message_configuration/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/extensions/ots/message_configuration/models.py b/extensions/ots/message_configuration/models.py new file mode 100644 index 0000000000..aa4d95176c --- /dev/null +++ b/extensions/ots/message_configuration/models.py @@ -0,0 +1,100 @@ +from django.db import models +from django.template.loader import get_template +from modelcluster.fields import ParentalKey +from modelcluster.models import ClusterableModel +from wagtail.admin.panels import FieldPanel, HelpPanel, InlinePanel +from wagtail.contrib.settings.models import BaseSiteSetting, register_setting +from wagtail.models import Orderable + +from hypha.apply.activity.options import MESSAGES + + +class MessagingHelpPanel(HelpPanel): + messages = { + MESSAGES.NEW_SUBMISSION: "messages/email_defaults/new_submission.html", + MESSAGES.DRAFT_SUBMISSION: "messages/email_defaults/draft_submission.html", + MESSAGES.DETERMINATION_OUTCOME: "messages/email_defaults/determination_outcome.html", + MESSAGES.INVITED_TO_PROPOSAL: "messages/email_defaults/invited_to_proposal.html", + MESSAGES.READY_FOR_REVIEW: "messages/email_defaults/ready_for_review.html", + MESSAGES.REVIEWERS_UPDATED: "messages/email_defaults/reviewers_updated.html", + MESSAGES.REVIEW_REMINDER: "messages/email_defaults/review_reminder.html", + MESSAGES.APPROVE_PAF: "messages/email_defaults/approve_paf.html", + MESSAGES.APPROVE_INVOICE: "messages/email_defaults/approve_invoice.html", + } + + def __init__(self, *args, **kwargs): + self.email_messages = {} + for message in MESSAGES: + if message in MessagingHelpPanel.messages: + self.email_messages[message] = get_template( + MessagingHelpPanel.messages[message] + ).render() + super().__init__("", "messaging_help.html", classname="messaging_help_panel") + + class BoundPanel(HelpPanel.BoundPanel): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.email_messages = self.panel.email_messages + + +@register_setting +class MessagingSetting(BaseSiteSetting, ClusterableModel): + """Allows settings per Message Type to be specified in Wagtail Settings and retrieved by the activity code. + This class affords a setting for a single Site to be referenced by the MessagingSettings model. This way + the BaseSiteSetting can be extended such that a setting appears in the Wagtail Settings menu but there can also be up to + one row per group for settings.""" + + email_default_send = models.BooleanField(default=True) + slack_default_send = models.BooleanField(default=True) + email_footer = models.TextField(null=True, blank=True) + email_header = models.TextField(null=True, blank=True) + + class Meta: + verbose_name = "Messaging Settings" + + panels = [ + MessagingHelpPanel(), + FieldPanel("email_default_send"), + FieldPanel("slack_default_send"), + FieldPanel("email_header"), + FieldPanel("email_footer"), + InlinePanel( + "messaging_settings", + classname="all_messaging_settings", + ), + ] + + +class MessagingSettings(Orderable): + class Meta: + verbose_name = "Messaging Settings Page" + constraints = [ + # There is a one-to-one relation for setting-to-site. Therefore, "setting" can be thought of as "site" here. + models.UniqueConstraint( + fields=["setting", "message_type"], name="unique_site_type" + ), + ] + + setting = ParentalKey( + to=MessagingSetting, + on_delete=models.CASCADE, + related_name="messaging_settings", + ) + message_type = models.CharField( + choices=MESSAGES.choices, + max_length=50, + ) + email_subject = models.TextField(null=True, blank=True) + email_message = models.TextField(null=True, blank=True) + slack_message = models.TextField(null=True, blank=True) + email_enabled = models.BooleanField() + slack_enabled = models.BooleanField() + + panels = [ + FieldPanel("message_type", classname="message_type"), + FieldPanel("email_enabled"), + FieldPanel("email_subject"), + FieldPanel("email_message", classname="email_message"), + FieldPanel("slack_enabled"), + FieldPanel("slack_message", classname="slack_message"), + ] diff --git a/extensions/ots/message_configuration/signals.py b/extensions/ots/message_configuration/signals.py new file mode 100644 index 0000000000..e7a19eb412 --- /dev/null +++ b/extensions/ots/message_configuration/signals.py @@ -0,0 +1,219 @@ +from django.conf import settings +from django.dispatch import receiver +from django.utils.html import strip_tags + +from hypha.apply.activity.adapters.emails import EmailAdapter +from hypha.apply.activity.adapters.slack import SlackAdapter +from hypha.apply.activity.signals import message_hook +from hypha.home.models import ApplyHomePage + +from .models import MessagingSetting, MessagingSettings + + +def replace_settings_message_keywords(message, **kwargs): + # Because this is working in tandem with a templating system that is very forgiving of + # things being the wrong type or absent, the method we use for these replacements is + # to attempt to add them, and just not add each replacement if the information is + # not in kwargs or is wrong. + request = kwargs.get("request") + source = kwargs.get("source") + submission = kwargs.get("submission") + invoice = kwargs.get("invoice") + user = kwargs.get("user") + determination = kwargs.get("determination") + + replacements = [] + + # Submission from source based replacements + try: + replacements.extend( + [ + ( + "SUBMISSION_URL", + "%s://%s%s" + % (request.scheme, request.get_host(), source.get_absolute_url()), + ), + ("SUBMISSION_FUND_TITLE", source.page.title), + ("SUBMISSION_TITLE", source.title), + ("SUBMISSION_USER_NAME", source.user.get_full_name()), + ("SUBMISSION_USER_EMAIL", source.user.email), + ( + "SUBMISSION_CONFIRMATION_TEXT_EXTRA", + source.page.specific.confirmation_text_extra, + ), + ] + ) + except AttributeError: + pass + + # Submission from submission based replacements + try: + replacements.extend( + [ + ( + "SUBMISSION_URL", + "%s://%s%s" + % ( + request.scheme, + request.get_host(), + submission.get_absolute_url(), + ), + ), + ("SUBMISSION_FUND_TITLE", submission.page.title), + ("SUBMISSION_TITLE", submission.title), + ("SUBMISSION_USER_NAME", submission.user.get_full_name()), + ("SUBMISSION_USER_EMAIL", submission.user.email), + ( + "SUBMISSION_CONFIRMATION_TEXT_EXTRA", + submission.page.specific.confirmation_text_extra, + ), + ] + ) + except AttributeError: + pass + + # Determination based replacements + try: + replacements.extend( + [ + ( + "DETERMINATION_URL", + "%s://%s%s" + % ( + request.scheme, + request.get_host(), + determination.get_absolute_url(), + ), + ), + ("DETERMINATION_MESSAGE", strip_tags(determination.message)), + ("DETERMINATION_OUTCOME", determination.clean_outcome), + ] + ) + except AttributeError: + pass + + # Project based replacements + try: + replacements.extend( + [ + ("PROJECT_TITLE", source.title), + ( + "PROJECT_URL", + "%s://%s%s" + % (request.scheme, request.get_host(), source.get_absolute_url()), + ), + ( + "SUBMISSION_URL", + "%s://%s%s" + % ( + request.scheme, + request.get_host(), + source.submission.get_absolute_url(), + ), + ), + ("PROJECT_LEAD_EMAIL", source.lead.email), + ("PROJECT_LEAD_NAME", source.lead.get_full_name()), + ] + ) + except AttributeError: + pass + + # Invoice based replacements + try: + replacements.extend( + [ + ( + "INVOICE_URL", + "%s://%s%s" + % (request.scheme, request.get_host(), invoice.get_absolute_url()), + ), + ] + ) + except AttributeError: + pass + + try: + replacements.extend( + [ + ("ORG_EMAIL", settings.ORG_EMAIL), + ("ORG_SHORT_NAME", settings.ORG_SHORT_NAME), + ("ORG_LONG_NAME", settings.ORG_LONG_NAME), + ("ORG_URL", settings.ORG_URL), + ("ORG_GUIDE_URL", settings.ORG_GUIDE_URL), + ] + ) + except AttributeError: + pass + + try: + replacements.append(("USER_NAME", str(user))) + except AttributeError: + pass + + for old, new in replacements: + if new: + message = message.replace(old, new) + + return message + + +@receiver(message_hook, sender=EmailAdapter) +def handle_email_message_hook(sender, message_type, **kwargs): + site = ApplyHomePage.objects.first().get_site() + messaging_setting = MessagingSetting.objects.filter(site=site).first() + + if not messaging_setting: + return {} + + response = {"should_send": messaging_setting.email_default_send} + + try: + messaging_setting_for_type = messaging_setting.messaging_settings.get( + message_type=message_type + ) + + response["extra_kwargs"] = {"subject": messaging_setting_for_type.email_subject} + response["should_send"] = messaging_setting_for_type.email_enabled + + message = "" + + if messaging_setting_for_type.email_message: + header = messaging_setting.email_header + footer = messaging_setting.email_footer + + if header: + message = message + header + "\n" + message = message + messaging_setting_for_type.email_message + if footer: + message = message + "\n" + footer + "\n" + response["message"] = replace_settings_message_keywords(message, **kwargs) + + except MessagingSettings.DoesNotExist: + pass + + return response + + +@receiver(message_hook, sender=SlackAdapter) +def handle_slack_message_hook(sender, message_type, **kwargs): + site = ApplyHomePage.objects.first().get_site() + messaging_setting = MessagingSetting.objects.filter(site=site).first() + + if not messaging_setting: + return {} + + response = {"should_send": messaging_setting.slack_default_send} + + try: + messaging_setting_for_type = messaging_setting.messaging_settings.get( + message_type=message_type + ) + + response["should_send"] = messaging_setting_for_type.slack_enabled + response["message"] = replace_settings_message_keywords( + messaging_setting_for_type.slack_message or "", **kwargs + ) + except MessagingSettings.DoesNotExist: + pass + + return response diff --git a/extensions/ots/message_configuration/static/css/message_configuration_wagtail_admin.css b/extensions/ots/message_configuration/static/css/message_configuration_wagtail_admin.css new file mode 100644 index 0000000000..732d007fdb --- /dev/null +++ b/extensions/ots/message_configuration/static/css/message_configuration_wagtail_admin.css @@ -0,0 +1,5 @@ +.hidden, +.is-hidden, +%is-hidden { + display: none; +} diff --git a/extensions/ots/message_configuration/static/js/message_configuration_wagtail_admin.js b/extensions/ots/message_configuration/static/js/message_configuration_wagtail_admin.js new file mode 100644 index 0000000000..cefc4db58a --- /dev/null +++ b/extensions/ots/message_configuration/static/js/message_configuration_wagtail_admin.js @@ -0,0 +1,34 @@ +"use strict"; + +(function ($) { + function add_update_events() { + $(".message_type").each(function () { + var message_type = $(this); + var textarea = message_type + .siblings(".email_message") + .find("textarea"); + var select = message_type.find("select"); + if (!select.attr("evented")) { + select.attr("evented", true); + select.change(function () { + var message_id = $(this).val(); + var message = $( + ".messaging_help_panel [attr-email-id='" + + message_id + + "']" + ) + .text() + .trim(); + textarea.val(message); + }); + } + }); + } + + $(function () { + $("#id_messaging_settings-ADD").click(function () { + add_update_events(); + }); + add_update_events(); + }); +})(jQuery); diff --git a/extensions/ots/message_configuration/templates/messages/email_defaults/approve_invoice.html b/extensions/ots/message_configuration/templates/messages/email_defaults/approve_invoice.html new file mode 100644 index 0000000000..16335f40a9 --- /dev/null +++ b/extensions/ots/message_configuration/templates/messages/email_defaults/approve_invoice.html @@ -0,0 +1,9 @@ +{% load i18n %} +{% trans "An Invoice is waiting for your approval." %} + +{% trans "Title" %}: PROJECT_TITLE +{% trans "Link" %}: INVOICE_URL +{% trans "Project" %}: PROJECT_URL + +{% blocktrans %}Please contact PROJECT_LEAD_NAME - PROJECT_LEAD_EMAIL if you have any questions.{% endblocktrans %} + diff --git a/extensions/ots/message_configuration/templates/messages/email_defaults/approve_paf.html b/extensions/ots/message_configuration/templates/messages/email_defaults/approve_paf.html new file mode 100644 index 0000000000..4d8034bfc3 --- /dev/null +++ b/extensions/ots/message_configuration/templates/messages/email_defaults/approve_paf.html @@ -0,0 +1,8 @@ +{% load i18n %} +{% trans "A Project is awaiting your review." %} + +{% trans "Title" %}: PROJECT_TITLE +{% trans "Link" %}: PROJECT_URL +{% trans "Original Submission" %}: SUBMISSION_URL + +{% blocktrans %}Please contact PROJECT_LEAD_NAME - PROJECT_LEAD_EMAIL if you have any questions.{% endblocktrans %} diff --git a/extensions/ots/message_configuration/templates/messages/email_defaults/determination_outcome.html b/extensions/ots/message_configuration/templates/messages/email_defaults/determination_outcome.html new file mode 100644 index 0000000000..eaa10060de --- /dev/null +++ b/extensions/ots/message_configuration/templates/messages/email_defaults/determination_outcome.html @@ -0,0 +1,7 @@ +{% load i18n %} + +{% trans "Your application has been reviewed and the outcome is" %}: DETERMINATION_OUTCOME + +DETERMINATION_MESSAGE + +{% trans "Read the full determination here" %}: DETERMINATION_URL diff --git a/extensions/ots/message_configuration/templates/messages/email_defaults/draft_submission.html b/extensions/ots/message_configuration/templates/messages/email_defaults/draft_submission.html new file mode 100644 index 0000000000..729a2dc337 --- /dev/null +++ b/extensions/ots/message_configuration/templates/messages/email_defaults/draft_submission.html @@ -0,0 +1,16 @@ +{% load i18n %} +{% block content %}{% blocktrans %}We appreciate your SUBMISSION_TITLE application submission to the ORG_LONG_NAME.{% endblocktrans %} + + {% trans "Please note that it is not submitted for review because it's still in draft." %} {% trans "You can access the draft at" %}: SUBMISSION_URL + + {% trans "If you have any questions, please submit them here" %}: SUBMISSION_URL#communications + + {% blocktrans %}If you have issues accessing the submission system or general inquiries, please email us at ORG_EMAIL.{% endblocktrans %} + + {% blocktrans %}For more information about our support options, review process, and selection criteria, please visit our website at ORG_URL.{% endblocktrans %} + + SUBMISSION_CONFIRMATION_TEXT_EXTRA + + {% trans "Project name" %}: SUBMISSION_TITLE + {% trans "Contact name" %}: SUBMISSION_USER_NAME + {% trans "Contact email" %}: SUBMISSION_USER_EMAIL{% endblock %} diff --git a/extensions/ots/message_configuration/templates/messages/email_defaults/invited_to_proposal.html b/extensions/ots/message_configuration/templates/messages/email_defaults/invited_to_proposal.html new file mode 100644 index 0000000000..d48076f135 --- /dev/null +++ b/extensions/ots/message_configuration/templates/messages/email_defaults/invited_to_proposal.html @@ -0,0 +1,11 @@ +{% load i18n %} +{% blocktrans %}We’ve reviewed your Concept note and think it could be a good fit for ORG_SHORT_NAME funding. We would like to invite you to submit a Proposal with more details about your project. You will receive a second email linking to a determination message with detailed feedback.{% endblocktrans %} + +{% blocktrans %}Please review our Proposal Guide at ORG_GUIDE_URL to learn more about the information we’d like to see. In the proposal please also address the feedback we provided in the concept note determination.{% endblocktrans %} + +{% trans "Here is the link to start creating your proposal" %}: SUBMISSION_URL +{% trans "If you have any questions, please submit them here" %}: SUBMISSION_URL#communications + +{% blocktrans %}The system will allow you to save a draft of your proposal as you work on it. When you feel it is ready for our review, please click the “Submit” button and we’ll know to take a look at it. We’ll reply to you with feedback on your Proposal as quickly as possible.{% endblocktrans %} + +{% blocktrans %}If you have any issues accessing the submission system or other general inquiries, please email us at ORG_EMAIL{% endblocktrans %} diff --git a/extensions/ots/message_configuration/templates/messages/email_defaults/new_submission.html b/extensions/ots/message_configuration/templates/messages/email_defaults/new_submission.html new file mode 100644 index 0000000000..f18f6cbb19 --- /dev/null +++ b/extensions/ots/message_configuration/templates/messages/email_defaults/new_submission.html @@ -0,0 +1,17 @@ +{% load i18n %} +{% block content %}{% blocktrans %}We appreciate your SUBMISSION_TITLE application submission to the ORG_LONG_NAME.{% endblocktrans %} + + {% trans "We will review and reply to your submission as quickly as possible." %} + + {% trans "If you have any questions, please submit them here" %}: SUBMISSION_URL#communications + + {% blocktrans %}If you have issues accessing the submission system or general inquiries, please email us at ORG_EMAIL.{% endblocktrans %} + + {% blocktrans %}For more information about our support options, review process, and selection criteria, please visit our website at ORG_URL.{% endblocktrans %} + + SUBMISSION_CONFIRMATION_TEXT_EXTRA + + {% trans "Project name" %}: SUBMISSION_TITLE + {% trans "Contact name" %}: SUBMISSION_USER_NAME + {% trans "Contact email" %}: SUBMISSION_USER_EMAIL{% endblock %} + diff --git a/extensions/ots/message_configuration/templates/messages/email_defaults/ready_for_review.html b/extensions/ots/message_configuration/templates/messages/email_defaults/ready_for_review.html new file mode 100644 index 0000000000..de9d32234e --- /dev/null +++ b/extensions/ots/message_configuration/templates/messages/email_defaults/ready_for_review.html @@ -0,0 +1,6 @@ +{% load i18n %} + +{% trans "This application is awaiting your review." %} + +{% trans "Title" %}: SUBMISSION_TITLE +{% trans "Link" %}: SUBMISSION_URL diff --git a/extensions/ots/message_configuration/templates/messages/email_defaults/review_reminder.html b/extensions/ots/message_configuration/templates/messages/email_defaults/review_reminder.html new file mode 100644 index 0000000000..de9d32234e --- /dev/null +++ b/extensions/ots/message_configuration/templates/messages/email_defaults/review_reminder.html @@ -0,0 +1,6 @@ +{% load i18n %} + +{% trans "This application is awaiting your review." %} + +{% trans "Title" %}: SUBMISSION_TITLE +{% trans "Link" %}: SUBMISSION_URL diff --git a/extensions/ots/message_configuration/templates/messages/email_defaults/reviewers_updated.html b/extensions/ots/message_configuration/templates/messages/email_defaults/reviewers_updated.html new file mode 100644 index 0000000000..de9d32234e --- /dev/null +++ b/extensions/ots/message_configuration/templates/messages/email_defaults/reviewers_updated.html @@ -0,0 +1,6 @@ +{% load i18n %} + +{% trans "This application is awaiting your review." %} + +{% trans "Title" %}: SUBMISSION_TITLE +{% trans "Link" %}: SUBMISSION_URL diff --git a/extensions/ots/message_configuration/templates/messaging_help.html b/extensions/ots/message_configuration/templates/messaging_help.html new file mode 100644 index 0000000000..3417e66698 --- /dev/null +++ b/extensions/ots/message_configuration/templates/messaging_help.html @@ -0,0 +1,53 @@ +{% load i18n %} + +
+ {% trans "Here you can configure message templates for different messages hypha sends out. You can configure the footer and header (which will apepar on each email), as we well as configure whether hypha sends out messages by default." %} +
++ {% trans "Click 'Add' at the bottom to configure a template for an outgoing message type." %} +
++ {% trans "Variables that will get replaced follow. Use the uppercase name (before the colon) in any subject, email message, or slack message." %} +
+ +{% trans "When the submission is available, the following are available:" %}
+ +{% trans "When the determination is the subject of the email, the following are also available:" %}
+{% trans "When a project is the subject of the email, the following are also available:" %}
+{% trans "When an invoice is the subject of the email, the following are also available:" %}
+{% trans "The following system variables are always available:" %}
+