diff --git a/build.gradle b/build.gradle index 2527211..2eb0cc6 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ plugins { } group = 'de.jottyfan.camporganizer' -version = '0.6.0' +version = '0.6.1' description = """CampOrganizer2""" diff --git a/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/ConfirmationBoardController.java b/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/ConfirmationBoardController.java index 1125905..97d4e88 100644 --- a/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/ConfirmationBoardController.java +++ b/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/ConfirmationBoardController.java @@ -1,6 +1,9 @@ package de.jottyfan.camporganizer.module.confirmation.board; +import java.io.IOException; import java.security.Principal; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @@ -9,6 +12,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import de.jottyfan.camporganizer.module.camplist.CommonController; +import jakarta.servlet.http.HttpServletResponse; /** * @@ -29,7 +33,20 @@ public class ConfirmationBoardController extends CommonController { @GetMapping("/confirmation/board/camp/{id}") public String getCamplist(Model model, @PathVariable Integer id, Principal principal) { + model.addAttribute("campId", id); + model.addAttribute("campStartDate", service.getCampStartDate(super.getCurrentUser(principal), id)); model.addAttribute("persons", service.loadPersonList(super.getCurrentUser(principal), id)); return "/confirmation/camplist"; } + + @GetMapping("/confirmation/board/download/{id}") + public void getCsvOfAll(@PathVariable Integer id, Principal principal, HttpServletResponse response) + throws IOException { + response.setContentType("text/csv"); + String filename = String.format("camplist_%d_%s.csv", id, + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"))); + response.setHeader("Content-Disposition", "attachment; filename=" + filename); + response.getWriter().write(service.getDownloadCsvOfAll(super.getCurrentUser(principal), id)); + response.flushBuffer(); + } } diff --git a/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/ConfirmationBoardRepository.java b/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/ConfirmationBoardRepository.java index 35d8a71..37f16f5 100644 --- a/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/ConfirmationBoardRepository.java +++ b/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/ConfirmationBoardRepository.java @@ -13,12 +13,14 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jooq.DSLContext; import org.jooq.Record; +import org.jooq.Record2; import org.jooq.Record6; import org.jooq.SelectConditionStep; import org.jooq.SelectSeekStep1; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; +import de.jottyfan.camporganizer.db.jooq.enums.EnumModule; import de.jottyfan.camporganizer.module.confirmation.board.model.CampBean; import de.jottyfan.camporganizer.module.confirmation.board.model.PersonBean; import de.jottyfan.camporganizer.module.confirmation.confirmation.ConfirmationRepository; @@ -46,7 +48,7 @@ public class ConfirmationBoardRepository { // @formatter:off .select(V_CAMP.NAME, V_CAMP.YEAR, V_CAMP.IS_OVER, V_CAMP.LOCATION_NAME, V_CAMP.PK, V_CAMP.ARRIVE) .from(T_PROFILE) - .leftJoin(T_CAMPPROFILE).on(T_CAMPPROFILE.FK_PROFILE.eq(T_PROFILE.PK)) + .leftJoin(T_CAMPPROFILE).on(T_CAMPPROFILE.FK_PROFILE.eq(T_PROFILE.PK)).and(T_CAMPPROFILE.MODULE.eq(EnumModule.registration)) .leftJoin(V_CAMP).on(V_CAMP.PK.eq(T_CAMPPROFILE.FK_CAMP)) .where(T_PROFILE.USERNAME.eq(username)) .orderBy(V_CAMP.ARRIVE); @@ -77,7 +79,7 @@ public class ConfirmationBoardRepository { // @formatter:off .select(T_PERSON.fields()) .from(T_PERSON) - .innerJoin(T_CAMPPROFILE).on(T_CAMPPROFILE.FK_CAMP.eq(T_PERSON.FK_CAMP)) + .innerJoin(T_CAMPPROFILE).on(T_CAMPPROFILE.FK_CAMP.eq(T_PERSON.FK_CAMP)).and(T_CAMPPROFILE.MODULE.eq(EnumModule.registration)) .innerJoin(T_PROFILE).on(T_PROFILE.USERNAME.eq(username)).and(T_PROFILE.PK.eq(T_CAMPPROFILE.FK_PROFILE)) .where(T_PERSON.FK_CAMP.eq(campId)); // @formatter:on @@ -104,4 +106,28 @@ public class ConfirmationBoardRepository { } return list; } + + /** + * get the camp start date of campId if username is allowed to + * + * @param username the user + * @param campId the ID of the camp + * @return the camp start time or null + */ + public LocalDateTime getCampStartDate(String username, Integer campId) { + SelectConditionStep> sql = jooq + // @formatter:off + .select(V_CAMP.NAME, V_CAMP.ARRIVE) + .from(T_PROFILE) + .leftJoin(T_CAMPPROFILE).on(T_CAMPPROFILE.FK_PROFILE.eq(T_PROFILE.PK)).and(T_CAMPPROFILE.MODULE.eq(EnumModule.registration)) + .leftJoin(V_CAMP).on(V_CAMP.PK.eq(T_CAMPPROFILE.FK_CAMP)) + .where(T_PROFILE.USERNAME.eq(username)) + .and(V_CAMP.PK.eq(campId)); + // @formatter:on + LOGGER.trace(sql); + for (Record2 r : sql.fetch()) { + return r.get(V_CAMP.ARRIVE); + } + return null; + } } diff --git a/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/ConfirmationBoardService.java b/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/ConfirmationBoardService.java index c63dbef..a051c3a 100644 --- a/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/ConfirmationBoardService.java +++ b/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/ConfirmationBoardService.java @@ -19,6 +19,9 @@ public class ConfirmationBoardService { @Autowired private ConfirmationBoardRepository repository; + @Autowired + private List2CSVService csvService; + public List loadCampList(String username) { return repository.getCamps(username); } @@ -26,4 +29,13 @@ public class ConfirmationBoardService { public List loadPersonList(String username, Integer campId) { return repository.getPersons(username, campId); } + + public String getDownloadCsvOfAll(String username, Integer campId) { + List list = repository.getPersons(username, campId); + return csvService.toCsv(list); + } + + public Object getCampStartDate(String username, Integer campId) { + return repository.getCampStartDate(username, campId); + } } diff --git a/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/List2CSVService.java b/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/List2CSVService.java new file mode 100644 index 0000000..df65b81 --- /dev/null +++ b/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/List2CSVService.java @@ -0,0 +1,66 @@ +package de.jottyfan.camporganizer.module.confirmation.board; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +import org.springframework.stereotype.Service; + +import de.jottyfan.camporganizer.module.confirmation.board.model.PersonBean; + +/** + * + * @author jotty + * + */ +@Service +public class List2CSVService { + private static final String QUOTE = "\""; + private static final String SEP = ","; + + private StringBuilder append(StringBuilder buf, String s) { + return buf.append(s == null || s.isEmpty() ? SEP : String.format("%s%s%s%s", QUOTE, s, QUOTE, SEP)); + } + + private StringBuilder append(StringBuilder buf, Double d) { + return buf.append(d == null ? SEP : String.format("%s%s%s%s", QUOTE, d.toString(), QUOTE, SEP)); + } + + private StringBuilder append(StringBuilder buf, Boolean b) { + return buf.append(b == null ? SEP : String.format("%s%s%s%s", QUOTE, b ? "ja" : "nein", QUOTE, SEP)); + } + + private StringBuilder append(StringBuilder buf, LocalDateTime l) { + return buf.append(l == null ? SEP : String.format("%s%s%s%s", QUOTE, l.format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")), QUOTE, SEP)); + } + + private StringBuilder append(StringBuilder buf, LocalDate l) { + return buf.append(l == null ? SEP : String.format("%s%s%s%s", QUOTE, l.format(DateTimeFormatter.ofPattern("dd.MM.yyyy")), QUOTE, SEP)); + } + + public String toCsv(List list) { + StringBuilder buf = new StringBuilder(); + buf.append("Bezahlt,Vorname,Nachname,Strasse,PLZ,Ort,Telefon,Email,Geschlecht,Rolle,Geburtsdatum,Anmeldestatus,Anmeldedatum,Fotoeinverständnis,Kommentar\n"); + for (PersonBean bean : list) { + append(buf, bean.getPaid()); + append(buf, bean.getForename()); + append(buf, bean.getSurname()); + append(buf, bean.getStreet()); + append(buf, bean.getZip()); + append(buf, bean.getCity()); + append(buf, bean.getPhone()); + append(buf, bean.getEmail()); + append(buf, bean.getSex()); + append(buf, bean.getCamprole()); + append(buf, bean.getBirthDate()); + append(buf, bean.getAccept()); + append(buf, bean.getCreated()); + append(buf, bean.getConsentCatalogPhoto()); + append(buf, bean.getComment()); + buf.append("\n"); + } + return buf.toString(); + } + +} diff --git a/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/model/PersonBean.java b/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/model/PersonBean.java index 6074759..4af042f 100644 --- a/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/model/PersonBean.java +++ b/src/main/java/de/jottyfan/camporganizer/module/confirmation/board/model/PersonBean.java @@ -3,6 +3,7 @@ package de.jottyfan.camporganizer.module.confirmation.board.model; import java.io.Serializable; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.Period; /** * @@ -29,7 +30,13 @@ public class PersonBean implements Serializable { private Boolean consentCatalogPhoto; public String getAge(LocalDate relation) { - return "?"; // TODO: calculate age in relation to the camp start. + if (relation == null) { + return "?"; + } else { + Period period = Period.between(birthDate, relation); + Integer years = period == null ? null : period.getYears(); + return years == null ? "?" : years.toString(); + } } public String getCamprolle() { diff --git a/src/main/java/de/jottyfan/camporganizer/module/confirmation/confirmation/ConfirmationService.java b/src/main/java/de/jottyfan/camporganizer/module/confirmation/confirmation/ConfirmationService.java index 18680c1..2fd2b2a 100644 --- a/src/main/java/de/jottyfan/camporganizer/module/confirmation/confirmation/ConfirmationService.java +++ b/src/main/java/de/jottyfan/camporganizer/module/confirmation/confirmation/ConfirmationService.java @@ -2,10 +2,6 @@ package de.jottyfan.camporganizer.module.confirmation.confirmation; import java.util.List; -import jakarta.servlet.http.HttpServletRequest; - -import org.jooq.exception.DataAccessException; -import org.keycloak.KeycloakSecurityContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; diff --git a/src/main/java/de/jottyfan/camporganizer/module/confirmation/person/PersonController.java b/src/main/java/de/jottyfan/camporganizer/module/confirmation/person/PersonController.java index 0693e0c..33d89e4 100644 --- a/src/main/java/de/jottyfan/camporganizer/module/confirmation/person/PersonController.java +++ b/src/main/java/de/jottyfan/camporganizer/module/confirmation/person/PersonController.java @@ -9,9 +9,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import de.jottyfan.camporganizer.module.camplist.CommonController; -import de.jottyfan.camporganizer.module.confirmation.confirmation.ConfirmationService; import de.jottyfan.camporganizer.module.confirmation.person.model.PersonBean; -import jakarta.servlet.http.HttpServletRequest; /** * diff --git a/src/main/resources/templates/confirmation/camplist.html b/src/main/resources/templates/confirmation/camplist.html index 07967af..9e2c6fc 100644 --- a/src/main/resources/templates/confirmation/camplist.html +++ b/src/main/resources/templates/confirmation/camplist.html @@ -7,6 +7,10 @@
+ +
@@ -25,20 +29,16 @@ - + - + +
+
+
-   -
 
-
-
-
-
-