From 61dca619aa812b059f7966791c0666bde31cebb5 Mon Sep 17 00:00:00 2001
From: Michael Simon <simon@kit.edu>
Date: Fri, 21 Jun 2024 07:04:58 +0200
Subject: [PATCH] ISSUE-200 add page and functions for email addresses

---
 .../entity/identity/EmailAddressStatus.java   |  7 ++
 .../identity/IdentityEmailAddressEntity.java  | 14 ++++
 .../identity/IdentityEmailAddressService.java | 65 +++++++++++++------
 .../service/identity/IdentityServiceImpl.java |  6 +-
 .../scc/webreg/bean/EmailAddressesBean.java   | 29 +++++++++
 .../main/resources/msg/messages_de.properties |  4 ++
 .../main/resources/msg/messages_en.properties |  4 ++
 .../main/resources/msg/messages_fr.properties |  4 ++
 .../user/delete-all-personal-data.xhtml       | 20 +++---
 .../main/webapp/user/email-addresses.xhtml    | 26 +++++++-
 .../user/unlink-and-delete-account.xhtml      | 47 +++++++-------
 .../scc/webreg/exc/VerificationException.java | 33 ++++++++++
 12 files changed, 202 insertions(+), 57 deletions(-)
 create mode 100644 bwreg-entities/src/main/java/edu/kit/scc/webreg/entity/identity/EmailAddressStatus.java
 create mode 100644 regapp-exc/src/main/java/edu/kit/scc/webreg/exc/VerificationException.java

diff --git a/bwreg-entities/src/main/java/edu/kit/scc/webreg/entity/identity/EmailAddressStatus.java b/bwreg-entities/src/main/java/edu/kit/scc/webreg/entity/identity/EmailAddressStatus.java
new file mode 100644
index 00000000..1d3d0a14
--- /dev/null
+++ b/bwreg-entities/src/main/java/edu/kit/scc/webreg/entity/identity/EmailAddressStatus.java
@@ -0,0 +1,7 @@
+package edu.kit.scc.webreg.entity.identity;
+
+public enum EmailAddressStatus {
+
+	VERIFIED,
+	UNVERIFIED
+}
diff --git a/bwreg-entities/src/main/java/edu/kit/scc/webreg/entity/identity/IdentityEmailAddressEntity.java b/bwreg-entities/src/main/java/edu/kit/scc/webreg/entity/identity/IdentityEmailAddressEntity.java
index ef42406f..aa58f74e 100644
--- a/bwreg-entities/src/main/java/edu/kit/scc/webreg/entity/identity/IdentityEmailAddressEntity.java
+++ b/bwreg-entities/src/main/java/edu/kit/scc/webreg/entity/identity/IdentityEmailAddressEntity.java
@@ -15,6 +15,8 @@ import java.util.Date;
 import edu.kit.scc.webreg.entity.AbstractBaseEntity;
 import jakarta.persistence.Column;
 import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
 import jakarta.persistence.JoinColumn;
 import jakarta.persistence.ManyToOne;
 import jakarta.persistence.Table;
@@ -47,6 +49,10 @@ public class IdentityEmailAddressEntity extends AbstractBaseEntity {
 	@Column(name = "token_valid_until")
 	protected Date tokenValidUntil;
 
+	@Enumerated(EnumType.STRING)
+    @Column(name = "email_status")
+	protected EmailAddressStatus emailStatus;
+
 	public IdentityEntity getIdentity() {
 		return identity;
 	}
@@ -103,4 +109,12 @@ public class IdentityEmailAddressEntity extends AbstractBaseEntity {
 		this.tokenValidUntil = tokenValidUntil;
 	}
 
+	public EmailAddressStatus getEmailStatus() {
+		return emailStatus;
+	}
+
+	public void setEmailStatus(EmailAddressStatus emailStatus) {
+		this.emailStatus = emailStatus;
+	}
+
 }
