Skip to content

Commit

Permalink
Merge branch 'develop' into 9573-configbaker
Browse files Browse the repository at this point in the history
  • Loading branch information
poikilotherm committed May 9, 2023
2 parents ceddf70 + bfa012e commit 36a43ac
Show file tree
Hide file tree
Showing 26 changed files with 440 additions and 382 deletions.
21 changes: 21 additions & 0 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version: 2

# HTML is always built, these are additional formats only
formats:
- pdf

build:
os: ubuntu-22.04
tools:
python: "3.10"
apt_packages:
- graphviz

python:
install:
- requirements: doc/sphinx-guides/requirements.txt


sphinx:
configuration: doc/sphinx-guides/source/conf.py
fail_on_warning: true
3 changes: 3 additions & 0 deletions doc/release-notes/9100-schema.org-updates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Changes made in v5.13 and v5.14 in multiple PRs to improve the embedded Schema.org metadata in dataset pages will only be propagated to the Schema.Org JSON-LD metadata export if a reExportAll() is done.

The 5.14 release notes should include the standard instructions for doing a reExportAll after updating the code.
12 changes: 12 additions & 0 deletions doc/release-notes/9185-contact-email-updates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## Contact Email Improvements

Email sent from the contact forms to the contact(s) for a collection, dataset, or datafile can now optionally be cc'd to a support email address. The support email address can be changed from the default :SystemEmail address to a separate :SupportEmail address. When multiple contacts are listed, the system will now send one email to all contacts (with the optional cc if configured) instead of separate emails to each contact. Contact names with a comma that refer to Organizations will no longer have the name parts reversed in the email greeting. A new protected feedback API has been added.

## Backward Incompatibilities

When there are multiple contacts, the system will now send one email with all of the contacts in the To: header instead of sending one email to each contact (with no indication that others have been notified).

## New JVM/MicroProfile Settings

dataverse.mail.support-email - allows a separate email, distinct from the :SystemEmail to be used as the to address in emails from the contact form/ feedback api.
dataverse.mail.cc-support-on-contact-emails - include the support email address as a CC: entry when contact/feedback emails are sent to the contacts for a collection, dataset, or datafile.
30 changes: 30 additions & 0 deletions doc/sphinx-guides/source/api/native-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1618,6 +1618,8 @@ The fully expanded example above (without environment variables) looks like this
The people who need to review the dataset (often curators or journal editors) can check their notifications periodically via API to see if any new datasets have been submitted for review and need their attention. See the :ref:`Notifications` section for details. Alternatively, these curators can simply check their email or notifications to know when datasets have been submitted (or resubmitted) for review.

.. _return-a-dataset:

Return a Dataset to Author
~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -1645,6 +1647,8 @@ The fully expanded example above (without environment variables) looks like this
The review process can sometimes resemble a tennis match, with the authors submitting and resubmitting the dataset over and over until the curators are satisfied. Each time the curators send a "reason for return" via API, that reason is persisted into the database, stored at the dataset version level.

The :ref:`send-feedback` API call may be useful as a way to move the conversation to email. However, note that these emails go to contacts (versus authors) and there is no database record of the email contents. (:ref:`dataverse.mail.cc-support-on-contact-email` will send a copy of these emails to the support email address which would provide a record.)

Link a Dataset
~~~~~~~~~~~~~~

Expand Down Expand Up @@ -4497,3 +4501,29 @@ A curl example using allowing access to a dataset's metadata
Please see :ref:`dataverse.api.signature-secret` for the configuration option to add a shared secret, enabling extra
security.
.. _send-feedback:
Send Feedback To Contact(s)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
This API call allows sending an email to the contacts for a collection, dataset, or datafile or to the support email address when no object is specified.
The call is protected by the normal /admin API protections (limited to localhost or requiring a separate key), but does not otherwise limit the sending of emails.
Administrators should be sure only trusted applications have access to avoid the potential for spam.
The call is a POST with a JSON object as input with four keys:
- "targetId" - the id of the collection, dataset, or datafile. Persistent ids and collection aliases are not supported. (Optional)
- "subject" - the email subject line
- "body" - the email body to send
- "fromEmail" - the email to list in the reply-to field. (Dataverse always sends mail from the system email, but does it "on behalf of" and with a reply-to for the specified user.)
A curl example using an ``ID``
.. code-block:: bash
export SERVER_URL=http://localhost
export JSON='{"targetId":24, "subject":"Data Question", "body":"Please help me understand your data. Thank you!", "fromEmail":"dataverseSupport@mailinator.com"}'
curl -X POST -H 'Content-Type:application/json' -d "$JSON" $SERVER_URL/api/admin/feedback
Note that this call could be useful in coordinating with dataset authors (assuming they are also contacts) as an alternative/addition to the functionality provided by :ref:`return-a-dataset`.
22 changes: 22 additions & 0 deletions doc/sphinx-guides/source/installation/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2349,6 +2349,27 @@ See :ref:`discovery-sign-posting` for details.

Can also be set via any `supported MicroProfile Config API source`_, e.g. the environment variable ``DATAVERSE_SIGNPOSTING_LEVEL1_ITEM_LIMIT``.

