rss and mail
This commit is contained in:
parent
2ecd3dbc38
commit
028c4d4fd4
@ -1,13 +1,2 @@
|
|||||||
arguments=
|
|
||||||
auto.sync=false
|
|
||||||
build.scans.enabled=false
|
|
||||||
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
|
|
||||||
connection.project.dir=
|
connection.project.dir=
|
||||||
eclipse.preferences.version=1
|
eclipse.preferences.version=1
|
||||||
gradle.user.home=
|
|
||||||
java.home=
|
|
||||||
jvm.arguments=
|
|
||||||
offline.mode=false
|
|
||||||
override.workspace.settings=false
|
|
||||||
show.console.view=false
|
|
||||||
show.executions.view=false
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project-modules id="moduleCoreId" project-version="1.5.0">
|
<project-modules id="moduleCoreId" project-version="1.5.0">
|
||||||
<wb-module deploy-name="camporganizer2">
|
<wb-module deploy-name="CampOrganizer2">
|
||||||
<property name="context-root" value="camporganizer2"/>
|
<property name="context-root" value="CampOrganizer2"/>
|
||||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/resources"/>
|
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/resources"/>
|
||||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/java"/>
|
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/java"/>
|
||||||
</wb-module>
|
</wb-module>
|
||||||
|
@ -63,6 +63,13 @@ dependencies {
|
|||||||
// backward compatibility until the complete registration is converted to keycloak
|
// backward compatibility until the complete registration is converted to keycloak
|
||||||
implementation 'org.jasypt:jasypt:1.9.3'
|
implementation 'org.jasypt:jasypt:1.9.3'
|
||||||
|
|
||||||
|
// rss support
|
||||||
|
implementation 'com.rometools:rome:1.18.0'
|
||||||
|
|
||||||
|
// mail support
|
||||||
|
implementation 'commons-validator:commons-validator:1.7'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-mail'
|
||||||
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-jooq'
|
implementation 'org.springframework.boot:spring-boot-starter-jooq'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-security'
|
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||||
|
@ -16,13 +16,11 @@ import org.jooq.DSLContext;
|
|||||||
import org.jooq.Record;
|
import org.jooq.Record;
|
||||||
import org.jooq.SelectSeekStep1;
|
import org.jooq.SelectSeekStep1;
|
||||||
import org.jooq.SelectSeekStep2;
|
import org.jooq.SelectSeekStep2;
|
||||||
import org.jooq.UpdateConditionStep;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import de.jottyfan.camporganizer.db.jooq.tables.TProfile;
|
import de.jottyfan.camporganizer.db.jooq.tables.TProfile;
|
||||||
import de.jottyfan.camporganizer.db.jooq.tables.records.TPersonRecord;
|
|
||||||
import de.jottyfan.camporganizer.db.jooq.tables.records.VCampRecord;
|
import de.jottyfan.camporganizer.db.jooq.tables.records.VCampRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -132,28 +130,4 @@ public class IndexGateway {
|
|||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* update defined fields of the bean
|
|
||||||
*
|
|
||||||
* @param bean the bean
|
|
||||||
* @return number of affected database rows; should be 1
|
|
||||||
*/
|
|
||||||
public Integer update(BookingBean 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.PHONE, bean.getPhone())
|
|
||||||
.set(T_PERSON.EMAIL, bean.getEmail())
|
|
||||||
.set(T_PERSON.COMMENT, bean.getComment())
|
|
||||||
.where(T_PERSON.PK.eq(bean.getPk()));
|
|
||||||
// @formatter:on
|
|
||||||
LOGGER.debug(sql.toString());
|
|
||||||
return sql.execute();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import de.jottyfan.camporganizer.db.jooq.tables.records.VCampRecord;
|
import de.jottyfan.camporganizer.db.jooq.tables.records.VCampRecord;
|
||||||
|
import de.jottyfan.camporganizer.module.dashboard.DashboardGateway;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -21,9 +22,13 @@ import de.jottyfan.camporganizer.db.jooq.tables.records.VCampRecord;
|
|||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class IndexService {
|
public class IndexService {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IndexGateway gateway;
|
private IndexGateway gateway;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DashboardGateway dashboardGateway;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get all camps from the database and prepare them for the view
|
* get all camps from the database and prepare them for the view
|
||||||
*
|
*
|
||||||
@ -54,6 +59,6 @@ public class IndexService {
|
|||||||
* @return true or false
|
* @return true or false
|
||||||
*/
|
*/
|
||||||
public Boolean update(BookingBean bean) {
|
public Boolean update(BookingBean bean) {
|
||||||
return gateway.update(bean) == 1;
|
return dashboardGateway.update(bean) == 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package de.jottyfan.camporganizer.module.common;
|
package de.jottyfan.camporganizer.module.common;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author henkej
|
* @author henkej
|
||||||
@ -7,8 +10,12 @@ package de.jottyfan.camporganizer.module.common;
|
|||||||
*/
|
*/
|
||||||
public class LambdaResultWrapper {
|
public class LambdaResultWrapper {
|
||||||
private Integer counter;
|
private Integer counter;
|
||||||
|
private Map<String, Boolean> mapBoolean;
|
||||||
|
private Map<String, String> mapString;
|
||||||
|
|
||||||
public LambdaResultWrapper() {
|
public LambdaResultWrapper() {
|
||||||
|
this.mapBoolean = new HashMap<>();
|
||||||
|
this.mapString = new HashMap<>();
|
||||||
counter = 0;
|
counter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,4 +26,20 @@ public class LambdaResultWrapper {
|
|||||||
public void add(Integer i) {
|
public void add(Integer i) {
|
||||||
counter += i;
|
counter += i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void putBoolean(String key, Boolean value) {
|
||||||
|
mapBoolean.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getBoolean(String key) {
|
||||||
|
return mapBoolean.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putString(String key, String value) {
|
||||||
|
mapString.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(String key) {
|
||||||
|
return mapString.get(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,10 @@ public interface IPersonService {
|
|||||||
* update bean in the database
|
* update bean in the database
|
||||||
*
|
*
|
||||||
* @param bean the bean
|
* @param bean the bean
|
||||||
|
* @param worker the user that is doing the changes
|
||||||
* @return number of affected database rows
|
* @return number of affected database rows
|
||||||
*/
|
*/
|
||||||
public Integer updatePerson(PersonBean bean);
|
public Integer updatePerson(PersonBean bean, String worker);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get all camps from the database that the user has access to
|
* get all camps from the database that the user has access to
|
||||||
|
@ -42,7 +42,8 @@ public class PersonController {
|
|||||||
|
|
||||||
@PostMapping("/confirmation/person/update")
|
@PostMapping("/confirmation/person/update")
|
||||||
public String doUpdate(@ModelAttribute PersonBean bean, Model model) {
|
public String doUpdate(@ModelAttribute PersonBean bean, Model model) {
|
||||||
personService.updatePerson(bean);
|
String username = confirmationService.getCurrentUser(request);
|
||||||
|
personService.updatePerson(bean, username);
|
||||||
return "redirect:/confirmation";
|
return "redirect:/confirmation";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,23 +5,28 @@ 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_LOCATION;
|
||||||
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PERSON;
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PERSON;
|
||||||
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PROFILE;
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PROFILE;
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_RSS;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.jooq.DSLContext;
|
import org.jooq.DSLContext;
|
||||||
|
import org.jooq.InsertValuesStep2;
|
||||||
import org.jooq.Record;
|
import org.jooq.Record;
|
||||||
import org.jooq.Record11;
|
import org.jooq.Record11;
|
||||||
import org.jooq.Record4;
|
import org.jooq.Record4;
|
||||||
import org.jooq.SelectConditionStep;
|
import org.jooq.SelectConditionStep;
|
||||||
import org.jooq.SelectSeekStep1;
|
import org.jooq.SelectSeekStep1;
|
||||||
import org.jooq.UpdateConditionStep;
|
import org.jooq.UpdateConditionStep;
|
||||||
|
import org.jooq.impl.DSL;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@ -29,7 +34,11 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import de.jottyfan.camporganizer.db.jooq.enums.EnumCamprole;
|
import de.jottyfan.camporganizer.db.jooq.enums.EnumCamprole;
|
||||||
import de.jottyfan.camporganizer.db.jooq.enums.EnumModule;
|
import de.jottyfan.camporganizer.db.jooq.enums.EnumModule;
|
||||||
import de.jottyfan.camporganizer.db.jooq.tables.TProfile;
|
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.TPersonRecord;
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.tables.records.TRssRecord;
|
||||||
|
import de.jottyfan.camporganizer.module.common.LambdaResultWrapper;
|
||||||
|
import de.jottyfan.camporganizer.module.mail.MailRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -44,6 +53,9 @@ public class PersonGateway {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private DSLContext jooq;
|
private DSLContext jooq;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MailRepository mailRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get all camps from the database if username is allowed to maintain it
|
* get all camps from the database if username is allowed to maintain it
|
||||||
*
|
*
|
||||||
@ -125,26 +137,119 @@ public class PersonGateway {
|
|||||||
* @param bean the bean
|
* @param bean the bean
|
||||||
* @return the number of affected database rows
|
* @return the number of affected database rows
|
||||||
*/
|
*/
|
||||||
public Integer updatePerson(PersonBean bean) {
|
public Integer updatePerson(PersonBean bean, String registrator) {
|
||||||
UpdateConditionStep<TPersonRecord> sql = jooq
|
LambdaResultWrapper lrw = new LambdaResultWrapper();
|
||||||
// @formatter:off
|
jooq.transaction(t -> {
|
||||||
.update(T_PERSON)
|
|
||||||
.set(T_PERSON.FORENAME, bean.getForename())
|
// get old accept value for comparison
|
||||||
.set(T_PERSON.SURNAME, bean.getSurname())
|
SelectConditionStep<TPersonRecord> sql = jooq.selectFrom(T_PERSON).where(T_PERSON.PK.eq(bean.getPk()));
|
||||||
.set(T_PERSON.STREET, bean.getStreet())
|
LOGGER.debug(sql.toString());
|
||||||
.set(T_PERSON.ZIP, bean.getZip())
|
TPersonRecord r = sql.fetchOne();
|
||||||
.set(T_PERSON.CITY, bean.getCity())
|
lrw.putBoolean("acceptOld", r == null ? null : r.getAccept());
|
||||||
.set(T_PERSON.BIRTHDATE, bean.getBirthdate())
|
lrw.putBoolean("acceptNew", bean.getAccept());
|
||||||
.set(T_PERSON.SEX, bean.getSex())
|
Integer fkCamp = r == null ? null : r.getFkCamp();
|
||||||
.set(T_PERSON.PHONE, bean.getPhone())
|
String email = r.getEmail(); // use the old one, too
|
||||||
.set(T_PERSON.EMAIL, bean.getEmail())
|
lrw.putString("oldEmail", email);
|
||||||
.set(T_PERSON.COMMENT, bean.getComment())
|
|
||||||
.set(T_PERSON.ACCEPT, bean.getAccept())
|
SelectConditionStep<TCampRecord> sql0 = jooq.selectFrom(T_CAMP).where(T_CAMP.PK.eq(fkCamp));
|
||||||
.set(T_PERSON.CAMPROLE, bean.getCamprole())
|
LOGGER.debug(sql0.toString());
|
||||||
.where(T_PERSON.PK.eq(bean.getPk()));
|
TCampRecord rc = sql0.fetchOne();
|
||||||
// @formatter:on
|
String campName = rc == null ? null : rc.getName();
|
||||||
LOGGER.debug(sql.toString());
|
LocalDateTime arrive = rc == null ? null : rc.getArrive();
|
||||||
return sql.execute();
|
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
|
||||||
|
// @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())
|
||||||
|
.set(T_PERSON.CAMPROLE, bean.getCamprole())
|
||||||
|
.where(T_PERSON.PK.eq(bean.getPk()));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug(sql1.toString());
|
||||||
|
lrw.add(sql1.execute());
|
||||||
|
|
||||||
|
// always
|
||||||
|
StringBuilder buf = new StringBuilder("Eine Anmeldung für ");
|
||||||
|
buf.append(campNameWithYear);
|
||||||
|
buf.append(" wurde von ").append(registrator);
|
||||||
|
buf.append(" korrigiert.");
|
||||||
|
|
||||||
|
InsertValuesStep2<TRssRecord, String, String> sql2 = 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();
|
||||||
|
});
|
||||||
|
|
||||||
|
// send email to user instead of rss feed
|
||||||
|
Boolean acceptNew = lrw.getBoolean("acceptNew");
|
||||||
|
Boolean acceptOld = lrw.getBoolean("acceptOld");
|
||||||
|
String campNameWithYear = lrw.getString("campNameWithYear");
|
||||||
|
String email = lrw.getString("oldEmail");
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
if (acceptNew == null) {
|
||||||
|
if (acceptOld != null) {
|
||||||
|
buf = new StringBuilder("Die Bestätigung der Anmeldung von ");
|
||||||
|
buf.append(bean.getForename());
|
||||||
|
buf.append(" ");
|
||||||
|
buf.append(bean.getSurname());
|
||||||
|
buf.append(" zur Freizeit ");
|
||||||
|
buf.append(campNameWithYear);
|
||||||
|
buf.append(" wurde von ");
|
||||||
|
buf.append(registrator);
|
||||||
|
buf.append(" wieder zurückgezogen.");
|
||||||
|
buf.append(
|
||||||
|
" Möglicherweise wurde die Anmeldung versehentlich bestätigt? Deine Anmeldung befindet sich jetzt wieder auf der Warteliste.");
|
||||||
|
}
|
||||||
|
} else if (acceptNew == true) {
|
||||||
|
if (acceptOld == null || !acceptOld) {
|
||||||
|
buf = new StringBuilder("Die Anmeldung von ");
|
||||||
|
buf.append(bean.getForename());
|
||||||
|
buf.append(" ");
|
||||||
|
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(" um die Bestätigungen herunterzuladen.");
|
||||||
|
}
|
||||||
|
} else if (acceptNew == false) {
|
||||||
|
if (acceptOld == null || acceptOld) {
|
||||||
|
buf = new StringBuilder("Die Anmeldung von ");
|
||||||
|
buf.append(bean.getForename());
|
||||||
|
buf.append(" ");
|
||||||
|
buf.append(bean.getSurname());
|
||||||
|
buf.append(" zur Freizeit ");
|
||||||
|
buf.append(campNameWithYear);
|
||||||
|
buf.append(" wurde leider abgelehnt.");
|
||||||
|
buf.append(
|
||||||
|
" Möglicherweise ist sie schon ausgebucht? Deine Anmeldung befindet sich jetzt auf der Nachrückerliste.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Set<String> to = new HashSet<>();
|
||||||
|
to.add(email);
|
||||||
|
to.add(bean.getEmail());
|
||||||
|
try {
|
||||||
|
mailRepository.sendMail(to, buf.toString()); // no matter if the sending works, do the persistence anyway
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return lrw.getCounter();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,8 +23,8 @@ public class PersonService implements IPersonService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer updatePerson(PersonBean bean) {
|
public Integer updatePerson(PersonBean bean, String worker) {
|
||||||
return gateway.updatePerson(bean);
|
return gateway.updatePerson(bean, worker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,137 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.dashboard;
|
||||||
|
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PERSON;
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PERSONDOCUMENT;
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_RSS;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.jooq.DSLContext;
|
||||||
|
import org.jooq.DeleteConditionStep;
|
||||||
|
import org.jooq.InsertValuesStep2;
|
||||||
|
import org.jooq.InsertValuesStep4;
|
||||||
|
import org.jooq.UpdateConditionStep;
|
||||||
|
import org.jooq.exception.DataAccessException;
|
||||||
|
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.EnumFiletype;
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.tables.records.TPersonRecord;
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.tables.records.TPersondocumentRecord;
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.tables.records.TRssRecord;
|
||||||
|
import de.jottyfan.camporganizer.module.common.BookingBean;
|
||||||
|
import de.jottyfan.camporganizer.module.common.LambdaResultWrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
@Transactional(transactionManager = "transactionManager")
|
||||||
|
public class DashboardGateway {
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(DashboardGateway.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DSLContext jooq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update defined fields of the bean
|
||||||
|
*
|
||||||
|
* @param bean the bean
|
||||||
|
* @return number of affected database rows; should be 1
|
||||||
|
*/
|
||||||
|
public Integer update(BookingBean 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.PHONE, bean.getPhone())
|
||||||
|
.set(T_PERSON.EMAIL, bean.getEmail())
|
||||||
|
.set(T_PERSON.COMMENT, bean.getComment())
|
||||||
|
.where(T_PERSON.PK.eq(bean.getPk()));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug(sql.toString());
|
||||||
|
return sql.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete entry from t_persondocument where pk = ?
|
||||||
|
*
|
||||||
|
* @param pk
|
||||||
|
* to be used as reference
|
||||||
|
* @return number of affected database lines
|
||||||
|
* @throws DataAccessException
|
||||||
|
*/
|
||||||
|
public Integer deletePersondocument(PersondocumentBean bean) throws DataAccessException {
|
||||||
|
LambdaResultWrapper lrw = new LambdaResultWrapper();
|
||||||
|
jooq.transaction(t -> {
|
||||||
|
|
||||||
|
DeleteConditionStep<TPersondocumentRecord> sql = DSL.using(t)
|
||||||
|
// @formatter:off
|
||||||
|
.deleteFrom(T_PERSONDOCUMENT)
|
||||||
|
.where(T_PERSONDOCUMENT.PK.eq(bean.getPk()));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql.toString());
|
||||||
|
lrw.add(sql.execute());
|
||||||
|
|
||||||
|
StringBuilder buf = new StringBuilder("Dokument ");
|
||||||
|
buf.append(bean.getName());
|
||||||
|
buf.append(" wurde wieder gelöscht.");
|
||||||
|
InsertValuesStep2<TRssRecord, String, String> sql2 = 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();
|
||||||
|
});
|
||||||
|
return lrw.getCounter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add document to database
|
||||||
|
*
|
||||||
|
* @param bean
|
||||||
|
* @throws DataAccessException
|
||||||
|
*/
|
||||||
|
public void addPersondocument(PersondocumentBean bean) throws DataAccessException {
|
||||||
|
jooq.transaction(t -> {
|
||||||
|
|
||||||
|
InsertValuesStep4<TPersondocumentRecord, String, EnumFiletype, Integer, String> sql = DSL.using(t)
|
||||||
|
// @formatter:off
|
||||||
|
.insertInto(T_PERSONDOCUMENT,
|
||||||
|
T_PERSONDOCUMENT.NAME,
|
||||||
|
T_PERSONDOCUMENT.FILETYPE,
|
||||||
|
T_PERSONDOCUMENT.FK_PERSON,
|
||||||
|
T_PERSONDOCUMENT.DOCUMENT
|
||||||
|
)
|
||||||
|
.values(bean.getName(), bean.getFiletype(), bean.getFkPerson(), bean.getDocument());
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql.toString());
|
||||||
|
sql.execute();
|
||||||
|
|
||||||
|
StringBuilder buf = new StringBuilder("Dokument ");
|
||||||
|
buf.append(bean.getName());
|
||||||
|
buf.append(" wurde angelegt.");
|
||||||
|
InsertValuesStep2<TRssRecord, String, String> sql2 = 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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.dashboard;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
import javax.servlet.http.Part;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.enums.EnumFiletype;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class PersondocumentBean {
|
||||||
|
|
||||||
|
private final Integer pk;
|
||||||
|
private Integer fkPerson;
|
||||||
|
private String name;
|
||||||
|
private String document;
|
||||||
|
private EnumFiletype filetype;
|
||||||
|
private Part uploadfile;
|
||||||
|
|
||||||
|
public PersondocumentBean(Integer pk) {
|
||||||
|
this.pk = pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void encodeUpload() throws IOException {
|
||||||
|
if (uploadfile != null) {
|
||||||
|
InputStream inputStream = uploadfile.getInputStream();
|
||||||
|
byte[] bytes = IOUtils.toByteArray(inputStream);
|
||||||
|
if (bytes.length > 0) {
|
||||||
|
document = Base64.getEncoder().encodeToString(bytes);
|
||||||
|
} // not uploaded files should not be changed, so document must be kept as is
|
||||||
|
} else {
|
||||||
|
throw new IOException("uploadfile is null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPk() {
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFkPerson(Integer fkPerson) {
|
||||||
|
this.fkPerson = fkPerson;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getFkPerson() {
|
||||||
|
return fkPerson;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDocument(String document) {
|
||||||
|
this.document = document;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDocument() {
|
||||||
|
return document;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFiletype(EnumFiletype filetype) {
|
||||||
|
this.filetype = filetype;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EnumFiletype getFiletype() {
|
||||||
|
return filetype;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Part getUploadfile() {
|
||||||
|
return uploadfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUploadfile(Part uploadfile) {
|
||||||
|
this.uploadfile = uploadfile;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.mail;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.mail.MessagingException;
|
||||||
|
import javax.mail.internet.MimeMessage;
|
||||||
|
|
||||||
|
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.mail.javamail.JavaMailSender;
|
||||||
|
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public class MailRepository {
|
||||||
|
|
||||||
|
private final static Logger LOGGER = LogManager.getLogger();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private JavaMailSender javaMailSender;
|
||||||
|
|
||||||
|
@Value("${spring.mail.username}")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an email with the message to the recipient. If email is blank, do
|
||||||
|
* nothing
|
||||||
|
*
|
||||||
|
* @param to the email addresses
|
||||||
|
* @param message the message
|
||||||
|
*/
|
||||||
|
public void sendMail(Set<String> to, String message) {
|
||||||
|
if (to != null && to.size() > 0) {
|
||||||
|
if (username != null && !username.isBlank()) {
|
||||||
|
try {
|
||||||
|
sendMail(to, message, username);
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
LOGGER.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGGER.error("no email.username in configuration for sending emails");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGGER.warn("no email address given, ignore informing the user about changes; message would have been: {}",
|
||||||
|
message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send the email
|
||||||
|
*
|
||||||
|
* @param to the recipients
|
||||||
|
* @param message the message
|
||||||
|
* @param from the username of the email account
|
||||||
|
* @throws MessagingException
|
||||||
|
*/
|
||||||
|
private void sendMail(Set<String> to, String message, String from) throws MessagingException {
|
||||||
|
if (to == null || to.size() < 1) {
|
||||||
|
throw new MessagingException("no recipient in " + to);
|
||||||
|
}
|
||||||
|
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
|
||||||
|
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,
|
||||||
|
StandardCharsets.UTF_8.name());
|
||||||
|
helper.setFrom(from);
|
||||||
|
helper.setSubject("Information zu Deiner Anmeldung zur Onkel Werner Freizeit");
|
||||||
|
helper.setText(message, false);
|
||||||
|
helper.setTo(to.toArray(new String[] {}));
|
||||||
|
javaMailSender.send(mimeMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* for junit tests only
|
||||||
|
*
|
||||||
|
* @param javaMailSender the java mail sender
|
||||||
|
*/
|
||||||
|
protected void setJavaMailSender(JavaMailSender javaMailSender) {
|
||||||
|
this.javaMailSender = javaMailSender;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* for junit tests only
|
||||||
|
*
|
||||||
|
* @param username the username
|
||||||
|
*/
|
||||||
|
protected void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.registration;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ProfileBean implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private Integer pk;
|
||||||
|
private String forename;
|
||||||
|
private String surname;
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
this.pk = null;
|
||||||
|
this.forename = null;
|
||||||
|
this.surname = null;
|
||||||
|
this.username = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getIsEmpty() {
|
||||||
|
return pk == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFullname() {
|
||||||
|
return new StringBuilder(forename == null ? "" : forename).append(" ").append(surname == null ? "" : surname)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getForename() {
|
||||||
|
return forename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForename(String forename) {
|
||||||
|
this.forename = forename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSurname() {
|
||||||
|
return surname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSurname(String surname) {
|
||||||
|
this.surname = surname;
|
||||||
|
}
|
||||||
|
public Integer getPk() {
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPk(Integer pk) {
|
||||||
|
this.pk = pk;
|
||||||
|
}
|
||||||
|
}
|
@ -49,6 +49,13 @@ public class RegistrationBean implements Serializable {
|
|||||||
private String login;
|
private String login;
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return forename + surname, separated by a space
|
||||||
|
*/
|
||||||
|
public String getFullname() {
|
||||||
|
return new StringBuilder().append(forename).append(" ").append(surname).toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the forename
|
* @return the forename
|
||||||
*/
|
*/
|
||||||
|
@ -4,9 +4,12 @@ import static de.jottyfan.camporganizer.db.jooq.Tables.T_CAMP;
|
|||||||
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PERSON;
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PERSON;
|
||||||
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PERSONDOCUMENT;
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PERSONDOCUMENT;
|
||||||
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PROFILE;
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PROFILE;
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PROFILEROLE;
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_RSS;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@ -18,11 +21,17 @@ import org.jooq.DeleteConditionStep;
|
|||||||
import org.jooq.InsertResultStep;
|
import org.jooq.InsertResultStep;
|
||||||
import org.jooq.InsertValuesStep12;
|
import org.jooq.InsertValuesStep12;
|
||||||
import org.jooq.InsertValuesStep13;
|
import org.jooq.InsertValuesStep13;
|
||||||
|
import org.jooq.InsertValuesStep2;
|
||||||
|
import org.jooq.Record;
|
||||||
import org.jooq.Record1;
|
import org.jooq.Record1;
|
||||||
|
import org.jooq.Record2;
|
||||||
|
import org.jooq.Record5;
|
||||||
import org.jooq.Record7;
|
import org.jooq.Record7;
|
||||||
import org.jooq.SelectConditionStep;
|
import org.jooq.SelectConditionStep;
|
||||||
|
import org.jooq.UpdateConditionStep;
|
||||||
import org.jooq.exception.DataAccessException;
|
import org.jooq.exception.DataAccessException;
|
||||||
import org.jooq.impl.DSL;
|
import org.jooq.impl.DSL;
|
||||||
|
import org.jooq.types.DayToSecond;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@ -33,6 +42,7 @@ 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.TPersonRecord;
|
||||||
import de.jottyfan.camporganizer.db.jooq.tables.records.TPersondocumentRecord;
|
import de.jottyfan.camporganizer.db.jooq.tables.records.TPersondocumentRecord;
|
||||||
import de.jottyfan.camporganizer.db.jooq.tables.records.TProfileRecord;
|
import de.jottyfan.camporganizer.db.jooq.tables.records.TProfileRecord;
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.tables.records.TRssRecord;
|
||||||
import de.jottyfan.camporganizer.module.common.BookingBean;
|
import de.jottyfan.camporganizer.module.common.BookingBean;
|
||||||
import de.jottyfan.camporganizer.module.common.LambdaResultWrapper;
|
import de.jottyfan.camporganizer.module.common.LambdaResultWrapper;
|
||||||
|
|
||||||
@ -102,7 +112,31 @@ public class RegistrationGateway {
|
|||||||
if (bean.getRegisterInKeycloak() && !loginNotYetInUse) {
|
if (bean.getRegisterInKeycloak() && !loginNotYetInUse) {
|
||||||
throw new DataAccessException("login already in use: " + bean.getLogin());
|
throw new DataAccessException("login already in use: " + bean.getLogin());
|
||||||
}
|
}
|
||||||
// TODO: check if teacher is at least 2 years older than the camp participants
|
|
||||||
|
// 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;
|
Integer fkProfile = null;
|
||||||
if (loginNotYetInUse) {
|
if (loginNotYetInUse) {
|
||||||
String oldPassword = new StrongPasswordEncryptor().encryptPassword(bean.getPassword());
|
String oldPassword = new StrongPasswordEncryptor().encryptPassword(bean.getPassword());
|
||||||
@ -120,6 +154,16 @@ public class RegistrationGateway {
|
|||||||
// @formatter:on
|
// @formatter:on
|
||||||
LOGGER.debug(sql1.toString());
|
LOGGER.debug(sql1.toString());
|
||||||
fkProfile = sql1.fetchOne().getPk();
|
fkProfile = sql1.fetchOne().getPk();
|
||||||
|
|
||||||
|
InsertValuesStep2<TRssRecord, String, String> sql2 = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.insertInto(T_RSS,
|
||||||
|
T_RSS.MSG,
|
||||||
|
T_RSS.RECIPIENT)
|
||||||
|
.values(new StringBuilder(bean.getFullname()).append(" hat sich als Nutzer im CampOrganizer2 registriert.").toString(), "admin");
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql2.toString());
|
||||||
|
sql2.execute();
|
||||||
} else {
|
} else {
|
||||||
SelectConditionStep<Record1<Integer>> sql1 = DSL.using(t)
|
SelectConditionStep<Record1<Integer>> sql1 = DSL.using(t)
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
@ -228,6 +272,32 @@ public class RegistrationGateway {
|
|||||||
public Integer removeBooking(Integer id) {
|
public Integer removeBooking(Integer id) {
|
||||||
LambdaResultWrapper lrw = new LambdaResultWrapper();
|
LambdaResultWrapper lrw = new LambdaResultWrapper();
|
||||||
jooq.transaction(t -> {
|
jooq.transaction(t -> {
|
||||||
|
SelectConditionStep<Record5<String, String, String, String, LocalDateTime>> sql0 = DSL.using(t)
|
||||||
|
// @formatter:off
|
||||||
|
.select(T_PROFILE.USERNAME, T_PERSON.FORENAME, T_PERSON.SURNAME, T_CAMP.NAME, T_CAMP.ARRIVE)
|
||||||
|
.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))
|
||||||
|
.where(T_PERSON.PK.eq(id));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug(sql0.toString());
|
||||||
|
Record5<String, String, String, String, LocalDateTime> r = sql0.fetchOne();
|
||||||
|
if (r == null) {
|
||||||
|
throw new DataAccessException("no such entry in t_person with id = " + id);
|
||||||
|
}
|
||||||
|
String username = r.get(T_PROFILE.USERNAME);
|
||||||
|
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);
|
||||||
|
|
||||||
|
StringBuilder rssMessage = new StringBuilder(username);
|
||||||
|
rssMessage.append(" hat die Buchung von ");
|
||||||
|
rssMessage.append(forename).append(" ").append(surname);
|
||||||
|
rssMessage.append(" an ");
|
||||||
|
rssMessage.append(campname).append(" ").append(arrive == null ? "" : arrive.format(DateTimeFormatter.ofPattern("YYYY")));
|
||||||
|
rssMessage.append(" storniert.");
|
||||||
|
|
||||||
DeleteConditionStep<TPersondocumentRecord> sql1 = DSL.using(t).deleteFrom(T_PERSONDOCUMENT)
|
DeleteConditionStep<TPersondocumentRecord> sql1 = DSL.using(t).deleteFrom(T_PERSONDOCUMENT)
|
||||||
.where(T_PERSONDOCUMENT.FK_PERSON.eq(id));
|
.where(T_PERSONDOCUMENT.FK_PERSON.eq(id));
|
||||||
LOGGER.debug(sql1.toString());
|
LOGGER.debug(sql1.toString());
|
||||||
@ -236,6 +306,16 @@ public class RegistrationGateway {
|
|||||||
DeleteConditionStep<TPersonRecord> sql2 = DSL.using(t).deleteFrom(T_PERSON).where(T_PERSON.PK.eq(id));
|
DeleteConditionStep<TPersonRecord> sql2 = DSL.using(t).deleteFrom(T_PERSON).where(T_PERSON.PK.eq(id));
|
||||||
LOGGER.debug(sql2.toString());
|
LOGGER.debug(sql2.toString());
|
||||||
lrw.add(sql2.execute());
|
lrw.add(sql2.execute());
|
||||||
|
|
||||||
|
InsertValuesStep2<TRssRecord, String, String> sql3 = DSL.using(t)
|
||||||
|
// @formatter:off
|
||||||
|
.insertInto(T_RSS,
|
||||||
|
T_RSS.MSG,
|
||||||
|
T_RSS.RECIPIENT)
|
||||||
|
.values(rssMessage.toString(), "registrator");
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql3.toString());
|
||||||
|
sql3.execute();
|
||||||
});
|
});
|
||||||
return lrw.getCounter();
|
return lrw.getCounter();
|
||||||
}
|
}
|
||||||
@ -261,4 +341,55 @@ public class RegistrationGateway {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove login
|
||||||
|
*
|
||||||
|
* @param bean
|
||||||
|
* containing username of dataset to be removed
|
||||||
|
* @throws DataAccessExceptionF
|
||||||
|
*/
|
||||||
|
public void removeLogin(ProfileBean bean) throws DataAccessException {
|
||||||
|
jooq.transaction(t -> {
|
||||||
|
UpdateConditionStep<TPersonRecord> sql = DSL.using(t)
|
||||||
|
// @formatter:off
|
||||||
|
.update(T_PERSON)
|
||||||
|
.set(T_PERSON.FK_PROFILE, (Integer) null)
|
||||||
|
.where(T_PERSON.FK_PROFILE.eq(bean.getPk()));
|
||||||
|
// @formatter:off
|
||||||
|
LOGGER.debug("{}", sql.toString());
|
||||||
|
sql.execute();
|
||||||
|
|
||||||
|
DeleteConditionStep<?> sql1 = DSL.using(t)
|
||||||
|
// @formatter:off
|
||||||
|
.deleteFrom(T_PROFILEROLE)
|
||||||
|
.where(T_PROFILEROLE.FK_PROFILE.in(
|
||||||
|
DSL.using(t)
|
||||||
|
.select(T_PROFILE.PK)
|
||||||
|
.from(T_PROFILE)
|
||||||
|
.where(T_PROFILE.USERNAME.eq(bean.getUsername())
|
||||||
|
)));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql1.toString());
|
||||||
|
sql1.execute();
|
||||||
|
|
||||||
|
DeleteConditionStep<?> sql2 = DSL.using(t)
|
||||||
|
// @formatter:off
|
||||||
|
.deleteFrom(T_PROFILE)
|
||||||
|
.where(T_PROFILE.USERNAME.eq(bean.getUsername()));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql2.toString());
|
||||||
|
sql2.execute();
|
||||||
|
|
||||||
|
InsertValuesStep2<TRssRecord, String, String> sql3 = DSL.using(t)
|
||||||
|
// @formatter:off
|
||||||
|
.insertInto(T_RSS,
|
||||||
|
T_RSS.MSG,
|
||||||
|
T_RSS.RECIPIENT)
|
||||||
|
.values(new StringBuilder(bean.getFullname()).append(" hat sich vom Portal CampOrganizer2 abgemeldet.").toString(), "admin");
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql3.toString());
|
||||||
|
sql3.execute();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.rss;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class RssBean implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public final Integer pk;
|
||||||
|
public String recipient;
|
||||||
|
public String message;
|
||||||
|
public LocalDateTime pubdate;
|
||||||
|
|
||||||
|
public RssBean(Integer pk) {
|
||||||
|
this.pk = pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage80() {
|
||||||
|
return message == null ? null : (message.length() > 80 ? message.substring(0, 80).concat("...") : message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPk() {
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getPubdate() {
|
||||||
|
return pubdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPubdate(LocalDateTime pubdate) {
|
||||||
|
this.pubdate = pubdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRecipient() {
|
||||||
|
return recipient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecipient(String recipient) {
|
||||||
|
this.recipient = recipient;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.rss;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
|
import com.rometools.rome.feed.synd.SyndFeed;
|
||||||
|
import com.rometools.rome.io.FeedException;
|
||||||
|
import com.rometools.rome.io.SyndFeedOutput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
public class RssController {
|
||||||
|
|
||||||
|
private String recipientCode;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RssService service;
|
||||||
|
|
||||||
|
@GetMapping("/rss")
|
||||||
|
public String toRss(HttpServletResponse response) throws IOException, FeedException {
|
||||||
|
List<RssBean> beans = new ArrayList<>();
|
||||||
|
if (recipientCode != null) {
|
||||||
|
beans = service.getRss(recipientCode);
|
||||||
|
} else {
|
||||||
|
RssBean bean = new RssBean(null);
|
||||||
|
bean.setPubdate(LocalDateTime.now());
|
||||||
|
bean.setMessage("Dieser Feed ist nicht mehr aktuell. Bitte gib einen recipientCode an.");
|
||||||
|
beans.add(bean);
|
||||||
|
}
|
||||||
|
SyndFeed feed = new RssModel().getRss(beans);
|
||||||
|
response.reset();
|
||||||
|
response.setCharacterEncoding("UTF-8");
|
||||||
|
response.setContentType("application/rss+xml");
|
||||||
|
response.setHeader("Content-Disposition", "attachment; filename=\"onkelwernerfreizeiten.de.xml\"");
|
||||||
|
PrintWriter writer;
|
||||||
|
writer = response.getWriter();
|
||||||
|
SyndFeedOutput output = new SyndFeedOutput();
|
||||||
|
output.output(feed, writer);
|
||||||
|
response.flushBuffer();
|
||||||
|
return "error";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.rss;
|
||||||
|
|
||||||
|
import static de.jottyfan.camporganizer.db.jooq.Tables.T_RSS;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
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.DeleteConditionStep;
|
||||||
|
import org.jooq.Record3;
|
||||||
|
import org.jooq.Record4;
|
||||||
|
import org.jooq.SelectConditionStep;
|
||||||
|
import org.jooq.SelectJoinStep;
|
||||||
|
import org.jooq.UpdateConditionStep;
|
||||||
|
import org.jooq.exception.DataAccessException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import de.jottyfan.camporganizer.db.jooq.tables.records.TRssRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
@Transactional(transactionManager = "transactionManager")
|
||||||
|
public class RssGateway {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(RssGateway.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DSLContext jooq;
|
||||||
|
|
||||||
|
public List<RssBean> getRss(String recipientCode) throws DataAccessException {
|
||||||
|
SelectConditionStep<Record3<Integer, String, LocalDateTime>> sql = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.select(T_RSS.PK,
|
||||||
|
T_RSS.MSG,
|
||||||
|
T_RSS.REGDATE)
|
||||||
|
.from(T_RSS)
|
||||||
|
.where(T_RSS.RECIPIENT.eq(recipientCode));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql.toString());
|
||||||
|
List<RssBean> list = new ArrayList<>();
|
||||||
|
for (Record3<Integer, String, LocalDateTime> r : sql.fetch()) {
|
||||||
|
RssBean bean = new RssBean(r.get(T_RSS.PK));
|
||||||
|
bean.setRecipient(recipientCode);
|
||||||
|
bean.setMessage(r.get(T_RSS.MSG));
|
||||||
|
bean.setPubdate(r.get(T_RSS.REGDATE));
|
||||||
|
list.add(bean);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RssBean> getAllRss() throws DataAccessException {
|
||||||
|
SelectJoinStep<Record4<Integer, String, String, LocalDateTime>> sql = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.select(T_RSS.PK,
|
||||||
|
T_RSS.RECIPIENT,
|
||||||
|
T_RSS.MSG,
|
||||||
|
T_RSS.REGDATE)
|
||||||
|
.from(T_RSS);
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql.toString());
|
||||||
|
List<RssBean> list = new ArrayList<>();
|
||||||
|
for (Record4<Integer, String, String, LocalDateTime> r : sql.fetch()) {
|
||||||
|
RssBean bean = new RssBean(r.get(T_RSS.PK));
|
||||||
|
bean.setRecipient(r.get(T_RSS.RECIPIENT));
|
||||||
|
bean.setMessage(r.get(T_RSS.MSG));
|
||||||
|
bean.setPubdate(r.get(T_RSS.REGDATE));
|
||||||
|
list.add(bean);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteRss(RssBean bean) throws DataAccessException {
|
||||||
|
DeleteConditionStep<TRssRecord> sql = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.deleteFrom(T_RSS)
|
||||||
|
.where(T_RSS.PK.eq(bean.getPk()));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql.toString());
|
||||||
|
sql.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(RssBean bean) throws DataAccessException {
|
||||||
|
UpdateConditionStep<TRssRecord> sql = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.update(T_RSS)
|
||||||
|
.set(T_RSS.MSG, bean.getMessage())
|
||||||
|
.where(T_RSS.PK.eq(bean.getPk()));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql.toString());
|
||||||
|
sql.execute();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.rss;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.rometools.rome.feed.synd.SyndContent;
|
||||||
|
import com.rometools.rome.feed.synd.SyndContentImpl;
|
||||||
|
import com.rometools.rome.feed.synd.SyndEntry;
|
||||||
|
import com.rometools.rome.feed.synd.SyndEntryImpl;
|
||||||
|
import com.rometools.rome.feed.synd.SyndFeed;
|
||||||
|
import com.rometools.rome.feed.synd.SyndFeedImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class RssModel {
|
||||||
|
public SyndFeed getRss(List<RssBean> beans) {
|
||||||
|
SyndFeed feed = new SyndFeedImpl();
|
||||||
|
feed.setFeedType("rss_2.0");
|
||||||
|
feed.setTitle("Onkel Werner Freizeiten e.V. Anmeldungsnotifier");
|
||||||
|
feed.setLink("https://www.onkelwernerfreizeiten.de/camporganizer/rss.jsf");
|
||||||
|
feed.setDescription("In diesem Feed werden Portalaktivitäten gesammelt.");
|
||||||
|
feed.setEncoding("UTF-8");
|
||||||
|
List<SyndEntry> entries = new ArrayList<>();
|
||||||
|
for (RssBean bean : beans) {
|
||||||
|
SyndEntry entry = new SyndEntryImpl();
|
||||||
|
entry.setTitle("neue Aktivität");
|
||||||
|
entry.setLink("https://www.onkelwernerfreizeiten.de/camporganizer/");
|
||||||
|
entry.setUri(new SimpleDateFormat("yyyyMMddHHmmssSSS").format(bean.getPubdate()));
|
||||||
|
entry.setPublishedDate(Timestamp.valueOf(bean.getPubdate()));
|
||||||
|
SyndContent description = new SyndContentImpl();
|
||||||
|
description.setType("text/plain");
|
||||||
|
description.setValue(bean.getMessage());
|
||||||
|
entry.setDescription(description);
|
||||||
|
entries.add(entry);
|
||||||
|
}
|
||||||
|
feed.setEntries(entries);
|
||||||
|
return feed;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package de.jottyfan.camporganizer.module.rss;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class RssService {
|
||||||
|
@Autowired
|
||||||
|
private RssGateway repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the recipient's rss feed
|
||||||
|
* @param recipientCode the code for the feed
|
||||||
|
* @return the list of rss beans; an empty list at least
|
||||||
|
*/
|
||||||
|
public List<RssBean> getRss(String recipientCode) {
|
||||||
|
return repository.getRss(recipientCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -18,6 +18,16 @@ keycloak.use-resource-role-mappings = ${keycloak.use-resource-role-mappings}
|
|||||||
ow.keycloak.admin.name = ${ow.keycloak.admin.name}
|
ow.keycloak.admin.name = ${ow.keycloak.admin.name}
|
||||||
ow.keycloak.admin.password = ${ow.keycloak.admin.password}
|
ow.keycloak.admin.password = ${ow.keycloak.admin.password}
|
||||||
|
|
||||||
|
spring.mail.default-encoding = ${spring.mail.default-encoding}
|
||||||
|
spring.mail.host = ${spring.mail.host}
|
||||||
|
spring.mail.username = ${spring.mail.username}
|
||||||
|
spring.mail.password = ${spring.mail.password}
|
||||||
|
spring.mail.port = ${spring.mail.port}
|
||||||
|
spring.mail.protocol = ${spring.mail.protocol}
|
||||||
|
spring.mail.test-connection = ${spring.mail.test-connection}
|
||||||
|
spring.mail.properties.mail.smtp.auth = ${spring.mail.properties.mail.smtp.auth}
|
||||||
|
spring.mail.properties.mail.smtp.starttls.enable = ${spring.mail.properties.mail.smtp.starttls.enable}
|
||||||
|
|
||||||
# for development only
|
# for development only
|
||||||
server.port = 8081
|
server.port = 8081
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user