diff --git a/bwreg-service/src/main/java/edu/kit/scc/webreg/service/identity/IdentityEmailAddressService.java b/bwreg-service/src/main/java/edu/kit/scc/webreg/service/identity/IdentityEmailAddressService.java
index 94f3877a..c398171f 100644
--- a/bwreg-service/src/main/java/edu/kit/scc/webreg/service/identity/IdentityEmailAddressService.java
+++ b/bwreg-service/src/main/java/edu/kit/scc/webreg/service/identity/IdentityEmailAddressService.java
@@ -13,22 +13,23 @@ import edu.kit.scc.regapp.mail.api.TemplateMailService;
 import edu.kit.scc.webreg.bootstrap.ApplicationConfig;
 import edu.kit.scc.webreg.dao.BaseDao;
 import edu.kit.scc.webreg.dao.identity.IdentityEmailAddressDao;
+import edu.kit.scc.webreg.dao.ops.RqlExpressions;
 import edu.kit.scc.webreg.entity.EventType;
+import edu.kit.scc.webreg.entity.identity.EmailAddressStatus;
 import edu.kit.scc.webreg.entity.identity.IdentityEmailAddressEntity;
+import edu.kit.scc.webreg.entity.identity.IdentityEmailAddressEntity_;
 import edu.kit.scc.webreg.entity.identity.IdentityEntity;
 import edu.kit.scc.webreg.event.EventSubmitter;
 import edu.kit.scc.webreg.event.IdentityEmailAddressEvent;
 import edu.kit.scc.webreg.event.exc.EventSubmitException;
+import edu.kit.scc.webreg.exc.VerificationException;
 import edu.kit.scc.webreg.service.impl.BaseServiceImpl;
 import jakarta.ejb.Stateless;
-import jakarta.ejb.TransactionManagement;
-import jakarta.ejb.TransactionManagementType;
 import jakarta.inject.Inject;
 import jakarta.mail.internet.AddressException;
 import jakarta.mail.internet.InternetAddress;
 
 @Stateless
