Skip to content

Commit

Permalink
feat(exportExcel): Send an email to user with download link once expo…
Browse files Browse the repository at this point in the history
…rt completed

Signed-off-by: Smruti Prakash Sahoo <smruti.sahoo@siemens.com>
  • Loading branch information
smrutis1 committed Apr 19, 2022
1 parent 63529bd commit ecbc418
Show file tree
Hide file tree
Showing 14 changed files with 303 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1553,6 +1553,12 @@ private void flattenlinkedReleaseOfRelease(Map<String, ReleaseRelationship> 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<String, String> createProjectCSRow(String relation, Project prj,
List<Map<String, String>> clearingStatusList) {
String projectId = prj.getId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ private void setSession() {
properties.setProperty("mail.smtp.ssl.enable", enableSsl);

properties.setProperty("mail.debug", enableDebug);
properties.setProperty("mail.smtp.starttls.enable", "true");
properties.setProperty("mail.smtp.ssl.protocols", "TLSv1.2");


if (!"false".equals(isAuthenticationNecessary)) {
Authenticator auth = new SMTPAuthenticator(login, password);
Expand Down
2 changes: 2 additions & 0 deletions backend/src-common/src/main/resources/sw360.properties
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,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 \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,4 +430,9 @@ public Set<String> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,9 @@ public class PortalConstants {

// Excel export
public static final String EXPORT_TO_EXCEL = "export_to_excel";
public static final String DOWNLOAD_EXCEL = "download_excel";
public static final String VERIFY_DOWNLOAD_EXCEL = "verify_download_excel";
public static final String GENERATE_EXCEL_PROJECT = "generateProjectExcel";
public static final String EXPORT_CLEARING_TO_EXCEL = "export_clearing_to_excel";
public static final String EXPORT_ID = "export_id";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URLConnection;
import java.time.format.DateTimeFormatter;
Expand Down Expand Up @@ -208,6 +209,8 @@ public void serveResource(ResourceRequest request, ResourceResponse response) th
updateVulnerabilityRating(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)) {
Expand Down Expand Up @@ -287,6 +290,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);
Expand Down Expand Up @@ -1021,23 +1043,52 @@ private void serveRemoveProject(ResourceRequest request, ResourceResponse respon
private void exportExcel(ResourceRequest request, ResourceResponse response) {
final User user = UserCacheHolder.getUserFromRequest(request);
final String projectId = request.getParameter(Project._Fields.ID.toString());
String filename = String.format("projects-%s.xlsx", SW360Utils.getCreatedOn());
String token = null;

try {
setSessionMessage(request, "Excel export 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));
List<Project> projects = getFilteredProjectList(request);
int total = client.getMyAccessibleProjectCounts(user);
PaginationData pageData = new PaginationData();
pageData.setAscending(true);
Map<PaginationData, List<Project>> pageDtToProjects;
Set<Project> 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<Project> listOfProjects = new ArrayList<Project>(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());
}
ProjectExporter exporter = new ProjectExporter(
thriftClients.makeComponentClient(),
thriftClients.makeProjectClient(),
user,
projects,
extendedByReleases);
PortletResponseUtil.sendFile(request, response, filename, exporter.makeExcelExport(projects), CONTENT_TYPE_OPENXML_SPREADSHEET);
} catch (IOException | SW360Exception e) {
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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@
<portlet:param name="<%=PortalConstants.ACTION%>" value='<%=PortalConstants.LOAD_PROJECT_LIST%>'/>
</portlet:resourceURL>

<portlet:resourceURL var="generateExcelReport">
<portlet:param name="<%=PortalConstants.ACTION%>" value="<%=PortalConstants.EXPORT_TO_EXCEL%>"/>
<portlet:param name="<%=PortalConstants.PROJECT_ID%>" value="${docid}"/>
</portlet:resourceURL>

<portlet:resourceURL var="downloadExcelReport">
<portlet:param name="<%=PortalConstants.ACTION%>" value="<%=PortalConstants.DOWNLOAD_EXCEL%>"/>
<portlet:param name="<%=PortalConstants.PROJECT_ID%>" value="${docid}"/>
</portlet:resourceURL>

<portlet:resourceURL var="verifyDownloadExcelReport">
<portlet:param name="<%=PortalConstants.ACTION%>" value="<%=PortalConstants.VERIFY_DOWNLOAD_EXCEL%>"/>
<portlet:param name="<%=PortalConstants.PROJECT_ID%>" value="${docid}"/>
</portlet:resourceURL>


<div class="container" style="display: none;">
<div class="row">
<div class="col-3 sidebar">
Expand Down Expand Up @@ -530,17 +546,15 @@
// Export Spreadsheet action
function exportSpreadsheet(type) {
var portletURL = PortletURL.createURL('<%= PortletURLFactoryUtil.create(request, portletDisplay.getId(), themeDisplay.getPlid(), PortletRequest.RESOURCE_PHASE) %>')
.setParameter('<%=PortalConstants.ACTION%>', '<%=PortalConstants.EXPORT_TO_EXCEL%>');
portletURL.setParameter('<%=Project._Fields.NAME%>', $('#project_name').val());
portletURL.setParameter('<%=Project._Fields.TYPE%>', $('#project_type').val());
portletURL.setParameter('<%=Project._Fields.PROJECT_RESPONSIBLE%>', $('#project_responsible').val());
portletURL.setParameter('<%=Project._Fields.BUSINESS_UNIT%>', $('#group').val());
portletURL.setParameter('<%=Project._Fields.STATE%>', $('#project_state').val());
portletURL.setParameter('<%=Project._Fields.TAG%>', $('#tag').val());
portletURL.setParameter('<%=PortalConstants.EXTENDED_EXCEL_EXPORT%>', type === 'projectWithReleases' ? 'true' : 'false');
window.location.href = portletURL.toString();
var isWithReleases = (type === 'projectWithReleases' ? 'true' : 'false');
$.ajax({
type: 'POST',
url: '<%=generateExcelReport%>',
cache: false,
data: {
"<portlet:namespace/><%=PortalConstants.EXTENDED_EXCEL_EXPORT%>": isWithReleases,
}
});
}
// delete action
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
package org.eclipse.sw360.exporter;


import org.apache.commons.compress.archivers.zip.Zip64Mode;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.eclipse.sw360.datahandler.common.SW360Utils;
import org.eclipse.sw360.datahandler.thrift.SW360Exception;
import org.eclipse.sw360.datahandler.thrift.users.User;
import org.eclipse.sw360.exporter.helper.ExporterHelper;
import org.eclipse.sw360.exporter.utils.SubTable;

Expand All @@ -27,7 +30,6 @@
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;

Expand All @@ -39,15 +41,16 @@
public class ExcelExporter<T, U extends ExporterHelper<T>> {

protected final U helper;
private static final String SLASH = "/";
private static final String TMP_EXPORTEDFILES = "/tmp/";

public ExcelExporter(U helper) {
this.helper = helper;
}

public String makeExcelExport(List<T> documents) throws IOException, SW360Exception {
public InputStream makeExcelExport(List<T> documents) throws IOException, SW360Exception {
final SXSSFWorkbook workbook = new SXSSFWorkbook();
//final ByteArrayInputStream stream;
String token = UUID.randomUUID().toString();
final ByteArrayInputStream stream;
try {
SXSSFSheet sheet = workbook.createSheet("Data");

Expand All @@ -68,22 +71,59 @@ public String makeExcelExport(List<T> documents) throws IOException, SW360Except
/** Copy the streams */
final ByteArrayOutputStream out = new ByteArrayOutputStream();
workbook.write(out);

try(OutputStream outputStream = new FileOutputStream("/tmp/"+token)) {
out.writeTo(outputStream);
out.flush();
}
//stream = new ByteArrayInputStream(out.toByteArray());
stream = new ByteArrayInputStream(out.toByteArray());
}finally{
workbook.dispose();
}
return token;
return stream;
}

public String makeExcelExportForProject(List<T> documents, User user) throws IOException, SW360Exception {
final SXSSFWorkbook workbook = new SXSSFWorkbook();
String token = UUID.randomUUID().toString();
String filePath = TMP_EXPORTEDFILES + user.getEmail() + SLASH;
File file;
try {
File dir = new File(filePath);
dir.mkdir();
file = new File(dir.getPath() + SLASH + SW360Utils.getCreatedOn() + "_" + token);
file.createNewFile();
SXSSFSheet sheet = workbook.createSheet("Data");

/** Adding styles to cells */
CellStyle cellStyle = createCellStyle(workbook);
CellStyle headerStyle = createHeaderStyle(workbook);

/** Create header row */
Row headerRow = sheet.createRow(0);
List<String> headerNames = helper.getHeaders();
fillRow(headerRow, headerNames, headerStyle);

/** Create data rows */
fillValues(sheet, documents, cellStyle);

// removed autosizing of spreadsheet columns for performance reasons

/** Copy the streams */

try (OutputStream outputStream = new FileOutputStream(file.getPath())) {
workbook.setZip64Mode(Zip64Mode.Always);
workbook.write(outputStream);
outputStream.close();
}
} finally {
workbook.dispose();
}
return file.getPath();
}

public InputStream downloadExcelSheet(String token) {
InputStream stream = null;
try {
stream = new FileInputStream(new File("/tmp/" + token));
File file = new File(token);
if (file.exists()) {
stream = new FileInputStream(new File(token));
}
} catch (FileNotFoundException e) {
// logger
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.eclipse.sw360.datahandler.thrift.projects.Project._Fields.DOCUMENT_STATE;
import static org.eclipse.sw360.datahandler.thrift.projects.Project._Fields.PERMISSIONS;
import static org.eclipse.sw360.datahandler.thrift.projects.Project._Fields.REVISION;
import static org.eclipse.sw360.datahandler.thrift.projects.Project._Fields.*;
//import static org.eclipse.sw360.datahandler.thrift.projects.Project._Fields.PERMISSIONS;
//import static org.eclipse.sw360.datahandler.thrift.projects.Project._Fields.REVISION;

public class ProjectExporter extends ExcelExporter<Project, ProjectHelper> {

Expand Down Expand Up @@ -71,9 +71,18 @@ public class ProjectExporter extends ExcelExporter<Project, ProjectHelper> {
.add(PERMISSIONS)
.build();

private static final List<Project._Fields> PROJECT_REQUIRED_FIELDS = ImmutableList.<Project._Fields>builder()
.add(NAME)
.add(VERSION)
.add(BUSINESS_UNIT)
.add(PROJECT_TYPE)
.add(TAG)
.add(CLEARING_STATE)
.build();

public static final List<Project._Fields> PROJECT_RENDERED_FIELDS = Project.metaDataMap.keySet()
.stream()
.filter(k -> ! PROJECT_IGNORED_FIELDS.contains(k))
.filter(k -> PROJECT_REQUIRED_FIELDS.contains(k))
.collect(Collectors.toList());

public static List<String> HEADERS = PROJECT_RENDERED_FIELDS
Expand All @@ -82,13 +91,18 @@ public class ProjectExporter extends ExcelExporter<Project, ProjectHelper> {
.map(n -> SW360Utils.displayNameFor(n, nameToDisplayName))
.collect(Collectors.toList());

public static List<String> HEADERS_EXTENDED_BY_RELEASES = ExporterHelper.addSubheadersWithPrefixesAsNeeded(HEADERS, ReleaseExporter.HEADERS, "release: ");
public static List<String> HEADERS_EXTENDED_BY_RELEASES = ExporterHelper.addSubheadersWithPrefixesAsNeeded(HEADERS, ReleaseExporter.RELEASE_HEADERS_PROJECT_EXPORT, "release: ");

public ProjectExporter(ComponentService.Iface componentClient, ProjectService.Iface projectClient, User user, List<Project> projects, boolean extendedByReleases) throws SW360Exception {
super(new ProjectHelper(projectClient, user, extendedByReleases, new ReleaseHelper(componentClient, user)));
preloadRelatedDataFor(projects, extendedByReleases, user);
}

public ProjectExporter(ComponentService.Iface componentClient, ProjectService.Iface projectClient, User user,
boolean extendedByReleases) throws SW360Exception {
super(new ProjectHelper(projectClient, user, extendedByReleases, new ReleaseHelper(componentClient, user)));
}

private void preloadRelatedDataFor(List<Project> projects, boolean withLinkedOfLinked, User user) throws SW360Exception {
Function<Function<Project, Map<String, ?>>, Set<String>> extractIds = mapExtractor -> projects
.stream()
Expand Down
Loading

0 comments on commit ecbc418

Please sign in to comment.