Skip to content

Commit

Permalink
Refactoing in prep for inquiry mailing.
Browse files Browse the repository at this point in the history
  • Loading branch information
jannistsiroyannis committed Nov 17, 2023
1 parent 1b8caa7 commit b9e0639
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package whelk.housekeeping

import groovy.transform.CompileStatic
import groovy.util.logging.Log4j2
import whelk.Whelk

import java.sql.Connection
import java.sql.PreparedStatement
import java.sql.ResultSet
import java.sql.Timestamp
import java.time.Instant
import java.time.ZoneOffset
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit

@CompileStatic
@Log4j2
class InquirySender extends HouseKeeper {
private final String STATE_KEY = "CXZ inquiry email sender"
private String status = "OK"
private final Whelk whelk

public InquirySender(Whelk whelk) {
this.whelk = whelk
}

@Override
String getName() {
return "Inquiry sender"
}

@Override
String getStatusDescription() {
return status
}

public String getCronSchedule() {
return "* * * * *"
}

@Override
void trigger() {

Timestamp from = Timestamp.from(Instant.now().minus(1, ChronoUnit.DAYS))
Map sendState = whelk.getStorage().getState(STATE_KEY)
if (sendState && sendState.notifiedChangesUpTo)
from = Timestamp.from( ZonedDateTime.parse( (String) sendState.notifiedChangesUpTo, DateTimeFormatter.ISO_OFFSET_DATE_TIME).toInstant() )

Connection connection
PreparedStatement statement
ResultSet resultSet

Instant notifiedChangesUpTo = from.toInstant()

connection = whelk.getStorage().getOuterConnection()
connection.setAutoCommit(false)
try {
String sql = "SELECT modified, data FROM lddb WHERE data#>>'{@graph,1,@type}' IN ('InquiryAction', 'ChangeNotice') AND modified > ?;"
connection.setAutoCommit(false)
statement = connection.prepareStatement(sql)
statement.setTimestamp(1, from)
statement.setFetchSize(512)
resultSet = statement.executeQuery()

while (resultSet.next()) {
String data = resultSet.getString("data")

// TODO: Send email!

Instant lastChangeObservationForInstance = resultSet.getTimestamp("modified").toInstant()
if (lastChangeObservationForInstance.isAfter(notifiedChangesUpTo))
notifiedChangesUpTo = lastChangeObservationForInstance
}
} catch (Throwable e) {
status = "Failed with:\n" + e + "\nat:\n" + e.getStackTrace().toString()
throw e
} finally {
connection.close()
if (notifiedChangesUpTo.isAfter(from.toInstant())) {
Map newState = new HashMap()
newState.notifiedChangesUpTo = notifiedChangesUpTo.atOffset(ZoneOffset.UTC).toString()
whelk.getStorage().putState(STATE_KEY, newState)
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,9 @@ class NotificationSender extends HouseKeeper {
private final String STATE_KEY = "CXZ notification email sender"
private String status = "OK"
private final Whelk whelk
private final Mailer mailer
private final String senderAddress

public NotificationSender(Whelk whelk) {
this.whelk = whelk
Properties props = PropertyLoader.loadProperties("secret")
if (props.containsKey("smtpServer") &&
props.containsKey("smtpPort") &&
props.containsKey("smtpSender") &&
props.containsKey("smtpUser") &&
props.containsKey("smtpPassword"))
mailer = MailerBuilder
.withSMTPServer(
(String) props.get("smtpServer"),
Integer.parseInt((String)props.get("smtpPort")),
(String) props.get("smtpUser"),
(String) props.get("smtpPassword")
).buildMailer()
senderAddress = props.get("smtpSender")
}

@Override
Expand All @@ -68,26 +52,7 @@ class NotificationSender extends HouseKeeper {

@Override
void trigger() {
// Build a multi-map of library -> list of settings objects for that library's users
Map<String, List<Map>> heldByToUserSettings = new HashMap<>();
{
List<Map> allUserSettingStrings = whelk.getStorage().getAllUserData()
for (Map settings : allUserSettingStrings) {
if (!settings["notificationEmail"])
continue
settings?.requestedNotifications?.each { request ->
if (!request instanceof Map)
return
if (!request["heldBy"])
return

String heldBy = request["heldBy"]
if (!heldByToUserSettings.containsKey(heldBy))
heldByToUserSettings.put(heldBy, [])
heldByToUserSettings[heldBy].add(settings)
}
}
}
Map<String, List<Map>> heldByToUserSettings = NotificationUtils.getAllSubscribingUsers(whelk)

// Determine the time interval of ChangeObservations to consider
Timestamp from = Timestamp.from(Instant.now().minus(1, ChronoUnit.DAYS)) // Default to last 24h if first time.
Expand Down Expand Up @@ -177,9 +142,7 @@ class NotificationSender extends HouseKeeper {

if (!matchedObservations.isEmpty() && user.notificationEmail && user.notificationEmail instanceof String) {
String body = generateEmailBody(instanceId, matchedObservations)
sendEmail(senderAddress, (String) user.notificationEmail, "CXZ", body)

System.err.println("Now send email to " + user.notificationEmail + "\n\t" + body)
NotificationUtils.sendEmail((String) user.notificationEmail, "CXZ", body)
}
}
}
Expand All @@ -199,22 +162,6 @@ class NotificationSender extends HouseKeeper {
return null
}

private void sendEmail(String sender, String recipient, String subject, String body) {
if (mailer) {
Email email = EmailBuilder.startingBlank()
.to(recipient)
.withSubject(subject)
.from(sender)
.withPlainText(body)
.buildEmail()

log.info("Sending notification (cxz) email to " + recipient)
mailer.sendMail(email)
} else {
log.info("Should now have sent notification (cxz) email to " + recipient + " but SMTP is not configured.")
}
}

private String generateEmailBody(String changedInstanceId, List<Map> triggeredObservations) {

Document current = whelk.getStorage().load(changedInstanceId)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package whelk.housekeeping

import groovy.transform.CompileStatic
import groovy.util.logging.Log4j2
import org.simplejavamail.api.email.Email
import org.simplejavamail.api.mailer.Mailer
import org.simplejavamail.email.EmailBuilder
import org.simplejavamail.mailer.MailerBuilder
import whelk.Whelk
import whelk.util.PropertyLoader

@CompileStatic
@Log4j2
class NotificationUtils {

/**
* Get all user settings and arrange them by requested library-uri, so that you
* might for example start with a uri https://libris.kb.se/library/Utb1 and from it
* get a list of user(-settings)s that subscribes to updates for things held by
* that library
*/
static Map<String, List<Map>> getAllSubscribingUsers(Whelk whelk) {
Map<String, List<Map>> libraryToUserSettings = new HashMap<>()
List<Map> allUserSettingStrings = whelk.getStorage().getAllUserData()
for (Map settings : allUserSettingStrings) {
if (!settings["notificationEmail"])
continue
settings?.requestedNotifications?.each { request ->
if (!request instanceof Map)
return
if (!request["heldBy"])
return

String heldBy = request["heldBy"]
if (!libraryToUserSettings.containsKey(heldBy))
libraryToUserSettings.put(heldBy, [])
libraryToUserSettings[heldBy].add(settings)
}
}
return libraryToUserSettings
}

static Mailer mailer = null
static String senderAddress
static synchronized void sendEmail(String recipient, String subject, String body) {
if (mailer == null) {
Properties props = PropertyLoader.loadProperties("secret")
if (props.containsKey("smtpServer") &&
props.containsKey("smtpPort") &&
props.containsKey("smtpSender") &&
props.containsKey("smtpUser") &&
props.containsKey("smtpPassword"))
mailer = MailerBuilder
.withSMTPServer(
(String) props.get("smtpServer"),
Integer.parseInt((String)props.get("smtpPort")),
(String) props.get("smtpUser"),
(String) props.get("smtpPassword")
).buildMailer()
senderAddress = props.get("smtpSender")
}

if (mailer) {
Email email = EmailBuilder.startingBlank()
.to(recipient)
.withSubject(subject)
.from(senderAddress)
.withPlainText(body)
.buildEmail()

log.info("Sending notification (cxz) email to " + recipient)
mailer.sendMail(email)
} else {
log.info("Should now have sent notification (cxz) email to " + recipient + " but SMTP is not configured.")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class WebInterface extends HttpServlet {
List<HouseKeeper> houseKeepers = [
new NotificationGenerator(whelk),
new NotificationSender(whelk),
new InquirySender(whelk),
new NotificationCleaner(whelk),
]

Expand Down

0 comments on commit b9e0639

Please sign in to comment.