From 860e420defb97bc0ff08b7f47e8d1e435eb98576 Mon Sep 17 00:00:00 2001 From: Jaideep Palit Date: Sun, 6 Mar 2022 15:54:08 +0530 Subject: [PATCH 1/2] feat(exportExcel): Generate and save excel to file system, Download generated file with token Signed-off-by: Jaideep Palit --- .../eclipse/sw360/exporter/ExcelExporter.java | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/libraries/exporters/src/main/java/org/eclipse/sw360/exporter/ExcelExporter.java b/libraries/exporters/src/main/java/org/eclipse/sw360/exporter/ExcelExporter.java index 834a4b1f5f..32fdeb4111 100644 --- a/libraries/exporters/src/main/java/org/eclipse/sw360/exporter/ExcelExporter.java +++ b/libraries/exporters/src/main/java/org/eclipse/sw360/exporter/ExcelExporter.java @@ -20,9 +20,16 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; import java.util.List; +import java.util.UUID; /** * Created on 06/02/15. @@ -37,9 +44,10 @@ public ExcelExporter(U helper) { this.helper = helper; } - public InputStream makeExcelExport(List documents) throws IOException, SW360Exception { + public String makeExcelExport(List documents) throws IOException, SW360Exception { final SXSSFWorkbook workbook = new SXSSFWorkbook(); - final ByteArrayInputStream stream; + //final ByteArrayInputStream stream; + String token = UUID.randomUUID().toString(); try { SXSSFSheet sheet = workbook.createSheet("Data"); @@ -60,10 +68,26 @@ public InputStream makeExcelExport(List documents) throws IOException, SW360E /** Copy the streams */ final ByteArrayOutputStream out = new ByteArrayOutputStream(); workbook.write(out); - stream = new ByteArrayInputStream(out.toByteArray()); + + try(OutputStream outputStream = new FileOutputStream("/tmp/"+token)) { + out.writeTo(outputStream); + out.flush(); + } + //stream = new ByteArrayInputStream(out.toByteArray()); }finally{ workbook.dispose(); } + return token; + } + + public InputStream downloadExcelSheet(String token) { + InputStream stream = null; + try { + stream = new FileInputStream(new File("/tmp/" + token)); + } catch (FileNotFoundException e) { + // logger + } + return stream; } From 26226fbb780f06e6f16fef50f60301e886f2364c Mon Sep 17 00:00:00 2001 From: Smruti Prakash Sahoo Date: Tue, 19 Apr 2022 12:22:40 +0530 Subject: [PATCH 2/2] feat(exportExcel): Send an email to user with download link once export completed Signed-off-by: Smruti Prakash Sahoo --- .../db/ProjectDatabaseHandler.java | 6 + .../org/eclipse/sw360/mail/MailConstants.java | 2 + .../java/org/eclipse/sw360/mail/MailUtil.java | 4 + .../src/main/resources/sw360.properties | 4 + .../sw360/projects/ProjectHandler.java | 5 + .../sw360/portal/common/PortalConstants.java | 4 + .../portlets/projects/ProjectPortlet.java | 106 +++++++++++++++++- .../META-INF/resources/html/projects/view.jsp | 37 ++++-- .../resources/content/Language.properties | 1 + .../resources/content/Language_ja.properties | 2 + .../resources/content/Language_vi.properties | 1 + .../eclipse/sw360/exporter/ExcelExporter.java | 70 +++++++++--- .../sw360/exporter/ProjectExporter.java | 76 +++++++------ .../sw360/exporter/ReleaseExporter.java | 73 ++++++++++++ .../sw360/exporter/helper/ProjectHelper.java | 6 +- .../sw360/exporter/helper/ReleaseHelper.java | 56 ++++++--- .../src/main/thrift/projects.thrift | 5 + 17 files changed, 378 insertions(+), 80 deletions(-) diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ProjectDatabaseHandler.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ProjectDatabaseHandler.java index c1cd6b79a4..3a108b0d36 100644 --- a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ProjectDatabaseHandler.java +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ProjectDatabaseHandler.java @@ -1553,6 +1553,12 @@ private void flattenlinkedReleaseOfRelease(Map rele })); } + public void sendExportSpreadsheetSuccessMail(String url, String recepient) throws TException { + mailUtil.sendMail(recepient, MailConstants.SUBJECT_SPREADSHEET_EXPORT_SUCCESS, + MailConstants.TEXT_SPREADSHEET_EXPORT_SUCCESS, SW360Constants.NOTIFICATION_CLASS_PROJECT, "", false, + url); + } + private Map createProjectCSRow(String relation, Project prj, List> clearingStatusList) { String projectId = prj.getId(); diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/mail/MailConstants.java b/backend/src-common/src/main/java/org/eclipse/sw360/mail/MailConstants.java index dc042be9a7..67b501b29e 100644 --- a/backend/src-common/src/main/java/org/eclipse/sw360/mail/MailConstants.java +++ b/backend/src-common/src/main/java/org/eclipse/sw360/mail/MailConstants.java @@ -41,6 +41,7 @@ public class MailConstants { public static final String SUBJECT_FOR_CLOSED_CLEARING_REQUEST = "subjectForClosedClearingRequest"; public static final String SUBJECT_FOR_REJECTED_CLEARING_REQUEST = "subjectForRejectedClearingRequest"; public static final String SUBJECT_FOR_UPDATED_PROJECT_WITH_CLEARING_REQUEST = "subjectForUpdatedProjectWithClearingRequest"; + public static final String SUBJECT_SPREADSHEET_EXPORT_SUCCESS = "subjectForSuccessfulExport"; public static final String TEXT_FOR_NEW_MODERATION_REQUEST = "textForNewModerationRequest"; public static final String TEXT_FOR_UPDATE_MODERATION_REQUEST = "textForUpdateModerationRequest"; @@ -55,6 +56,7 @@ public class MailConstants { public static final String TEXT_FOR_UPDATE_PROJECT = "textForUpdateProject"; public static final String TEXT_FOR_CLOSED_CLEARING_REQUEST = "textForClosedClearingRequest"; public static final String TEXT_FOR_REJECTED_CLEARING_REQUEST = "textForRejectedClearingRequest"; + public static final String TEXT_SPREADSHEET_EXPORT_SUCCESS = "textForSuccessfulExport"; private MailConstants() { // Utility class with only static functions diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/mail/MailUtil.java b/backend/src-common/src/main/java/org/eclipse/sw360/mail/MailUtil.java index 07d3de65b5..2b35c51009 100644 --- a/backend/src-common/src/main/java/org/eclipse/sw360/mail/MailUtil.java +++ b/backend/src-common/src/main/java/org/eclipse/sw360/mail/MailUtil.java @@ -72,6 +72,7 @@ public class MailUtil extends BackendUtils { private String enableSsl; private String enableDebug; private String supportMailAddress; + private String smtpSSLProtocol; public MailUtil() { mailExecutor = fixedThreadPoolWithQueueSize(MAIL_ASYNC_SEND_THREAD_LIMIT, MAIL_ASYNC_SEND_QUEUE_LIMIT); @@ -96,6 +97,7 @@ private void setBasicProperties() { password = loadedProperties.getProperty("MailUtil_password", ""); enableDebug = loadedProperties.getProperty("MailUtil_enableDebug", "false"); supportMailAddress = loadedProperties.getProperty("MailUtil_supportMailAddress",""); + smtpSSLProtocol = loadedProperties.getProperty("MailUtil_smtpSSLProtocol", ""); } private void setSession() { @@ -111,6 +113,8 @@ private void setSession() { properties.setProperty("mail.smtp.ssl.enable", enableSsl); properties.setProperty("mail.debug", enableDebug); + properties.setProperty("mail.smtp.ssl.protocols", smtpSSLProtocol); + if (!"false".equals(isAuthenticationNecessary)) { Authenticator auth = new SMTPAuthenticator(login, password); diff --git a/backend/src-common/src/main/resources/sw360.properties b/backend/src-common/src/main/resources/sw360.properties index 1f55cb9886..b85d7fdc42 100644 --- a/backend/src-common/src/main/resources/sw360.properties +++ b/backend/src-common/src/main/resources/sw360.properties @@ -25,6 +25,7 @@ MailUtil_login= MailUtil_password= MailUtil_enableDebug= MailUtil_supportMailAddress= +MailUtil_smtpSSLProtocol= # text patterns for mail utility defaultBegin = \ @@ -53,7 +54,9 @@ subjectForUpdatedClearingRequest= Your clearing request <%s> has been updated fo subjectForClosedClearingRequest= Your clearing request <%s> has been closed for Project <%s> subjectForRejectedClearingRequest= Your clearing request <%s> has been rejected for Project <%s> subjectForUpdatedProjectWithClearingRequest= Project <%s> with clearing request <%s> updated +subjectForSuccessfulExport = Spreadsheet Export Successful +textForSuccessfulExport = The project spreadsheet export successfully completed. Please find the download link(%s) here. textForNewModerationRequest= a new moderation request has been added to your SW360-account.\n\n textForUpdateModerationRequest= \ one of the moderation requests previously added to your \ @@ -79,3 +82,4 @@ textForRejectedClearingRequest= your clearing request with id: %s for the projec enable.sw360.change.log=false sw360changelog.output.path=sw360changelog/sw360changelog auto.set.ecc.status=false +send.project.spreadsheet.export.to.mail.enabled=false diff --git a/backend/src/src-projects/src/main/java/org/eclipse/sw360/projects/ProjectHandler.java b/backend/src/src-projects/src/main/java/org/eclipse/sw360/projects/ProjectHandler.java index 2e695860e9..1490239797 100644 --- a/backend/src/src-projects/src/main/java/org/eclipse/sw360/projects/ProjectHandler.java +++ b/backend/src/src-projects/src/main/java/org/eclipse/sw360/projects/ProjectHandler.java @@ -430,4 +430,9 @@ public Set getGroups() throws TException { public int getMyAccessibleProjectCounts(User user) throws TException { return handler.getMyAccessibleProjects(user); } + + @Override + public void sendExportSpreadsheetSuccessMail(String url, String recepient) throws TException { + handler.sendExportSpreadsheetSuccessMail(url, recepient); + } } diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/PortalConstants.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/PortalConstants.java index 04160c8d22..1f12fd8a5a 100644 --- a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/PortalConstants.java +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/PortalConstants.java @@ -45,6 +45,7 @@ public class PortalConstants { public static final String CLEARING_REPORT_TEMPLATE_TO_FILENAMEMAPPING; public static final String CLEARING_REPORT_TEMPLATE_FORMAT; public static final String DISABLE_CLEARING_REQUEST_FOR_PROJECT_WITH_GROUPS; + public static final Boolean SEND_PROJECT_SPREADSHEET_EXPORT_TO_MAIL_ENABLED; public static final String LOAD_OPEN_MODERATION_REQUEST = "loadOpenModerationRequest"; public static final String LOAD_CLOSED_MODERATION_REQUEST = "loadClosedModerationRequest"; @@ -592,6 +593,8 @@ public class PortalConstants { // Excel export public static final String EXPORT_TO_EXCEL = "export_to_excel"; + public static final String EMAIL_EXPORTED_EXCEL = "email_exported_excel"; + public static final String DOWNLOAD_EXCEL = "download_excel"; public static final String EXPORT_CLEARING_TO_EXCEL = "export_clearing_to_excel"; public static final String EXPORT_ID = "export_id"; @@ -695,6 +698,7 @@ public class PortalConstants { IS_COMPONENT_VISIBILITY_RESTRICTION_ENABLED = Boolean.parseBoolean( System.getProperty("RunComponentVisibilityRestrictionTest", props.getProperty("component.visibility.restriction.enabled", "false"))); DISABLE_CLEARING_REQUEST_FOR_PROJECT_WITH_GROUPS = props.getProperty("org.eclipse.sw360.disable.clearing.request.for.project.group", ""); + SEND_PROJECT_SPREADSHEET_EXPORT_TO_MAIL_ENABLED = Boolean.parseBoolean(props.getProperty("send.project.spreadsheet.export.to.mail.enabled", "false")); } private PortalConstants() { diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/projects/ProjectPortlet.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/projects/ProjectPortlet.java index 23d6e63086..e1ded78bf3 100644 --- a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/projects/ProjectPortlet.java +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/projects/ProjectPortlet.java @@ -207,8 +207,12 @@ public void serveResource(ResourceRequest request, ResourceResponse response) th updateVulnerabilitiesProject(request, response); } else if (PortalConstants.UPDATE_VULNERABILITY_RATINGS.equals(action)) { updateVulnerabilityRating(request, response); + } else if (PortalConstants.EMAIL_EXPORTED_EXCEL.equals(action)) { + exportExcelWithEmail(request, response); } else if (PortalConstants.EXPORT_TO_EXCEL.equals(action)) { exportExcel(request, response); + } else if (PortalConstants.DOWNLOAD_EXCEL.equals(action)) { + downloadExcel(request, response); } else if (PortalConstants.EXPORT_CLEARING_TO_EXCEL.equals(action)) { exportReleasesSpreadsheet(request, response); } else if (PortalConstants.DOWNLOAD_LICENSE_INFO.equals(action)) { @@ -290,6 +294,25 @@ else if ((PortalConstants.LOAD_OBLIGATIONS_EDIT.equals(action) } } + private void downloadExcel(ResourceRequest request, ResourceResponse response) { + final User user = UserCacheHolder.getUserFromRequest(request); + final String token = request.getParameter("token"); + String filename = null; + + try { + boolean extendedByReleases = Boolean.valueOf(request.getParameter(PortalConstants.EXTENDED_EXCEL_EXPORT)); + ProjectExporter exporter = new ProjectExporter(thriftClients.makeComponentClient(), + thriftClients.makeProjectClient(), user, extendedByReleases); + filename = String.format("projects-%s.xlsx", SW360Utils.getCreatedOn()); + PortletResponseUtil.sendFile(request, response, filename, exporter.downloadExcelSheet(token), + CONTENT_TYPE_OPENXML_SPREADSHEET); + } catch (IOException | TException e) { + log.error("An error occurred while generating the Excel export", e); + response.setProperty(ResourceResponse.HTTP_STATUS_CODE, + Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); + } + } + private void serveViewVendor(ResourceRequest request, ResourceResponse response) throws IOException, PortletException { String what = request.getParameter(PortalConstants.WHAT); String where = request.getParameter(PortalConstants.WHERE); @@ -1027,9 +1050,26 @@ private void exportExcel(ResourceRequest request, ResourceResponse response) { String filename = String.format("projects-%s.xlsx", SW360Utils.getCreatedOn()); try { boolean extendedByReleases = Boolean.valueOf(request.getParameter(PortalConstants.EXTENDED_EXCEL_EXPORT)); - List projects = getFilteredProjectList(request); + ProjectService.Iface client = thriftClients.makeProjectClient(); + int total = client.getMyAccessibleProjectCounts(user); + PaginationData pageData = new PaginationData(); + pageData.setAscending(true); + Map> pageDtToProjects; + Set projects = new HashSet<>(); + int displayStart = 0; + int rowsPerPage = 500; + while (0 < total) { + pageData.setDisplayStart(displayStart); + pageData.setRowsPerPage(rowsPerPage); + displayStart = displayStart + rowsPerPage; + pageDtToProjects = client.getAccessibleProjectsSummaryWithPagination(user, pageData); + projects.addAll(pageDtToProjects.entrySet().iterator().next().getValue()); + total = total - rowsPerPage; + } + + List listOfProjects = new ArrayList(projects); if (!isNullOrEmpty(projectId)) { - Project project = projects.stream().filter(p -> p.getId().equals(projectId)).findFirst().get(); + Project project = listOfProjects.stream().filter(p -> p.getId().equals(projectId)).findFirst().get(); fillVendor(project); filename = String.format("project-%s-%s-%s.xlsx", project.getName(), project.getVersion(), SW360Utils.getCreatedOn()); } @@ -1037,10 +1077,66 @@ private void exportExcel(ResourceRequest request, ResourceResponse response) { thriftClients.makeComponentClient(), thriftClients.makeProjectClient(), user, - projects, + listOfProjects, extendedByReleases); - PortletResponseUtil.sendFile(request, response, filename, exporter.makeExcelExport(projects), CONTENT_TYPE_OPENXML_SPREADSHEET); - } catch (IOException | SW360Exception e) { + PortletResponseUtil.sendFile(request, response, filename, exporter.makeExcelExport(listOfProjects), CONTENT_TYPE_OPENXML_SPREADSHEET); + } catch (IOException | TException e) { + log.error("An error occurred while generating the Excel export", e); + response.setProperty(ResourceResponse.HTTP_STATUS_CODE, + Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); + } + } + + private void exportExcelWithEmail(ResourceRequest request, ResourceResponse response) { + final User user = UserCacheHolder.getUserFromRequest(request); + final String projectId = request.getParameter(Project._Fields.ID.toString()); + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + String token = null; + + try { + setSessionMessage(request, LanguageUtil.get(resourceBundle,"excel.report.generation.has.started.we.will.send.you.an.email.with.download.link.once.completed")); + ProjectService.Iface client = thriftClients.makeProjectClient(); + boolean extendedByReleases = Boolean.valueOf(request.getParameter(PortalConstants.EXTENDED_EXCEL_EXPORT)); + int total = client.getMyAccessibleProjectCounts(user); + PaginationData pageData = new PaginationData(); + pageData.setAscending(true); + Map> pageDtToProjects; + Set projects = new HashSet<>(); + int displayStart = 0; + int rowsPerPage = 500; + while (0 < total) { + pageData.setDisplayStart(displayStart); + pageData.setRowsPerPage(rowsPerPage); + displayStart = displayStart + rowsPerPage; + pageDtToProjects = client.getAccessibleProjectsSummaryWithPagination(user, pageData); + projects.addAll(pageDtToProjects.entrySet().iterator().next().getValue()); + total = total - rowsPerPage; + } + + List listOfProjects = new ArrayList(projects); + if (!isNullOrEmpty(projectId)) { + Project project = listOfProjects.stream().filter(p -> p.getId().equals(projectId)).findFirst().get(); + fillVendor(project); + } + ProjectExporter exporter = new ProjectExporter(thriftClients.makeComponentClient(), + thriftClients.makeProjectClient(), user, listOfProjects, extendedByReleases); + + token = exporter.makeExcelExportForProject(listOfProjects, user); + + String portletId = (String) request.getAttribute(WebKeys.PORTLET_ID); + ThemeDisplay tD = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY); + long plid = tD.getPlid(); + + LiferayPortletURL projectUrl = PortletURLFactoryUtil.create(request, portletId, plid, + PortletRequest.RESOURCE_PHASE); + projectUrl.setParameter("action", PortalConstants.DOWNLOAD_EXCEL); + projectUrl.setParameter("token", token); + projectUrl.setParameter(PortalConstants.EXTENDED_EXCEL_EXPORT, String.valueOf(extendedByReleases)); + + if(!CommonUtils.isNullEmptyOrWhitespace(token)) { + client.sendExportSpreadsheetSuccessMail(projectUrl.toString(), user.getEmail()); + } + } catch (IOException | TException | PortletException e) { log.error("An error occurred while generating the Excel export", e); response.setProperty(ResourceResponse.HTTP_STATUS_CODE, Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/projects/view.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/projects/view.jsp index 5442895093..50c7956353 100644 --- a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/projects/view.jsp +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/projects/view.jsp @@ -71,6 +71,11 @@ + + + + +