added download csv file feature
This commit is contained in:
		| @@ -8,7 +8,7 @@ plugins { | ||||
| } | ||||
|  | ||||
| group = 'de.jottyfan.camporganizer' | ||||
| version = '0.6.0' | ||||
| version = '0.6.1' | ||||
|  | ||||
| description = """CampOrganizer2""" | ||||
|  | ||||
|   | ||||
| @@ -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(); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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<Record2<String, LocalDateTime>> 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<String, LocalDateTime> r : sql.fetch()) { | ||||
| 			return r.get(V_CAMP.ARRIVE); | ||||
| 		} | ||||
| 		return null; | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -19,6 +19,9 @@ public class ConfirmationBoardService { | ||||
| 	@Autowired | ||||
| 	private ConfirmationBoardRepository repository; | ||||
|  | ||||
| 	@Autowired | ||||
| 	private List2CSVService csvService; | ||||
|  | ||||
| 	public List<CampBean> loadCampList(String username) { | ||||
| 		return repository.getCamps(username); | ||||
| 	} | ||||
| @@ -26,4 +29,13 @@ public class ConfirmationBoardService { | ||||
| 	public List<PersonBean> loadPersonList(String username, Integer campId) { | ||||
| 		return repository.getPersons(username, campId); | ||||
| 	} | ||||
|  | ||||
| 	public String getDownloadCsvOfAll(String username, Integer campId) { | ||||
| 		List<PersonBean> list = repository.getPersons(username, campId); | ||||
| 		return csvService.toCsv(list); | ||||
| 	} | ||||
|  | ||||
| 	public Object getCampStartDate(String username, Integer campId) { | ||||
| 		return repository.getCampStartDate(username, campId); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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<PersonBean> 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(); | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -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() { | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
| /** | ||||
|  * | ||||
|   | ||||
| @@ -7,6 +7,10 @@ | ||||
| <body> | ||||
| 	<th:block layout:fragment="content"> | ||||
| 		<div sec:authorize="hasRole('registrator')" style="margin: 8px"> | ||||
| 			<div class="btn-group" role="group"> | ||||
| 				<a class="btn btn-outline-primary" role="button" th:href="@{/confirmation/board/download/{id}(id=${campId})}"><i class="fas fa-download"></i> alles als CSV exportieren</a> | ||||
| 			</div> | ||||
| 			<br /> | ||||
| 			<table id="table" class="table table-striped"> | ||||
| 				<thead> | ||||
| 					<tr> | ||||
| @@ -25,20 +29,16 @@ | ||||
| 				</thead> | ||||
| 				<tbody> | ||||
| 					<tr th:each="p : ${persons}"> | ||||
| 						<td th:text="${p.paid}"></td> | ||||
| 						<td th:text="${#strings.replace(#numbers.formatCurrency(p.paid), '¤', '€')}"></td> | ||||
| 						<td th:text="${p.forename}"></td> | ||||
| 						<td th:text="${p.surname}"></td> | ||||
| 						<td><div th:text="${p.street}"></div> | ||||
| 						<span th:text="${p.zip}"></span> <span th:text="${p.city}"></span> | ||||
| 						</td> | ||||
| 						<td><div th:text="${p.street}"></div> <span th:text="${p.zip}"></span> <span th:text="${p.city}"></span></td> | ||||
| 						<td><div th:text="'Tel.: ' + ${p.phone}"></div> | ||||
| 						<div  th:text="${p.email}"></div> | ||||
| 						</td> | ||||
| 							<div th:text="${p.email}"></div></td> | ||||
| 						<td><div th:text="${p.sex == 'male' ? 'männlich' : 'weiblich'}"></div> | ||||
| 							<div th:text="${p.camprolle}"></div></td> | ||||
| 						<td><div th:text="${#temporals.format(p.birthDate, 'dd.MM.yyyy')}"></div> | ||||
| 						<div th:text="${p.getAge(p.birthDate)} + ' Jahre'"></div> | ||||
| 						</td> | ||||
| 							<div th:text="${p.getAge(campStartDate)} + ' Jahre'"></div></td> | ||||
| 						<td th:text="${p.accept}"></td> | ||||
| 						<td th:text="${#temporals.format(p.created, 'dd.MM.yyyy HH:mm')}"></td> | ||||
| 						<td><span th:text="${p.consentCatalogPhoto ? 'ja' : 'nein'}" th:if="${p.consentCatalogPhoto}"></span></td> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user