diff --git a/modules/CommonGUI/src/main/java/org/janelia/workstation/common/nb_action/ReportABugMenuAction.java b/modules/CommonGUI/src/main/java/org/janelia/workstation/common/nb_action/ReportABugMenuAction.java index e7d13f3ebe..95b29cf7ae 100644 --- a/modules/CommonGUI/src/main/java/org/janelia/workstation/common/nb_action/ReportABugMenuAction.java +++ b/modules/CommonGUI/src/main/java/org/janelia/workstation/common/nb_action/ReportABugMenuAction.java @@ -5,7 +5,7 @@ import javax.swing.AbstractAction; import org.janelia.workstation.core.logging.LoggingUtils; -import org.janelia.workstation.core.util.MailDialogueBox; +import org.janelia.workstation.core.util.ErrorReportDialogueBox; import org.janelia.workstation.integration.util.FrameworkAccess; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; @@ -27,19 +27,19 @@ public final class ReportABugMenuAction extends AbstractAction { @Override public void actionPerformed(ActionEvent e) { - String subject = LoggingUtils.getReportEmailSubject(false)+" -- Bug Report"; + String subject = LoggingUtils.getErrorReportSubject(false)+" -- Bug Report"; - MailDialogueBox popup = MailDialogueBox.newDialog(FrameworkAccess.getMainFrame()) + ErrorReportDialogueBox popup = ErrorReportDialogueBox.newDialog(FrameworkAccess.getMainFrame()) .withTitle("Create A Ticket") .withPromptText("Problem Description:") - .withEmailSubject(subject) + .withSubject(subject) .appendStandardPrefix() .append("\n\nMessage:\n"); String desc = popup.showPopup(); if (desc!=null) { popup.appendLine(desc); - popup.sendEmail(); + popup.sendReport(); } } diff --git a/modules/Core/src/main/java/org/janelia/workstation/core/logging/LoggingUtils.java b/modules/Core/src/main/java/org/janelia/workstation/core/logging/LoggingUtils.java index cfbdfc7bd1..20005a182e 100644 --- a/modules/Core/src/main/java/org/janelia/workstation/core/logging/LoggingUtils.java +++ b/modules/Core/src/main/java/org/janelia/workstation/core/logging/LoggingUtils.java @@ -8,7 +8,7 @@ */ public class LoggingUtils { - public static String getReportEmailSubject(boolean isAutoReport) { + public static String getErrorReportSubject(boolean isAutoReport) { AccessManager accessManager = AccessManager.getAccessManager(); diff --git a/modules/Core/src/main/java/org/janelia/workstation/core/logging/NBExceptionHandler.java b/modules/Core/src/main/java/org/janelia/workstation/core/logging/NBExceptionHandler.java index 31ab25844e..c239b1a442 100644 --- a/modules/Core/src/main/java/org/janelia/workstation/core/logging/NBExceptionHandler.java +++ b/modules/Core/src/main/java/org/janelia/workstation/core/logging/NBExceptionHandler.java @@ -9,7 +9,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import org.janelia.workstation.core.api.AccessManager; import org.janelia.workstation.core.util.ConsoleProperties; -import org.janelia.workstation.core.util.MailDialogueBox; +import org.janelia.workstation.core.util.ErrorReportDialogueBox; import org.janelia.workstation.core.util.SystemInfo; import org.janelia.workstation.integration.util.FrameworkAccess; import org.slf4j.Logger; @@ -117,10 +117,10 @@ private synchronized void autoSendNovelExceptions() { // Allow one exception report every cooldown cycle. Our RateLimiter allows one access every // second, so we need to acquire a cooldown's worth of locks. if (!rateLimiter.tryAcquire(COOLDOWN_TIME_SEC, 0, TimeUnit.SECONDS)) { - log.warn("Exception reports exceeded email rate limit. Omitting auto-send of: {}", firstLine); + log.warn("Exception reports exceeded rate limit. Omitting auto-send of: {}", firstLine); return; } - sendEmail(st, false); + sendReport(st, false); } else { int count = exceptionCounts.count(traceHash); @@ -186,45 +186,45 @@ public void actionPerformed(ActionEvent e) { SwingUtilities.windowForComponent(newFunctionButton).setVisible(false); // Due to the way the NotifyExcPanel works, this might not be the exception the user is currently looking at! // Maybe it's better than nothing if it's right 80% of the time? - sendEmail(ExceptionUtils.getStackTrace(throwable), true); + sendReport(ExceptionUtils.getStackTrace(throwable), true); } - private void sendEmail(String stacktrace, boolean askForInput) { + private void sendReport(String stacktrace, boolean askForInput) { try { String firstLine = getSummary(stacktrace); log.info("Reporting exception: "+firstLine); - String subject = LoggingUtils.getReportEmailSubject(!askForInput)+" -- "+firstLine; + String subject = LoggingUtils.getErrorReportSubject(!askForInput)+" -- "+firstLine; - MailDialogueBox mailDialogueBox = MailDialogueBox.newDialog(FrameworkAccess.getMainFrame()) + ErrorReportDialogueBox errorReportDialogueBox = ErrorReportDialogueBox.newDialog(FrameworkAccess.getMainFrame()) .withTitle("Create A Ticket") .withPromptText("If possible, please describe what you were doing when the error occurred:") - .withEmailSubject(subject) + .withSubject(subject) .appendStandardPrefix(); if (askForInput) { - String problemDesc = mailDialogueBox.showPopup(); + String problemDesc = errorReportDialogueBox.showPopup(); if (problemDesc==null) { // User pressed cancel return; } else { - mailDialogueBox.append("\n\nProblem Description:\n"); - mailDialogueBox.append(problemDesc); + errorReportDialogueBox.append("\n\nProblem Description:\n"); + errorReportDialogueBox.append(problemDesc); } } - mailDialogueBox.append("\n\nStack Trace:\n"); - mailDialogueBox.append(stacktrace); + errorReportDialogueBox.append("\n\nStack Trace:\n"); + errorReportDialogueBox.append(stacktrace); - mailDialogueBox.sendEmail(); + errorReportDialogueBox.sendReport(); } catch (Exception ex) { - log.warn("Error sending exception email",ex); - if (askForInput) { // JW-25430: Only show this message if the email was initiated by the user + log.warn("Error sending exception report",ex); + if (askForInput) { // JW-25430: Only show this message if the report was initiated by the user JOptionPane.showMessageDialog(FrameworkAccess.getMainFrame(), "Your message was NOT able to be sent to our support staff. " - + "Please contact your support representative.", "Error sending email", JOptionPane.ERROR_MESSAGE); + + "Please contact your support representative.", "Error sending report", JOptionPane.ERROR_MESSAGE); } } } diff --git a/modules/Core/src/main/java/org/janelia/workstation/core/util/ErrorReportDialogueBox.java b/modules/Core/src/main/java/org/janelia/workstation/core/util/ErrorReportDialogueBox.java new file mode 100644 index 0000000000..61d852afc2 --- /dev/null +++ b/modules/Core/src/main/java/org/janelia/workstation/core/util/ErrorReportDialogueBox.java @@ -0,0 +1,258 @@ +package org.janelia.workstation.core.util; + +import java.awt.BorderLayout; +import java.io.File; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; + +import org.janelia.workstation.core.api.AccessManager; +import org.janelia.workstation.core.api.ConnectionMgr; +import org.janelia.workstation.core.api.LocalCacheMgr; +import org.openide.modules.Places; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Creates a dialog to get the user's input and then sends a report to create a ticket, + * either via email or via GitHub API. + */ +public class ErrorReportDialogueBox { + + private static final Logger log = LoggerFactory.getLogger(ErrorReportDialogueBox.class); + + private static final String LOG_FILE_NAME = "messages.log"; + + // for GitHub reporting + private static final String ISSUES_BRANCH = "issues"; + private static final String ATTACHMENTS_FOLDER = "attachments"; + + private static final String SUBJECT_PREFIX = "[JW] "; + + private String subject = ""; + private String initialBody = ""; + private String title = ""; + private String promptText = ""; + private StringBuffer body = new StringBuffer(); + private JFrame parentFrame; + + // flag to track whether we've reported an error about reporting errors already + private static boolean silenceErrorReportingFailure = false; + + private ErrorReportDialogueBox(JFrame parentFrame) { + this.parentFrame = parentFrame; + } + + public static ErrorReportDialogueBox newDialog(JFrame parentFrame) { + return new ErrorReportDialogueBox(parentFrame); + } + + public ErrorReportDialogueBox withTitle(String title) { + this.title = title; + return this; + } + + public ErrorReportDialogueBox withPromptText(String promptText) { + this.promptText = promptText; + return this; + } + + public ErrorReportDialogueBox withTextAreaBody(String initialBody) { + this.initialBody = initialBody; + return this; + } + + public ErrorReportDialogueBox withSubject(String subject) { + if (!subject.startsWith(SUBJECT_PREFIX)) { + subject = SUBJECT_PREFIX + subject; + } + this.subject = subject; + return this; + } + + public ErrorReportDialogueBox append(String str) { + body.append(str); + return this; + } + + public ErrorReportDialogueBox appendStandardPrefix() { + append("\nSubject: ").append(AccessManager.getSubjectKey()); + append("\nApplication: ").append(SystemInfo.appName).append(" v").append(SystemInfo.appVersion); + append("\nServer: ").append(ConnectionMgr.getConnectionMgr().getConnectionString()); + append("\nOperating System: ").append(SystemInfo.getOSInfo()); + append("\nJava: ").append(SystemInfo.getRuntimeJavaInfo()); + append("\nDisk Cache Usage: ").append(LocalCacheMgr.getInstance().getFileCacheGigabyteUsagePercent()+"%"); + append("\nSystem Memory Usage: ").append(SystemInfo.getSystemMemoryUsagePercent()+"%"); + append("\nJVM Memory: ").append(SystemInfo.getJVMMemory()); + append("\nMemory Setting: "); + if (Utils.getMemoryAllocation()==null) { + append("default"); + } + else { + append(""+Utils.getMemoryAllocation()); + } + return this; + } + + public ErrorReportDialogueBox appendLine(String str) { + body.append(str).append("\n"); + return this; + } + + public String showPopup() { + String desc = null; + JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + panel.add(new JLabel(promptText), BorderLayout.NORTH); + JTextArea textArea = new JTextArea(4, 40); + textArea.setText(initialBody); + panel.add(new JScrollPane(textArea), BorderLayout.CENTER); + int ans = JOptionPane.showConfirmDialog(parentFrame, panel, title, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + if (ans == JOptionPane.CANCEL_OPTION) return null; + desc = textArea.getText() + "\n"; + return desc; + } + + public void sendReport() { + String method = ConsoleProperties.getString("console.ErrorReportingMethod", null); + if (method == null) { + // "email" was our original implementation, so if unset, default to "email" for + // backward compatibility + method = "email"; + } + + if (method.equals("email")) { + sendEmail(); + } else if (method.equals("github")) { + sendGitHub(); + } else { + log.error("Cannot send error report; unknown value {} for console.ErrorReportingMethod", method); + return; + } + } + + public void sendEmail() { + String fromEmail = ConsoleProperties.getString("console.FromEmail", null); + if (fromEmail==null) { + log.error("Cannot send exception report: no value for console.FromEmail is configured."); + return; + } + String toEmail = ConsoleProperties.getString("console.HelpEmail", null); + if (toEmail==null) { + log.error("Cannot send exception report: no value for console.HelpEmail is configured."); + return; + } + + String filename = ""; + File logfile = getLogfile(); + if (logfile != null) { + filename = AccessManager.getSubjectName()+"_"+LOG_FILE_NAME; + } + + log.info("Sending email from {} to {} with attachment {}", fromEmail, toEmail, logfile); + + MailHelper helper = new MailHelper(); + boolean result = helper.sendEmail(fromEmail, toEmail, subject, body.toString(), logfile, filename); + if (!result) { + String message = "Error reporting email not sent or error in sending email"; + reportErrorReportingFailure(message); + } + } + + public void sendGitHub() { + String githubURL = ConsoleProperties.getString("console.GitHubErrorProjectURL", null); + if (githubURL==null) { + log.error("Cannot send exception report: no value for console.GitHubErrorProjectURL is configured."); + return; + } + String githubToken = ConsoleProperties.getString("console.GitHubErrorProjectAccessToken", null); + if (githubToken==null) { + log.error("Cannot send exception report: no value for console.GitHubErrorProjectAccessToken is configured."); + return; + } + + File logfile = getLogfile(); + log.info("Creating GitHub issue in project {} with logfile attachment {}", githubURL, logfile); + + // note that our logfiles are far too long for a GitHub issue (65k char limit), + // so this is a three step process: create issue with body text, upload the + // logfile to the repo, then create a comment with a link to the logfile + + GitHubRestClient client = new GitHubRestClient(); + + int issueNumber = client.createIssue(subject, body.toString()); + if (issueNumber <= 0) { + String message = "GitHub issue not created for error report"; + log.error(message); + reportErrorReportingFailure(message); + return; + } + + String path = ATTACHMENTS_FOLDER + "/issue-" + issueNumber + "-" + LOG_FILE_NAME; + String permalink = client.uploadLogFile(ISSUES_BRANCH, logfile, path); + if (permalink.isEmpty()) { + String message = "Logfile not uploaded to GitHub or error in generating permalink"; + log.error(message); + reportErrorReportingFailure(message); + return; + } + + String comment = "[Link to uploaded log file.](" + permalink + ")"; + boolean success = client.addComment(issueNumber, comment); + if (!success) { + String message = "Failed to add comment to GitHub issue with permalink to log."; + log.error(message); + reportErrorReportingFailure(message); + } + + } + + private File getLogfile() { + + // Flush all long handlers so that we have a complete log file + java.util.logging.Logger logger = java.util.logging.Logger.getLogger(""); + for (java.util.logging.Handler handler : logger.getHandlers()) { + handler.flush(); + } + + File logDir = new File(Places.getUserDirectory(), "var/log"); + File logfile = new File(logDir, LOG_FILE_NAME); + if (!logfile.canRead()) { + log.info("Can't read log file at " + logfile.getAbsolutePath()); + logfile = null; + } + + return logfile; + } + + private void reportErrorReportingFailure(String message) { + if (silenceErrorReportingFailure) { + return; + } + + Object[] buttons = {"Silence", "Continue"}; + message = "Error reporting failed:\n\n" + message + + "\n\nPlease report this issue to the site admins, as it cannot be reported automatically!" + + "\n\nContinue to show this dialog when error reporting fails, or Silence these dialogs for this session?"; + Object response = JOptionPane.showOptionDialog(null, + message, + "Error not reported!", + JOptionPane.DEFAULT_OPTION, + JOptionPane.ERROR_MESSAGE, + null, + buttons, + buttons[0] + ); + int index = (int) response; + if (index < 0 || index >= buttons.length) { + return; + } + if (buttons[index].equals("Silence")) { + silenceErrorReportingFailure = true; + } + } +} diff --git a/modules/Core/src/main/java/org/janelia/workstation/core/util/GitHubRestClient.java b/modules/Core/src/main/java/org/janelia/workstation/core/util/GitHubRestClient.java new file mode 100644 index 0000000000..a6a55dd863 --- /dev/null +++ b/modules/Core/src/main/java/org/janelia/workstation/core/util/GitHubRestClient.java @@ -0,0 +1,147 @@ +package org.janelia.workstation.core.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.client.*; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import java.util.Scanner; + +public class GitHubRestClient { + private static final Logger logger = LoggerFactory.getLogger(GitHubRestClient.class); + + private final String projectURL; + private final String accessToken; + + private Client client; + + public GitHubRestClient() { + this.projectURL = ConsoleProperties.getInstance().getProperty("console.GitHubErrorProjectURL"); + this.accessToken = ConsoleProperties.getInstance().getProperty("console.GitHubErrorProjectAccessToken"); + logger.debug("Using project URL: {}", this.projectURL); + + client = ClientBuilder.newClient(); + } + + private Invocation.Builder getBuilder(String path) { + WebTarget baseTarget = client.target(projectURL); + WebTarget pathTarget = baseTarget.path(path); + return pathTarget.request(MediaType.APPLICATION_JSON).header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken); + } + + // this method is for testing and debugging + public List getIssueList() { + List issues = new ArrayList<>(); + + Response response = getBuilder("issues").get(); + if (response.getStatus() != Response.Status.OK.getStatusCode()) { + logger.error("Error getting issues list; status {}, body {}", response.getStatus(), response.readEntity(String.class)); + return issues; + } + + String json = response.readEntity(String.class); + try { + ObjectMapper mapper = new ObjectMapper(); + JsonNode nodes = mapper.readValue(json, JsonNode.class); + for (JsonNode node: nodes) { + issues.add(node.at("/title").asText()); + } + } catch (JsonProcessingException e) { + logger.error("Error parsing json for issues list"); + return issues; + } + + return issues; + } + + public int createIssue(String title, String body) { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode newIssue = mapper.createObjectNode(); + newIssue.put("title", title); + newIssue.put("body", body); + + Response response = getBuilder("issues").post(Entity.json(newIssue)); + if (response.getStatus() != Response.Status.CREATED.getStatusCode()) { + logger.error("Error creating new issue; status {}, body {}", response.getStatus(), response.readEntity(String.class)); + return 0; + } + + String json = response.readEntity(String.class); + try { + ObjectMapper mapper2 = new ObjectMapper(); + JsonNode node = mapper2.readTree(json); + if (!node.has("number")) { + logger.error("Returned json doesn't contain issue number"); + return 0; + } + return Integer.parseInt(node.get("number").asText()); + } catch (JsonProcessingException e) { + logger.error("Error parsing json for created issue"); + return 0; + } + } + + public String uploadLogFile(String branch, File logfile, String path) { + String unencodedLog = ""; + try (Scanner scanner = new Scanner(logfile)) { + unencodedLog = scanner.useDelimiter("\\A").next(); + } catch (IOException e) { + logger.error("Error reading log file"); + return ""; + } + String encodedLog = Base64.getEncoder().encodeToString(unencodedLog.getBytes()); + + ObjectMapper mapper = new ObjectMapper(); + ObjectNode upload = mapper.createObjectNode(); + upload.put("message", "uploaded attachment"); + upload.put("branch", branch); + upload.put("content", encodedLog); + + Response response = getBuilder("contents/" + path).put(Entity.json(upload)); + if (response.getStatus() != Response.Status.CREATED.getStatusCode()) { + logger.error("Error uploading logfile; status {}, body {}", response.getStatus(), response.readEntity(String.class)); + return ""; + } + + // generate permalink to the uploaded file + String json = response.readEntity(String.class); + String permalink = ""; + try { + ObjectMapper mapper2 = new ObjectMapper(); + JsonNode tree = mapper2.readTree(json); + String sha = tree.at("/commit/sha").asText(); + permalink = projectURL.replace("api.", "").replace("/repos", "") + + "/blob/" + sha + "/" + path; + } catch (JsonProcessingException e) { + logger.error("Error parsing json from logfile upload"); + return ""; + } + return permalink; + } + + public boolean addComment(int issueId, String comment) { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode commentNode = mapper.createObjectNode(); + commentNode.put("body", comment); + + Response response = getBuilder("issues/" + issueId + "/comments").post(Entity.json(commentNode)); + if (response.getStatus() != Response.Status.CREATED.getStatusCode()) { + logger.error("Error adding comment; status {}, body {}", response.getStatus(), response.readEntity(String.class)); + return false; + } else { + return true; + } + } + +} diff --git a/modules/Core/src/main/java/org/janelia/workstation/core/util/MailDialogueBox.java b/modules/Core/src/main/java/org/janelia/workstation/core/util/MailDialogueBox.java deleted file mode 100644 index a3ffecfcc7..0000000000 --- a/modules/Core/src/main/java/org/janelia/workstation/core/util/MailDialogueBox.java +++ /dev/null @@ -1,151 +0,0 @@ -package org.janelia.workstation.core.util; - -import java.awt.BorderLayout; -import java.io.File; - -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; - -import org.janelia.workstation.core.api.AccessManager; -import org.janelia.workstation.core.api.ConnectionMgr; -import org.janelia.workstation.core.api.LocalCacheMgr; -import org.openide.modules.Places; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Creates a dialog to get the user's input and then sends an email to JIRA to create a ticket. - * - * @author kimmelr - * @author Konrad Rokicki - */ -public class MailDialogueBox { - - private static final Logger log = LoggerFactory.getLogger(MailDialogueBox.class); - - private static final String LOG_FILE_NAME = "messages.log"; - - private String subject = ""; - private String initialBody = ""; - private String title = ""; - private String promptText = ""; - private StringBuffer body = new StringBuffer(); - private JFrame parentFrame; - - private MailDialogueBox(JFrame parentFrame) { - this.parentFrame = parentFrame; - } - - public static MailDialogueBox newDialog(JFrame parentFrame) { - return new MailDialogueBox(parentFrame); - } - - public MailDialogueBox withTitle(String title) { - this.title = title; - return this; - } - - public MailDialogueBox withPromptText(String promptText) { - this.promptText = promptText; - return this; - } - - public MailDialogueBox withTextAreaBody(String initialBody) { - this.initialBody = initialBody; - return this; - } - - public MailDialogueBox withEmailSubject(String subject) { - this.subject = subject; - return this; - } - - public MailDialogueBox append(String str) { - body.append(str); - return this; - } - - public MailDialogueBox appendStandardPrefix() { - append("\nSubject: ").append(AccessManager.getSubjectKey()); - append("\nApplication: ").append(SystemInfo.appName).append(" v").append(SystemInfo.appVersion); - append("\nServer: ").append(ConnectionMgr.getConnectionMgr().getConnectionString()); - append("\nOperating System: ").append(SystemInfo.getOSInfo()); - append("\nJava: ").append(SystemInfo.getRuntimeJavaInfo()); - append("\nDisk Cache Usage: ").append(LocalCacheMgr.getInstance().getFileCacheGigabyteUsagePercent()+"%"); - append("\nSystem Memory Usage: ").append(SystemInfo.getSystemMemoryUsagePercent()+"%"); - append("\nJVM Memory: ").append(SystemInfo.getJVMMemory()); - append("\nMemory Setting: "); - if (Utils.getMemoryAllocation()==null) { - append("default"); - } - else { - append(""+Utils.getMemoryAllocation()); - } - return this; - } - - public MailDialogueBox appendLine(String str) { - body.append(str).append("\n"); - return this; - } - - public String showPopup() { - String desc = null; - JPanel panel = new JPanel(); - panel.setLayout(new BorderLayout()); - panel.add(new JLabel(promptText), BorderLayout.NORTH); - JTextArea textArea = new JTextArea(4, 40); - textArea.setText(initialBody); - panel.add(new JScrollPane(textArea), BorderLayout.CENTER); - int ans = JOptionPane.showConfirmDialog(parentFrame, panel, title, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); - if (ans == JOptionPane.CANCEL_OPTION) return null; - desc = textArea.getText() + "\n"; - return desc; - } - - public void sendEmail() { - - String fromEmail = ConsoleProperties.getString("console.FromEmail", null); - if (fromEmail==null) { - log.error("Cannot send exception report: no value for console.FromEmail is configured."); - return; - } - - String toEmail = ConsoleProperties.getString("console.HelpEmail", null); - if (toEmail==null) { - log.error("Cannot send exception report: no value for console.HelpEmail is configured."); - return; - } - - // Flush all long handlers so that we have a complete log file - java.util.logging.Logger logger = java.util.logging.Logger.getLogger(""); - for (java.util.logging.Handler handler : logger.getHandlers()) { - handler.flush(); - } - - String filename = null; - File logDir = new File(Places.getUserDirectory(), "var/log"); - File logfile = new File(logDir, LOG_FILE_NAME); - if (!logfile.canRead()) { - log.info("Can't read log file at "+logfile.getAbsolutePath()); - logfile = null; - } - else { - filename = AccessManager.getSubjectName()+"_"+LOG_FILE_NAME; - } - - log.info("Sending email from {} to {} with attachment {}", fromEmail, toEmail, logfile); - - MailHelper helper = new MailHelper(); - helper.sendEmail(fromEmail, toEmail, subject, body.toString(), logfile, filename); - - // TODO: this should only be shown when the user manually reports a bug -// JOptionPane.showMessageDialog( -// FrameworkAccess.getMainFrame(), "Bug was reported successfully", "Success", -// JOptionPane.INFORMATION_MESSAGE); - } -} diff --git a/modules/Core/src/main/java/org/janelia/workstation/core/util/MailHelper.java b/modules/Core/src/main/java/org/janelia/workstation/core/util/MailHelper.java index 41b0dd7de3..1471efa56e 100644 --- a/modules/Core/src/main/java/org/janelia/workstation/core/util/MailHelper.java +++ b/modules/Core/src/main/java/org/janelia/workstation/core/util/MailHelper.java @@ -23,11 +23,11 @@ public class MailHelper { public MailHelper() { } - public void sendEmail(String from, String to, String subject, String bodyText) { - this.sendEmail(from, to, subject, bodyText, null, null); + public boolean sendEmail(String from, String to, String subject, String bodyText) { + return this.sendEmail(from, to, subject, bodyText, null, null); } - public void sendEmail(String from, String to, String subject, String bodyText, File attachedFile, String filename) { + public boolean sendEmail(String from, String to, String subject, String bodyText, File attachedFile, String filename) { try { String mailServer = ConsoleProperties.getString("console.MailServer"); String mailUser = ConsoleProperties.getString("console.MailUser", ""); @@ -64,7 +64,7 @@ protected PasswordAuthentication getPasswordAuthentication() { Message message = new MimeMessage(session); message.setFrom(new InternetAddress(from)); message.setRecipients(RecipientType.TO, InternetAddress.parse(to)); - message.setSubject("[JW] " + subject); + message.setSubject(subject); BodyPart messagePart = new MimeBodyPart(); messagePart.setText(bodyText); Multipart multipart = new MimeMultipart(); @@ -88,9 +88,12 @@ protected PasswordAuthentication getPasswordAuthentication() { log.info(" To: " + to); log.info(" Body: " + bodyText); + return true; + } catch (MessagingException var13) { log.error("Error sending email", var13); + return false; } } diff --git a/modules/LMDataBrowser/src/main/java/org/janelia/workstation/lm/actions/context/ReportProblemAction.java b/modules/LMDataBrowser/src/main/java/org/janelia/workstation/lm/actions/context/ReportProblemAction.java index dd027dac04..bc431d5f8d 100644 --- a/modules/LMDataBrowser/src/main/java/org/janelia/workstation/lm/actions/context/ReportProblemAction.java +++ b/modules/LMDataBrowser/src/main/java/org/janelia/workstation/lm/actions/context/ReportProblemAction.java @@ -5,8 +5,7 @@ import org.janelia.workstation.common.actions.BaseContextualNodeAction; import org.janelia.workstation.core.activity_logging.ActivityLogHelper; import org.janelia.workstation.core.api.AccessManager; -import org.janelia.workstation.core.util.ConsoleProperties; -import org.janelia.workstation.core.util.MailHelper; +import org.janelia.workstation.core.util.ErrorReportDialogueBox; import org.janelia.workstation.integration.util.FrameworkAccess; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; @@ -45,8 +44,7 @@ protected void processContext() { if (getNodeContext().isSingleObjectOfType(Sample.class)) { this.selectedObject = getNodeContext().getSingleObjectOfType(Sample.class); setEnabledAndVisible(true); - } - else { + } else { setEnabledAndVisible(false); } } @@ -61,66 +59,37 @@ public void performAction() { reportData(domainObject); JOptionPane.showMessageDialog(FrameworkAccess.getMainFrame(), - "Successfully reported problem with "+domainObject.getName(), + "Successfully reported problem with " + domainObject.getName(), "Data Problem Reported", JOptionPane.PLAIN_MESSAGE); - } - catch (Exception ex) { + } catch (Exception ex) { FrameworkAccess.handleException(ex); } } private void reportData(DomainObject domainObject) { - String fromEmail = ConsoleProperties.getString("console.FromEmail", null); - if (fromEmail==null) { - log.error("Cannot send exception report: no value for console.FromEmail is configured."); - return; - } + String subject = "Reported Data: " + domainObject.getName(); - String toEmail = ConsoleProperties.getString("console.HelpEmail", null); - if (toEmail==null) { - log.error("Cannot send exception report: no value for console.HelpEmail is configured."); - return; - } + // this dialog box will not be displayed; we do not call errorReportDialogueBox.showPopup() + ErrorReportDialogueBox errorReportDialogueBox = ErrorReportDialogueBox.newDialog(FrameworkAccess.getMainFrame()) + .withTitle("not displayed") + .withPromptText("not displayed") + .withSubject(subject); - DataReporter reporter = new DataReporter(fromEmail, toEmail); - reporter.reportData(domainObject, null); + errorReportDialogueBox.append(createEntityReport(domainObject)); + errorReportDialogueBox.sendReport(); } - public static class DataReporter { - - private final String fromEmail; - private final String toEmail; + private String createEntityReport(DomainObject domainObject) { + StringBuilder sBuf = new StringBuilder(); - public DataReporter(String fromEmail, String toEmail) { - this.fromEmail = fromEmail; - this.toEmail = toEmail; - } + String user = AccessManager.getSubjectKey(); + sBuf.append("Reporting user: ").append(user).append("\n"); - private String createEntityReport(DomainObject domainObject, String annotation) { - StringBuilder sBuf = new StringBuilder(); - - String user = AccessManager.getSubjectKey(); - sBuf.append("Reporting user: ").append(user).append("\n"); - - sBuf.append("GUID: ").append(domainObject.getId().toString()).append("\n"); - sBuf.append("Type: ").append(domainObject.getType()).append("\n"); - sBuf.append("Owner: ").append(domainObject.getOwnerKey()).append("\n"); - sBuf.append("Name: ").append(domainObject.getName()).append("\n"); - if (annotation!=null) { - sBuf.append("Annotation: ").append(annotation).append("\n\n"); - } - return sBuf.toString(); - } - - public void reportData(DomainObject domainObject, String annotation) { - String subject = "Reported Data: " + domainObject.getName(); - if (annotation!=null) { - subject += " ("+annotation+")"; - } - String report = createEntityReport(domainObject, annotation); - MailHelper helper = new MailHelper(); - helper.sendEmail(fromEmail, toEmail, subject, report); - } + sBuf.append("GUID: ").append(domainObject.getId().toString()).append("\n"); + sBuf.append("Type: ").append(domainObject.getType()).append("\n"); + sBuf.append("Owner: ").append(domainObject.getOwnerKey()).append("\n"); + sBuf.append("Name: ").append(domainObject.getName()).append("\n"); + return sBuf.toString(); } -} \ No newline at end of file +} diff --git a/modules/ViewerInfoPanel/src/main/java/org/janelia/workstation/infopanel/WorkspaceInfoPanel.java b/modules/ViewerInfoPanel/src/main/java/org/janelia/workstation/infopanel/WorkspaceInfoPanel.java index 4ac4b00e2f..1c8932cbc6 100644 --- a/modules/ViewerInfoPanel/src/main/java/org/janelia/workstation/infopanel/WorkspaceInfoPanel.java +++ b/modules/ViewerInfoPanel/src/main/java/org/janelia/workstation/infopanel/WorkspaceInfoPanel.java @@ -58,7 +58,7 @@ public void loadWorkspace(TmWorkspace workspace) { */ private void updateMetaData(final TmWorkspace workspace) { if (TmModelManager.getInstance().getCurrentSample() == null) { - setSampleName("(no sample"); + setSampleName("(no sample)"); setWorkspaceName("(no workspace)", false); return; } else {