siehe #44
This commit is contained in:
parent
c4f81c425b
commit
45e6c4cbd4
@ -18,7 +18,7 @@ apply plugin: 'war'
|
||||
apply plugin: 'application'
|
||||
|
||||
group = 'de.jottyfan.camporganizer'
|
||||
version = '0.4.1'
|
||||
version = '0.4.2'
|
||||
sourceCompatibility = 17
|
||||
mainClassName = "de.jottyfan.camporganizer.Main"
|
||||
|
||||
|
@ -1,48 +0,0 @@
|
||||
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
|
||||
* @param worker the user that is doing the changes
|
||||
* @return number of affected database rows
|
||||
*/
|
||||
public Integer updatePerson(PersonBean bean, String worker);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||
import de.jottyfan.camporganizer.module.camplist.CommonController;
|
||||
import de.jottyfan.camporganizer.module.confirmation.confirmation.IConfirmationService;
|
||||
import de.jottyfan.camporganizer.module.confirmation.person.impl.PersonBean;
|
||||
import de.jottyfan.camporganizer.module.confirmation.person.impl.PersonService;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -29,7 +30,7 @@ public class PersonController extends CommonController {
|
||||
private IConfirmationService confirmationService;
|
||||
|
||||
@Autowired
|
||||
private IPersonService personService;
|
||||
private PersonService personService;
|
||||
|
||||
@GetMapping("/confirmation/person/{pk}")
|
||||
public String getIndex(Model model, @PathVariable Integer pk) {
|
||||
|
@ -34,6 +34,7 @@ import de.jottyfan.camporganizer.db.jooq.enums.EnumModule;
|
||||
import de.jottyfan.camporganizer.db.jooq.tables.TProfile;
|
||||
import de.jottyfan.camporganizer.db.jooq.tables.records.TCampRecord;
|
||||
import de.jottyfan.camporganizer.db.jooq.tables.records.TPersonRecord;
|
||||
import de.jottyfan.camporganizer.db.jooq.tables.records.TProfileRecord;
|
||||
import de.jottyfan.camporganizer.db.jooq.tables.records.TRssRecord;
|
||||
import de.jottyfan.camporganizer.module.camplist.LambdaResultWrapper;
|
||||
import de.jottyfan.camporganizer.module.mail.MailBean;
|
||||
@ -140,26 +141,30 @@ public class PersonRepository {
|
||||
LambdaResultWrapper lrw = new LambdaResultWrapper();
|
||||
jooq.transaction(t -> {
|
||||
|
||||
SelectConditionStep<TProfileRecord> sql0 = jooq.selectFrom(T_PROFILE).where(T_PROFILE.USERNAME.eq(registrator));
|
||||
LOGGER.debug(sql0.toString());
|
||||
Integer fkRegistrator = sql0.fetchOne(T_PROFILE.PK);
|
||||
|
||||
// get old accept value for comparison
|
||||
SelectConditionStep<TPersonRecord> sql = jooq.selectFrom(T_PERSON).where(T_PERSON.PK.eq(bean.getPk()));
|
||||
LOGGER.debug(sql.toString());
|
||||
TPersonRecord r = sql.fetchOne();
|
||||
SelectConditionStep<TPersonRecord> sql1 = jooq.selectFrom(T_PERSON).where(T_PERSON.PK.eq(bean.getPk()));
|
||||
LOGGER.debug(sql1.toString());
|
||||
TPersonRecord r = sql1.fetchOne();
|
||||
lrw.putBoolean("acceptOld", r == null ? null : r.getAccept());
|
||||
lrw.putBoolean("acceptNew", bean.getAccept());
|
||||
Integer fkCamp = r == null ? null : r.getFkCamp();
|
||||
String email = r.getEmail(); // use the old one, too
|
||||
lrw.putString("oldEmail", email);
|
||||
|
||||
SelectConditionStep<TCampRecord> sql0 = jooq.selectFrom(T_CAMP).where(T_CAMP.PK.eq(fkCamp));
|
||||
LOGGER.debug(sql0.toString());
|
||||
TCampRecord rc = sql0.fetchOne();
|
||||
SelectConditionStep<TCampRecord> sql2 = jooq.selectFrom(T_CAMP).where(T_CAMP.PK.eq(fkCamp));
|
||||
LOGGER.debug(sql2.toString());
|
||||
TCampRecord rc = sql2.fetchOne();
|
||||
String campName = rc == null ? null : rc.getName();
|
||||
LocalDateTime arrive = rc == null ? null : rc.getArrive();
|
||||
String campNameWithYear = new StringBuilder(campName == null ? "" : campName).append(" ")
|
||||
.append(arrive == null ? "" : arrive.format(DateTimeFormatter.ofPattern("YYYY"))).toString();
|
||||
lrw.putString("campNameWithYear", campNameWithYear);
|
||||
|
||||
UpdateConditionStep<TPersonRecord> sql1 = jooq
|
||||
UpdateConditionStep<TPersonRecord> sql3 = jooq
|
||||
// @formatter:off
|
||||
.update(T_PERSON)
|
||||
.set(T_PERSON.FORENAME, bean.getForename())
|
||||
@ -174,10 +179,11 @@ public class PersonRepository {
|
||||
.set(T_PERSON.COMMENT, bean.getComment())
|
||||
.set(T_PERSON.ACCEPT, bean.getAccept())
|
||||
.set(T_PERSON.CAMPROLE, bean.getCamprole())
|
||||
.set(T_PERSON.FK_REGISTRATOR, fkRegistrator)
|
||||
.where(T_PERSON.PK.eq(bean.getPk()));
|
||||
// @formatter:on
|
||||
LOGGER.debug(sql1.toString());
|
||||
lrw.add(sql1.execute());
|
||||
LOGGER.debug(sql3.toString());
|
||||
lrw.add(sql3.execute());
|
||||
|
||||
// always
|
||||
StringBuilder buf = new StringBuilder("Eine Anmeldung für ");
|
||||
@ -185,15 +191,15 @@ public class PersonRepository {
|
||||
buf.append(" wurde von ").append(registrator);
|
||||
buf.append(" korrigiert.");
|
||||
|
||||
InsertValuesStep2<TRssRecord, String, String> sql2 = DSL.using(t)
|
||||
InsertValuesStep2<TRssRecord, String, String> sql4 = DSL.using(t)
|
||||
// @formatter:off
|
||||
.insertInto(T_RSS,
|
||||
T_RSS.MSG,
|
||||
T_RSS.RECIPIENT)
|
||||
.values(buf.toString(), "registrator");
|
||||
// @formatter:on
|
||||
LOGGER.debug("{}", sql2.toString());
|
||||
sql2.execute();
|
||||
LOGGER.debug("{}", sql4.toString());
|
||||
sql4.execute();
|
||||
});
|
||||
|
||||
// send email to user instead of rss feed
|
||||
@ -229,7 +235,7 @@ public class PersonRepository {
|
||||
buf.append(bean.getSurname());
|
||||
buf.append(" zur Freizeit ");
|
||||
buf.append(campNameWithYear);
|
||||
buf.append(" wurde bestätigt. Melde Dich jetzt unter https://www.onkelwernerfreizeiten.de/camporganizer an,");
|
||||
buf.append(" wurde bestätigt. Melde Dich jetzt unter https://www.onkelwernerfreizeiten.de an,");
|
||||
buf.append(" um die zu unterschreibenden Dokumente herunterzuladen, auszudrucken und uns zukommen zu lassen.");
|
||||
sendMail = true;
|
||||
}
|
||||
@ -300,7 +306,11 @@ public class PersonRepository {
|
||||
LocalDateTime created = r.get(T_PERSON.CREATED);
|
||||
EnumCamprole role = r.get(T_PERSON.CAMPROLE);
|
||||
String createdString = created.format(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
|
||||
if (bookerForename == null && bookerSurname == null) {
|
||||
buf.append(String.format("angemeldet ohne Registrierung am %s\n", createdString));
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
|
@ -5,36 +5,29 @@ 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 {
|
||||
public class PersonService {
|
||||
@Autowired
|
||||
private PersonRepository gateway;
|
||||
|
||||
@Override
|
||||
public PersonBean getPerson(String username, Integer pk) {
|
||||
return gateway.getPerson(username, pk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer updatePerson(PersonBean bean, String worker) {
|
||||
return gateway.updatePerson(bean, worker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CampBean> getCamps(String username) {
|
||||
return gateway.getCamps(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAnnotations(Integer pk) {
|
||||
return gateway.getAnnotations(pk);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import de.jottyfan.camporganizer.db.jooq.enums.EnumCamprole;
|
||||
import de.jottyfan.camporganizer.db.jooq.enums.EnumSex;
|
||||
import de.jottyfan.camporganizer.module.registration.validate.TeacherAgeCheck;
|
||||
import de.jottyfan.camporganizer.module.registration.validate.UnusedUsername;
|
||||
|
||||
/**
|
||||
@ -19,6 +20,7 @@ import de.jottyfan.camporganizer.module.registration.validate.UnusedUsername;
|
||||
*
|
||||
*/
|
||||
@UnusedUsername(field = "login", message = "Dieses Login ist leider bereits vergeben. Bitte wähle ein anderes.")
|
||||
@TeacherAgeCheck(field = "birthDate", fkCamp = "fkCamp", campRole = "campRole", message = "Als Mitarbeiter bist Du leider zu jung für diese Freizeit.")
|
||||
public class RegistrationBean implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
@ -52,7 +52,7 @@ public class RegistrationController extends CommonController {
|
||||
model.addAttribute("roles", EnumConverter.getRoles());
|
||||
return "/registration/registration";
|
||||
}
|
||||
Boolean result = service.register(bean, (String) model.getAttribute("currentUser"));
|
||||
Boolean result = service.register(bean, getCurrentUser());
|
||||
return result ? "/registration/success" : "/error";
|
||||
}
|
||||
|
||||
|
@ -112,31 +112,6 @@ public class RegistrationRepository {
|
||||
if (bean.getRegisterInKeycloak() && !loginNotYetInUse) {
|
||||
throw new DataAccessException("login already in use: " + bean.getLogin());
|
||||
}
|
||||
|
||||
// TODO: move to bean validator instead:
|
||||
// check for valid birthdate of teachers
|
||||
LocalDateTime birthDate = bean.getBirthDate().atStartOfDay();
|
||||
|
||||
if (EnumCamprole.teacher.equals(bean.getCampRole())) {
|
||||
SelectConditionStep<Record2<Integer, DayToSecond>> sql = jooq
|
||||
// @formatter:off
|
||||
.select(T_CAMP.MAX_AGE,
|
||||
DSL.localDateTimeDiff(T_CAMP.DEPART, birthDate).as("teacherAge"))
|
||||
.from(T_CAMP)
|
||||
.where(T_CAMP.PK.eq(bean.getFkCamp()));
|
||||
// @formatter:on
|
||||
LOGGER.debug(sql.toString());
|
||||
Record r = sql.fetchOne();
|
||||
Integer minTeacherAge = r.get(T_CAMP.MAX_AGE) + 2; // by default, we need 2 years older teachers at least
|
||||
DayToSecond currentTeacherAge = r.get("teacherAge", DayToSecond.class);
|
||||
double totalYears = currentTeacherAge.getTotalDays() / 365.25; // in years
|
||||
int years = (int) totalYears;
|
||||
if (years < minTeacherAge) {
|
||||
throw new DataAccessException("Als Mitarbeiter bist Du leider zu jung für diese Freizeit.");
|
||||
}
|
||||
}
|
||||
// end of check
|
||||
|
||||
Integer fkProfile = null;
|
||||
if (loginNotYetInUse) {
|
||||
String oldPassword = new StrongPasswordEncryptor().encryptPassword(bean.getPassword());
|
||||
@ -410,4 +385,34 @@ public class RegistrationRepository {
|
||||
LOGGER.debug("{}", sql.toString());
|
||||
sql.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the age of the teacher in campRole fits to the valid ones
|
||||
*
|
||||
* @param birthDate the birth date of the person
|
||||
* @param fkCamp the ID of the camp
|
||||
* @param campRole the role; if it is a teacher, check for the age
|
||||
* @return true if it fits, false otherwise
|
||||
*/
|
||||
public Boolean checkAgeOfTeacher(LocalDate birthDate, Integer fkCamp, EnumCamprole campRole) {
|
||||
LocalDateTime birthDateDay = birthDate.atStartOfDay();
|
||||
if (EnumCamprole.teacher.equals(campRole)) {
|
||||
SelectConditionStep<Record2<Integer, DayToSecond>> sql = jooq
|
||||
// @formatter:off
|
||||
.select(T_CAMP.MAX_AGE,
|
||||
DSL.localDateTimeDiff(T_CAMP.DEPART, birthDateDay).as("teacherAge"))
|
||||
.from(T_CAMP)
|
||||
.where(T_CAMP.PK.eq(fkCamp));
|
||||
// @formatter:on
|
||||
LOGGER.debug(sql.toString());
|
||||
Record r = sql.fetchOne();
|
||||
Integer minTeacherAge = r.get(T_CAMP.MAX_AGE) + 2; // by default, we need 2 years older teachers at least
|
||||
DayToSecond currentTeacherAge = r.get("teacherAge", DayToSecond.class);
|
||||
double totalYears = currentTeacherAge.getTotalDays() / 365.25; // in years
|
||||
int years = (int) totalYears;
|
||||
return years >= minTeacherAge;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
package de.jottyfan.camporganizer.module.registration.validate;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jotty
|
||||
*
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Constraint(validatedBy = TeacherAgeCheckValidator.class)
|
||||
@Documented
|
||||
public @interface TeacherAgeCheck {
|
||||
String message() default "teacher is too young";
|
||||
|
||||
String field();
|
||||
String fkCamp();
|
||||
String campRole();
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package de.jottyfan.camporganizer.module.registration.validate;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.format.datetime.DateFormatter;
|
||||
|
||||
import de.jottyfan.camporganizer.db.jooq.enums.EnumCamprole;
|
||||
import de.jottyfan.camporganizer.module.registration.RegistrationRepository;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jotty
|
||||
*
|
||||
*/
|
||||
public class TeacherAgeCheckValidator implements ConstraintValidator<TeacherAgeCheck, Object> {
|
||||
|
||||
private String field;
|
||||
private String fkCamp;
|
||||
private String campRole;
|
||||
private String message;
|
||||
|
||||
@Autowired
|
||||
private RegistrationRepository gateway;
|
||||
|
||||
public void initialize(TeacherAgeCheck tac) {
|
||||
this.field = tac.field();
|
||||
this.fkCamp = tac.fkCamp();
|
||||
this.campRole = tac.campRole();
|
||||
this.message = tac.message();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Object value, ConstraintValidatorContext context) {
|
||||
Object birthDate = new BeanWrapperImpl(value).getPropertyValue(field);
|
||||
Object campId = new BeanWrapperImpl(value).getPropertyValue(fkCamp);
|
||||
Object roleInCamp = new BeanWrapperImpl(value).getPropertyValue(campRole);
|
||||
Boolean result = true;
|
||||
if (birthDate != null && campId != null) {
|
||||
LocalDate bd = (LocalDate) birthDate;
|
||||
Integer camp = (Integer) campId;
|
||||
EnumCamprole role = (EnumCamprole) roleInCamp;
|
||||
result = gateway.checkAgeOfTeacher(bd, camp, role);
|
||||
if (!result) {
|
||||
context.buildConstraintViolationWithTemplate(message).addPropertyNode(field).addConstraintViolation()
|
||||
.disableDefaultConstraintViolation();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -17,13 +17,11 @@
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label for="inputForename" class="col-sm-2 col-form-label">Vorname</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="col-sm-4">
|
||||
<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">
|
||||
<div class="col-sm-4">
|
||||
<input type="text" th:field="*{surname}" class="inputSurname form-control" />
|
||||
</div>
|
||||
</div>
|
||||
@ -35,25 +33,21 @@
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label for="inputZip" class="col-sm-2 col-form-label">PLZ</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="col-sm-2">
|
||||
<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">
|
||||
<div class="col-sm-6">
|
||||
<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">
|
||||
<label for="inputBirthdate" class="col-sm-2 col-form-label">Geburtstag</label>
|
||||
<div class="col-sm-4">
|
||||
<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">
|
||||
<div class="col-sm-4">
|
||||
<select class="form-select" th:field="*{sex}">
|
||||
<option value="male">männlich</option>
|
||||
<option value="female">weiblich</option>
|
||||
@ -62,13 +56,11 @@
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label for="inputPhone" class="col-sm-2 col-form-label">Telefon</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="col-sm-4">
|
||||
<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">
|
||||
<div class="col-sm-4">
|
||||
<div class="input-group">
|
||||
<input type="email" th:field="*{email}" class="inputEmail form-control" />
|
||||
<a class="btn btn-outline-secondary" th:href="'mailto:' + *{email}"><i class="fas fa-envelope-square"></i></a>
|
||||
|
@ -35,7 +35,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6 rowdist">
|
||||
<span class="error" th:each="error : ${#fields.errors('birthDate')}">[[${error}]]<br /></span>
|
||||
<input type="date" placeholder="Geburtsdatum" th:field="*{birthDate}" th:class="${'form-control ' + (#fields.hasErrors('birthDate') ? 'inputerror' : '')}" />
|
||||
<input type="date" placeholder="Geburtsdatum" th:field="*{birthDate}" th:class="${'form-control ' + (#fields.hasErrors('birthDate') ? 'inputerror' : '')}" onfocus="this.type = 'date'" onblur="this.type = 'text'" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
Loading…
x
Reference in New Issue
Block a user