-@TransactionManagement(TransactionManagementType.BEAN)
 public class IdentityEmailAddressService extends BaseServiceImpl<IdentityEmailAddressEntity> implements Serializable {
 
 	private static final long serialVersionUID = 1L;
@@ -48,7 +49,8 @@ public class IdentityEmailAddressService extends BaseServiceImpl<IdentityEmailAd
 	@Inject
 	private EventSubmitter eventSubmitter;
 
-	public IdentityEmailAddressEntity addEmailAddress(IdentityEntity identity, String emailAddress, String executor) throws AddressException {
+	public IdentityEmailAddressEntity addEmailAddress(IdentityEntity identity, String emailAddress, String executor)
+			throws AddressException {
 		InternetAddress email = new InternetAddress(emailAddress, true);
 
 		IdentityEmailAddressEntity entity = dao.createNew();
@@ -56,6 +58,7 @@ public class IdentityEmailAddressService extends BaseServiceImpl<IdentityEmailAd
 		entity.setEmailAddress(email.getAddress());
 		entity.setVerificationToken(generateToken());
 		entity.setTokenValidUntil(generateTokenValidity());
+		entity.setEmailStatus(EmailAddressStatus.UNVERIFIED);
 		entity = dao.persist(entity);
 
 		sendVerificationEmail(entity);
@@ -86,23 +89,43 @@ public class IdentityEmailAddressService extends BaseServiceImpl<IdentityEmailAd
 		}
 	}
 
-	public boolean checkVerification(IdentityEmailAddressEntity entity, String token, String executor) {
+	public void deleteEmailAddress(IdentityEmailAddressEntity entity, String executor) {
 		entity = dao.fetch(entity.getId());
-		if (entity.getVerificationToken().equals(token)) {
-			entity.setVerificationToken(null);
-			entity.setVerifiedOn(new Date());
-			entity.setValidUntil(generateValidity());
-
-			IdentityEmailAddressEvent event = new IdentityEmailAddressEvent(entity);
-			try {
-				eventSubmitter.submit(event, EventType.EMAIL_ADDRESS_VERIFIED, executor);
-			} catch (EventSubmitException e) {
-				logger.warn("Could not submit event", e);
-			}
-			return true;
-		} else {
-			return false;
+		if (entity.equals(entity.getIdentity().getPrimaryEmail())) {
+			entity.getIdentity().setPrimaryEmail(null);
 		}
+		dao.delete(entity);
+	}
+
+	public IdentityEmailAddressEntity checkVerification(IdentityEntity identity, String token, String executor)
+			throws VerificationException {
+		IdentityEmailAddressEntity entity = dao
+				.find(RqlExpressions.equal(IdentityEmailAddressEntity_.verificationToken, token));
+
+		if (entity == null) {
+			throw new VerificationException("no_token_found");
+		}
+		
+		if (!identity.equals(entity.getIdentity())) {
+			throw new VerificationException("not_owner");
+		}
+
+		if (entity.getTokenValidUntil().before(new Date())) {
+			throw new VerificationException("token_expired");
+		}
+		
+		entity.setVerificationToken(null);
+		entity.setVerifiedOn(new Date());
+		entity.setValidUntil(generateValidity());
+		entity.setEmailStatus(EmailAddressStatus.VERIFIED);
+
+		IdentityEmailAddressEvent event = new IdentityEmailAddressEvent(entity);
+		try {
+			eventSubmitter.submit(event, EventType.EMAIL_ADDRESS_VERIFIED, executor);
+		} catch (EventSubmitException e) {
+			logger.warn("Could not submit event", e);
+		}
+		return entity;
 	}
 
 	private String generateToken() {
@@ -112,7 +135,7 @@ public class IdentityEmailAddressService extends BaseServiceImpl<IdentityEmailAd
 	}
 
 	private Date generateTokenValidity() {
-		Long validity = 30 * 60 * 60 * 1000L;
+		Long validity = 30 * 60 * 1000L;
 		if (appConfig.getConfigValue("email_token_validity") != null) {
 			validity = Long.parseLong(appConfig.getConfigValue("email_token_validity"));
 		}
@@ -129,7 +152,7 @@ public class IdentityEmailAddressService extends BaseServiceImpl<IdentityEmailAd
 		return new Date(System.currentTimeMillis() + validity);
 	}
 
-	public void sendVerificationEmail(IdentityEmailAddressEntity emailAddress) {
+	protected void sendVerificationEmail(IdentityEmailAddressEntity emailAddress) {
 
 		logger.debug("Sending Email verification mail for identity {} (email: {})", emailAddress.getIdentity().getId(),
 				emailAddress.getEmailAddress());
diff --git a/bwreg-service/src/main/java/edu/kit/scc/webreg/service/identity/IdentityServiceImpl.java b/bwreg-service/src/main/java/edu/kit/scc/webreg/service/identity/IdentityServiceImpl.java
index 1211e5e5..507064cf 100644
--- a/bwreg-service/src/main/java/edu/kit/scc/webreg/service/identity/IdentityServiceImpl.java
+++ b/bwreg-service/src/main/java/edu/kit/scc/webreg/service/identity/IdentityServiceImpl.java
@@ -22,9 +22,6 @@ import java.util.List;
 import java.util.Set;
 import java.util.UUID;
 
-import jakarta.ejb.Stateless;
-import jakarta.inject.Inject;
-
 import org.slf4j.Logger;
 
 import edu.kit.scc.webreg.dao.BaseDao;
@@ -32,7 +29,6 @@ import edu.kit.scc.webreg.dao.RegistryDao;
 import edu.kit.scc.webreg.dao.SshPubKeyDao;
 import edu.kit.scc.webreg.dao.UserDao;
 import edu.kit.scc.webreg.dao.identity.IdentityDao;
-import edu.kit.scc.webreg.dao.ops.RqlExpressions;
 import edu.kit.scc.webreg.entity.RegistryEntity;
 import edu.kit.scc.webreg.entity.RegistryEntity_;
 import edu.kit.scc.webreg.entity.SshPubKeyEntity;
@@ -43,6 +39,8 @@ import edu.kit.scc.webreg.entity.UserStatus;
 import edu.kit.scc.webreg.entity.identity.IdentityEntity;
 import edu.kit.scc.webreg.entity.identity.IdentityEntity_;
 import edu.kit.scc.webreg.service.impl.BaseServiceImpl;
+import jakarta.ejb.Stateless;
+import jakarta.inject.Inject;
 
 @Stateless
 public class IdentityServiceImpl extends BaseServiceImpl<IdentityEntity> implements IdentityService {
diff --git a/bwreg-webapp/src/main/java/edu/kit/scc/webreg/bean/EmailAddressesBean.java b/bwreg-webapp/src/main/java/edu/kit/scc/webreg/bean/EmailAddressesBean.java
index 58aa2565..a08ad67e 100644
--- a/bwreg-webapp/src/main/java/edu/kit/scc/webreg/bean/EmailAddressesBean.java
+++ b/bwreg-webapp/src/main/java/edu/kit/scc/webreg/bean/EmailAddressesBean.java
@@ -12,8 +12,10 @@ package edu.kit.scc.webreg.bean;
 
 import java.io.Serializable;
 
+import edu.kit.scc.webreg.entity.identity.IdentityEmailAddressEntity;
 import edu.kit.scc.webreg.entity.identity.IdentityEntity;
 import edu.kit.scc.webreg.entity.identity.IdentityEntity_;
+import edu.kit.scc.webreg.exc.VerificationException;
 import edu.kit.scc.webreg.service.identity.IdentityEmailAddressService;
 import edu.kit.scc.webreg.service.identity.IdentityService;
 import edu.kit.scc.webreg.session.SessionManager;
@@ -23,6 +25,7 @@ import jakarta.faces.view.ViewScoped;
 import jakarta.inject.Inject;
 import jakarta.inject.Named;
 import jakarta.mail.internet.AddressException;
+import jakarta.validation.constraints.Email;
 
 @Named
 @ViewScoped
@@ -44,8 +47,11 @@ public class EmailAddressesBean implements Serializable {
 
 	private IdentityEntity identity;
 
+	@Email
 	private String addEmailAddress;
 
+	private String token;
+	
 	public void preRenderView(ComponentSystemEvent ev) {
 	}
 
@@ -59,6 +65,21 @@ public class EmailAddressesBean implements Serializable {
 		}
 	}
 
+	public void deleteEmailAddress(IdentityEmailAddressEntity address) {
+		service.deleteEmailAddress(address, "idty-" + session.getIdentityId());
+		identity = null;
+	}
+	
+	public void checkVerification() {
+		try {
+			service.checkVerification(getIdentity(), getToken(), "idty-" + session.getIdentityId());
+			token = null;
+			identity = null;
+		} catch (VerificationException e) {
+			messageGenerator.addResolvedErrorMessage("email_addresses." + e.getMessage());
+		}
+	}
+	
 	public IdentityEntity getIdentity() {
 		if (identity == null) {
 			identity = identityService.findByIdWithAttrs(session.getIdentityId(), IdentityEntity_.emailAddresses);
@@ -73,4 +94,12 @@ public class EmailAddressesBean implements Serializable {
 	public void setAddEmailAddress(String addEmailAddress) {
 		this.addEmailAddress = addEmailAddress;
 	}
+
+	public String getToken() {
+		return token;
+	}
+
+	public void setToken(String token) {
+		this.token = token;
+	}
 }
diff --git a/bwreg-webapp/src/main/resources/msg/messages_de.properties b/bwreg-webapp/src/main/resources/msg/messages_de.properties
index 58505ef9..8740280e 100644
--- a/bwreg-webapp/src/main/resources/msg/messages_de.properties
+++ b/bwreg-webapp/src/main/resources/msg/messages_de.properties
@@ -373,6 +373,10 @@ email_address = E-Mail-Adresse
 
 email_address_more = E-Mail-Adresse (weitere)
 
+email_addresses.heading              = Meine E-Mail Adressen
+email_addresses.no_primary_email_set = Keine gesetzt
+email_addresses.primary_email        = Prim\u00E4re E-Mail Adresse
+
 email_signature_keys = Schl\u00FCssel zum Signieren
 
 email_signature_keys_deposited = Schl\u00FCssel zum Signieren von Emails sind hinterlegt
diff --git a/bwreg-webapp/src/main/resources/msg/messages_en.properties b/bwreg-webapp/src/main/resources/msg/messages_en.properties
index e0389b32..9d67eca3 100644
--- a/bwreg-webapp/src/main/resources/msg/messages_en.properties
+++ b/bwreg-webapp/src/main/resources/msg/messages_en.properties
@@ -373,6 +373,10 @@ email_address = E-Mail address
 
 email_address_more = E-Mail address (more)
 
+email_addresses.heading              = My E-Mail-Addresses
+email_addresses.no_primary_email_set = None set
+email_addresses.primary_email        = Primary e-mail address
+
 email_signature_keys = Keys for signing emails
 
 email_signature_keys_deposited = Keys for signing emails are deposited
diff --git a/bwreg-webapp/src/main/resources/msg/messages_fr.properties b/bwreg-webapp/src/main/resources/msg/messages_fr.properties
index 61a27e34..8f3f6082 100644
--- a/bwreg-webapp/src/main/resources/msg/messages_fr.properties
+++ b/bwreg-webapp/src/main/resources/msg/messages_fr.properties
@@ -373,6 +373,10 @@ email_address = Adresse \u00E9lectronique
 
 email_address_more = Adresse \u00E9lectronique (plus)
 
+email_addresses.heading              = Mes adresses e-mail
+email_addresses.no_primary_email_set = Aucune d\u00E9finie
+email_addresses.primary_email        = Adresse e-mail primaire
+
 email_signature_keys = Cl\u00E9s pour signer des e-mails
 
 email_signature_keys_deposited = Les cl\u00E9s de signature des e-mails sont d\u00E9pos\u00E9es
diff --git a/bwreg-webapp/src/main/webapp/user/delete-all-personal-data.xhtml b/bwreg-webapp/src/main/webapp/user/delete-all-personal-data.xhtml
index e789ee20..a1e238fb 100644
--- a/bwreg-webapp/src/main/webapp/user/delete-all-personal-data.xhtml
+++ b/bwreg-webapp/src/main/webapp/user/delete-all-personal-data.xhtml
@@ -30,20 +30,22 @@
 			<div class="text full">	
 				<h:outputText value="#{messages['my_data.delete_all.text']}" escape="false" />
 			</div>
-			<h:panelGroup rendered="#{deleteAllPersonalDataBean.registryList.size() > 0}" 
-						styleClass="text full" >
+			<h:panelGroup rendered="#{deleteAllPersonalDataBean.registryList.size() > 0}"
+						styleClass="text" >
 				
 				<h4 class="text-danger" style="margin-top: 1em;"><h:outputText value="#{messages['my_data.delete_all.registered_services_head']}"/></h4>
 				<br/>
 				<h:outputText value="#{messages['my_data.delete_all.registered_services']}" escape="false" />
 				
-				<ul style="margin-top: 1em;">
-					<ui:repeat var="r" value="#{deleteAllPersonalDataBean.registryList}">
-						<li>
-							<h:outputText value="#{r.service.name}" />
-						</li>				
-					</ui:repeat>
-				</ul>
+				<div class="text" style="margin-top: 1em;">
+					<ul>
+						<ui:repeat var="r" value="#{deleteAllPersonalDataBean.registryList}">
+							<li>
+								<h:outputText value="#{r.service.name}" />
+							</li>				
+						</ui:repeat>
+					</ul>
+				</div>
 			</h:panelGroup>
 		
 			<div class="form" style="margin-top: 1em;">
diff --git a/bwreg-webapp/src/main/webapp/user/email-addresses.xhtml b/bwreg-webapp/src/main/webapp/user/email-addresses.xhtml
index f523c534..22b12b3e 100644
--- a/bwreg-webapp/src/main/webapp/user/email-addresses.xhtml
+++ b/bwreg-webapp/src/main/webapp/user/email-addresses.xhtml
@@ -36,9 +36,33 @@
 		</div>
 
 		<ui:repeat var="email" value="#{emailAddressesBean.identity.emailAddresses}">
-			<div><h:outputText value="#{email.emailAddress}" /></div>
+			<div>
+				<h:outputText value="#{email.emailAddress}" />, 
+				<h:outputText value="#{email.emailStatus}" />, 
+				<h:outputText value="#{email.tokenValidUntil}" />, 
+				<h:outputText value="#{email.verificationSent}" />, 
+				<h:outputText value="#{email.verifiedOn}" />,
+				<h:outputText value="#{email.validUntil}" />, 
+				<p:commandLink action="#{emailAddressesBean.deleteEmailAddress(email)}" value="#{messages['delete']}" update="@all"/>
+			</div>
 		</ui:repeat>
+
+		<div>
+			<h:outputText value="#{messages['email_addresses.add_email_address']}: "/>
+			<p:inputText type="email" value="#{emailAddressesBean.addEmailAddress}" />
+			<div class="form">
+				<p:commandButton action="#{emailAddressesBean.addEmailAddress()}" value="#{messages['add']}" validateClient="true" ajax="true" update="@all" />
+			</div>
+		</div>
 	
+		<div>
+			<h:outputText value="#{messages['email_addresses.verification_token']}: "/>
+			<p:inputText value="#{emailAddressesBean.token}" />
+			<div class="form">
+				<p:commandButton action="#{emailAddressesBean.checkVerification()}" value="#{messages['check']}" ajax="true" update="@all" />
+			</div>
+		</div>
+		
 		<div class="text full" style="margin-top: 0.4em;">
 			<a href="../index.xhtml"><h:outputText value="#{messages.back}"/></a>
 		</div>		
diff --git a/bwreg-webapp/src/main/webapp/user/unlink-and-delete-account.xhtml b/bwreg-webapp/src/main/webapp/user/unlink-and-delete-account.xhtml
index 497a4178..dd6ac643 100644
--- a/bwreg-webapp/src/main/webapp/user/unlink-and-delete-account.xhtml
+++ b/bwreg-webapp/src/main/webapp/user/unlink-and-delete-account.xhtml
@@ -24,56 +24,59 @@
 	<ui:param name="title" value="#{messages.title}"/>
 
 	<ui:define name="content">
-	<h:form id="form" prependId="false" class="full form">
+	<h:form id="form" prependId="false" class="full">
 
 	<h2 class="text-danger"><h:outputText value="#{messages['my_data.unlink_and_delete_account.header']}"/></h2>
 
-	<p:panel id="blockPanel" rendered="#{not sessionManager.loggedInUserList.contains(unlinkAndDeleteAccountBean.user.id)}">
+	<h:panelGroup id="blockPanel" rendered="#{not sessionManager.loggedInUserList.contains(unlinkAndDeleteAccountBean.user.id)}">
 
 		<div>
 			<h:outputText value="#{messages['my_data.unlink_and_delete_account.text']}" escape="false" />
 		</div>
 	
-		<p:panel rendered="#{unlinkAndDeleteAccountBean.registryList.size() > 0}" 
-				header="#{messages['my_data.unlink_and_delete_account.registered_services_head']}"
-				style="margin-top: 1em;">
+		<h:panelGroup rendered="#{unlinkAndDeleteAccountBean.registryList.size() > 0}" 
+				styleClass="text">
+
+			<h4 class="text-danger" style="margin-top: 1em;"><h:outputText value="#{messages['my_data.delete_all.registered_services_head']}"/></h4>
 			<br/>
 			<h:outputText value="#{messages['my_data.unlink_and_delete_account.registered_services']}" escape="false" />
 			
-			<ul style="margin-top: 1em;">
-				<ui:repeat var="r" value="#{unlinkAndDeleteAccountBean.registryList}">
-					<li>
-						<h:outputText value="#{r.service.name}" />
-					</li>				
-				</ui:repeat>
-			</ul>
-		</p:panel>
+			<div class="text" style="margin-top: 1em;">
+				<ul>
+					<ui:repeat var="r" value="#{unlinkAndDeleteAccountBean.registryList}">
+						<li>
+							<h:outputText value="#{r.service.name}" />
+						</li>				
+					</ui:repeat>
+				</ul>
+			</div>
+		</h:panelGroup>
 	
-		<div style="margin-top: 16px;">
+		<div style="margin-top: 1em;" class="form">
 			<p:commandButton id="cancel" action="#{unlinkAndDeleteAccountBean.cancel}" 
 				value="#{messages.cancel}"/>
 			<p:commandButton id="save" oncomplete="PF('confirmDlg').show();"  
-				value="#{messages['my_data.unlink_and_delete_account.commit']}" class="text-danger"/>
+				value="#{messages['my_data.unlink_and_delete_account.commit']}" class="text-danger" style="margin-left: 1em;"/>
 		</div>		
-	</p:panel>
-	<p:panel id="errPanel" rendered="#{sessionManager.loggedInUserList.contains(unlinkAndDeleteAccountBean.user.id)}">
+	</h:panelGroup>
+	<h:panelGroup id="errPanel" rendered="#{sessionManager.loggedInUserList.contains(unlinkAndDeleteAccountBean.user.id)}">
 		Account is logged in and can't be unlinked.
-		<div style="margin-top: 16px;">
+		<div style="margin-top: 1em;" class="form">
 			<p:commandButton id="errCancel" action="#{unlinkAndDeleteAccountBean.cancel}" 
 				value="#{messages.cancel}"/>
 		</div>
-	</p:panel>
+	</h:panelGroup>
 	<p:dialog header="#{messages['my_data.unlink_and_delete_account.confirm_header']}" 
 					widgetVar="confirmDlg" id="confirmDlgId" modal="true" closable="false" closeOnEscape="false"
 					showEffect="fade" hideEffect="fade">
-		<div class="panel text full" style="width:480px;">
+		<div class="panel text full" style="width:480px; font-size:1.25rem;">
 			<h:outputText value="#{messages['my_data.unlink_and_delete_account.confirm_text']}" escape="false" />
 		</div>
-		<div style="margin-top: 16px;">
+		<div style="margin-top: 1em;" class="form">
 			<p:commandButton id="cancel2" action="#{unlinkAndDeleteAccountBean.cancel}" 
 				value="#{messages.cancel}"/>
 			<p:commandButton id="save2" action="#{unlinkAndDeleteAccountBean.commit}" 
-				value="#{messages['my_data.unlink_and_delete_account.commit2']}" class="text-danger"/>
+				value="#{messages['my_data.unlink_and_delete_account.commit2']}" class="text-danger" style="margin-left: 1em;"/>
 		</div>		
 	</p:dialog>
 	<p:blockUI block="confirmDlgId" trigger="save2">  
diff --git a/regapp-exc/src/main/java/edu/kit/scc/webreg/exc/VerificationException.java b/regapp-exc/src/main/java/edu/kit/scc/webreg/exc/VerificationException.java
new file mode 100644
index 00000000..a23f47f7
--- /dev/null
+++ b/regapp-exc/src/main/java/edu/kit/scc/webreg/exc/VerificationException.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Michael Simon.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Public License v3.0
+ * which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/gpl.html
+ * 
+ * Contributors:
+ *     Michael Simon - initial
+ ******************************************************************************/
+package edu.kit.scc.webreg.exc;
+
+public class VerificationException extends Exception {
+
+	private static final long serialVersionUID = 1L;
+
+	public VerificationException() {
+		super();
+	}
+
+	public VerificationException(String arg0, Throwable arg1) {
+		super(arg0, arg1);
+	}
+
+	public VerificationException(Throwable cause) {
+		super(cause);
+	}
+
+	public VerificationException(String arg0) {
+		super(arg0);
+	}
+	
+}
-- 
GitLab