From 0e599c4d9613b1474e9e4a190ac548904c8c037b Mon Sep 17 00:00:00 2001 From: Roland Haeder Date: Tue, 12 Apr 2016 18:58:39 +0200 Subject: [PATCH] Continued with adding user by administrator: - added addUser() method - removed creation timestamp as the EJB takes care of it - renamed errorHandler -> exception as this will become a page for thrown exceptions (later better handling) - updated jar(s) --- lib/jcontacts-core.jar | Bin 20582 -> 20471 bytes nbproject/faces-config.NavData | 64 ++++---- .../user/PizzaAdminUserWebSessionBean.java | 151 ++++++++++++++++++ .../PizzaAdminUserWebSessionController.java | 7 + .../beans/user/PizzaUserWebSessionBean.java | 34 ++-- .../user/PizzaUserWebSessionController.java | 5 + .../country/PizzaCountryConverter.java | 1 + .../PizzaSmsProviderConverter.java | 1 + web/WEB-INF/faces-config.xml | 11 +- web/errorHandler.xhtml | 52 ------ web/exception.xhtml | 20 +++ 11 files changed, 242 insertions(+), 104 deletions(-) delete mode 100644 web/errorHandler.xhtml create mode 100644 web/exception.xhtml diff --git a/lib/jcontacts-core.jar b/lib/jcontacts-core.jar index b94b468717c61b0b3d1b03d19f855d1a15815723..356a84c0658c6bd20121144e4a1e4f16f3c3fec7 100644 GIT binary patch delta 2373 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 TE;k=!Kmq?u<9~{ayQTFvbNCZ9 diff --git a/nbproject/faces-config.NavData b/nbproject/faces-config.NavData index a7dbd6ef..87613f96 100644 --- a/nbproject/faces-config.NavData +++ b/nbproject/faces-config.NavData @@ -2,38 +2,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/org/mxchange/pizzaapplication/beans/user/PizzaAdminUserWebSessionBean.java b/src/java/org/mxchange/pizzaapplication/beans/user/PizzaAdminUserWebSessionBean.java index 37dfe37b..f30ddb58 100644 --- a/src/java/org/mxchange/pizzaapplication/beans/user/PizzaAdminUserWebSessionBean.java +++ b/src/java/org/mxchange/pizzaapplication/beans/user/PizzaAdminUserWebSessionBean.java @@ -24,16 +24,30 @@ import java.util.Objects; import javax.annotation.PostConstruct; import javax.enterprise.context.SessionScoped; import javax.faces.view.facelets.FaceletException; +import javax.inject.Inject; import javax.inject.Named; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; +import org.mxchange.jcontacts.contact.Contact; +import org.mxchange.jcontacts.contact.UserContact; import org.mxchange.jcontacts.contact.gender.Gender; import org.mxchange.jcountry.data.Country; +import org.mxchange.jphone.phonenumbers.cellphone.CellphoneNumber; +import org.mxchange.jphone.phonenumbers.cellphone.DialableCellphoneNumber; +import org.mxchange.jphone.phonenumbers.fax.DialableFaxNumber; +import org.mxchange.jphone.phonenumbers.fax.FaxNumber; +import org.mxchange.jphone.phonenumbers.landline.DialableLandLineNumber; +import org.mxchange.jphone.phonenumbers.landline.LandLineNumber; import org.mxchange.jphone.phonenumbers.smsprovider.SmsProvider; +import org.mxchange.jusercore.exceptions.EmailAddressAlreadyRegisteredException; +import org.mxchange.jusercore.exceptions.UserNameAlreadyRegisteredException; import org.mxchange.jusercore.exceptions.UserNotFoundException; +import org.mxchange.jusercore.exceptions.UserPasswordMismatchException; +import org.mxchange.jusercore.model.user.LoginUser; import org.mxchange.jusercore.model.user.User; import org.mxchange.jusercore.model.user.UserSessionBeanRemote; +import org.mxchange.jusercore.model.user.UserUtils; import org.mxchange.jusercore.model.user.profilemodes.ProfileMode; /** @@ -181,6 +195,12 @@ public class PizzaAdminUserWebSessionBean implements PizzaAdminUserWebSessionCon */ private Integer zipCode; + /** + * Regular user controller + */ + @Inject + private PizzaUserWebSessionController userController; + /** * Default constructor */ @@ -201,6 +221,128 @@ public class PizzaAdminUserWebSessionBean implements PizzaAdminUserWebSessionCon } } + @Override + public void addUser () { + // Create new user instance + User user = new LoginUser(); + user.setUserName(this.getUserName()); + user.setUserProfileMode(this.getUserProfileMode()); + + // Generate phone number + DialableLandLineNumber phone = new LandLineNumber(this.getPhoneCountry(), this.getPhoneAreaCode(), this.getPhoneNumber()); + DialableCellphoneNumber cellphone = new CellphoneNumber(this.getCellphoneCarrier(), this.getCellphoneNumber()); + DialableFaxNumber fax = new FaxNumber(this.getFaxCountry(), this.getFaxAreaCode(), this.getFaxNumber()); + + // Create new contact + Contact contact = new UserContact(this.getGender(), this.getFirstName(), this.getFamilyName()); + contact.setContactStreet(this.getStreet()); + contact.setContactHouseNumber(this.getHouseNumber()); + contact.setContactZipCode(this.getZipCode()); + contact.setContactCity(this.getCity()); + contact.setContactCountry(this.getCountry()); + contact.setContactEmailAddress(this.getEmailAddress()); + + // Don't set null or wrong references + if ((phone instanceof DialableLandLineNumber) && (phone.getPhoneCountry() instanceof Country) && (this.getPhoneAreaCode() != null) && (this.getPhoneNumber() != null) && (this.getPhoneAreaCode() > 0) && (this.getPhoneNumber() > 0)) { + // Now the number must be given + if (phone.getPhoneAreaCode() == null) { + // Is null + throw new NullPointerException("phone.phoneAreaCode is null"); //NOI18N + } else if (phone.getPhoneAreaCode() < 1) { + // Abort here + throw new IllegalArgumentException("phone.phoneAreaCode is zero or below."); //NOI18N + } else if (phone.getPhoneNumber() == null) { + // Is null + throw new NullPointerException("phone.phoneNumber is null"); //NOI18N + } else if (phone.getPhoneNumber() < 1) { + // Abort here + throw new IllegalArgumentException("phone.phoneNumber is zero or below."); //NOI18N + } + + // Set phone number + contact.setContactLandLineNumber(phone); + } + + // Don't set null or wrong references + if ((fax instanceof DialableFaxNumber) && (fax.getPhoneCountry() instanceof Country) && (this.getFaxAreaCode() != null) && (this.getFaxNumber() != null) && (this.getFaxAreaCode() > 0) && (this.getFaxNumber() > 0)) { + // Now the number must be given + if (fax.getPhoneAreaCode() == null) { + // Is null + throw new NullPointerException("fax.phoneAreaCode is null"); //NOI18N + } else if (fax.getPhoneAreaCode() < 1) { + // Abort here + throw new IllegalArgumentException("fax.phoneAreaCode is zero or below."); //NOI18N + } else if (fax.getPhoneNumber() == null) { + // Is null + throw new NullPointerException("fax.phoneNumber is null"); //NOI18N + } else if (fax.getPhoneNumber() < 1) { + // Abort here + throw new IllegalArgumentException("fax.phoneNumber is zero or below."); //NOI18N + } + + // Set fax number + contact.setContactFaxNumber(fax); + } + + // Is the provider set? + if ((cellphone instanceof DialableCellphoneNumber) && (this.getCellphoneCarrier() instanceof SmsProvider) && (this.getCellphoneNumber() != null) && (this.getCellphoneNumber() > 0)) { + // Is the number set? + if (cellphone.getPhoneNumber() == null) { + // Is null + throw new NullPointerException("cellphone.phoneNumber is null"); //NOI18N + } else if (cellphone.getPhoneNumber() < 1) { + // Abort here + throw new IllegalArgumentException("cellphone.phoneNumber is zero or below."); //NOI18N + } + + // Set cellphone number + contact.setContactCellphoneNumber(cellphone); + } + + contact.setContactBirthday(this.getBirthday()); + contact.setContactComment(this.getComment()); + + // Set contact in user + user.setUserContact(contact); + + // Init variable for password + String password = null; + + // Is the user name or email address used already? + // @TODO Add password length check + if (this.userController.isUserNameRegistered(user)) { + // User name is already used + throw new FaceletException(new UserNameAlreadyRegisteredException(user)); + } else if (this.userController.isEmailAddressRegistered(user)) { + // Email address is already used + throw new FaceletException(new EmailAddressAlreadyRegisteredException(user)); + } else if ((this.getUserPassword().isEmpty()) && (this.getUserPasswordRepeat().isEmpty())) { + // Empty password entered, then generate one + password = UserUtils.createRandomPassword(PizzaUserWebSessionController.MINIMUM_PASSWORD_LENGTH); + } else if (!this.isSamePasswordEntered()) { + // Both passwords don't match + throw new FaceletException(new UserPasswordMismatchException(user)); + } else { + // Both match, so get it from this bean + password = this.getUserPassword(); + } + + // The password should not be null and at least 5 characters long + assert (password != null) : "password is null"; + assert (password.length() >= PizzaUserWebSessionController.MINIMUM_PASSWORD_LENGTH) : "Password is not long enough."; + + // Encrypt password and set it + user.setUserEncryptedPassword(UserUtils.encryptPassword(password)); + + try { + // Now, that all is set, call EJB + this.userBean.addUser(user); + } catch (final UserNameAlreadyRegisteredException | EmailAddressAlreadyRegisteredException ex) { + // Throw again + throw new FaceletException(ex); + } + } + @Override public List allUsers () { // Return it @@ -461,6 +603,15 @@ public class PizzaAdminUserWebSessionBean implements PizzaAdminUserWebSessionCon this.userList = this.userBean.allUsers(); } + /** + * Checks if same password is entered and that they are not empty. + *

+ * @return Whether the same password was entered + */ + private boolean isSamePasswordEntered () { + return ((!this.getUserPassword().isEmpty()) && (Objects.equals(this.getUserPassword(), this.getUserPasswordRepeat()))); + } + @Override public User lookupUserById (final Long userId) throws UserNotFoundException { // Init variable diff --git a/src/java/org/mxchange/pizzaapplication/beans/user/PizzaAdminUserWebSessionController.java b/src/java/org/mxchange/pizzaapplication/beans/user/PizzaAdminUserWebSessionController.java index cb34c073..d24cf739 100644 --- a/src/java/org/mxchange/pizzaapplication/beans/user/PizzaAdminUserWebSessionController.java +++ b/src/java/org/mxchange/pizzaapplication/beans/user/PizzaAdminUserWebSessionController.java @@ -59,6 +59,13 @@ public interface PizzaAdminUserWebSessionController extends Serializable { */ boolean hasUsers (); + /** + * Adds user instance to database by preparing a complete user instance and + * sending it to the EJB. The data set in the controller is being verified, + * e.g. if the user name or email address is not used yet. + */ + void addUser (); + /** * Getter for birth day *

diff --git a/src/java/org/mxchange/pizzaapplication/beans/user/PizzaUserWebSessionBean.java b/src/java/org/mxchange/pizzaapplication/beans/user/PizzaUserWebSessionBean.java index 4b99a4d0..fcad6353 100644 --- a/src/java/org/mxchange/pizzaapplication/beans/user/PizzaUserWebSessionBean.java +++ b/src/java/org/mxchange/pizzaapplication/beans/user/PizzaUserWebSessionBean.java @@ -19,7 +19,6 @@ package org.mxchange.pizzaapplication.beans.user; import java.text.MessageFormat; import java.util.Collections; import java.util.Date; -import java.util.GregorianCalendar; import java.util.Iterator; import java.util.List; import java.util.Objects; @@ -344,12 +343,11 @@ public class PizzaUserWebSessionBean implements PizzaUserWebSessionController { User user = new LoginUser(); user.setUserName(this.getUserName()); user.setUserProfileMode(this.getUserProfileMode()); - user.setUserCreated(new GregorianCalendar()); // Generate phone number - DialableLandLineNumber phone = new LandLineNumber(this.getPhoneCountry(), this.getPhoneAreaCode(), this.getPhoneNumber(), new GregorianCalendar()); - DialableCellphoneNumber cellphone = new CellphoneNumber(this.getCellphoneCarrier(), this.getCellphoneNumber(), new GregorianCalendar()); - DialableFaxNumber fax = new FaxNumber(this.getFaxCountry(), this.getFaxAreaCode(), this.getFaxNumber(), new GregorianCalendar()); + DialableLandLineNumber phone = new LandLineNumber(this.getPhoneCountry(), this.getPhoneAreaCode(), this.getPhoneNumber()); + DialableCellphoneNumber cellphone = new CellphoneNumber(this.getCellphoneCarrier(), this.getCellphoneNumber()); + DialableFaxNumber fax = new FaxNumber(this.getFaxCountry(), this.getFaxAreaCode(), this.getFaxNumber()); // Create new contact Contact contact = new UserContact(this.getGender(), this.getFirstName(), this.getFamilyName()); @@ -421,7 +419,6 @@ public class PizzaUserWebSessionBean implements PizzaUserWebSessionController { contact.setContactComment(this.getComment()); // Created timestamp and ownContact - contact.setContactCreated(new GregorianCalendar()); contact.setContactOwnContact(Boolean.TRUE); // Set contact in user @@ -429,6 +426,7 @@ public class PizzaUserWebSessionBean implements PizzaUserWebSessionController { // Trace message //this.getLogger().logTrace(MessageFormat.format("createUserInstance: user={0} - EXIT!", user)); + // Return it return user; } @@ -730,32 +728,32 @@ public class PizzaUserWebSessionBean implements PizzaUserWebSessionController { } @Override - public boolean isRequiredPersonalDataSet () { - return ((this.getUserName() != null) && - (this.getUserProfileMode() != null) && + public boolean isRequiredChangePersonalDataSet () { + return ((this.getUserProfileMode() != null) && (this.getGender() != null) && (this.getFirstName() != null) && (this.getFamilyName() != null) && (this.getStreet() != null) && (this.getHouseNumber() != null) && (this.getZipCode() != null) && - (this.getCity() != null) && - (this.getEmailAddress() != null) && - (this.getEmailAddressRepeat() != null) && - (this.getUserPassword() != null) && - (this.getUserPasswordRepeat() != null)); + (this.getCity() != null)); } @Override - public boolean isRequiredChangePersonalDataSet () { - return ((this.getUserProfileMode() != null) && + public boolean isRequiredPersonalDataSet () { + return ((this.getUserName() != null) && + (this.getUserProfileMode() != null) && (this.getGender() != null) && (this.getFirstName() != null) && (this.getFamilyName() != null) && (this.getStreet() != null) && (this.getHouseNumber() != null) && (this.getZipCode() != null) && - (this.getCity() != null)); + (this.getCity() != null) && + (this.getEmailAddress() != null) && + (this.getEmailAddressRepeat() != null) && + (this.getUserPassword() != null) && + (this.getUserPasswordRepeat() != null)); } @Override @@ -765,7 +763,7 @@ public class PizzaUserWebSessionBean implements PizzaUserWebSessionController { @Override public boolean isSamePasswordEntered () { - return (Objects.equals(this.getUserPassword(), this.getUserPasswordRepeat())); + return ((!this.getUserPassword().isEmpty()) && (Objects.equals(this.getUserPassword(), this.getUserPasswordRepeat()))); } @Override diff --git a/src/java/org/mxchange/pizzaapplication/beans/user/PizzaUserWebSessionController.java b/src/java/org/mxchange/pizzaapplication/beans/user/PizzaUserWebSessionController.java index 10d309f3..ec3bbc06 100644 --- a/src/java/org/mxchange/pizzaapplication/beans/user/PizzaUserWebSessionController.java +++ b/src/java/org/mxchange/pizzaapplication/beans/user/PizzaUserWebSessionController.java @@ -35,6 +35,11 @@ import org.mxchange.jusercore.model.user.profilemodes.ProfileMode; */ public interface PizzaUserWebSessionController extends Serializable { + /** + * Minimum password length + */ + public static final Integer MINIMUM_PASSWORD_LENGTH = 5; + /** * Tries to lookup user by given id number. If the user is not found or the * account status is not CONFIRMED proper exceptions are thrown. diff --git a/src/java/org/mxchange/pizzaapplication/converter/country/PizzaCountryConverter.java b/src/java/org/mxchange/pizzaapplication/converter/country/PizzaCountryConverter.java index 3189fc23..5b522269 100644 --- a/src/java/org/mxchange/pizzaapplication/converter/country/PizzaCountryConverter.java +++ b/src/java/org/mxchange/pizzaapplication/converter/country/PizzaCountryConverter.java @@ -136,4 +136,5 @@ public class PizzaCountryConverter implements Converter { // Return category id return String.valueOf(((Country) value).getCountryId()); } + } diff --git a/src/java/org/mxchange/pizzaapplication/converter/smsprovider/PizzaSmsProviderConverter.java b/src/java/org/mxchange/pizzaapplication/converter/smsprovider/PizzaSmsProviderConverter.java index ab14e679..cfacaaa9 100644 --- a/src/java/org/mxchange/pizzaapplication/converter/smsprovider/PizzaSmsProviderConverter.java +++ b/src/java/org/mxchange/pizzaapplication/converter/smsprovider/PizzaSmsProviderConverter.java @@ -136,4 +136,5 @@ public class PizzaSmsProviderConverter implements Converter { // Return category id return String.valueOf(((SmsProvider) value).getProviderId()); } + } diff --git a/web/WEB-INF/faces-config.xml b/web/WEB-INF/faces-config.xml index 02ee416a..23b1d5f3 100644 --- a/web/WEB-INF/faces-config.xml +++ b/web/WEB-INF/faces-config.xml @@ -72,8 +72,8 @@ /basket.xhtml - item_not_changed - /errorHandler.xhtml + exception + /exception.xhtml admin_delete_user @@ -160,4 +160,11 @@ /admin/admin_country_edit.xhtml + diff --git a/web/errorHandler.xhtml b/web/errorHandler.xhtml deleted file mode 100644 index f4970d90..00000000 --- a/web/errorHandler.xhtml +++ /dev/null @@ -1,52 +0,0 @@ -<%-- -Document : errorHandler -Created on : 05.08.2016, 12:06:39 -Author : Roland Haeder ---%> - -<%@page import="java.io.PrintWriter"%> -<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> -<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> - - -<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - - - - - - - Pizza-Service - Fehler - - - -

- - - -
-
-

An error occurred:

-
- -
- Unfortunately an unexpected error has occurred. Below you can find the error details. -
    -
  • Timestamp:
  • -
  • Action:
  • -
  • Exception:
  • -
  • Message:
  • -
  • Status code:
  • -
  • User agent:
  • -
-
-
- - - - diff --git a/web/exception.xhtml b/web/exception.xhtml new file mode 100644 index 00000000..cbb6ce54 --- /dev/null +++ b/web/exception.xhtml @@ -0,0 +1,20 @@ + + + + + + #{msg.PAGE_TITLE_EXCEPTION_THROWN} + + + #{msg.CONTENT_TITLE_EXCEPTION_THROWN} + + + + Unfortunately an unexpected error has occurred. + + + -- 2.39.5