dataverse.mail.support-email
++++++++++++++++++++++++++++

This provides an email address distinct from the :ref:`systemEmail` that will be used as the email address for Contact Forms and Feedback API. This address is used as the To address when the Contact form is launched from the Support entry in the top navigation bar and, if configured via :ref:`dataverse.mail.cc-support-on-contact-email`, as a CC address when the form is launched from a Dataverse/Dataset Contact button.
This allows configuration of a no-reply email address for :ref:`systemEmail` while allowing feedback to go to/be cc'd to the support email address, which would normally accept replies. If not set, the :ref:`systemEmail` is used for the feedback API/contact form email.

Note that only the email address is required, which you can supply without the ``<`` and ``>`` signs, but if you include the text, it's the way to customize the name of your support team, which appears in the "from" address in emails as well as in help text in the UI. If you don't include the text, the installation name (see :ref:`Branding Your Installation`) will appear in the "from" address.

Can also be set via any `supported MicroProfile Config API source`_, e.g. the environment variable ``DATAVERSE_MAIL_SUPPORT_EMAIL``.

.. _dataverse.mail.cc-support-on-contact-email:

dataverse.mail.cc-support-on-contact-email
++++++++++++++++++++++++++++++++++++++++++

If this setting is true, the contact forms and feedback API will cc the system (:SupportEmail if set, :SystemEmail if not) when sending email to the collection, dataset, or datafile contacts.
A CC line is added to the contact form when this setting is true so that users are aware that the cc will occur.
The default is false.

Can also be set via *MicroProfile Config API* sources, e.g. the environment variable ``DATAVERSE_MAIL_CC_SUPPORT_ON_CONTACT_EMAIL``.


.. _feature-flags:

Expand Down Expand Up @@ -3831,3 +3852,4 @@ A true(default)/false option determining whether datafiles listed on the dataset
A true/false (default) option determining whether the dataset datafile table display includes checkboxes enabling users to turn folder ordering and/or category ordering (if an order is defined by :CategoryOrder) on and off dynamically.

.. _supported MicroProfile Config API source: https://docs.payara.fish/community/docs/Technical%20Documentation/MicroProfile/Config/Overview.html

