camp admin added

This commit is contained in:
Jottyfan
2025-01-30 22:37:22 +01:00
parent bdc0d84e69
commit 30fb52a606
9 changed files with 245 additions and 8 deletions

View File

@ -8,7 +8,7 @@ plugins {
}
group = 'de.jottyfan.bico'
version = '0.2.1'
version = '0.2.2'
description = """BibleClassOrganizer"""

View File

@ -12,6 +12,7 @@ import org.springframework.security.web.SecurityFilterChain;
*/
@Configuration
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(

View File

@ -3,8 +3,6 @@ package de.jottyfan.bico.modules;
import java.security.Principal;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
@ -12,6 +10,7 @@ import org.springframework.security.oauth2.client.authentication.OAuth2Authentic
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.web.bind.annotation.ModelAttribute;
import de.jottyfan.bico.Main;
import de.jottyfan.bico.modules.profile.ProfileService;
/**
@ -20,8 +19,7 @@ import de.jottyfan.bico.modules.profile.ProfileService;
*
*/
public abstract class CommonController {
private static final Logger LOGGER = LogManager.getLogger(CommonController.class);
private static final List<String> admins = List.of("andre.sieber", "tobias.kuehne", "jotty");
@Autowired
private ProfileService profileService;
@ -29,6 +27,11 @@ public abstract class CommonController {
@Value("${spring.security.oauth2.client.provider.nextcloud.issuer-uri}")
private String nextcloudUrl;
@ModelAttribute("isCampAdmin")
public Boolean isCampAdmin(Principal principal) {
return admins.contains(principal.getName());
}
@ModelAttribute("hasBUrole")
public Boolean hasBURole(Principal principal) {
OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) principal;
@ -38,7 +41,7 @@ public abstract class CommonController {
List<String> roles = (List<String>) user.getAttributes().get("roles");
return roles.contains("Bibelunterricht");
} else {
LOGGER.warn("token is null, no roles can be detected");
Main.LOGGER.warn("token is null, no roles can be detected");
return false;
}
}
@ -52,7 +55,7 @@ public abstract class CommonController {
List<String> roles = (List<String>) user.getAttributes().get("roles");
return roles.contains("Kinderstunde klein");
} else {
LOGGER.warn("token is null, no roles can be detected");
Main.LOGGER.warn("token is null, no roles can be detected");
return false;
}
}
@ -66,7 +69,7 @@ public abstract class CommonController {
List<String> roles = (List<String>) user.getAttributes().get("roles");
return roles.size() > 0;
} else {
LOGGER.warn("token is null, no roles can be detected");
Main.LOGGER.warn("token is null, no roles can be detected");
return false;
}
}

View File

@ -0,0 +1,51 @@
package de.jottyfan.bico.modules.camp;
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.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import de.jottyfan.bico.modules.CommonController;
import jakarta.servlet.http.HttpServletResponse;
/**
*
* @author jotty
*
*/
@Configuration
@Controller
public class AdminRegistrationController extends CommonController {
@Autowired
private AdminRegistrationService service;
@GetMapping("/camp/registration/admin")
public String getList(Model model, Principal principal) {
if (isCampAdmin(principal)) {
model.addAttribute("list", service.getAllRegistrations());
model.addAttribute("ages", service.getAges());
}
return "/camp/list";
}
@GetMapping("/camp/registration/admin/download")
@ResponseBody
public String download(HttpServletResponse response, Principal principal) throws IOException {
if (isCampAdmin(principal)) {
response.setHeader("Content-Disposition", String.format("attachment; filename=Gemeindefreizeit-Anmeldungen-%s.csv",
LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME)));
response.setContentType("text/csv; charset=utf-8");
return service.getDownload();
} else {
return "forbidden";
}
}
}

View File

