Skip to content

Commit

Permalink
Feature/email on submission approval (#1255)
Browse files Browse the repository at this point in the history
* approve add dialog

* approval function

* set submission doc approval properties

* init WIP todo generate approval mail function in implementation

* reference

* Add submission_accepted email template and mail generator

* Set submission accept generator in mail notification implementation

* typo

* note
  • Loading branch information
alexgao1 authored Jan 7, 2025
1 parent c313040 commit c402b8c
Show file tree
Hide file tree
Showing 12 changed files with 354 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ textarea.submission_deny_dialog_reason {
margin-bottom: 5px;
}

textarea.submission_approve_dialog_message {
width: 460px;
height: 125px;
}

.submission_approve_dialog_options {
margin-top: 5px;
margin-bottom: 5px;
}

span.patchSelected, div.patchSelected {
font-weight: bold;
color: #00ff00;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,45 +278,128 @@
});
}

,_approve: function(subDocId, approvedDoc){
,_approve: function(subDocId, approvedDoc, approveFn){
var _this = this;

this._getSubmissionDocument({
subDocId: subDocId
,onSuccess: function(subDoc){
subDoc.nunaliit_submission.state = 'approved';
$n2.couchDocument.adjustDocument(subDoc);

if( approvedDoc ){
subDoc.nunaliit_submission.approved_doc = {};
subDoc.nunaliit_submission.approved_reserved = {};
for(var key in approvedDoc){
if( key.length > 0 && key[0] === '_' ) {
var effectiveKey = key.substr(1);
subDoc.nunaliit_submission.approved_reserved[effectiveKey] =
approvedDoc[key];
} else {
subDoc.nunaliit_submission.approved_doc[key] =
approvedDoc[key];
collectApprovalMessage(function(message, sendEmail) {
_this._getSubmissionDocument({
subDocId: subDocId
,onSuccess: function(subDoc){
subDoc.nunaliit_submission.state = 'approved';
$n2.couchDocument.adjustDocument(subDoc);

if( approvedDoc ){

if (message && message !== '') {
subDoc.nunaliit_submission.approval_message = message;
}

if (sendEmail) {
subDoc.nunaliit_submission.approval_email = {
requested: true
}
}

subDoc.nunaliit_submission.approved_doc = {};
subDoc.nunaliit_submission.approved_reserved = {};
for(var key in approvedDoc){
if( key.length > 0 && key[0] === '_' ) {
var effectiveKey = key.substr(1);
subDoc.nunaliit_submission.approved_reserved[effectiveKey] =
approvedDoc[key];
} else {
subDoc.nunaliit_submission.approved_doc[key] =
approvedDoc[key];
};
};
};
};

_this.submissionDb.updateDocument({
data: subDoc
,onSuccess: function(docInfo){
_this.logger.log( _loc('Submission approved') );
_this._refreshSubmissions();
}
,onError: function(err){
_this.logger.error( _loc('Unable to update submission document: {err}',{err:err}) );
}

_this.submissionDb.updateDocument({
data: subDoc
,onSuccess: function(docInfo){
_this.logger.log( _loc('Submission approved') );
if( typeof approveFn === 'function' ){
approveFn();
};
_this._refreshSubmissions();
}
,onError: function(err){
_this.logger.error( _loc('Unable to update submission document: {err}',{err:err}) );
}
});
}
,onError: function(err){
_this.logger.error( _loc('Unable to obtain submission document: {err}',{err:err}) );
}
});
})

function collectApprovalMessage(callback, sendEmail){
var diagId = $n2.getUniqueId();
var $diag = $('<div>')
.attr('id',diagId)
.addClass('submission_approve_dialog')
.appendTo( $('body') );

$('<textarea>')
.addClass('submission_approve_dialog_message')
.appendTo($diag);

var $options = $('<div>')
.addClass('submission_approve_dialog_options')
.appendTo($diag);

var cbId = $n2.getUniqueId();
$('<input type="checkbox">')
.attr('id',cbId)
.attr('name','send_email')
.appendTo($options);
$('<label>')
.attr('for',cbId)
.text( _loc('Send e-mail to submitter with message') )
.appendTo($options);

var $buttons = $('<div>')
.addClass('submission_approve_dialog_buttons')
.appendTo($diag);

$('<button>')
.addClass('n2_button_ok')
.text( _loc('OK') )
.appendTo($buttons)
.click(function(){
var $diag = $('#'+diagId);

var comment = $diag.find('textarea.submission_approve_dialog_message').val();
var email = $diag.find('input[name="send_email"]').is(':checked');

$diag.dialog('close');
if( typeof callback === 'function' ){
callback(comment,email);
};
});
}
,onError: function(err){
_this.logger.error( _loc('Unable to obtain submission document: {err}',{err:err}) );
}
});

$('<button>')
.addClass('n2_button_cancel')
.text( _loc('Cancel') )
.appendTo($buttons)
.click(function(){
var $diag = $('#'+diagId);
$diag.dialog('close');
});

$diag.dialog({
autoOpen: true
,title: _loc('Enter approval message')
,modal: true
,width: 'auto'
,close: function(event, ui){
var diag = $(event.target);
diag.dialog('destroy');
diag.remove();
}
});
}
}

,_deny: function(subDocId, onDeniedFn){
Expand Down Expand Up @@ -1013,9 +1096,10 @@
.text( _loc('Approve') )
.appendTo($buttons)
.click(function(){
_this._approve(subDocId, proposedDoc);
var $diag = $('#'+diagId);
$diag.dialog('close');
_this._approve(subDocId, proposedDoc, function() {
var $diag = $('#'+diagId);
$diag.dialog('close');
});
return false;
});
$('<button>')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import ca.carleton.gcrc.couch.submission.mail.SubmissionMailNotifierImpl;
import ca.carleton.gcrc.couch.submission.mail.SubmissionMailNotifierNull;
import ca.carleton.gcrc.couch.submission.mail.SubmissionRejectionGenerator;
import ca.carleton.gcrc.couch.submission.mail.SubmissionAcceptedGenerator;
import ca.carleton.gcrc.couch.submission.SubmissionConstants;
import ca.carleton.gcrc.couch.user.UserDesignDocumentImpl;
import ca.carleton.gcrc.couch.user.UserServlet;
Expand Down Expand Up @@ -618,6 +619,15 @@ private void initMail(ServletContext servletContext) throws ServletException {
);
submissionNotifier.setDocumentCreatedGenerator(couchdbTemplate);
}
{
MailMessageGenerator template = new SubmissionAcceptedGenerator();
CouchDbTemplateMailMessageGenerator couchdbTemplate = new CouchDbTemplateMailMessageGenerator(
documentDatabase,
"org.nunaliit.email_template.submission_accepted",
template
);
submissionNotifier.setSubmissionAcceptedGenerator(couchdbTemplate);
}

mailNotification = mail;
this.submissionNotifier = submissionNotifier;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.nunaliit.email_template.submission_accepted
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<html>
<head>
<title>Submission Approved</title>
</head>
<body>
<h1>Submission Approved</h1>
<p>Your submission was approved and is now available in the atlas.</p>
{{#approvalMessage}}
<p>{{approvalMessage}}</p>
{{/approvalMessage}}
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Submission Approved - {{#submissionDocId}}{{.}}{{/submissionDocId}}{{^submissionDocId}}<unknown>{{/submissionDocId}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
email_template
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,17 @@ public void performWork(String submissionDocId) throws Exception {
}
}

boolean sendApprovalEmail = false;
JSONObject approvalEmail = submissionInfo.optJSONObject("approval_email");
if (null != approvalEmail) {
boolean requested = approvalEmail.optBoolean("requested", false);
boolean sent = approvalEmail.optBoolean("sent", false);

if (requested && !sent) {
sendApprovalEmail = true;
}
}

// Get document in document database
CouchDb documentDb = documentDbDesignDocument.getDatabase();
JSONObject currentDoc = null;
Expand All @@ -232,6 +243,9 @@ public void performWork(String submissionDocId) throws Exception {
performSubmittedWork(submissionDoc, currentDoc);

} else if( "approved".equals(stateStr) ) {
if (sendApprovalEmail) {
performApprovalEmail(submissionDoc, currentDoc);
}
performApprovedWork(submissionDoc, currentDoc);

} else if( sendDenialEmail ) {
Expand Down Expand Up @@ -508,6 +522,83 @@ public void performDenialEmail(JSONObject submissionDoc, JSONObject currentDoc)
submissionDb.updateDocument(submissionDoc);
}

public void performApprovalEmail(JSONObject submissionDoc, JSONObject currentDoc) throws Exception {
JSONObject submissionInfo = submissionDoc.getJSONObject("nunaliit_submission");
JSONObject approval_email = submissionInfo.getJSONObject("approval_email");

// Find user that submitted the update
String userId = submissionInfo.optString("submitter_name", null);

// Get user document
CouchUserDocContext userDocContext = null;
if (null != userId) {
try {
userDocContext = userDb.getUserFromName(userId);
} catch (Exception e) {
// Ignore if we can not find user
}
}

// Get list of e-mails
List<String> emails = new Vector<String>();
String userName = null;
if (null != userDocContext) {
JSONObject userDoc = userDocContext.getUserDoc();

Set<String> validatedEmails = new HashSet<String>();
JSONArray jsonValidated = userDoc.optJSONArray("nunaliit_validated_emails");
if (null != jsonValidated) {
for (int i = 0; i < jsonValidated.length(); ++i) {
String email = jsonValidated.getString(i);
validatedEmails.add(email);
}
}

JSONArray jsonEmails = userDoc.optJSONArray("nunaliit_emails");
if (null != jsonEmails) {
for (int i = 0; i < jsonEmails.length(); ++i) {
String email = jsonEmails.getString(i);
if (validatedEmails.contains(email)) {
emails.add(email);
}
}
}

userName = userDoc.optString("display", null);
if (null == userName) {
userName = userDoc.optString("name", null);
}
}

// If no e-mails, just quit
if (emails.size() < 1) {
CouchDb submissionDb = submissionDbDesignDocument.getDatabase();
approval_email.put("sent", true);
submissionDb.updateDocument(submissionDoc);
return;
}

// Convert e-mail addresses into recipient
List<MailRecipient> recipients = new ArrayList<MailRecipient>(emails.size());
for (String email : emails) {
MailRecipient recipient = null;
if (null != userName) {
recipient = new MailRecipient(email, userName);
} else {
recipient = new MailRecipient(email);
}
recipients.add(recipient);
}

// Send notification
mailNotifier.sendSubmissionApprovalNotification(submissionDoc, recipients);

// Remember it was sent
CouchDb submissionDb = submissionDbDesignDocument.getDatabase();
approval_email.put("sent", true);
submissionDb.updateDocument(submissionDoc);
}

public void sendDocumentCreatedEmail(JSONObject submissionDoc, JSONObject currentDoc) throws Exception {
JSONObject submissionInfo = submissionDoc.getJSONObject("nunaliit_submission");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package ca.carleton.gcrc.couch.submission.mail;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;

import ca.carleton.gcrc.mail.MailMessage;
import ca.carleton.gcrc.mail.messageGenerator.MailMessageGenerator;

public class SubmissionAcceptedGenerator implements MailMessageGenerator {

@Override
public void generateMessage(
MailMessage message,
Map<String, String> parameters) throws Exception {

String submissionDocId = parameters.get("submissionDocId");
String approvalMessage = parameters.get("approvalMessage");

if (null == submissionDocId) {
message.setSubject("Submission Approved - <unknown>");
} else {
message.setSubject("Submission Approved - " + submissionDocId);
}

StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println("<html><head><title>Submission Approved</title></head><body><h1>Submission Approved</h1>");
pw.println("<p>Your submission was approved and is now available in the atlas.</p>");
if (null != approvalMessage) {
pw.println("<p>" + approvalMessage + "</p>");
}
pw.println("</body></html>");
pw.flush();
message.setHtmlContent(sw.toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public interface SubmissionMailNotifier {
void sendSubmissionWaitingForApprovalNotification(JSONObject submissionDoc) throws Exception;

void sendSubmissionRejectionNotification(JSONObject submissionDoc, List<MailRecipient> recipients) throws Exception;


void sendSubmissionApprovalNotification(JSONObject submissionDoc, List<MailRecipient> recipients) throws Exception;

void sendDocumentCreatedNotification(JSONObject submissionDb, UserDocument currentUser) throws Exception;
}
Loading

0 comments on commit c402b8c

Please sign in to comment.