49 changes: 4 additions & 45 deletions src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,37 +81,6 @@ public class MailServiceBean implements java.io.Serializable {
public MailServiceBean() {
}

public void sendMail(String host, String reply, String to, String subject, String messageText) {
Properties props = System.getProperties();
props.put("mail.smtp.host", host);
Session session = Session.getDefaultInstance(props, null);

try {
MimeMessage msg = new MimeMessage(session);
String[] recipientStrings = to.split(",");
InternetAddress[] recipients = new InternetAddress[recipientStrings.length];
try {
InternetAddress fromAddress = getSystemAddress();
setContactDelegation(reply, fromAddress);
msg.setFrom(fromAddress);
msg.setReplyTo(new Address[] {new InternetAddress(reply, charset)});
for (int i = 0; i < recipients.length; i++) {
recipients[i] = new InternetAddress(recipientStrings[i], "", charset);
}
} catch (UnsupportedEncodingException ex) {
logger.severe(ex.getMessage());
}
msg.setRecipients(Message.RecipientType.TO, recipients);
msg.setSubject(subject, charset);
msg.setText(messageText, charset);
Transport.send(msg, recipients);
} catch (AddressException ae) {
ae.printStackTrace(System.out);
} catch (MessagingException me) {
me.printStackTrace(System.out);
}
}

@Resource(name = "mail/notifyMailSession")
private Session session;

Expand Down Expand Up @@ -177,11 +146,7 @@ public InternetAddress getSystemAddress() {
}

//@Resource(name="mail/notifyMailSession")
public void sendMail(String from, String to, String subject, String messageText) {
sendMail(from, to, subject, messageText, new HashMap<>());
}

public void sendMail(String reply, String to, String subject, String messageText, Map<Object, Object> extraHeaders) {
public void sendMail(String reply, String to, String cc, String subject, String messageText) {
try {
MimeMessage msg = new MimeMessage(session);
// Always send from system address to avoid email being blocked
Expand All @@ -202,18 +167,12 @@ public void sendMail(String reply, String to, String subject, String messageText
msg.setSentDate(new Date());
msg.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(to, false));
if (cc != null) {
msg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(cc, false));
}
msg.setSubject(subject, charset);
msg.setText(messageText, charset);

if (extraHeaders != null) {
for (Object key : extraHeaders.keySet()) {
String headerName = key.toString();
String headerValue = extraHeaders.get(key).toString();

msg.addHeader(headerName, headerValue);
}
}

Transport.send(msg);
} catch (AddressException ae) {
ae.printStackTrace(System.out);
Expand Down
55 changes: 37 additions & 18 deletions src/main/java/edu/harvard/iq/dataverse/SendFeedbackDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import edu.harvard.iq.dataverse.branding.BrandingUtil;
import edu.harvard.iq.dataverse.feedback.Feedback;
import edu.harvard.iq.dataverse.feedback.FeedbackUtil;
import edu.harvard.iq.dataverse.settings.JvmSettings;
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
import edu.harvard.iq.dataverse.util.BundleUtil;
import edu.harvard.iq.dataverse.util.MailUtil;
import edu.harvard.iq.dataverse.util.SystemConfig;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.logging.Logger;
import javax.ejb.EJB;
Expand Down Expand Up @@ -62,7 +63,7 @@ public class SendFeedbackDialog implements java.io.Serializable {
* Either the dataverse or the dataset that the message is pertaining to. If
* there is no recipient, this is a general feedback message.
*/
private DvObject recipient;
private DvObject feedbackTarget;

/**
* :SystemEmail (the main support address for an installation).
Expand Down Expand Up @@ -97,11 +98,11 @@ public void initUserInput(ActionEvent ae) {
userMessage = "";
messageSubject = "";
Random random = new Random();
op1 = new Long(random.nextInt(10));
op2 = new Long(random.nextInt(10));
op1 = Long.valueOf(random.nextInt(10));
op2 = Long.valueOf(random.nextInt(10));
userSum = null;
String systemEmail = settingsService.getValueForKey(SettingsServiceBean.Key.SystemEmail);
systemAddress = MailUtil.parseSystemAddress(systemEmail);
String supportEmail = JvmSettings.SUPPORT_EMAIL.lookupOptional().orElse(settingsService.getValueForKey(SettingsServiceBean.Key.SystemEmail));
systemAddress = MailUtil.parseSystemAddress(supportEmail);
}

public Long getOp1() {
Expand Down Expand Up @@ -129,19 +130,27 @@ public void setUserSum(Long userSum) {
}

public String getMessageTo() {
if (recipient == null) {
if (feedbackTarget == null) {
return BrandingUtil.getSupportTeamName(systemAddress);
} else if (recipient.isInstanceofDataverse()) {
return ((Dataverse) recipient).getDisplayName() + " " + BundleUtil.getStringFromBundle("contact.contact");
} else if (feedbackTarget.isInstanceofDataverse()) {
return ((Dataverse) feedbackTarget).getDisplayName() + " " + BundleUtil.getStringFromBundle("contact.contact");
} else {
return BundleUtil.getStringFromBundle("dataset") + " " + BundleUtil.getStringFromBundle("contact.contact");
}
}

public String getMessageCC() {
if (ccSupport()) {
return BrandingUtil.getSupportTeamName(systemAddress);
}
return null;
}


public String getFormHeader() {
if (recipient == null) {
if (feedbackTarget == null) {
return BrandingUtil.getContactHeader(systemAddress);
} else if (recipient.isInstanceofDataverse()) {
} else if (feedbackTarget.isInstanceofDataverse()) {
return BundleUtil.getStringFromBundle("contact.dataverse.header");
} else {
return BundleUtil.getStringFromBundle("contact.dataset.header");
Expand Down Expand Up @@ -173,11 +182,11 @@ public String loggedInUserEmail() {
}

public DvObject getRecipient() {
return recipient;
return feedbackTarget;
}

public void setRecipient(DvObject recipient) {
this.recipient = recipient;
this.feedbackTarget = recipient;
}

public void validateUserSum(FacesContext context, UIComponent component, Object value) throws ValidatorException {
Expand All @@ -200,16 +209,26 @@ public void validateUserEmail(FacesContext context, UIComponent component, Objec
public String sendMessage() {
String installationBrandName = BrandingUtil.getInstallationBrandName();
String supportTeamName = BrandingUtil.getSupportTeamName(systemAddress);
List<Feedback> feedbacks = FeedbackUtil.gatherFeedback(recipient, dataverseSession, messageSubject, userMessage, systemAddress, userEmail, systemConfig.getDataverseSiteUrl(), installationBrandName, supportTeamName);
if (feedbacks.isEmpty()) {

Feedback feedback = FeedbackUtil.gatherFeedback(feedbackTarget, dataverseSession, messageSubject, userMessage, systemAddress, userEmail, systemConfig.getDataverseSiteUrl(), installationBrandName, supportTeamName, ccSupport());
if (feedback==null) {
logger.warning("No feedback has been sent!");
return null;
}
for (Feedback feedback : feedbacks) {
logger.fine("sending feedback: " + feedback);
mailService.sendMail(feedback.getFromEmail(), feedback.getToEmail(), feedback.getSubject(), feedback.getBody());
}
mailService.sendMail(feedback.getFromEmail(), feedback.getToEmail(), feedback.getCcEmail(), feedback.getSubject(), feedback.getBody());
return null;
}

public boolean ccSupport() {
return ccSupport(feedbackTarget);
}

public static boolean ccSupport(DvObject feedbackTarget) {
//Setting is enabled and this isn't already a direct message to support (no feedbackTarget)
Optional<Boolean> ccSupport = JvmSettings.CC_SUPPORT_ON_CONTACT_EMAIL.lookupOptional(Boolean.class);

return feedbackTarget!=null && ccSupport.isPresent() &&ccSupport.get();
}

}

0 comments on commit 36a43ac

Please sign in to comment.