@ -0,0 +1,33 @@
package de.jottyfan.bico.modules.camp;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import de.jottyfan.bico.db.camp.tables.records.TAgeRecord;
import de.jottyfan.bico.modules.camp.model.RegistrationBean;
/**
*
* @author jotty
*
*/
@Service
public class AdminRegistrationService {
@Autowired
private RegistrationRepository repository;
public List<RegistrationBean> getAllRegistrations() {
return repository.getAllRegistrations();
}
public List<TAgeRecord> getAges() {
return repository.getAges();
}
public String getDownload() {
return repository.getDownload();
}
}

View File

@ -3,12 +3,15 @@ package de.jottyfan.bico.modules.camp;
import static de.jottyfan.bico.db.camp.Tables.T_AGE;
import static de.jottyfan.bico.db.camp.Tables.T_REGISTRATION;
import java.time.LocalDateTime;
import java.util.List;
import org.jooq.DSLContext;
import org.jooq.DeleteConditionStep;
import org.jooq.InsertValuesStep20;
import org.jooq.Record19;
import org.jooq.SelectConditionStep;
import org.jooq.SelectOnConditionStep;
import org.jooq.SelectSeekStep1;
import org.jooq.UpdateConditionStep;
import org.jooq.impl.DSL;
@ -102,6 +105,21 @@ public class RegistrationRepository {
});
}
/**
* get all registrations (for admins only)
*
* @return the registrations
*/
public List<RegistrationBean> getAllRegistrations() {
SelectSeekStep1<TRegistrationRecord, LocalDateTime> sql = jooq
// @formatter:off
.selectFrom(T_REGISTRATION)
.orderBy(T_REGISTRATION.CREATED);
// @formatter:on
Main.LOGGER.trace(sql);
return sql.fetchInto(RegistrationBean.class);
}
/**
* get all registrations of name
*
@ -167,4 +185,38 @@ public class RegistrationRepository {
Main.LOGGER.trace(sql);
return sql.fetchInto(TAgeRecord.class);
}
/**
* get CSV version of the list, only for admins
*
* @return the csv
*/
public String getDownload() {
SelectOnConditionStep<Record19<LocalDateTime, String, String, EnumSex, String, Boolean, Boolean, Boolean, Boolean, Boolean, Boolean, Boolean, Boolean, Boolean, Boolean, String, String, Integer, Boolean>> sql = jooq
// @formatter:off
.select(T_REGISTRATION.CREATED,
T_REGISTRATION.FORENAME,
T_REGISTRATION.SURNAME,
T_REGISTRATION.SEX,
T_AGE.NAME,
T_REGISTRATION.DAY0,
T_REGISTRATION.DAY1,
T_REGISTRATION.DAY2,
T_REGISTRATION.DAY3,
T_REGISTRATION.DAY4,
T_REGISTRATION.BARRIER_FREE,
T_REGISTRATION.TOWELS,
T_REGISTRATION.BED_LINEN,
T_REGISTRATION.COT,
T_REGISTRATION.REQUIRE_PAYMENT,
T_REGISTRATION.DISEASES,
T_REGISTRATION.NUTRITION,
T_REGISTRATION.DRIVER_PROVIDE_PLACES,
T_REGISTRATION.WANT_PLACE_IN_CAR)
.from(T_REGISTRATION)
.leftJoin(T_AGE).on(T_AGE.PK_AGE.eq(T_REGISTRATION.FK_AGE));
// @formatter:on
Main.LOGGER.trace(sql);
return sql.fetch().formatCSV(true);
}
}

View File

