Skip to content

Commit

Permalink
implement #549 waiting queue export (#635)
Browse files Browse the repository at this point in the history
* #549 implement export waiting queue api + refactor

* add ui+additional data #549
  • Loading branch information
syjer authored and cbellone committed May 5, 2019
1 parent ba9f47c commit 5b7822f
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import alfio.model.system.Configuration;
import alfio.model.system.ConfigurationKeys;
import alfio.util.EventUtil;
import alfio.util.ExportUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.lang3.tuple.Pair;
Expand All @@ -36,10 +37,12 @@
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.Principal;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static alfio.model.system.ConfigurationKeys.STOP_WAITING_QUEUE_SUBSCRIPTIONS;
import static java.util.Collections.singletonList;
Expand Down Expand Up @@ -110,6 +113,31 @@ public List<WaitingQueueSubscription> loadAllSubscriptions(@PathVariable("eventN
return Collections.emptyList();
}

@GetMapping("/download")
public void downloadAllSubscriptions(@PathVariable("eventName") String eventName,
@RequestParam(name = "format", defaultValue = "excel") String format,
Principal principal, HttpServletResponse response) throws IOException {
var event = eventManager.getSingleEvent(eventName, principal.getName());
var found = waitingQueueManager.loadAllSubscriptionsForEvent(event.getId());

var header = new String[] {"Type", "Firstname", "Lastname", "Email", "Language", "Status", "Date"};
var lines = convertSubscriptions(found, event);
if ("excel".equals(format)) {
ExportUtils.exportExcel(eventName + "-waiting-queue.xlsx", "waiting-queue",
header,
lines, response);
} else {
ExportUtils.exportCsv(eventName + "-waiting-queue.csv", header, lines, response);
}
}

private static Stream<String[]> convertSubscriptions(List<WaitingQueueSubscription> l, Event event) {
return l.stream().map(s -> new String[] {s.getSubscriptionType().toString(),
s.getFirstName(), s.getLastName(), s.getEmailAddress(),
s.getLocale().toLanguageTag(), s.getStatus().name(),
s.getCreation().withZoneSameInstant(event.getZoneId()).toString()});
}

@RequestMapping(value = "/subscriber/{subscriberId}", method = RequestMethod.DELETE)
public ResponseEntity<Map<String, Object>> removeSubscriber(@PathVariable("eventName") String eventName,
@PathVariable("subscriberId") int subscriberId,
Expand Down
69 changes: 11 additions & 58 deletions src/main/java/alfio/controller/api/admin/EventApiController.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,11 @@
import alfio.repository.DynamicFieldTemplateRepository;
import alfio.repository.SponsorScanRepository;
import alfio.repository.TicketFieldRepository;
import alfio.util.ExportUtils;
import alfio.util.MonetaryUtil;
import alfio.util.TemplateManager;
import alfio.util.Validator;
import ch.digitalfondue.basicxlsx.Cell;
import ch.digitalfondue.basicxlsx.StreamingWorkbook;
import ch.digitalfondue.basicxlsx.Style;
import com.opencsv.CSVReader;
import com.opencsv.CSVWriter;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
Expand All @@ -61,13 +58,11 @@
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.security.Principal;
import java.text.DateFormat;
Expand Down Expand Up @@ -279,7 +274,6 @@ public String unbindTickets(@PathVariable("eventName") String eventName, @PathVa
private static final List<String> FIXED_FIELDS = Arrays.asList("ID", "Creation", "Category", "Event", "Status", "OriginalPrice", "PaidPrice", "Discount", "VAT", "ReservationID", "Full Name", "First Name", "Last Name", "E-Mail", "Locked", "Language", "Confirmation", "Billing Address", "Payment ID", "Payment Method");
private static final List<SerializablePair<String, String>> FIXED_PAIRS = FIXED_FIELDS.stream().map(f -> SerializablePair.of(f, f)).collect(toList());
private static final List<String> ITALIAN_E_INVOICING_FIELDS = List.of("Fiscal Code", "Reference Type", "Addressee Code", "PEC");
private static final int[] BOM_MARKERS = new int[] {0xEF, 0xBB, 0xBF};

@RequestMapping("/events/{eventName}/export")
public void downloadAllTicketsCSV(@PathVariable("eventName") String eventName, @RequestParam(name = "format", defaultValue = "excel") String format, HttpServletRequest request, HttpServletResponse response, Principal principal) throws IOException {
Expand All @@ -296,47 +290,18 @@ public void downloadAllTicketsCSV(@PathVariable("eventName") String eventName, @
}

private void exportTicketExcel(String eventName, HttpServletResponse response, Principal principal, List<String> fields, Map<Integer,TicketCategory> categoriesMap, ZoneId eventZoneId) throws IOException {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=" + eventName + "-export.xlsx");
ExportUtils.exportExcel(eventName + "-export.xlsx",
eventName + " export",
exportHeader(fields),
exportLines(eventName, principal, fields, categoriesMap, eventZoneId), response);

try (ServletOutputStream out = response.getOutputStream()) {
exportExcel(eventName + " export", exportHeader(fields), exportLines(eventName, principal, fields, categoriesMap, eventZoneId).collect(Collectors.toList()), out);
}
}

private void exportExcel(String sheetName, String[] header, List<String[]> data, OutputStream out) throws IOException {
try (StreamingWorkbook workbook = new StreamingWorkbook(out)) {
Style boldFont = workbook.defineStyle().font().bold(true).build();

StreamingWorkbook.Row headerRow = StreamingWorkbook.row(Arrays.stream(header)
.map(v -> Cell.cell(v).withStyle(boldFont))
.collect(Collectors.toList()));

Stream<StreamingWorkbook.Row> dataStream = data.stream()
.map(rowData -> Arrays.stream(rowData).map(Cell::cell).collect(Collectors.toList()))
.map(StreamingWorkbook::row);

workbook.withSheet(sheetName, Stream.concat(Stream.of(headerRow), dataStream));
}
}

private void exportTicketCSV(String eventName, HttpServletResponse response,
Principal principal, List<String> fields,
Map<Integer, TicketCategory> categoriesMap,
ZoneId eventZoneId) throws IOException {

response.setContentType("text/csv;charset=UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=" + eventName + "-export.csv");

try(ServletOutputStream out = response.getOutputStream(); CSVWriter writer = new CSVWriter(new OutputStreamWriter(out))) {
for (int marker : BOM_MARKERS) {//UGLY-MODE_ON: specify that the file is written in UTF-8 with BOM, thanks to alexr http://stackoverflow.com/a/4192897
out.write(marker);
}
writer.writeNext(exportHeader(fields));
exportLines(eventName, principal, fields, categoriesMap, eventZoneId).forEachOrdered(writer::writeNext);
writer.flush();
out.flush();
}
ExportUtils.exportCsv(eventName + "-export.csv", exportHeader(fields), exportLines(eventName, principal, fields, categoriesMap, eventZoneId), response);
}

private String[] exportHeader(List<String> fields) {
Expand Down Expand Up @@ -451,27 +416,15 @@ public void downloadSponsorScanExport(@PathVariable("eventName") String eventNam

private void exportSponsorScanExcel(String eventName, List<String> header, Stream<String[]> sponsorScans,
HttpServletResponse response) throws IOException {

response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=" + eventName + "-sponsor-scan.xlsx");
try (OutputStream os = response.getOutputStream()) {
exportExcel(eventName + " sponsor scan", header.toArray(new String[0]), sponsorScans.collect(toList()), os);
}
ExportUtils.exportExcel(eventName + "-sponsor-scan.xlsx",
eventName + " sponsor scan",
header.toArray(new String[0]),
sponsorScans, response);
}

private void exportSponsorScanCSV(String eventName, List<String> header, Stream<String[]> sponsorScans,
HttpServletResponse response) throws IOException {
response.setContentType("text/csv;charset=UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=" + eventName + "-sponsor-scan.csv");
try (ServletOutputStream out = response.getOutputStream(); CSVWriter writer = new CSVWriter(new OutputStreamWriter(out))) {
for (int marker : BOM_MARKERS) {
out.write(marker);
}
writer.writeNext(header.toArray(new String[0]));
sponsorScans.forEachOrdered(writer::writeNext);
writer.flush();
out.flush();
}
ExportUtils.exportCsv(eventName + "-sponsor-scan.csv", header.toArray(new String[0]), sponsorScans, response);
}

@RequestMapping("/events/{eventName}/fields")
Expand Down
69 changes: 69 additions & 0 deletions src/main/java/alfio/util/ExportUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* This file is part of alf.io.
*
* alf.io is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* alf.io is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with alf.io. If not, see <http://www.gnu.org/licenses/>.
*/
package alfio.util;

import ch.digitalfondue.basicxlsx.Cell;
import ch.digitalfondue.basicxlsx.StreamingWorkbook;
import com.opencsv.CSVWriter;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ExportUtils {

public static final int[] BOM_MARKERS = new int[] {0xEF, 0xBB, 0xBF};

public static void exportExcel(String fileName, String sheetName, String[] header, Stream<String[]> data, HttpServletResponse response) throws IOException {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);


try (ServletOutputStream out = response.getOutputStream(); StreamingWorkbook workbook = new StreamingWorkbook(out)) {
var boldFont = workbook.defineStyle().font().bold(true).build();

var headerRow = StreamingWorkbook.row(Arrays.stream(header)
.map(v -> Cell.cell(v).withStyle(boldFont))
.collect(Collectors.toList()));

var dataStream = data
.map(rowData -> Arrays.stream(rowData).map(Cell::cell).collect(Collectors.toList()))
.map(StreamingWorkbook::row);

workbook.withSheet(sheetName, Stream.concat(Stream.of(headerRow), dataStream));
}
}

public static void exportCsv(String fileName, String[] header, Stream<String[]> data, HttpServletResponse response) throws IOException {
response.setContentType("text/csv;charset=UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);

try (ServletOutputStream out = response.getOutputStream(); CSVWriter writer = new CSVWriter(new OutputStreamWriter(out))) {
for (int marker : ExportUtils.BOM_MARKERS) {
out.write(marker);
}
writer.writeNext(header);
data.forEachOrdered(writer::writeNext);
writer.flush();
out.flush();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div class="modal-header">
<h3>Download waiting queue data</h3>
</div>
<div class="modal-body">
<p>
<label><input type="radio" name="format" value="excel" ng-model="format"> Excel</label>
<label><input type="radio" name="format" value="csv" ng-model="format"> csv</label>
</p>
</div>
<div class="modal-footer">
<div class="pull-right">
<button class="btn btn-primary" type="button" data-ng-click="download()" ><i class="fa fa-download"></i> download waiting queue data</button>
<button class="btn btn-default" type="button" data-ng-click="ctrl.close()"><i class="fa fa-times"></i> close</button>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<a data-uib-dropdown-toggle id="download-dpdwn" class="btn btn-default"><i class="fa fa-download"></i> Download <span class="caret"></span></a>
<ul class="dropdown-menu" data-uib-dropdown-menu role="menu" aria-labelledby="download-dpdwn">
<li role="menuitem"><a data-ng-click="ctrl.openFieldSelectionModal()"><i class="fa fa-users"></i> attendees' data</a></li>
<li role="menuitem"><a data-ng-click="ctrl.openWaitingQueueModal()" ><i class="fa fa-group"></i> waiting queue</a></li>
<li role="menuitem"><a data-ng-click="ctrl.downloadSponsorsScan()" ><i class="fa fa-barcode"></i> sponsors scan</a></li>
<li role="menuitem"><a data-ng-click="ctrl.downloadInvoices()" ><i class="fa fa-file-o"></i> all invoices</a></li>
</ul>
Expand Down
28 changes: 27 additions & 1 deletion src/main/webapp/resources/js/admin/directive/admin-directive.js
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,7 @@
scope: {},
controllerAs: 'ctrl',
templateUrl: '/resources/angular-templates/admin/partials/main/sidebar.html',
controller: ['$location', '$anchorScroll', '$scope', 'NotificationHandler', function($location, $anchorScroll, $scope, NotificationHandler) {
controller: ['$location', '$anchorScroll', '$scope', 'NotificationHandler', '$uibModal', function($location, $anchorScroll, $scope, NotificationHandler, $uibModal) {
var ctrl = this;
var toUnbind = [];
var detectCurrentView = function(state) {
Expand Down Expand Up @@ -916,6 +916,32 @@
}
$window.open(pathName+"api/events/"+ctrl.event.shortName+"/sponsor-scan/export");
};
ctrl.openWaitingQueueModal = function() {
var modal = $uibModal.open({
size:'lg',
templateUrl: '/resources/angular-templates/admin/partials/event/fragment/download-waiting-queue.html',
backdrop: 'static',
controllerAs: 'ctrl',
controller: function($scope) {
var outCtrl = ctrl;
var ctrl = this;
$scope.format = 'excel';

$scope.download = function() {
var queryString = "format="+$scope.format;
var pathName = $window.location.pathname;
if(!pathName.endsWith("/")) {
pathName = pathName + "/";
}
$window.open(pathName+"api/event/" + event.event.shortName + "/waiting-queue/download?"+queryString);
}

ctrl.close = function() {
modal.close();
}
}
});
};
ctrl.downloadInvoices = function() {
EventService.countInvoices(ctrl.event.shortName).then(function (res) {
var count = res.data;
Expand Down

0 comments on commit 5b7822f

Please sign in to comment.