package ui; import dao.MarkingProperties; import dao.ResultDAO; import jakarta.mail.AuthenticationFailedException; import java.net.ConnectException; import java.util.Collection; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import javax.swing.JOptionPane; import model.Student; import org.slf4j.LoggerFactory; import report.FeedbackReportGenerator; import report.SendReport; import static report.TimeStamp.getTimeStamp; /** * * @author Mark George <mark.george@otago.ac.nz> */ public final class BatchMailer extends javax.swing.JDialog { private static final org.slf4j.Logger logger = LoggerFactory.getLogger(BatchMailer.class); private Boolean stopped = false; /** * Creates new form BatchMailer */ public BatchMailer(java.awt.Window parent, boolean modal) { super(parent); this.setModal(modal); initComponents(); addMessage("FROM: " + MarkingProperties.markerEmail()); addMessage("CC: " + MarkingProperties.ccEmail()); addMessage(""); } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { jScrollPane1 = new javax.swing.JScrollPane(); txtMessages = new javax.swing.JTextArea(); btnClose = new javax.swing.JButton(); btnStop = new javax.swing.JButton(); btnStart = new javax.swing.JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); jScrollPane1.setName("jScrollPane1"); // NOI18N txtMessages.setColumns(20); txtMessages.setRows(5); txtMessages.setName("txtMessages"); // NOI18N jScrollPane1.setViewportView(txtMessages); btnClose.setText("Close"); btnClose.setName("btnClose"); // NOI18N btnClose.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnCloseActionPerformed(evt); } }); btnStop.setText("Cancel Sending"); btnStop.setName("btnStop"); // NOI18N btnStop.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnStopActionPerformed(evt); } }); btnStart.setText("Start Sending"); btnStart.setName("btnStart"); // NOI18N btnStart.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnStartActionPerformed(evt); } }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 588, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addComponent(btnStart) .addGap(18, 18, 18) .addComponent(btnStop) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(btnClose, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE))) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 545, Short.MAX_VALUE) .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(btnClose) .addComponent(btnStop) .addComponent(btnStart)) .addContainerGap()) ); pack(); }// </editor-fold>//GEN-END:initComponents private void btnStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStopActionPerformed int result = JOptionPane.showConfirmDialog(this, "Stop sending emails?", "Stop Sending?", JOptionPane.YES_NO_OPTION); // did the user click the yes button? if (result == JOptionPane.YES_OPTION) { this.stopped = true; addMessage("Stopped. Messages that are in the process of being retried will continue to be retried."); } }//GEN-LAST:event_btnStopActionPerformed public void addMessage(String message) { txtMessages.append(message + "\n"); } private void btnStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStartActionPerformed CompletableFuture.runAsync(() -> { Collection<Student> students = new ResultDAO().getStudents(); for (Student student : students) { if (stopped) { break; } if (!student.getSendFeedback() || student.getEmailSent()) { continue; } String title = MarkingProperties.reportTitle(); String footer = MarkingProperties.reportFooter(); new FeedbackReportGenerator(new ResultDAO().getResult(student.getId()), MarkingProperties.reportPath(), MarkingProperties.attachmentFilePrefix(), title, footer).generate(student); String report = MarkingProperties.reportPath() + "/" + MarkingProperties.attachmentFilePrefix() + "-" + student.getId() + ".pdf"; if (MarkingProperties.isEmailEnabled()) { try { new SendReport(BatchMailer.this).sendReport(student, report, true); } catch(AuthenticationFailedException ex) { addMessage("Authentication failed. Click 'Start Sending' to try again.\n"); return; } catch(ConnectException ex) { addMessage("Could not connect to SMTP server!\n"); return; } try { int delay = MarkingProperties.emailDelay(); TimeUnit.SECONDS.sleep(delay); // delay to minimise triggering rate limiting } catch (InterruptedException e) { logger.error(e.getLocalizedMessage(), e); } } } addMessage(""); addMessage(getTimeStamp() + " - Done\n"); }); }//GEN-LAST:event_btnStartActionPerformed private void btnCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCloseActionPerformed dispose(); }//GEN-LAST:event_btnCloseActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnClose; private javax.swing.JButton btnStart; private javax.swing.JButton btnStop; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTextArea txtMessages; // End of variables declaration//GEN-END:variables }