@ -50,4 +50,19 @@ body {
.centeredalert {
width: 400px;
margin: auto;
}
.campbadge {
border: 1px solid #222;
color: #222;
}
[data-bs-theme=dark] .campbadge {
border-color: silver;
color: silver;
}
.full-size {
width: 100% !important;
max-width: inherit !important;
}

View File

@ -0,0 +1,81 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" layout:decorate="~{template}" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<body>
<th:block layout:fragment="content">
<div class="borderdist">
<div class="container full-size">
<div class="row g-2">
<div class="col-sm-12">
<h2>Anmeldungen zur Gemeindefreizeit 2025</h2>
</div>
</div>
<div class="alert alert-danger" th:unless="${list}">Sie haben keine Berechtigung, die Anmeldungen einzusehen.</div>
<div th:if="${list}">
<table id="table" class="table table-striped">
<thead>
<tr>
<th>Vorname</th>
<th>Nachname</th>
<th>Geschlecht</th>
<th>Alter</th>
<th>Tage dabei</th>
<th>Extras</th>
<th>Unverträglichkeit</th>
<th>Mitfahrplätze</th>
<th>Besonderheiten</th>
</tr>
</thead>
<tbody>
<tr th:each="l : ${list}">
<td th:text="${l.forename}"></td>
<td th:text="${l.surname}"></td>
<td th:text="${l.sex}"></td>
<td>
<th:block th:each="a : ${ages}">
<span th:text="${a.name}" th:if="${a.pkAge == l.fkAge}"></span>
</th:block>
</td>
<td>
<span th:if="${l.day0}" class="badge campbadge">Donnerstag</span>
<span th:if="${l.day1}" class="badge campbadge">Freitag</span>
<span th:if="${l.day2}" class="badge campbadge">Sonnabend</span>
<span th:if="${l.day3}" class="badge campbadge">Sonntag</span>
<span th:if="${l.day4}" class="badge campbadge">Montag</span>
</td>
<td>
<span th:if="${l.barrierFree}" class="badge campbadge">barrierefrei</span>
<span th:if="${l.towels}" class="badge campbadge">Handtücher</span>
<span th:if="${l.bedLinen}" class="badge campbadge">Bettwäsche</span>
<span th:if="${l.cot}" class="badge campbadge">Kinderbett</span>
<span th:if="${l.requirePayment}" class="badge campbadge">finanzielle Unterstützung erbeten</span>
</td>
<td th:text="${l.nutrition}"></td>
<td>
<span th:if="${l.driverProvidePlaces}">biete <span th:text="${l.driverProvidePlaces}"></span></span>
<span th:if="${l.wantPlaceInCar}">benötige 1</span>
</td>
<td th:text="${l.diseases}"></td>
</tr>
</tbody>
</table>
<script th:inline="javascript">
/*<![CDATA[*/
$(document).ready(function() {
$("#table").DataTable({
"language" : locale_de,
"responsive" : true
});
});
/*]]>*/
</script>
</div>
<div class="row g-2" th:if="${list}">
<div class="col-sm-12">
<a th:href="@{/camp/registration/admin/download}" class="btn btn-outline-primary">Download</a>
</div>
</div>
</div>
</div>
</th:block>
</body>
</html>

View File

@ -26,6 +26,7 @@
<div class="collapse navbar-collapse" id="navbarSupportedContent" style="margin-right: 20px">
<ul class="navbar-nav mb-2 mb-lg-0" th:if="${hasAnyRole}">
<li class="nav-item"><a class="btn btn-outline-secondary" th:href="@{/camp/registration}" style="margin-left: 12px">Anmeldung Gemeindefreizeit</a></li>
<li class="nav-item"><a class="btn btn-outline-secondary" th:href="@{/camp/registration/admin}" style="margin-left: 12px" th:if="${isCampAdmin}">Gemeindefreizeitliste</a></li>
<li class="nav-item"><a class="btn btn-outline-secondary" th:href="@{/next}" style="margin-left: 12px" th:if="${hasDateRole || hasBUrole}">Dienstplan</a></li>
<li class="nav-item"><a class="btn btn-outline-secondary" th:href="@{/sheet}" style="margin-left: 12px" th:if="${hasBUrole}">Einteilung</a></li>
<li class="nav-item"><a class="btn btn-outline-secondary" th:href="@{/subject/list}" style="margin-left: 12px" th:if="${hasBUrole}">Themen</a></li>