From a9df7c56783227aa67b2454c3225d7af8f1645e1 Mon Sep 17 00:00:00 2001 From: gaetancollaud Date: Fri, 21 Aug 2015 22:58:34 +0200 Subject: [PATCH] export --- pom.xml | 27 +++++-- .../collaud/fablab/manager/data/UserEO.java | 13 +++ .../manager/data/virtual/HistoryEntry.java | 9 +++ .../data/virtual/HistoryEntryUser.java | 5 ++ .../fablab/manager/export/CsvExport.java | 17 ++++ .../fablab/manager/export/CsvExporter.java | 81 +++++++++++++++++++ .../fablab/manager/export/CsvField.java | 16 ++++ .../fablab/manager/rest/v1/AccoutingWS.java | 24 ++++++ .../rest/v1/base/ReadRestWebservice.java | 22 ++++- .../accounting/accounting-list-ctrl.js | 23 +++--- src/main/webapp/components/user/list-ctrl.js | 4 + .../webapp/components/user/list-view.html | 2 +- 12 files changed, 223 insertions(+), 20 deletions(-) create mode 100644 src/main/java/net/collaud/fablab/manager/export/CsvExport.java create mode 100644 src/main/java/net/collaud/fablab/manager/export/CsvExporter.java create mode 100644 src/main/java/net/collaud/fablab/manager/export/CsvField.java diff --git a/pom.xml b/pom.xml index 85e39c8b..f6feedfc 100644 --- a/pom.xml +++ b/pom.xml @@ -192,11 +192,11 @@ - - net.tanesha.recaptcha4j - recaptcha4j - 0.0.7 - + + net.tanesha.recaptcha4j + recaptcha4j + 0.0.7 + @@ -208,6 +208,19 @@ + + + + org.apache.maven.plugins + maven-release-plugin + 2.5.2 + + true + true + + + + org.apache.maven.plugins @@ -255,6 +268,6 @@ https://github.com/gaetancollaud/fablab-manager scm:git:git://github.com/gaetancollaud/fablab-manager.git scm:git:git@github.com:gaetancollaud/fablab-manager.git - HEAD - + HEAD + \ No newline at end of file diff --git a/src/main/java/net/collaud/fablab/manager/data/UserEO.java b/src/main/java/net/collaud/fablab/manager/data/UserEO.java index 4a066960..75712ba3 100644 --- a/src/main/java/net/collaud/fablab/manager/data/UserEO.java +++ b/src/main/java/net/collaud/fablab/manager/data/UserEO.java @@ -31,6 +31,8 @@ import lombok.Setter; import lombok.ToString; import net.collaud.fablab.manager.data.type.Gender; +import net.collaud.fablab.manager.export.CsvExport; +import net.collaud.fablab.manager.export.CsvField; /** * @@ -43,6 +45,7 @@ @ToString @NoArgsConstructor @AllArgsConstructor +@CsvExport(fileName = "users") public class UserEO extends AbstractDataEO implements Serializable { private static final long serialVersionUID = 1L; @@ -64,26 +67,33 @@ public class UserEO extends AbstractDataEO implements Serializable { @JsonProperty private String passwordNew; + @CsvField(headerName="Firstname") @Column(name = "firstname", nullable = false) private String firstname; + @CsvField(headerName="Lastname") @Column(name = "lastname", nullable = false) private String lastname; + @CsvField(headerName="Email") @Column(name = "email", nullable = false, unique = true) private String email; + @CsvField(headerName="Inscription date") @Column(name = "date_inscr", nullable = false) @Temporal(TemporalType.TIMESTAMP) private Date dateInscr; + @CsvField(headerName="Rfid") @Column(name = "rfid", nullable = true) private String rfid; + @CsvField(headerName="birthdate") @Column(name = "birthdate", nullable = true) @Temporal(TemporalType.DATE) private Date birthdate; + @CsvField(headerName="Gender") @Column(name = "gender", nullable = true) @Enumerated(EnumType.ORDINAL) private Gender gender; @@ -92,12 +102,15 @@ public class UserEO extends AbstractDataEO implements Serializable { @Column(name = "enabled", nullable = false) private boolean enabled; + @CsvField(headerName="Phone") @Column(name = "phone", nullable = true) private String phone; + @CsvField(headerName="Address") @Column(name = "address", nullable = true) private String address; + @CsvField(headerName="Comment") @Column(name = "comment", nullable = true) private String comment; diff --git a/src/main/java/net/collaud/fablab/manager/data/virtual/HistoryEntry.java b/src/main/java/net/collaud/fablab/manager/data/virtual/HistoryEntry.java index fc3af4aa..886f71d0 100644 --- a/src/main/java/net/collaud/fablab/manager/data/virtual/HistoryEntry.java +++ b/src/main/java/net/collaud/fablab/manager/data/virtual/HistoryEntry.java @@ -9,6 +9,8 @@ import net.collaud.fablab.manager.data.UsageEO; import net.collaud.fablab.manager.data.UserEO; import net.collaud.fablab.manager.data.type.HistoryEntryType; +import net.collaud.fablab.manager.export.CsvExport; +import net.collaud.fablab.manager.export.CsvField; /** * @@ -17,14 +19,21 @@ @Getter @Setter @EqualsAndHashCode(of = {"id", "type"}) +@CsvExport(fileName = "accounting") public class HistoryEntry implements Comparable { private final int id; + @CsvField(headerName = "type") private final HistoryEntryType type; + @CsvField(headerName = "comment") private final String comment; + @CsvField(headerName = "date") private final Date date; + @CsvField(headerName = "amount") private final double amount; + @CsvField(headerName = "detail") private final String detail; + @CsvField(headerName = "user") private final HistoryEntryUser user; public HistoryEntry(PaymentEO payment) { diff --git a/src/main/java/net/collaud/fablab/manager/data/virtual/HistoryEntryUser.java b/src/main/java/net/collaud/fablab/manager/data/virtual/HistoryEntryUser.java index 6fc80da7..7ba124ec 100644 --- a/src/main/java/net/collaud/fablab/manager/data/virtual/HistoryEntryUser.java +++ b/src/main/java/net/collaud/fablab/manager/data/virtual/HistoryEntryUser.java @@ -21,4 +21,9 @@ public HistoryEntryUser(UserEO user){ this.firstname = user.getFirstname(); } + @Override + public String toString() { + return firstname+" "+lastname; + } + } diff --git a/src/main/java/net/collaud/fablab/manager/export/CsvExport.java b/src/main/java/net/collaud/fablab/manager/export/CsvExport.java new file mode 100644 index 00000000..3c2e879a --- /dev/null +++ b/src/main/java/net/collaud/fablab/manager/export/CsvExport.java @@ -0,0 +1,17 @@ +package net.collaud.fablab.manager.export; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author Gaetan Collaud + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface CsvExport { + public String fileName(); + +} diff --git a/src/main/java/net/collaud/fablab/manager/export/CsvExporter.java b/src/main/java/net/collaud/fablab/manager/export/CsvExporter.java new file mode 100644 index 00000000..dbf1b4f3 --- /dev/null +++ b/src/main/java/net/collaud/fablab/manager/export/CsvExporter.java @@ -0,0 +1,81 @@ +package net.collaud.fablab.manager.export; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.BinaryOperator; +import lombok.extern.slf4j.Slf4j; + +/** + * + * @author Gaetan Collaud + */ +@Slf4j +public class CsvExporter { + + public static final String FIELD_SEPARATOR = ";"; + public static final String LINE_SEPARATOR = "\n"; + public static final String ESCAPE_CHAR = "\""; + + private final Map fields; + private final CsvExport classAnnotation; + private final StringBuilder builder; + + public CsvExporter(Class type) { + fields = new LinkedHashMap<>(); + builder = new StringBuilder(); + classAnnotation = Optional.ofNullable(type.getAnnotation(CsvExport.class)) + .orElseThrow(() -> new IllegalArgumentException("Class " + type.getSimpleName() + " has no CsvExport annotation")); + Arrays.stream(type.getDeclaredFields()) + .filter(f -> f.getAnnotation(CsvField.class) != null) + .forEach(f -> fields.put(f, f.getAnnotation(CsvField.class))); + } + + public CsvExporter writeHeader() { + return writeLine(fields.values().stream() + .map(f -> f.headerName()) + .reduce(reduce()) + .orElse("")); + } + + public CsvExporter writeRow(T obj) { + return writeLine(fields.keySet().stream() + .map(f -> getFieldValue(obj, f)) + .reduce(reduce()) + .orElse("")); + } + + private BinaryOperator reduce() { + return (l, r) ->l + FIELD_SEPARATOR + r ; + } + + @Override + public String toString() { + return builder.toString(); + } + + public String getFileName() { + return classAnnotation.fileName(); + } + + private String getFieldValue(T obj, Field f) { + try { + f.setAccessible(true); + return Optional.ofNullable(f.get(obj)) + .map(v -> v.toString()) + .orElse(""); + } catch (IllegalAccessException ex) { + log.error("Cannot access field " + f.getName(), ex); + return ""; + } + } + + private CsvExporter writeLine(String l) { + builder.append(l); + builder.append(LINE_SEPARATOR); + return this; + } + +} diff --git a/src/main/java/net/collaud/fablab/manager/export/CsvField.java b/src/main/java/net/collaud/fablab/manager/export/CsvField.java new file mode 100644 index 00000000..eb1b2860 --- /dev/null +++ b/src/main/java/net/collaud/fablab/manager/export/CsvField.java @@ -0,0 +1,16 @@ +package net.collaud.fablab.manager.export; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author Gaetan Collaud + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +public @interface CsvField { + public String headerName(); +} diff --git a/src/main/java/net/collaud/fablab/manager/rest/v1/AccoutingWS.java b/src/main/java/net/collaud/fablab/manager/rest/v1/AccoutingWS.java index 902f072a..4459c9f6 100644 --- a/src/main/java/net/collaud/fablab/manager/rest/v1/AccoutingWS.java +++ b/src/main/java/net/collaud/fablab/manager/rest/v1/AccoutingWS.java @@ -1,6 +1,11 @@ package net.collaud.fablab.manager.rest.v1; +import java.util.Date; +import java.util.List; +import javax.servlet.http.HttpServletResponse; import net.collaud.fablab.manager.annotation.JavascriptAPIConstant; +import net.collaud.fablab.manager.data.virtual.HistoryEntry; +import net.collaud.fablab.manager.export.CsvExporter; import net.collaud.fablab.manager.rest.v1.criteria.PeriodSearchCriteria; import net.collaud.fablab.manager.rest.v1.model.BaseModel; import net.collaud.fablab.manager.rest.v1.model.DataModel; @@ -10,6 +15,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; /** @@ -29,4 +36,21 @@ public BaseModel search(@Validated @RequestBody PeriodSearchCriteria search) { return new DataModel(paymentService.getPaymentEntries(search)); } + @RequestMapping(value = "export", method = RequestMethod.GET, produces = "text/csv") + @ResponseBody + public String export(@RequestParam("dateFrom") Long dateFrom,@RequestParam("dateTo") Long dateTo, HttpServletResponse response) { + response.setContentType("text/csv"); + Date from = new Date(dateFrom*1000); + Date to = new Date(dateTo*1000); + final List list = paymentService.getPaymentEntries(new PeriodSearchCriteria(from, to)); + if (list.isEmpty()) { + return ""; + } + CsvExporter exporter = new CsvExporter<>(list.get(0).getClass()); + response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s.csv\"",exporter.getFileName())); + exporter.writeHeader(); + list.forEach(l -> exporter.writeRow(l)); + return exporter.toString(); + } + } diff --git a/src/main/java/net/collaud/fablab/manager/rest/v1/base/ReadRestWebservice.java b/src/main/java/net/collaud/fablab/manager/rest/v1/base/ReadRestWebservice.java index 486de5fe..5f7cdd89 100644 --- a/src/main/java/net/collaud/fablab/manager/rest/v1/base/ReadRestWebservice.java +++ b/src/main/java/net/collaud/fablab/manager/rest/v1/base/ReadRestWebservice.java @@ -1,9 +1,11 @@ package net.collaud.fablab.manager.rest.v1.base; import java.util.List; +import javax.servlet.http.HttpServletResponse; import lombok.Getter; import lombok.Setter; import net.collaud.fablab.manager.data.AbstractDataEO; +import net.collaud.fablab.manager.export.CsvExporter; import net.collaud.fablab.manager.rest.v1.model.BaseModel; import net.collaud.fablab.manager.rest.v1.model.DataModel; import net.collaud.fablab.manager.service.global.ReadService; @@ -19,11 +21,11 @@ * @param repository */ abstract public class ReadRestWebservice> { - + @Setter @Getter private SERVICE service; - + @RequestMapping(method = RequestMethod.GET) @ResponseBody public BaseModel list() { @@ -32,6 +34,22 @@ public BaseModel list() { return model; } + @RequestMapping(value = "/export", method = RequestMethod.GET, produces = "text/csv") + @ResponseBody + public String export(HttpServletResponse response) { + response.setContentType("text/csv"); + + List list = service.findAll(); + if (list.isEmpty()) { + return ""; + } + CsvExporter exporter = new CsvExporter<>(list.get(0).getClass()); + response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s.csv\"",exporter.getFileName())); + exporter.writeHeader(); + list.forEach(l -> exporter.writeRow(l)); + return exporter.toString(); + } + @RequestMapping(value = "/{id}", method = RequestMethod.GET) @ResponseBody public BaseModel get(@PathVariable("id") Integer id) { diff --git a/src/main/webapp/components/accounting/accounting-list-ctrl.js b/src/main/webapp/components/accounting/accounting-list-ctrl.js index 51d3a7bb..09713099 100644 --- a/src/main/webapp/components/accounting/accounting-list-ctrl.js +++ b/src/main/webapp/components/accounting/accounting-list-ctrl.js @@ -52,32 +52,35 @@ $scope.updateAccounting(); }; - var computeInAndOut = function(){ + var computeInAndOut = function () { var moneyIn = 0; var sell = 0; - angular.forEach($scope.history, function(h){ - if(h.amount>0){ + angular.forEach($scope.history, function (h) { + if (h.amount > 0) { moneyIn += h.amount; - }else{ + } else { sell -= h.amount; } }); $scope.results = { - moneyIn : moneyIn, + moneyIn: moneyIn, sell: sell, - delta : moneyIn-sell + delta: moneyIn - sell }; }; $scope.updateAccounting = function () { - AccountingService.search($scope.criteria.dateFrom, $scope.criteria.dateTo, function(data){ + AccountingService.search($scope.criteria.dateFrom, $scope.criteria.dateTo, function (data) { $scope.history = data; computeInAndOut(); }); }; - - $scope.export = function(){ - alert('todo'); + + $scope.export = function () { + var format = 'DD-MM-YYYY hh:mm:ss' + var from = moment($scope.criteria.dateFrom).format('X'); + var to = moment($scope.criteria.dateTo).format('X'); + window.location = App.API.ACCOUNTING_API + "/export?dateFrom=" + from + "&dateTo=" + to; }; $scope.periodPreset($scope.intervals[2]);//this month diff --git a/src/main/webapp/components/user/list-ctrl.js b/src/main/webapp/components/user/list-ctrl.js index 7500197d..7e47ad65 100644 --- a/src/main/webapp/components/user/list-ctrl.js +++ b/src/main/webapp/components/user/list-ctrl.js @@ -43,6 +43,10 @@ angular.module('Fablab').controller('UserListController', function ($scope, $fil NotificationService.notify("success", "TODO Mailing list mise à jour"); }); }; + + $scope.export = function(){ + window.location=App.API.USER_API+"/export"; + } updateUserList(); diff --git a/src/main/webapp/components/user/list-view.html b/src/main/webapp/components/user/list-view.html index 00164d29..8a368d75 100644 --- a/src/main/webapp/components/user/list-view.html +++ b/src/main/webapp/components/user/list-view.html @@ -2,7 +2,7 @@