integrated module confirmation
This commit is contained in:
parent
fc0bc35e28
commit
0e9088dc1c
@ -57,7 +57,7 @@ public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
|
|||||||
super.configure(http);
|
super.configure(http);
|
||||||
http.authorizeRequests()
|
http.authorizeRequests()
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
.antMatchers("/dashboard/**", "/business/**").authenticated()
|
.antMatchers("/dashboard/**", "/business/**", "/confirmation/**").authenticated()
|
||||||
.anyRequest().permitAll();
|
.anyRequest().permitAll();
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
// http.anonymous().disable();
|
// http.anonymous().disable();
|
||||||
|
@ -9,7 +9,7 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author henkej
|
* @author jotty
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Controller
|
@Controller
|
||||||
|
@ -16,7 +16,7 @@ import de.jottyfan.camporganizer.module.business.privileges.impl.PrivilegesBean;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author henkej
|
* @author jotty
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Controller
|
@Controller
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.confirmation.confirmation;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
|
import de.jottyfan.camporganizer.module.confirmation.confirmation.impl.CampOverviewBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
public class ConfirmationController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private HttpServletRequest request;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IConfirmationService indexService;
|
||||||
|
|
||||||
|
@GetMapping("/confirmation")
|
||||||
|
public String getIndex(Model model) {
|
||||||
|
String username = indexService.getCurrentUser(request);
|
||||||
|
List<CampOverviewBean> campoverview = indexService.getCampOverview(request);
|
||||||
|
CampOverviewBean campoverviewsummary = new CampOverviewBean(LocalDate.now(), "summary");
|
||||||
|
for (CampOverviewBean bean : campoverview) {
|
||||||
|
campoverviewsummary.setApproved(bean.getApproved() + campoverviewsummary.getApproved());
|
||||||
|
campoverviewsummary.setRejected(bean.getRejected() + campoverviewsummary.getRejected());
|
||||||
|
campoverviewsummary.setUntouched(bean.getUntouched() + campoverviewsummary.getUntouched());
|
||||||
|
}
|
||||||
|
model.addAttribute("currentUser", username);
|
||||||
|
model.addAttribute("campoverview", campoverview);
|
||||||
|
model.addAttribute("campoverviewsummary", campoverviewsummary);
|
||||||
|
model.addAttribute("untouched", indexService.getUntouched(request));
|
||||||
|
model.addAttribute("approved", indexService.getApproved(request));
|
||||||
|
model.addAttribute("rejected", indexService.getRejected(request));
|
||||||
|
return "confirmation/confirmation";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.confirmation.confirmation;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import de.jottyfan.camporganizer.module.confirmation.confirmation.impl.BookingBean;
|
||||||
|
import de.jottyfan.camporganizer.module.confirmation.confirmation.impl.CampOverviewBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface IConfirmationService {
|
||||||
|
/**
|
||||||
|
* get the user of this session
|
||||||
|
*
|
||||||
|
* @param request the request
|
||||||
|
* @return the username of the current user
|
||||||
|
*/
|
||||||
|
public String getCurrentUser(HttpServletRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a list of the camps and its booking status
|
||||||
|
*
|
||||||
|
* @param request the request
|
||||||
|
* @return the camp overview beans
|
||||||
|
*/
|
||||||
|
public List<CampOverviewBean> getCampOverview(HttpServletRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a list of bookings that have not yet been worked on
|
||||||
|
*
|
||||||
|
* @param request the request
|
||||||
|
* @return the list of untouched bookings
|
||||||
|
*/
|
||||||
|
public List<BookingBean> getUntouched(HttpServletRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a list of approved bookings
|
||||||
|
*
|
||||||
|
* @param request the request
|
||||||
|
* @return the list of approved bookings
|
||||||
|
*/
|
||||||
|
public List<BookingBean> getApproved(HttpServletRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a list of rejected bookings
|
||||||
|
*
|
||||||
|
* @param request the request
|
||||||
|
* @return the list of rejected bookings
|
||||||
|
*/
|
||||||
|
public List<BookingBean> getRejected(HttpServletRequest request);
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.confirmation.confirmation.impl;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.enums.EnumCamprole;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class BookingBean implements Serializable, Comparable<BookingBean> {
|
||||||
|
private static final long serialVersionUID = 2L;
|
||||||
|
|
||||||
|
private final Integer pkPerson;
|
||||||
|
private final LocalDate date;
|
||||||
|
private final String camp;
|
||||||
|
private String fullname;
|
||||||
|
private String role;
|
||||||
|
private LocalDateTime registered;
|
||||||
|
|
||||||
|
public BookingBean(Integer pkPerson, LocalDate date, String camp) {
|
||||||
|
this.pkPerson = pkPerson;
|
||||||
|
this.date = date;
|
||||||
|
this.camp = camp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(BookingBean bean) {
|
||||||
|
return date == null || bean == null || bean.getDate() == null ? 0 : bean.getDate().compareTo(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the German role name
|
||||||
|
*
|
||||||
|
* @return the German role name
|
||||||
|
*/
|
||||||
|
public String getRolename() {
|
||||||
|
if (EnumCamprole.student.getLiteral().equals(role)) {
|
||||||
|
return "Teilnehmer";
|
||||||
|
} else if (EnumCamprole.teacher.getLiteral().equals(role)) {
|
||||||
|
return "Mitarbeiter";
|
||||||
|
} else if (EnumCamprole.director.getLiteral().equals(role)) {
|
||||||
|
return "Leiter";
|
||||||
|
} else if (EnumCamprole.feeder.getLiteral().equals(role)) {
|
||||||
|
return "Küchenteam";
|
||||||
|
} else {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the fullname
|
||||||
|
*/
|
||||||
|
public String getFullname() {
|
||||||
|
return fullname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param fullname the fullname to set
|
||||||
|
*/
|
||||||
|
public void setFullname(String fullname) {
|
||||||
|
this.fullname = fullname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the role
|
||||||
|
*/
|
||||||
|
public String getRole() {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param role the role to set
|
||||||
|
*/
|
||||||
|
public void setRole(String role) {
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the registered
|
||||||
|
*/
|
||||||
|
public LocalDateTime getRegistered() {
|
||||||
|
return registered;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param registered the registered to set
|
||||||
|
*/
|
||||||
|
public void setRegistered(LocalDateTime registered) {
|
||||||
|
this.registered = registered;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the date
|
||||||
|
*/
|
||||||
|
public LocalDate getDate() {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the camp
|
||||||
|
*/
|
||||||
|
public String getCamp() {
|
||||||
|
return camp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPkPerson() {
|
||||||
|
return pkPerson;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.confirmation.confirmation.impl;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CampOverviewBean implements Serializable, Comparable<CampOverviewBean> {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final LocalDate date;
|
||||||
|
private final String camp;
|
||||||
|
private Integer approved;
|
||||||
|
private Integer rejected;
|
||||||
|
private Integer untouched;
|
||||||
|
|
||||||
|
public CampOverviewBean(LocalDate date, String camp) {
|
||||||
|
this.date = date;
|
||||||
|
this.camp = camp;
|
||||||
|
this.approved = 0;
|
||||||
|
this.rejected = 0;
|
||||||
|
this.untouched = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(CampOverviewBean bean) {
|
||||||
|
return date == null || bean == null || bean.getDate() == null ? 0 : bean.getDate().compareTo(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the camp
|
||||||
|
*/
|
||||||
|
public String getCamp() {
|
||||||
|
return camp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the approved
|
||||||
|
*/
|
||||||
|
public Integer getApproved() {
|
||||||
|
return approved;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param approved the approved to set
|
||||||
|
*/
|
||||||
|
public void setApproved(Integer approved) {
|
||||||
|
this.approved = approved;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the rejected
|
||||||
|
*/
|
||||||
|
public Integer getRejected() {
|
||||||
|
return rejected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param rejected the rejected to set
|
||||||
|
*/
|
||||||
|
public void setRejected(Integer rejected) {
|
||||||
|
this.rejected = rejected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the untouched
|
||||||
|
*/
|
||||||
|
public Integer getUntouched() {
|
||||||
|
return untouched;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param untouched the untouched to set
|
||||||
|
*/
|
||||||
|
public void setUntouched(Integer untouched) {
|
||||||
|
this.untouched = untouched;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the date
|
||||||
|
*/
|
||||||
|
public LocalDate getDate() {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,162 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.confirmation.confirmation.impl;
|
||||||
|
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_CAMP;
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_CAMPPROFILE;
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PERSON;
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PROFILE;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.jooq.Condition;
|
||||||
|
import org.jooq.DSLContext;
|
||||||
|
import org.jooq.Name;
|
||||||
|
import org.jooq.Record4;
|
||||||
|
import org.jooq.Record7;
|
||||||
|
import org.jooq.SelectHavingStep;
|
||||||
|
import org.jooq.SelectSeekStep1;
|
||||||
|
import org.jooq.impl.DSL;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.enums.EnumCamprole;
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.enums.EnumModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
@Transactional(transactionManager = "transactionManager")
|
||||||
|
public class ConfirmationGateway {
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(ConfirmationGateway.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DSLContext jooq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get an overview of camps
|
||||||
|
*
|
||||||
|
* @param currentUser the current user to check for its privileges
|
||||||
|
* @return a list of camp overview beans
|
||||||
|
*/
|
||||||
|
public List<CampOverviewBean> getCampOverviewBeans(String currentUser) {
|
||||||
|
Name COUNT = DSL.name("count");
|
||||||
|
SelectHavingStep<Record4<Integer, Boolean, String, LocalDateTime>> sql = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.select(DSL.count(T_PERSON.PK).as(COUNT),
|
||||||
|
T_PERSON.ACCEPT,
|
||||||
|
T_CAMP.NAME,
|
||||||
|
T_CAMP.ARRIVE)
|
||||||
|
.from(T_PERSON)
|
||||||
|
.leftJoin(T_CAMP).on(T_CAMP.PK.eq(T_PERSON.FK_CAMP))
|
||||||
|
.leftJoin(T_CAMPPROFILE).on(T_CAMPPROFILE.FK_CAMP.eq(T_PERSON.FK_CAMP))
|
||||||
|
.leftJoin(T_PROFILE).on(T_PROFILE.PK.eq(T_CAMPPROFILE.FK_PROFILE))
|
||||||
|
.where(T_CAMP.ARRIVE.isNotNull())
|
||||||
|
.and(T_CAMPPROFILE.MODULE.eq(EnumModule.registration))
|
||||||
|
.and(T_PROFILE.USERNAME.eq(currentUser))
|
||||||
|
.groupBy(T_CAMP.NAME, T_CAMP.ARRIVE, T_PERSON.ACCEPT);
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug(sql.toString());
|
||||||
|
Map<LocalDateTime, CampOverviewBean> map = new HashMap<>();
|
||||||
|
for (Record4<Integer, Boolean, String, LocalDateTime> r : sql.fetch()) {
|
||||||
|
Integer count = r.get(COUNT, Integer.class);
|
||||||
|
Boolean accept = r.get(T_PERSON.ACCEPT);
|
||||||
|
String campname = r.get(T_CAMP.NAME);
|
||||||
|
LocalDateTime arrive = r.get(T_CAMP.ARRIVE);
|
||||||
|
CampOverviewBean bean = map.get(arrive);
|
||||||
|
if (bean == null) {
|
||||||
|
bean = new CampOverviewBean(arrive.toLocalDate(), campname);
|
||||||
|
map.put(arrive, bean);
|
||||||
|
}
|
||||||
|
if (accept == null) {
|
||||||
|
bean.setUntouched(count);
|
||||||
|
} else if (accept) {
|
||||||
|
bean.setApproved(count);
|
||||||
|
} else {
|
||||||
|
bean.setRejected(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<CampOverviewBean> list = new ArrayList<>(map.values());
|
||||||
|
Collections.sort(list);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all bookings with condition that this user can manage
|
||||||
|
*
|
||||||
|
* @param currentUser the current user
|
||||||
|
* @param condition the condition e.g. T_PERSON.ACCEPT.isNull()
|
||||||
|
* @return a list of booking beans; an empty one at least
|
||||||
|
*/
|
||||||
|
private List<BookingBean> getListWithCondition(String currentUser, Condition condition) {
|
||||||
|
SelectSeekStep1<Record7<Integer, String, String, String, LocalDateTime, EnumCamprole, LocalDateTime>, LocalDateTime> sql = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.select(T_PERSON.PK, T_PERSON.FORENAME, T_PERSON.SURNAME, T_CAMP.NAME, T_CAMP.ARRIVE, T_PERSON.CAMPROLE, T_PERSON.CREATED)
|
||||||
|
.from(T_PERSON)
|
||||||
|
.leftJoin(T_CAMP).on(T_CAMP.PK.eq(T_PERSON.FK_CAMP))
|
||||||
|
.leftJoin(T_CAMPPROFILE).on(T_CAMPPROFILE.FK_CAMP.eq(T_PERSON.FK_CAMP))
|
||||||
|
.leftJoin(T_PROFILE).on(T_PROFILE.PK.eq(T_CAMPPROFILE.FK_PROFILE))
|
||||||
|
.where(condition)
|
||||||
|
.and(T_CAMPPROFILE.MODULE.eq(EnumModule.registration))
|
||||||
|
.and(T_PROFILE.USERNAME.eq(currentUser))
|
||||||
|
.orderBy(T_PERSON.CREATED.desc());
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug(sql.toString());
|
||||||
|
List<BookingBean> list = new ArrayList<>();
|
||||||
|
for (Record7<Integer, String, String, String, LocalDateTime, EnumCamprole, LocalDateTime> r : sql.fetch()) {
|
||||||
|
String forename = r.get(T_PERSON.FORENAME);
|
||||||
|
String surname = r.get(T_PERSON.SURNAME);
|
||||||
|
String campname = r.get(T_CAMP.NAME);
|
||||||
|
LocalDateTime arrive = r.get(T_CAMP.ARRIVE);
|
||||||
|
EnumCamprole role = r.get(T_PERSON.CAMPROLE);
|
||||||
|
LocalDateTime created = r.get(T_PERSON.CREATED);
|
||||||
|
Integer pkPerson = r.get(T_PERSON.PK);
|
||||||
|
BookingBean bean = new BookingBean(pkPerson, arrive.toLocalDate(), campname);
|
||||||
|
bean.setRole(role == null ? null : role.getLiteral());
|
||||||
|
bean.setRegistered(created);
|
||||||
|
bean.setFullname(new StringBuilder().append(forename).append(" ").append(surname).toString());
|
||||||
|
list.add(bean);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all untouched bookings that this user can manage
|
||||||
|
*
|
||||||
|
* @param currentUser the current user
|
||||||
|
* @return a list of booking beans; an empty one at least
|
||||||
|
*/
|
||||||
|
public List<BookingBean> getUntouched(String currentUser) {
|
||||||
|
return getListWithCondition(currentUser, T_PERSON.ACCEPT.isNull());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all approved bookings that this user can manage
|
||||||
|
*
|
||||||
|
* @param currentUser the current user
|
||||||
|
* @return a list of booking beans; an empty one at least
|
||||||
|
*/
|
||||||
|
public List<BookingBean> getApproved(String currentUser) {
|
||||||
|
return getListWithCondition(currentUser, T_PERSON.ACCEPT.isTrue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all rejected bookings that this user can manage
|
||||||
|
*
|
||||||
|
* @param currentUser the current user
|
||||||
|
* @return a list of booking beans; an empty one at least
|
||||||
|
*/
|
||||||
|
public List<BookingBean> getRejected(String currentUser) {
|
||||||
|
return getListWithCondition(currentUser, T_PERSON.ACCEPT.isFalse());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.confirmation.confirmation.impl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.jooq.exception.DataAccessException;
|
||||||
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import de.jottyfan.camporganizer.module.confirmation.confirmation.IConfirmationService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class ConfirmationService implements IConfirmationService {
|
||||||
|
@Autowired
|
||||||
|
private ConfirmationGateway gateway;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCurrentUser(HttpServletRequest request) {
|
||||||
|
KeycloakSecurityContext ksc = (KeycloakSecurityContext) request
|
||||||
|
.getAttribute(KeycloakSecurityContext.class.getName());
|
||||||
|
if (ksc == null) {
|
||||||
|
throw new DataAccessException("no keycloak user in session");
|
||||||
|
}
|
||||||
|
return ksc.getIdToken().getPreferredUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CampOverviewBean> getCampOverview(HttpServletRequest request) {
|
||||||
|
return gateway.getCampOverviewBeans(getCurrentUser(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BookingBean> getUntouched(HttpServletRequest request) {
|
||||||
|
return gateway.getUntouched(getCurrentUser(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BookingBean> getApproved(HttpServletRequest request) {
|
||||||
|
return gateway.getApproved(getCurrentUser(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BookingBean> getRejected(HttpServletRequest request) {
|
||||||
|
return gateway.getRejected(getCurrentUser(request));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.confirmation.person;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.jottyfan.camporganizer.module.confirmation.person.impl.CampBean;
|
||||||
|
import de.jottyfan.camporganizer.module.confirmation.person.impl.PersonBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface IPersonService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get person bean from db if username can read it
|
||||||
|
*
|
||||||
|
* @param username the user to read from the database
|
||||||
|
* @param pk the ID of the person to be read
|
||||||
|
* @return the person or null
|
||||||
|
*/
|
||||||
|
public PersonBean getPerson(String username, Integer pk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update bean in the database
|
||||||
|
*
|
||||||
|
* @param bean the bean
|
||||||
|
* @return number of affected database rows
|
||||||
|
*/
|
||||||
|
public Integer updatePerson(PersonBean bean);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all camps from the database that the user has access to
|
||||||
|
*
|
||||||
|
* @param username the user
|
||||||
|
* @return a list of camp beans; an empty one at least
|
||||||
|
*/
|
||||||
|
public List<CampBean> getCamps(String username);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get several annotations as a String
|
||||||
|
*
|
||||||
|
* @param pk the ID of the person
|
||||||
|
* @return the annotations; may be an empty string
|
||||||
|
*/
|
||||||
|
public String getAnnotations(Integer pk);
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.confirmation.person;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
|
||||||
|
import de.jottyfan.camporganizer.module.confirmation.confirmation.IConfirmationService;
|
||||||
|
import de.jottyfan.camporganizer.module.confirmation.person.impl.PersonBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
public class PersonController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private HttpServletRequest request;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IConfirmationService confirmationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IPersonService personService;
|
||||||
|
|
||||||
|
@GetMapping("/confirmation/person/{pk}")
|
||||||
|
public String getIndex(Model model, @PathVariable Integer pk) {
|
||||||
|
String username = confirmationService.getCurrentUser(request);
|
||||||
|
model.addAttribute("currentUser", username);
|
||||||
|
model.addAttribute("person", personService.getPerson(username, pk));
|
||||||
|
model.addAttribute("camps", personService.getCamps(username));
|
||||||
|
model.addAttribute("annotations", personService.getAnnotations(pk));
|
||||||
|
return "confirmation/person";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/confirmation/person/update")
|
||||||
|
public String doUpdate(@ModelAttribute PersonBean bean, Model model) {
|
||||||
|
personService.updatePerson(bean);
|
||||||
|
return "redirect:/confirmation";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.confirmation.person.impl;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CampBean implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private Integer pk;
|
||||||
|
private String name;
|
||||||
|
private LocalDateTime arrive;
|
||||||
|
private String location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pk
|
||||||
|
*/
|
||||||
|
public Integer getPk() {
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param pk the pk to set
|
||||||
|
*/
|
||||||
|
public void setPk(Integer pk) {
|
||||||
|
this.pk = pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name the name to set
|
||||||
|
*/
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the arrive
|
||||||
|
*/
|
||||||
|
public LocalDateTime getArrive() {
|
||||||
|
return arrive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param arrive the arrive to set
|
||||||
|
*/
|
||||||
|
public void setArrive(LocalDateTime arrive) {
|
||||||
|
this.arrive = arrive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the location
|
||||||
|
*/
|
||||||
|
public String getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param location the location to set
|
||||||
|
*/
|
||||||
|
public void setLocation(String location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,276 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.confirmation.person.impl;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.enums.EnumCamprole;
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.enums.EnumSex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class PersonBean implements Serializable {
|
||||||
|
private static final long serialVersionUID = 2L;
|
||||||
|
|
||||||
|
private Integer pk;
|
||||||
|
private String forename;
|
||||||
|
private String surname;
|
||||||
|
private String street;
|
||||||
|
private String zip;
|
||||||
|
private String city;
|
||||||
|
private String phone;
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate birthdate;
|
||||||
|
private EnumCamprole camprole;
|
||||||
|
private String email;
|
||||||
|
private Integer fkCamp;
|
||||||
|
private Integer fkProfile;
|
||||||
|
private Boolean accept;
|
||||||
|
private LocalDateTime created;
|
||||||
|
private EnumSex sex;
|
||||||
|
private Integer fkRegistrator;
|
||||||
|
private String comment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the forename
|
||||||
|
*/
|
||||||
|
public String getForename() {
|
||||||
|
return forename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param forename the forename to set
|
||||||
|
*/
|
||||||
|
public void setForename(String forename) {
|
||||||
|
this.forename = forename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the surname
|
||||||
|
*/
|
||||||
|
public String getSurname() {
|
||||||
|
return surname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param surname the surname to set
|
||||||
|
*/
|
||||||
|
public void setSurname(String surname) {
|
||||||
|
this.surname = surname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the street
|
||||||
|
*/
|
||||||
|
public String getStreet() {
|
||||||
|
return street;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param street the street to set
|
||||||
|
*/
|
||||||
|
public void setStreet(String street) {
|
||||||
|
this.street = street;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the zip
|
||||||
|
*/
|
||||||
|
public String getZip() {
|
||||||
|
return zip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param zip the zip to set
|
||||||
|
*/
|
||||||
|
public void setZip(String zip) {
|
||||||
|
this.zip = zip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the city
|
||||||
|
*/
|
||||||
|
public String getCity() {
|
||||||
|
return city;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param city the city to set
|
||||||
|
*/
|
||||||
|
public void setCity(String city) {
|
||||||
|
this.city = city;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the phone
|
||||||
|
*/
|
||||||
|
public String getPhone() {
|
||||||
|
return phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param phone the phone to set
|
||||||
|
*/
|
||||||
|
public void setPhone(String phone) {
|
||||||
|
this.phone = phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the birthdate
|
||||||
|
*/
|
||||||
|
public LocalDate getBirthdate() {
|
||||||
|
return birthdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param birthdate the birthdate to set
|
||||||
|
*/
|
||||||
|
public void setBirthdate(LocalDate birthdate) {
|
||||||
|
this.birthdate = birthdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the camprole
|
||||||
|
*/
|
||||||
|
public EnumCamprole getCamprole() {
|
||||||
|
return camprole;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param camprole the camprole to set
|
||||||
|
*/
|
||||||
|
public void setCamprole(EnumCamprole camprole) {
|
||||||
|
this.camprole = camprole;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the email
|
||||||
|
*/
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param email the email to set
|
||||||
|
*/
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the fkCamp
|
||||||
|
*/
|
||||||
|
public Integer getFkCamp() {
|
||||||
|
return fkCamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param fkCamp the fkCamp to set
|
||||||
|
*/
|
||||||
|
public void setFkCamp(Integer fkCamp) {
|
||||||
|
this.fkCamp = fkCamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the fkProfile
|
||||||
|
*/
|
||||||
|
public Integer getFkProfile() {
|
||||||
|
return fkProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param fkProfile the fkProfile to set
|
||||||
|
*/
|
||||||
|
public void setFkProfile(Integer fkProfile) {
|
||||||
|
this.fkProfile = fkProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the accept
|
||||||
|
*/
|
||||||
|
public Boolean getAccept() {
|
||||||
|
return accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param accept the accept to set
|
||||||
|
*/
|
||||||
|
public void setAccept(Boolean accept) {
|
||||||
|
this.accept = accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the created
|
||||||
|
*/
|
||||||
|
public LocalDateTime getCreated() {
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param created the created to set
|
||||||
|
*/
|
||||||
|
public void setCreated(LocalDateTime created) {
|
||||||
|
this.created = created;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the sex
|
||||||
|
*/
|
||||||
|
public EnumSex getSex() {
|
||||||
|
return sex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param sex the sex to set
|
||||||
|
*/
|
||||||
|
public void setSex(EnumSex sex) {
|
||||||
|
this.sex = sex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the fkRegistrator
|
||||||
|
*/
|
||||||
|
public Integer getFkRegistrator() {
|
||||||
|
return fkRegistrator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param fkRegistrator the fkRegistrator to set
|
||||||
|
*/
|
||||||
|
public void setFkRegistrator(Integer fkRegistrator) {
|
||||||
|
this.fkRegistrator = fkRegistrator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the comment
|
||||||
|
*/
|
||||||
|
public String getComment() {
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param comment the comment to set
|
||||||
|
*/
|
||||||
|
public void setComment(String comment) {
|
||||||
|
this.comment = comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pk
|
||||||
|
*/
|
||||||
|
public Integer getPk() {
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param pk the pk to set
|
||||||
|
*/
|
||||||
|
public void setPk(Integer pk) {
|
||||||
|
this.pk = pk;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,205 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.confirmation.person.impl;
|
||||||
|
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_CAMP;
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_CAMPPROFILE;
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_LOCATION;
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PERSON;
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PROFILE;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.jooq.DSLContext;
|
||||||
|
import org.jooq.Record;
|
||||||
|
import org.jooq.Record11;
|
||||||
|
import org.jooq.Record4;
|
||||||
|
import org.jooq.SelectConditionStep;
|
||||||
|
import org.jooq.SelectSeekStep1;
|
||||||
|
import org.jooq.UpdateConditionStep;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.enums.EnumCamprole;
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.enums.EnumModule;
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.tables.TProfile;
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.tables.records.TPersonRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
@Transactional(transactionManager = "transactionManager")
|
||||||
|
public class PersonGateway {
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(PersonGateway.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DSLContext jooq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all camps from the database if username is allowed to maintain it
|
||||||
|
*
|
||||||
|
* @param username the username of the requesting person
|
||||||
|
* @return all camps
|
||||||
|
*/
|
||||||
|
public List<CampBean> getCamps(String username) {
|
||||||
|
SelectSeekStep1<Record4<Integer, String, LocalDateTime, String>, LocalDateTime> sql = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.select(T_CAMP.PK, T_CAMP.NAME, T_CAMP.ARRIVE, T_LOCATION.NAME)
|
||||||
|
.from(T_CAMP)
|
||||||
|
.leftJoin(T_LOCATION).on(T_LOCATION.PK.eq(T_CAMP.FK_LOCATION))
|
||||||
|
.leftJoin(T_CAMPPROFILE).on(T_CAMPPROFILE.FK_CAMP.eq(T_CAMP.PK))
|
||||||
|
.leftJoin(T_PROFILE).on(T_PROFILE.PK.eq(T_CAMPPROFILE.FK_PROFILE))
|
||||||
|
.where(T_CAMPPROFILE.MODULE.eq(EnumModule.registration))
|
||||||
|
.and(T_PROFILE.USERNAME.eq(username))
|
||||||
|
.orderBy(T_CAMP.ARRIVE.desc());
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug(sql.toString());
|
||||||
|
List<CampBean> list = new ArrayList<>();
|
||||||
|
for (Record r : sql.fetch()) {
|
||||||
|
CampBean bean = new CampBean();
|
||||||
|
bean.setPk(r.get(T_CAMP.PK));
|
||||||
|
bean.setName(r.get(T_CAMP.NAME));
|
||||||
|
bean.setArrive(r.get(T_CAMP.ARRIVE));
|
||||||
|
bean.setLocation(r.get(T_LOCATION.NAME));
|
||||||
|
list.add(bean);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the person referenced by pk if username is allowed to read it
|
||||||
|
*
|
||||||
|
* @param username the username of the requesting person
|
||||||
|
* @param pk the ID of the person
|
||||||
|
* @return the person bean if found; null otherwise
|
||||||
|
*/
|
||||||
|
public PersonBean getPerson(String username, Integer pk) {
|
||||||
|
SelectConditionStep<Record> sql = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.select(T_PERSON.fields())
|
||||||
|
.from(T_PERSON)
|
||||||
|
.leftJoin(T_CAMP).on(T_CAMP.PK.eq(T_PERSON.FK_CAMP))
|
||||||
|
.leftJoin(T_CAMPPROFILE).on(T_CAMPPROFILE.FK_CAMP.eq(T_PERSON.FK_CAMP))
|
||||||
|
.leftJoin(T_PROFILE).on(T_PROFILE.PK.eq(T_CAMPPROFILE.FK_PROFILE))
|
||||||
|
.where(T_PERSON.PK.eq(pk))
|
||||||
|
.and(T_CAMPPROFILE.MODULE.eq(EnumModule.registration))
|
||||||
|
.and(T_PROFILE.USERNAME.eq(username));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug(sql.toString());
|
||||||
|
for (Record r : sql.fetch()) {
|
||||||
|
PersonBean bean = new PersonBean();
|
||||||
|
bean.setPk(pk);
|
||||||
|
bean.setAccept(r.get(T_PERSON.ACCEPT));
|
||||||
|
bean.setBirthdate(r.get(T_PERSON.BIRTHDATE));
|
||||||
|
bean.setCamprole(r.get(T_PERSON.CAMPROLE));
|
||||||
|
bean.setCity(r.get(T_PERSON.CITY));
|
||||||
|
bean.setComment(r.get(T_PERSON.COMMENT));
|
||||||
|
bean.setCreated(r.get(T_PERSON.CREATED));
|
||||||
|
bean.setEmail(r.get(T_PERSON.EMAIL));
|
||||||
|
bean.setFkCamp(r.get(T_PERSON.FK_CAMP));
|
||||||
|
bean.setFkProfile(r.get(T_PERSON.FK_PROFILE));
|
||||||
|
bean.setFkRegistrator(r.get(T_PERSON.FK_REGISTRATOR));
|
||||||
|
bean.setForename(r.get(T_PERSON.FORENAME));
|
||||||
|
bean.setSurname(r.get(T_PERSON.SURNAME));
|
||||||
|
bean.setPhone(r.get(T_PERSON.PHONE));
|
||||||
|
bean.setSex(r.get(T_PERSON.SEX));
|
||||||
|
bean.setStreet(r.get(T_PERSON.STREET));
|
||||||
|
bean.setZip(r.get(T_PERSON.ZIP));
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update that bean in the database
|
||||||
|
*
|
||||||
|
* @param bean the bean
|
||||||
|
* @return the number of affected database rows
|
||||||
|
*/
|
||||||
|
public Integer updatePerson(PersonBean bean) {
|
||||||
|
UpdateConditionStep<TPersonRecord> sql = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.update(T_PERSON)
|
||||||
|
.set(T_PERSON.FORENAME, bean.getForename())
|
||||||
|
.set(T_PERSON.SURNAME, bean.getSurname())
|
||||||
|
.set(T_PERSON.STREET, bean.getStreet())
|
||||||
|
.set(T_PERSON.ZIP, bean.getZip())
|
||||||
|
.set(T_PERSON.CITY, bean.getCity())
|
||||||
|
.set(T_PERSON.BIRTHDATE, bean.getBirthdate())
|
||||||
|
.set(T_PERSON.SEX, bean.getSex())
|
||||||
|
.set(T_PERSON.PHONE, bean.getPhone())
|
||||||
|
.set(T_PERSON.EMAIL, bean.getEmail())
|
||||||
|
.set(T_PERSON.COMMENT, bean.getComment())
|
||||||
|
.set(T_PERSON.ACCEPT, bean.getAccept())
|
||||||
|
.where(T_PERSON.PK.eq(bean.getPk()));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug(sql.toString());
|
||||||
|
return sql.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get annotations of person
|
||||||
|
*
|
||||||
|
* @param pk the ID of the person
|
||||||
|
* @return annotations if found; an empty string if not
|
||||||
|
*/
|
||||||
|
public String getAnnotations(Integer pk) {
|
||||||
|
TProfile REGISTRATOR = T_PROFILE.as("registrator");
|
||||||
|
SelectConditionStep<Record11<LocalDate, LocalDateTime, EnumCamprole, LocalDateTime, LocalDateTime, Integer, Integer, String, String, String, String>> sql = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.select(T_PERSON.BIRTHDATE, T_PERSON.CREATED, T_PERSON.CAMPROLE,
|
||||||
|
T_CAMP.ARRIVE, T_CAMP.DEPART,
|
||||||
|
T_CAMP.MIN_AGE, T_CAMP.MAX_AGE,
|
||||||
|
T_PROFILE.FORENAME, T_PROFILE.SURNAME,
|
||||||
|
REGISTRATOR.FORENAME, REGISTRATOR.SURNAME)
|
||||||
|
.from(T_PERSON)
|
||||||
|
.leftJoin(T_CAMP).on(T_CAMP.PK.eq(T_PERSON.FK_CAMP))
|
||||||
|
.leftJoin(T_PROFILE).on(T_PROFILE.PK.eq(T_PERSON.FK_PROFILE))
|
||||||
|
.leftJoin(REGISTRATOR).on(REGISTRATOR.PK.eq(T_PERSON.FK_REGISTRATOR))
|
||||||
|
.where(T_PERSON.PK.eq(pk));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug(sql.toString());
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
for (Record r : sql.fetch()) {
|
||||||
|
LocalDate birthdate = r.get(T_PERSON.BIRTHDATE);
|
||||||
|
LocalDateTime arrive = r.get(T_CAMP.ARRIVE);
|
||||||
|
LocalDateTime depart = r.get(T_CAMP.DEPART);
|
||||||
|
Integer minAge = r.get(T_CAMP.MIN_AGE);
|
||||||
|
Integer maxAge = r.get(T_CAMP.MAX_AGE);
|
||||||
|
String bookerForename = r.get(T_PROFILE.FORENAME);
|
||||||
|
String bookerSurname = r.get(T_PROFILE.SURNAME);
|
||||||
|
String registratorForename = r.get(REGISTRATOR.FORENAME);
|
||||||
|
String registratorSurname = r.get(REGISTRATOR.SURNAME);
|
||||||
|
LocalDateTime created = r.get(T_PERSON.CREATED);
|
||||||
|
EnumCamprole role = r.get(T_PERSON.CAMPROLE);
|
||||||
|
String createdString = created.format(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
|
||||||
|
buf.append(String.format("angemeldet von %s %s am %s\n", bookerForename, bookerSurname, createdString));
|
||||||
|
if (registratorForename != null || registratorSurname != null) {
|
||||||
|
buf.append(String.format("bearbeitet von %s %s\n", registratorForename, registratorSurname));
|
||||||
|
}
|
||||||
|
if (birthdate == null) {
|
||||||
|
buf.append("Geburtstag wurde nicht angegeben\n");
|
||||||
|
} else if (arrive.isBefore(birthdate.atStartOfDay()) && depart.isAfter(birthdate.atStartOfDay())) {
|
||||||
|
buf.append("hat während der Freizeit Geburtstag\n");
|
||||||
|
}
|
||||||
|
if (birthdate == null || arrive == null) {
|
||||||
|
buf.append("Alter konnte wegen fehlendem Geburtstag nicht ermittelt werden\n");
|
||||||
|
} else {
|
||||||
|
long age = ChronoUnit.YEARS.between(birthdate, arrive);
|
||||||
|
if (EnumCamprole.student.equals(role) && (minAge > age || maxAge < age)) {
|
||||||
|
buf.append("passt vom Alter her nicht in die Freizeit");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.confirmation.person.impl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import de.jottyfan.camporganizer.module.confirmation.person.IPersonService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class PersonService implements IPersonService {
|
||||||
|
@Autowired
|
||||||
|
private PersonGateway gateway;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersonBean getPerson(String username, Integer pk) {
|
||||||
|
return gateway.getPerson(username, pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer updatePerson(PersonBean bean) {
|
||||||
|
return gateway.updatePerson(bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CampBean> getCamps(String username) {
|
||||||
|
return gateway.getCamps(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAnnotations(Integer pk) {
|
||||||
|
return gateway.getAnnotations(pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -87,6 +87,49 @@ body {
|
|||||||
color: darkcyan;
|
color: darkcyan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badgetodo {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid black;
|
||||||
|
color: white;
|
||||||
|
font-weight: bolder;
|
||||||
|
background-image: linear-gradient(to right bottom, rgb(153, 193, 241), rgb(26, 95, 180));
|
||||||
|
padding: 2px 4px 2px 4px;
|
||||||
|
margin: 0px 2px 0px 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badgewarn {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid black;
|
||||||
|
color: white;
|
||||||
|
font-weight: bolder;
|
||||||
|
background-image: linear-gradient(to right bottom, #fa0, #a70);
|
||||||
|
padding: 2px 4px 2px 4px;
|
||||||
|
margin: 0px 2px 0px 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badgeinfo {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid black;
|
||||||
|
color: white;
|
||||||
|
font-weight: bolder;
|
||||||
|
background-image: linear-gradient(to right bottom, rgb(143, 240, 164), rgb(38, 162, 105));
|
||||||
|
padding: 2px 4px 2px 4px;
|
||||||
|
margin: 0px 2px 0px 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dist8 {
|
||||||
|
margin: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.locked {
|
||||||
|
background-color: rgba(255, 255, 255, 0.2) !important;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
.mytoggle_collapsed {
|
.mytoggle_collapsed {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
169
src/main/resources/templates/confirmation/confirmation.html
Normal file
169
src/main/resources/templates/confirmation/confirmation.html
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html th:replace="~{template :: layout(~{::title}, ~{::libs}, ~{::header}, ~{::content})}" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||||
|
<head>
|
||||||
|
<title>Camp Organizer Confirmation</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<libs></libs>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<a th:href="@{/}" class="btn btn-secondary btn-icon-silent" title="zur Hauptseite"><i class="fas fa-home"></i></a>
|
||||||
|
<a th:href="@{/confirmation}" class="btn btn-secondary btn-icon-silent" title="aktualisieren"><i class="fas fa-sync"></i></a>
|
||||||
|
</header>
|
||||||
|
<content>
|
||||||
|
<div class="mainpage">
|
||||||
|
<div class="accordion" id="mainacc" sec:authorize="hasRole('registrator')">
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="untouchedpanel">
|
||||||
|
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#untoucheddiv" aria-expanded="true" aria-control="untoucheddiv">unbearbeitete Anmeldungen
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="untoucheddiv" class="accordion-collapse collapse show dist8" aria-labelled="untouchedpanel" data-bs-parent="#mainacc">
|
||||||
|
<table id="untouched">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Freizeit</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Rolle</th>
|
||||||
|
<th>Anmeldedatum</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr th:each="u : ${untouched}">
|
||||||
|
<td><a th:href="@{'/confirmation/person/' + ${u.pkPerson}}" th:text="${u.camp} + ' ' + ${#temporals.format(u.date, 'yyyy')}"></a></td>
|
||||||
|
<td><a th:href="@{'/confirmation/person/' + ${u.pkPerson}}" th:text="${u.fullname}"></a></td>
|
||||||
|
<td><a th:href="@{'/confirmation/person/' + ${u.pkPerson}}" th:text="${u.rolename}"></a></td>
|
||||||
|
<td><a th:href="@{'/confirmation/person/' + ${u.pkPerson}}" th:text="${#temporals.format(u.registered, 'dd.MM.yyyy')}"></a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#untouched").DataTable({
|
||||||
|
language : locale_de,
|
||||||
|
pageLength : 5,
|
||||||
|
lengthMenu : [ [ 5, 25, 50, -1 ], [ 5, 25, 50, "Alle" ] ]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="approvedpanel">
|
||||||
|
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#approveddiv" aria-expanded="true" aria-control="approveddiv">kürzlich bestätigte
|
||||||
|
Anmeldungen</button>
|
||||||
|
</h2>
|
||||||
|
<div id="approveddiv" class="accordion-collapse collapse dist8" aria-labelled="approvedpanel" data-bs-parent="#mainacc">
|
||||||
|
<table id="approved">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Freizeit</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Rolle</th>
|
||||||
|
<th>Anmeldedatum</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr th:each="u : ${approved}">
|
||||||
|
<td><a th:href="@{'/confirmation/person/' + ${u.pkPerson}}" th:text="${u.camp} + ' ' + ${#temporals.format(u.date, 'yyyy')}"></a></td>
|
||||||
|
<td><a th:href="@{'/confirmation/person/' + ${u.pkPerson}}" th:text="${u.fullname}"></a></td>
|
||||||
|
<td><a th:href="@{'/confirmation/person/' + ${u.pkPerson}}" th:text="${u.rolename}"></a></td>
|
||||||
|
<td><a th:href="@{'/confirmation/person/' + ${u.pkPerson}}" th:text="${#temporals.format(u.registered, 'dd.MM.yyyy')}"></a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#approved").DataTable({
|
||||||
|
language : locale_de,
|
||||||
|
pageLength : 5,
|
||||||
|
lengthMenu : [ [ 5, 25, 50, -1 ], [ 5, 25, 50, "Alle" ] ]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="rejectedpanel">
|
||||||
|
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#rejecteddiv" aria-expanded="true" aria-control="rejecteddiv">kürzlich abgelehnte
|
||||||
|
Anmeldungen</button>
|
||||||
|
</h2>
|
||||||
|
<div id="rejecteddiv" class="accordion-collapse collapse dist8" aria-labelled="rejectedpanel" data-bs-parent="#mainacc">
|
||||||
|
<table id="rejected">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Freizeit</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Rolle</th>
|
||||||
|
<th>Anmeldedatum</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr th:each="u : ${rejected}">
|
||||||
|
<td><a th:href="@{'/confirmation/person/' + ${u.pkPerson}}" th:text="${u.camp} + ' ' + ${#temporals.format(u.date, 'yyyy')}"></a></td>
|
||||||
|
<td><a th:href="@{'/confirmation/person/' + ${u.pkPerson}}" th:text="${u.fullname}"></a></td>
|
||||||
|
<td><a th:href="@{'/confirmation/person/' + ${u.pkPerson}}" th:text="${u.rolename}"></a></td>
|
||||||
|
<td><a th:href="@{'/confirmation/person/' + ${u.pkPerson}}" th:text="${#temporals.format(u.registered, 'dd.MM.yyyy')}"></a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#rejected").DataTable({
|
||||||
|
language : locale_de,
|
||||||
|
pageLength : 5,
|
||||||
|
lengthMenu : [ [ 5, 25, 50, -1 ], [ 5, 25, 50, "Alle" ] ]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="overviewpanel">
|
||||||
|
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#overviewdiv" aria-expanded="true" aria-control="overviewdiv">Freizeitenübersicht</button>
|
||||||
|
</h2>
|
||||||
|
<div id="overviewdiv" class="accordion-collapse collapse dist8" aria-labelled="overviewpanel" data-bs-parent="#mainacc">
|
||||||
|
<table id="campoverview">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Freizeit</th>
|
||||||
|
<th style="min-width: 64px">u/a/b</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr th:each="o : ${campoverview}">
|
||||||
|
<td th:text="${o.camp} + ' ' + ${#temporals.format(o.date, 'yyyy')}"></td>
|
||||||
|
<td><span th:text="${o.untouched}" class="badgetodo"></span> / <span th:text="${o.rejected}" class="badgewarn"></span> / <span th:text="${o.approved}" class="badgeinfo"></span></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td>Zusammenfassung</td>
|
||||||
|
<td><span th:text="${campoverviewsummary.untouched}" class="badgetodo"></span> / <span th:text="${campoverviewsummary.rejected}" class="badgewarn"></span> / <span
|
||||||
|
th:text="${campoverviewsummary.approved}" class="badgeinfo"></span></td>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#campoverview").DataTable({
|
||||||
|
language : locale_de,
|
||||||
|
pageLength : 5,
|
||||||
|
lengthMenu : [ [ 5, 25, 50, -1 ], [ 5, 25, 50, "Alle" ] ]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<span>Legende:</span><span class="badgetodo">unbearbeitet</span><span class="badgewarn">abgelehnt</span><span class="badgeinfo">bestätigt</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="searchpanel">
|
||||||
|
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#searchdiv" aria-expanded="true" aria-control="searchdiv">Suchmaske</button>
|
||||||
|
</h2>
|
||||||
|
<div id="searchdiv" class="accordion-collapse collapse dist8" aria-labelled="searchpanel" data-bs-parent="#mainacc">TODO: add an ajax based search field for persons to directly edit
|
||||||
|
them</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</content>
|
||||||
|
</body>
|
||||||
|
</html>
|
135
src/main/resources/templates/confirmation/person.html
Normal file
135
src/main/resources/templates/confirmation/person.html
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html th:replace="~{template :: layout(~{::title}, ~{::libs}, ~{::header}, ~{::content})}" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||||
|
<head>
|
||||||
|
<title>Camp Organizer Confirmation</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<libs></libs>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<a th:href="@{/}" class="btn btn-secondary btn-icon-silent" title="zur Hauptseite"><i class="fas fa-home"></i></a>
|
||||||
|
<a th:href="@{/confirmation}" class="btn btn-secondary btn-icon-silent" title="Anmeldungen"><i class="fas fa-user-check"></i></a>
|
||||||
|
<a th:href="@{/confirmation/person/{pk}(pk=${person.pk})}" class="btn btn-secondary btn-icon-silent" title="aktualisieren" th:if="${person != null}"><i class="fas fa-sync"></i></a>
|
||||||
|
</header>
|
||||||
|
<content>
|
||||||
|
<div class="mainpage">
|
||||||
|
<div class="container" style="max-width: 100%" sec:authorize="hasRole('registrator')">
|
||||||
|
<form action="#" th:action="@{/confirmation/person/update}" th:object="${person}" method="post" th:if="${person != null}">
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="outputPk" class="col-sm-2 col-form-label">ID</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" th:field="*{pk}" class="outputPk form-control locked"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="inputForename" class="col-sm-2 col-form-label">Vorname</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" th:field="*{forename}" class="inputForename form-control" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="inputSurname" class="col-sm-2 col-form-label">Nachname</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" th:field="*{surname}" class="inputSurname form-control" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="inputStreet" class="col-sm-2 col-form-label">Straße</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" th:field="*{street}" class="inputStreet form-control" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="inputZip" class="col-sm-2 col-form-label">PLZ</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" th:field="*{zip}" class="inputZip form-control" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="inputCity" class="col-sm-2 col-form-label">Ort</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" th:field="*{city}" class="inputCity form-control" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="inputBirthdate" class="col-sm-2 col-form-label">Geburtstag (TODO)</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="date" th:field="*{birthdate}" class="inputBirthdate form-control" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="inputSex" class="col-sm-2 col-form-label">Geschlecht</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select class="form-select" th:field="*{sex}">
|
||||||
|
<option value="male">männlich</option>
|
||||||
|
<option value="female">weiblich</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="inputPhone" class="col-sm-2 col-form-label">Telefon</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" th:field="*{phone}" class="inputPhone form-control" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="inputEmail" class="col-sm-2 col-form-label">E-Mail</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="email" th:field="*{email}" class="inputEmail form-control" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="outputCamp" class="col-sm-2 col-form-label">Freizeit</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select class="form-select locked" th:field="*{fkCamp}" disabled="disabled">
|
||||||
|
<option th:each="c : ${camps}" th:value="${c.pk}" th:text="${c.name} + ' ' + ${#temporals.format(c.arrive, 'yyyy')} + ' in ' + ${c.location}"></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="outputCamprole" class="col-sm-2 col-form-label">Rolle</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select class="outputCamprole form-select locked" th:field="*{camprole}" disabled="disabled">
|
||||||
|
<option value="student">Teilnehmer</option>
|
||||||
|
<option value="teacher">Mitarbeiter</option>
|
||||||
|
<option value="director">Leiter</option>
|
||||||
|
<option value="feeder">Küchenteam</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="inputComment" class="col-sm-2 col-form-label">Kommentar</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<textarea th:field="*{comment}" class="inputComment form-control"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="outputAnno" class="col-sm-2 col-form-label">Anmerkungen</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<pre class="form-control locked" th:text="${annotations}"></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="inputAccept" class="col-sm-2 col-form-label">Status</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select class="form-select" th:field="*{accept}">
|
||||||
|
<option th:value="null">offen</option>
|
||||||
|
<option th:value="true">bestätigt</option>
|
||||||
|
<option th:value="false">abgelehnt</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label for="inputAccept" class="col-sm-2 col-form-label"></label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<button type="submit" class="btn btn-primary">Ok</button>
|
||||||
|
<a th:href="@{/confirmation/}" class="btn btn-secondary">Abbrechen</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div th:if="${person == null}" class="error">In der Datenbank wurde keine Person mit entsprechender ID gefunden.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</content>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -8,7 +8,8 @@
|
|||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
<a th:href="@{/}" class="btn btn-secondary btn-icon-silent" title="aktualisieren"><i class="fas fa-sync"></i></a>
|
<a th:href="@{/}" class="btn btn-secondary btn-icon-silent" title="aktualisieren"><i class="fas fa-sync"></i></a>
|
||||||
<a th:href="@{/business}" class="btn btn-secondary btn-icon-silent" title="Abrechnungen"><i class="far fa-money-bill-alt"></i></a>
|
<a th:href="@{/business}" class="btn btn-secondary btn-icon-silent" title="Abrechnungen" sec:authorize="hasRole('business')"><i class="far fa-money-bill-alt"></i></a>
|
||||||
|
<a th:href="@{/confirmation}" class="btn btn-secondary btn-icon-silent" title="Anmeldungen" sec:authorize="hasRole('registrator')"><i class="fas fa-user-check"></i></a>
|
||||||
<a href="https://www.onkelwernerfreizeiten.de/nextcloud" class="btn btn-secondary btn-icon-silent" title="Nextcloud" target="_blank"><img th:src="@{images/nextcloud.png}" width="20px"/></a>
|
<a href="https://www.onkelwernerfreizeiten.de/nextcloud" class="btn btn-secondary btn-icon-silent" title="Nextcloud" target="_blank"><img th:src="@{images/nextcloud.png}" width="20px"/></a>
|
||||||
</header>
|
</header>
|
||||||
<content>
|
<content>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user