keycloak registration done
This commit is contained in:
parent
b6658655be
commit
29e8ff7798
@ -25,19 +25,19 @@ import org.springframework.stereotype.Repository;
|
||||
public class KeycloakRepository {
|
||||
private final static Logger LOGGER = LogManager.getLogger(KeycloakRepository.class);
|
||||
|
||||
@Value("${keycloak.resource:biblecamp}")
|
||||
@Value("${keycloak.resource}")
|
||||
private String keycloakClientId;
|
||||
|
||||
@Value("${keycloak.auth-server-url}")
|
||||
private String keycloakUrl;
|
||||
|
||||
@Value("${keycloak.realm:ow}")
|
||||
@Value("${keycloak.realm}")
|
||||
private String keycloakRealm;
|
||||
|
||||
@Value("${ow.keycloak.admin.name:admin")
|
||||
@Value("${ow.keycloak.admin.name}")
|
||||
private String keycloakAdminName;
|
||||
|
||||
@Value("${ow.keycloak.admin.password:password")
|
||||
@Value("${ow.keycloak.admin.password}")
|
||||
private String keycloakAdminPassword;
|
||||
|
||||
/**
|
||||
@ -54,28 +54,32 @@ public class KeycloakRepository {
|
||||
/**
|
||||
* register the login in keycloak
|
||||
*
|
||||
* @param forename the forename
|
||||
* @param surname the surname
|
||||
* @param login the username
|
||||
* @param password the password
|
||||
* @param email the email
|
||||
* @return true or false
|
||||
*/
|
||||
public boolean register(String login, String password, String email) {
|
||||
UserRepresentation user = getUserRepresentation(login, password, email);
|
||||
UsersResource resource = getUsersResource(keycloakUrl, keycloakRealm, keycloakAdminName, keycloakAdminPassword, keycloakClientId);
|
||||
boolean result = register(resource, user);
|
||||
sendVerificationLink(login, resource);
|
||||
return result;
|
||||
public boolean register(String forename, String surname, String login, String password, String email) {
|
||||
UserRepresentation user = getUserRepresentation(forename, surname, login, password, email);
|
||||
UsersResource resource = getUsersResource(keycloakUrl, keycloakRealm, keycloakAdminName, keycloakAdminPassword,
|
||||
keycloakClientId);
|
||||
return register(resource, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* generate a user representation
|
||||
*
|
||||
* @param login the login
|
||||
* @param forename the forename
|
||||
* @param surname the surname
|
||||
* @param login the login
|
||||
* @param password the password
|
||||
* @param email the email
|
||||
* @param email the email
|
||||
* @return the user representation
|
||||
*/
|
||||
protected UserRepresentation getUserRepresentation(String login, String password, String email) {
|
||||
protected UserRepresentation getUserRepresentation(String forename, String surname, String login, String password,
|
||||
String email) {
|
||||
CredentialRepresentation passwordCredentials = new CredentialRepresentation();
|
||||
passwordCredentials.setTemporary(false);
|
||||
passwordCredentials.setType(CredentialRepresentation.PASSWORD);
|
||||
@ -83,6 +87,8 @@ public class KeycloakRepository {
|
||||
|
||||
UserRepresentation user = new UserRepresentation();
|
||||
user.setUsername(login);
|
||||
user.setFirstName(forename);
|
||||
user.setLastName(surname);
|
||||
user.setEmail(email);
|
||||
user.setCredentials(Collections.singletonList(passwordCredentials));
|
||||
user.setEnabled(true);
|
||||
@ -94,37 +100,42 @@ public class KeycloakRepository {
|
||||
* register a user in keycloak
|
||||
*
|
||||
* @param resource the resource
|
||||
* @param user the user
|
||||
* @param user the user
|
||||
* @return true or false
|
||||
*/
|
||||
protected boolean register(UsersResource resource, UserRepresentation user) {
|
||||
Response response = resource.create(user);
|
||||
LOGGER.info("created new keycloak user {}", user.getUsername());
|
||||
return Status.OK.equals(response.getStatusInfo());
|
||||
Boolean success = Status.CREATED.equals(response.getStatusInfo());
|
||||
if (success) {
|
||||
LOGGER.info("created new keycloak user {}", user.getUsername());
|
||||
} else {
|
||||
LOGGER.error("error on creating keycloak user {}: {}", user.getUsername(), response.getStatus());
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* generate a keycloak object with the special arguments
|
||||
*
|
||||
* @param url the url
|
||||
* @param realm the realm
|
||||
* @param admin the admin of the realm
|
||||
* @param url the url
|
||||
* @param realm the realm
|
||||
* @param admin the admin of the realm
|
||||
* @param password the password
|
||||
* @param clientId the client ID
|
||||
* @return the keycloak object
|
||||
*/
|
||||
public KeycloakBuilder getKeycloak(String url, String realm, String admin, String password, String clientId) {
|
||||
return KeycloakBuilder.builder().serverUrl(url).realm(realm).grantType(OAuth2Constants.PASSWORD)
|
||||
.username(admin).password(password).clientId(clientId)
|
||||
return KeycloakBuilder.builder().serverUrl(url).realm(realm).grantType(OAuth2Constants.PASSWORD).username(admin)
|
||||
.password(password).clientId(clientId)
|
||||
.resteasyClient(new ResteasyClientBuilderImpl().connectionPoolSize(10).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* generate a users resource object
|
||||
*
|
||||
* @param url the url
|
||||
* @param realm the realm
|
||||
* @param admin the admin of the realm
|
||||
* @param url the url
|
||||
* @param realm the realm
|
||||
* @param admin the admin of the realm
|
||||
* @param password the password
|
||||
* @param clientId the client ID
|
||||
* @return the users resource
|
||||
@ -138,8 +149,9 @@ public class KeycloakRepository {
|
||||
*
|
||||
* @param userId the ID of the user
|
||||
*/
|
||||
public void sendVerificationLink(String userId, UsersResource usersResource) {
|
||||
usersResource.get(userId).sendVerifyEmail();
|
||||
public void sendVerificationLink(String userId) {
|
||||
getUsersResource(keycloakUrl, keycloakRealm, keycloakAdminName, keycloakAdminPassword, keycloakClientId).get(userId)
|
||||
.sendVerifyEmail();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -37,20 +37,32 @@ public class RegistrationController extends CommonController {
|
||||
bean.setFkCamp(fkCamp);
|
||||
bean.setRegisterInKeycloak(true); // we want people to register generally
|
||||
model.addAttribute("bean", bean);
|
||||
return "/registration";
|
||||
return "/registration/registration";
|
||||
}
|
||||
|
||||
@PostMapping("/registration/register")
|
||||
public String register(@Valid @ModelAttribute RegistrationBean bean, final BindingResult bindingResult, Model model) {
|
||||
public String register(@Valid @ModelAttribute("bean") RegistrationBean bean, final BindingResult bindingResult, Model model) {
|
||||
super.setupSession(model, request);
|
||||
if (bindingResult.hasErrors()) {
|
||||
super.setupSession(model, request);
|
||||
CampBean campBean = service.getCamp(bean.getFkCamp());
|
||||
model.addAttribute("camp", campBean);
|
||||
model.addAttribute("bean", bean);
|
||||
return "/registration";
|
||||
return "/registration/registration";
|
||||
}
|
||||
Boolean result = service.register(bean);
|
||||
// TODO: give the user a message about success or error and, if registered in keycloak, a note about how to login
|
||||
return index(bean.getFkCamp(), model);
|
||||
return result ? "/registration/success" : "/error";
|
||||
}
|
||||
|
||||
@GetMapping("/registration/cancel/{id}")
|
||||
public String cancellation(@PathVariable Integer id, final Model model) {
|
||||
super.setupSession(model, request);
|
||||
model.addAttribute("bean", service.getBooking(id));
|
||||
return "/registration/cancellation";
|
||||
}
|
||||
|
||||
@GetMapping("/registration/remove/{id}")
|
||||
public String remove(@PathVariable Integer id, final Model model) {
|
||||
super.setupSession(model, request);
|
||||
service.removeBooking(id);
|
||||
return "redirect:/dashboard";
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package de.jottyfan.camporganizer.module.registration;
|
||||
|
||||
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_PERSONDOCUMENT;
|
||||
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PROFILE;
|
||||
|
||||
import java.time.LocalDate;
|
||||
@ -13,9 +14,11 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jasypt.util.password.StrongPasswordEncryptor;
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.DeleteConditionStep;
|
||||
import org.jooq.InsertResultStep;
|
||||
import org.jooq.InsertValuesStep12;
|
||||
import org.jooq.InsertValuesStep13;
|
||||
import org.jooq.Record7;
|
||||
import org.jooq.SelectConditionStep;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.impl.DSL;
|
||||
@ -27,7 +30,9 @@ import de.jottyfan.camporganizer.db.jooq.enums.EnumCamprole;
|
||||
import de.jottyfan.camporganizer.db.jooq.enums.EnumSex;
|
||||
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.TPersondocumentRecord;
|
||||
import de.jottyfan.camporganizer.db.jooq.tables.records.TProfileRecord;
|
||||
import de.jottyfan.camporganizer.module.common.BookingBean;
|
||||
import de.jottyfan.camporganizer.module.common.LambdaResultWrapper;
|
||||
|
||||
/**
|
||||
@ -163,4 +168,61 @@ public class RegistrationGateway {
|
||||
});
|
||||
return lrw.getCounter() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the booking from the database
|
||||
*
|
||||
* @param id the id of the booking
|
||||
* @return the booking bean or null
|
||||
*/
|
||||
public BookingBean getBooking(Integer id) {
|
||||
SelectConditionStep<Record7<Integer, String, String, EnumCamprole, String, LocalDateTime, LocalDateTime>> sql = jooq
|
||||
// @formatter:off
|
||||
.select(T_PERSON.PK,
|
||||
T_PERSON.FORENAME,
|
||||
T_PERSON.SURNAME,
|
||||
T_PERSON.CAMPROLE,
|
||||
T_CAMP.NAME,
|
||||
T_CAMP.ARRIVE,
|
||||
T_CAMP.DEPART)
|
||||
.from(T_PERSON)
|
||||
.leftJoin(T_CAMP).on(T_CAMP.PK.eq(T_PERSON.FK_CAMP))
|
||||
.where(T_PERSON.PK.eq(id));
|
||||
// @formatter:on
|
||||
LOGGER.debug(sql.toString());
|
||||
Record7<Integer, String, String, EnumCamprole, String, LocalDateTime, LocalDateTime> r = sql.fetchOne();
|
||||
if (r != null) {
|
||||
BookingBean bean = new BookingBean();
|
||||
bean.setPk(r.get(T_PERSON.PK));
|
||||
bean.setForename(r.get(T_PERSON.FORENAME));
|
||||
bean.setSurname(r.get(T_PERSON.SURNAME));
|
||||
bean.setCampName(r.get(T_CAMP.NAME));
|
||||
bean.setArrive(r.get(T_CAMP.ARRIVE));
|
||||
bean.setDepart(r.get(T_CAMP.DEPART));
|
||||
bean.setCamprole(r.get(T_PERSON.CAMPROLE));
|
||||
return bean;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove the booking and all of its dependencies
|
||||
*
|
||||
* @param id the pk of t_person
|
||||
* @return number of affected database rows, should be 1
|
||||
*/
|
||||
public Integer removeBooking(Integer id) {
|
||||
LambdaResultWrapper lrw = new LambdaResultWrapper();
|
||||
jooq.transaction(t -> {
|
||||
DeleteConditionStep<TPersondocumentRecord> sql1 = DSL.using(t).deleteFrom(T_PERSONDOCUMENT)
|
||||
.where(T_PERSONDOCUMENT.FK_PERSON.eq(id));
|
||||
LOGGER.debug(sql1.toString());
|
||||
sql1.execute();
|
||||
|
||||
DeleteConditionStep<TPersonRecord> sql2 = DSL.using(t).deleteFrom(T_PERSON).where(T_PERSON.PK.eq(id));
|
||||
LOGGER.debug(sql2.toString());
|
||||
lrw.add(sql2.execute());
|
||||
});
|
||||
return lrw.getCounter();
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,12 @@
|
||||
package de.jottyfan.camporganizer.module.registration;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import de.jottyfan.camporganizer.module.common.BookingBean;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jotty
|
||||
@ -10,6 +14,7 @@ import org.springframework.stereotype.Service;
|
||||
*/
|
||||
@Service
|
||||
public class RegistrationService {
|
||||
private final static Logger LOGGER = LogManager.getLogger(RegistrationService.class);
|
||||
|
||||
@Autowired
|
||||
private RegistrationGateway gateway;
|
||||
@ -36,8 +41,34 @@ public class RegistrationService {
|
||||
public Boolean register(RegistrationBean bean) {
|
||||
Boolean result = gateway.register(bean);
|
||||
if (result && bean.getRegisterInKeycloak()) {
|
||||
keycloak.register(bean.getLogin(), bean.getPassword(), bean.getEmail());
|
||||
keycloak.register(bean.getForename(), bean.getSurname(), bean.getLogin(), bean.getPassword(), bean.getEmail());
|
||||
if (bean.getEmail() != null && !bean.getEmail().isBlank()) {
|
||||
try {
|
||||
keycloak.sendVerificationLink(bean.getLogin());
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the booking bean
|
||||
*
|
||||
* @param id the id of the registration (t_person.pk)
|
||||
* @return the booking bean or null
|
||||
*/
|
||||
public BookingBean getBooking(Integer id) {
|
||||
return gateway.getBooking(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* remove the booking and all of its dependencies
|
||||
*
|
||||
* @param id the id of the booking (t_person.pk)
|
||||
*/
|
||||
public Boolean removeBooking(Integer id) {
|
||||
return gateway.removeBooking(id) > 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,22 @@
|
||||
# database credentials from defined config file
|
||||
spring.config.import=/etc/CampOrganizer2/prod.properties
|
||||
spring.config.import = /etc/CampOrganizer2/prod.properties
|
||||
|
||||
# define overwriteable arguments
|
||||
spring.datasource.driver-class-name=${spring.datasource.driver-class-name:org.postgresql.Driver}
|
||||
spring.datasource.url=${spring.datasource.url}
|
||||
spring.datasource.username=${spring.datasource.username}
|
||||
spring.datasource.password=${spring.datasource.password}
|
||||
spring.datasource.driver-class-name = ${spring.datasource.driver-class-name:org.postgresql.Driver}
|
||||
spring.datasource.url = ${spring.datasource.url}
|
||||
spring.datasource.username = ${spring.datasource.username}
|
||||
spring.datasource.password = ${spring.datasource.password}
|
||||
|
||||
server.servlet.context-path=${server.servlet.context-path:/CampOrganizer2}
|
||||
server.servlet.context-path = ${server.servlet.context-path:/CampOrganizer2}
|
||||
|
||||
keycloak.auth-server-url=${keycloak.auth-server-url}
|
||||
keycloak.realm=${keycloak.realm:ow}
|
||||
keycloak.resource=${keycloak.resource:biblecamp}
|
||||
keycloak.public-client=${keycloak.public-client}
|
||||
keycloak.use-resource-role-mappings=${keycloak.use-resource-role-mappings}
|
||||
keycloak.auth-server-url = ${keycloak.auth-server-url}
|
||||
keycloak.realm = ${keycloak.realm:ow}
|
||||
keycloak.resource = ${keycloak.resource:biblecamp}
|
||||
keycloak.public-client = ${keycloak.public-client}
|
||||
keycloak.use-resource-role-mappings = ${keycloak.use-resource-role-mappings}
|
||||
|
||||
ow.keycloak.admin.name=${ow.keycloak.admin.name}
|
||||
ow.keycloak.admin.password=${ow.keycloak.admin.password}
|
||||
ow.keycloak.admin.name = ${ow.keycloak.admin.name}
|
||||
ow.keycloak.admin.password = ${ow.keycloak.admin.password}
|
||||
|
||||
# for development only
|
||||
server.port = 8081
|
||||
|
@ -28,7 +28,7 @@
|
||||
</script>
|
||||
<div class="accordion" id="acc">
|
||||
<div class="accordion-item" th:each="b : ${mybookings}">
|
||||
<h2 class="accordion-header" th:id="'acc-head-' + ${b.pk}">
|
||||
<h2 class="accordion-header" th:id="'acc-head-' + ${b.pk}" th:if="${b.pk}">
|
||||
<button th:class="'accordion-button collapsed acc_' + ${b.accept}" type="button" data-bs-toggle="collapse" th:data-bs-target="'#acc-body-' + ${b.pk}" aria-expanded="true"
|
||||
th:aria-controls="'#acc-body-' + ${b.pk}">
|
||||
<i class="fas fa-check framed framed-green" th:if="${b.accept}"></i> <i class="fas fa-ban framed framed-red" th:if="${b.accept} == false"></i> <i
|
||||
@ -37,7 +37,7 @@
|
||||
th:text="${b.locationName}"></span>
|
||||
</button>
|
||||
</h2>
|
||||
<div th:id="'acc-body-' + ${b.pk}" class="accordion-collapse collapse" th:aria-labelledby="'acc-head-' + ${b.pk}">
|
||||
<div th:id="'acc-body-' + ${b.pk}" class="accordion-collapse collapse" th:aria-labelledby="'acc-head-' + ${b.pk}" th:if="${b.pk}">
|
||||
<div class="accordion-body">
|
||||
<div class="card">
|
||||
<div class="card-header">Freizeitdaten</div>
|
||||
@ -112,7 +112,7 @@
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-2">Foto-Einverständnis:</div>
|
||||
<span class="col-sm-10" th:text="${b.consentCatalogPhoto ? 'ja' : 'nein'}"></span>
|
||||
<span class="col-sm-10"><span th:text="${b.consentCatalogPhoto ? 'ja' : 'nein'}" th:if="${b.consentCatalogPhoto}"></span></span>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-2">Kommentar:</div>
|
||||
@ -120,9 +120,12 @@
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-10">
|
||||
<div class="col-sm-8">
|
||||
<input type="submit" class="btn btn-primary" value="Änderungen übernehmen" />
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<a th:href="@{/registration/cancel/{id}(id=${b.pk})}" class="btn btn-outline-danger">stornieren</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -13,7 +13,7 @@
|
||||
</ul>
|
||||
<ul class="navbar-nav mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="btn btn-icon-silent menufont" href="http://anmeldung.onkelwernerfreizeiten.de">Unsere Freizeiten</a>
|
||||
<a class="btn btn-icon-silent menufont" th:href="@{/}">Unsere Freizeiten</a>
|
||||
</li>
|
||||
</ul>
|
||||
</th:block>
|
||||
@ -56,7 +56,7 @@
|
||||
<div class="row">
|
||||
<div class="col-sm-3"></div>
|
||||
<div class="col-sm-9">
|
||||
<a class="btn btn-primary buttonfont" href="http://anmeldung.onkelwernerfreizeiten.de">jetzt anmelden</a>
|
||||
<a class="btn btn-primary buttonfont" th:href="@{/registration/{id}(id=${c.pk})}">jetzt anmelden</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
44
src/main/resources/templates/registration/cancellation.html
Normal file
44
src/main/resources/templates/registration/cancellation.html
Normal file
@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" layout:decorate="~{template}" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
<head>
|
||||
<title>Camp Organizer 2</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
</head>
|
||||
<body>
|
||||
<th:block layout:fragment="header">
|
||||
<ul class="navbar-nav mb-2 mb-lg-0">
|
||||
<li class="nav-item"><a th:href="@{${keycloakProfileUrl}}" class="btn btn-secondary btn-icon-silent" target="_blank">Profil</a></li>
|
||||
</ul>
|
||||
<ul class="navbar-nav mb-2 mb-lg-0">
|
||||
<li class="nav-item"><a th:href="@{/business}" class="btn btn-secondary btn-icon-silent" sec:authorize="hasRole('business')">Abrechnung</a></li>
|
||||
</ul>
|
||||
<ul class="navbar-nav mb-2 mb-lg-0">
|
||||
<li class="nav-item"><a th:href="@{/confirmation}" class="btn btn-secondary btn-icon-silent" sec:authorize="hasRole('registrator')">Bestätigung</a></li>
|
||||
</ul>
|
||||
<ul class="navbar-nav mb-2 mb-lg-0">
|
||||
<li class="nav-item"><a href="https://www.onkelwernerfreizeiten.de/cloud" class="btn btn-secondary btn-icon-silent" target="_blank">Nextcloud</a></li>
|
||||
</ul>
|
||||
</th:block>
|
||||
<th:block layout:fragment="content">
|
||||
<div class="mainpage">
|
||||
<div class="alert alert-warning">
|
||||
<span th:if="${bean.isStudent}">Willst du deine Anmeldung wirklich stornieren und damit den Freizeitplatz für einen anderen Teilnehmer freigeben? Diese Stornierung kann nicht
|
||||
rückgängig gemacht werden.</span> <span th:if="${!bean.isStudent}">Willst du deine Anmeldung wirklich stornieren?</span>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<span th:text="${bean.campName + ' ' + #temporals.format(bean.arrive, 'dd.MM.') + ' - ' + #temporals.format(bean.depart, 'dd.MM.yyyy')}"
|
||||
th:if="${bean.arrive != null and bean.depart != null}"></span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<span th:text="${bean.forename + ' ' + bean.surname}"></span>, <span th:if="${bean.isStudent}">Teilnehmer</span><span th:if="${bean.isTeacher}">Mitarbeiter</span> <span
|
||||
th:if="${bean.isDirector}">Leiter</span><span th:if="${bean.isFeeder}">Küchenhilfe</span>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a th:href="@{/registration/remove/{id}(id=${bean.pk})}" class="btn btn-danger">Ja, stornieren</a> <a th:href="@{/dashboard}" class="btn btn-outline-success">Stornierung abbrechen</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
||||
</body>
|
||||
</html>
|
31
src/main/resources/templates/registration/success.html
Normal file
31
src/main/resources/templates/registration/success.html
Normal file
@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" layout:decorate="~{template}" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
<head>
|
||||
<title>Camp Organizer 2</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
</head>
|
||||
<body>
|
||||
<th:block layout:fragment="header">
|
||||
<ul class="navbar-nav mb-2 mb-lg-0">
|
||||
<li class="nav-item"><a th:href="@{${keycloakProfileUrl}}" class="btn btn-secondary btn-icon-silent" target="_blank">Profil</a></li>
|
||||
</ul>
|
||||
<ul class="navbar-nav mb-2 mb-lg-0">
|
||||
<li class="nav-item"><a th:href="@{/business}" class="btn btn-secondary btn-icon-silent" sec:authorize="hasRole('business')">Abrechnung</a></li>
|
||||
</ul>
|
||||
<ul class="navbar-nav mb-2 mb-lg-0">
|
||||
<li class="nav-item"><a th:href="@{/confirmation}" class="btn btn-secondary btn-icon-silent" sec:authorize="hasRole('registrator')">Bestätigung</a></li>
|
||||
</ul>
|
||||
<ul class="navbar-nav mb-2 mb-lg-0">
|
||||
<li class="nav-item"><a href="https://www.onkelwernerfreizeiten.de/cloud" class="btn btn-secondary btn-icon-silent" target="_blank">Nextcloud</a></li>
|
||||
</ul>
|
||||
</th:block>
|
||||
<th:block layout:fragment="content">
|
||||
<div class="mainpage">
|
||||
<div class="alert alert-success">
|
||||
Deine Anmeldung wurde entgegengenommen. Falls du dir auch ein Login eingerichtet hast, kannst du dich jetzt oben rechts einloggen und deine Anmeldung bearbeiten.
|
||||
</div>
|
||||
<div><a th:href="@{/}" class="btn btn-outline-secondary">zur Hauptseite</a></div>
|
||||
</div>
|
||||
</th:block>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user