]> git.mxchange.org Git - jjobs-war.git/blob - src/java/org/mxchange/jjobs/beans/user/register/JobsUserRegisterWebRequestBean.java
77d79963bf73e52723de4709d7c8a5a7856c12bc
[jjobs-war.git] / src / java / org / mxchange / jjobs / beans / user / register / JobsUserRegisterWebRequestBean.java
1 /*
2  * Copyright (C) 2016 - 2020 Free Software Foundation
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Affero General Public License as
6  * published by the Free Software Foundation, either version 3 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Affero General Public License for more details.
13  *
14  * You should have received a copy of the GNU Affero General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 package org.mxchange.jjobs.beans.user.register;
18
19 import java.util.Objects;
20 import javax.ejb.EJB;
21 import javax.enterprise.context.RequestScoped;
22 import javax.enterprise.event.Event;
23 import javax.enterprise.event.Observes;
24 import javax.enterprise.inject.Any;
25 import javax.faces.application.FacesMessage;
26 import javax.faces.view.facelets.FaceletException;
27 import javax.inject.Inject;
28 import javax.inject.Named;
29 import org.mxchange.jcontacts.model.contact.Contact;
30 import org.mxchange.jcontacts.model.contact.UserContact;
31 import org.mxchange.jcoreee.utils.FacesUtils;
32 import org.mxchange.jjobs.beans.BaseJobsBean;
33 import org.mxchange.jjobs.beans.contact.JobsContactWebRequestController;
34 import org.mxchange.jjobs.beans.features.JobsFeaturesWebApplicationController;
35 import org.mxchange.jjobs.beans.user.JobsUserWebRequestController;
36 import org.mxchange.jusercore.events.user.clear.password.ClearUserPasswordEvent;
37 import org.mxchange.jusercore.events.user.clear.password.ObservableClearUserPasswordEvent;
38 import org.mxchange.jusercore.events.user.clear.username.ClearUserNameEvent;
39 import org.mxchange.jusercore.events.user.clear.username.ObservableClearUserNameEvent;
40 import org.mxchange.jusercore.exceptions.DataRepeatMismatchException;
41 import org.mxchange.jusercore.exceptions.EmailAddressAlreadyRegisteredException;
42 import org.mxchange.jusercore.exceptions.UserNameAlreadyRegisteredException;
43 import org.mxchange.jusercore.model.user.LoginUser;
44 import org.mxchange.jusercore.model.user.User;
45 import org.mxchange.jusercore.model.user.Users;
46 import org.mxchange.jusercore.model.user.password_history.PasswordHistory;
47 import org.mxchange.jusercore.model.user.password_history.UserPasswordHistory;
48 import org.mxchange.jusercore.model.user.profilemodes.ProfileMode;
49 import org.mxchange.jusercore.model.user.status.UserAccountStatus;
50 import org.mxchange.juserlogincore.events.registration.ObservableUserRegisteredEvent;
51 import org.mxchange.juserlogincore.events.registration.UserRegisteredEvent;
52 import org.mxchange.juserlogincore.events.user.password_change.ObservableUpdatedUserPasswordEvent;
53 import org.mxchange.juserlogincore.events.user.password_change.UpdatedUserPasswordEvent;
54 import org.mxchange.juserlogincore.login.UserLoginUtils;
55 import org.mxchange.juserlogincore.model.user.register.UserRegistrationSessionBeanRemote;
56
57 /**
58  * A web bean for user registration
59  * <p>
60  * @author Roland Häder<roland@mxchange.org>
61  */
62 @Named ("userRegistrationController")
63 @RequestScoped
64 public class JobsUserRegisterWebRequestBean extends BaseJobsBean implements JobsUserRegisterWebRequestController {
65
66         /**
67          * Serial number
68          */
69         private static final long serialVersionUID = 47_828_986_719_691_592L;
70
71         /**
72          * Contact controller
73          */
74         @Inject
75         private JobsContactWebRequestController contactController;
76
77         /**
78          * Features controller
79          */
80         @Inject
81         private JobsFeaturesWebApplicationController featureController;
82
83         /**
84          * Localization controller
85          */
86         @Inject
87         private FinancialsLocalizationSessionController localizationController;
88
89         /**
90          * Remote register session-scoped bean
91          */
92         @EJB (lookup = "java:global/jjobs-ejb/userRegistration!org.mxchange.juserlogincore.model.user.register.UserRegistrationSessionBeanRemote")
93         private UserRegistrationSessionBeanRemote registerBean;
94
95         /**
96          * User list controller
97          */
98         @Inject
99         private FinancialsUserListWebViewController userListController;
100
101         /**
102          * User name
103          */
104         private String userName;
105
106         /**
107          * User password (clear-text from web form)
108          */
109         private String userPassword;
110
111         /**
112          * An event being fired when a user password was changed
113          */
114         @Inject
115         @Any
116         private Event<ObservableUpdatedUserPasswordEvent> userPasswordChangedEvent;
117
118         /**
119          * User password repeated (clear-text from web form)
120          */
121         private String userPasswordRepeat;
122
123         /**
124          * Whether the user wants a public profile
125          */
126         private ProfileMode userProfileMode;
127
128         /**
129          * An event being fired when a new user has registered
130          */
131         @Inject
132         @Any
133         private Event<ObservableUserRegisteredEvent> userRegisteredEvent;
134
135         /**
136          * Default constructor
137          */
138         public JobsUserRegisterWebRequestBean () {
139                 // Call super constructor
140                 super();
141         }
142
143         /**
144          * Event observer for user password changes
145          * <p>
146          * @param event Event being fired
147          */
148         public void afterUserPasswordChangedEvent (@Observes final ObservableUpdatedUserPasswordEvent event) {
149                 // Is it valid?
150                 if (null == event) {
151                         // Throw NPE
152                         throw new NullPointerException("event is null"); //NOI18N
153                 } else if (event.getUserPassword() == null) {
154                         // Throw NPE
155                         throw new NullPointerException("event.userPassword is null"); //NOI18N
156                 } else if (event.getUserPassword().isEmpty()) {
157                         // Throw NPE
158                         throw new IllegalArgumentException("event.userPassword is empty"); //NOI18N
159                 }
160
161                 // Set it here
162                 this.setUserPassword(event.getUserPassword());
163                 this.setUserPasswordRepeat(event.getUserPassword());
164         }
165
166         /**
167          * Registers the user, if not found. Otherwise this method should throw an
168          * exception.
169          * <p>
170          * @return Redirection target
171          */
172         public String doFinishRegistration () {
173                 // Is registration enabled?
174                 if (!this.featureController.isFeatureEnabled("user_registration")) { //NOI18N
175                         // Is not enabled
176                         throw new FaceletException("Registration is disabled."); //NOI18N
177                 }
178
179                 // Get user instance
180                 final User user = this.createUserInstance(true);
181
182                 // Null random password means registration requires user-entered password
183                 String randomPassword = null;
184
185                 // Is the user already used?
186                 if (null == user) {
187                         // user must be set
188                         throw new NullPointerException("user is null after createUserInstance() was called"); //NOI18N
189                 } else if (!this.isRequiredPersonalDataSet()) {
190                         // Not all required fields are set
191                         throw new FaceletException("Not all required fields are set."); //NOI18N
192                 } else if ((this.featureController.isFeatureEnabled("user_login_require_user_name")) && (this.userListController.isUserNameRegistered(user))) { //NOI18N
193                         // Is multi-page enabled?
194                         if (this.featureController.isFeatureEnabled("user_register_multiple_page")) { //NOI18N
195                                 // User name is already used, should not happen here
196                                 throw new FaceletException(new UserNameAlreadyRegisteredException(user));
197                         } else {
198                                 // May happen here, clear user name
199                                 this.clearUserName();
200
201                                 // Output message
202                                 this.showFacesMessage("form_register_single:userName", "ERROR_USER_NAME_ALREADY_USED", FacesMessage.SEVERITY_WARN); //NOI18N
203                                 return ""; //NOI18N
204                         }
205                 } else if (this.contactController.isEmailAddressRegistered(user.getUserContact())) {
206                         // Is multi-page enabled?
207                         if (this.featureController.isFeatureEnabled("user_register_multiple_page")) { //NOI18N
208                                 // Email address has already been taken, should not happen here
209                                 throw new FaceletException(new EmailAddressAlreadyRegisteredException(user));
210                         } else {
211                                 // May happen here, reset fields
212                                 this.contactController.clearEmailAddresses();
213                                 this.showFacesMessage("form_register_single:emailAddressRepeat", "ERROR_EMAIL_ADDRESS_ALREADY_USED", FacesMessage.SEVERITY_WARN); //NOI18N
214                                 return ""; //NOI18N
215                         }
216                 } else if (!this.contactController.isSameEmailAddressEntered()) {
217                         // Is multi-page enabled?
218                         if (this.featureController.isFeatureEnabled("user_register_multiple_page")) { //NOI18N
219                                 // Not same email address entered, should not happen here
220                                 throw new FaceletException(new DataRepeatMismatchException("Email addresses not matching.")); //NOI18N
221                         } else {
222                                 // May happen here, reset fields
223                                 this.contactController.clearEmailAddresses();
224                                 this.showFacesMessage("form_register_single:emailAddressRepeat", "ERROR_EMAIL_ADDRESSES_MISMATCHING", FacesMessage.SEVERITY_INFO); //NOI18N
225                                 return ""; //NOI18N
226                         }
227                 } else if (!this.isSamePasswordEntered()) {
228                         // Is multi-page enabled?
229                         if (this.featureController.isFeatureEnabled("user_register_multiple_page")) { //NOI18N
230                                 // Not same password entered, should no longer happen here
231                                 throw new FaceletException(new DataRepeatMismatchException("Passwords not matching.")); //NOI18N
232                         } else if (this.ifBothPasswordsEmptyAllowed()) {
233                                 // Both passwords are left empty and is allowed, then generate a random password
234                                 randomPassword = UserLoginUtils.createRandomPassword(JobsUserWebRequestController.MINIMUM_PASSWORD_LENGTH);
235
236                                 // Generate (ignored) password-history
237                                 final PasswordHistory passwordHistory = new UserPasswordHistory(randomPassword, user);
238
239                                 // Fire event
240                                 this.userPasswordChangedEvent.fire(new UpdatedUserPasswordEvent(passwordHistory, randomPassword));
241                         }
242                 }
243
244                 // Encrypt password
245                 final String encryptedPassword = UserLoginUtils.encryptPassword(this.getUserPassword());
246
247                 // Set it here
248                 user.setUserEncryptedPassword(encryptedPassword);
249
250                 // Is developer mode?
251                 if (this.isDebugModeEnabled("register")) { //NOI18N
252                         // For debugging/programming only:
253                         user.setUserAccountStatus(UserAccountStatus.CONFIRMED);
254                 } else {
255                         // No debugging of this part
256                         user.setUserAccountStatus(UserAccountStatus.UNCONFIRMED);
257
258                         // Ask EJB for generating a not-existing confirmation key
259                         final String confirmKey = this.registerBean.generateConfirmationKey(user);
260
261                         // Set it in user
262                         user.setUserConfirmKey(confirmKey);
263                 }
264
265                 try {
266                         // Get base URL
267                         final String baseUrl = FacesUtils.generateBaseUrl();
268
269                         // Call bean
270                         final User registeredUser = this.registerBean.registerUser(user, baseUrl, randomPassword);
271
272                         // The id number should be set
273                         assert (registeredUser.getUserId() instanceof Long) : "registeredUser.userId is null after registerUser() was called."; //NOI18N
274
275                         // Fire event
276                         this.userRegisteredEvent.fire(new UserRegisteredEvent(registeredUser));
277
278                         // All fine, redirect to proper page
279                         return "user_register_done"; //NOI18N
280                 } catch (final UserNameAlreadyRegisteredException | EmailAddressAlreadyRegisteredException ex) {
281                         // Continue to throw
282                         throw new FaceletException(ex);
283                 }
284         }
285
286         /**
287          * Handles registration request send from first page. The (maybe) entered
288          * user name and email address is not used and that privacy and T&C are
289          * accepted.
290          * <p>
291          * @return Redirect
292          */
293         public String doRegisterMultiPage1 () {
294                 // Is registration enabled?
295                 if (!this.featureController.isFeatureEnabled("user_registration")) { //NOI18N
296                         // Is not enabled
297                         throw new FaceletException("Registration is disabled."); //NOI18N
298                 }
299
300                 // Get user instance
301                 final User user = this.createUserInstance(false);
302
303                 // First check if user is not null and user name is not used + if same email address is entered
304                 if (null == user) {
305                         // user must be set
306                         throw new NullPointerException("user is null after createUserInstance() was called"); //NOI18N
307                 } else if ((this.featureController.isFeatureEnabled("user_login_require_user_name")) && (this.userListController.isUserNameRegistered(user))) { //NOI18N
308                         // User name is already used, so clear it
309                         this.clearUserName();
310
311                         // Output message
312                         this.showFacesMessage("form_register_page1:userName", "ERROR_USER_NAME_ALREADY_USED", FacesMessage.SEVERITY_WARN); //NOI18N
313                         return ""; //NOI18N
314                 } else if (!this.contactController.isSameEmailAddressEntered()) {
315                         // Not same email address entered, clear both
316                         this.contactController.clearEmailAddresses();
317                         this.showFacesMessage("form_register_page1:emailAddressRepeat", "ERROR_EMAIL_ADDRESSES_MISMATCHING", FacesMessage.SEVERITY_WARN); //NOI18N
318                         return ""; //NOI18N
319                 } else if (!this.isSamePasswordEntered()) {
320                         // Is multi-page enabled?
321                         if (this.featureController.isFeatureEnabled("user_register_multiple_page")) { //NOI18N
322                                 // Clear passwords
323                                 this.clearUserPasswords();
324
325                                 // Output faces message
326                                 this.showFacesMessage("form_register_page1:userPassword", "ERROR_USER_PASSWORD_EMPTY", FacesMessage.SEVERITY_WARN); //NOI18N
327                                 this.showFacesMessage("form_register_page1:userPasswordRepeat", "ERROR_USER_PASSWORD_REPEAT_EMPTY", FacesMessage.SEVERITY_WARN); //NOI18N
328                                 return ""; //NOI18N
329                         } else if (this.ifBothPasswordsEmptyAllowed()) {
330                                 // Both passwords are left empty and is allowed, then generate a random password
331                                 final String randomPassword = UserLoginUtils.createRandomPassword(FinancialsUserWebRequestController.MINIMUM_PASSWORD_LENGTH);
332
333                                 // Generate (ignored) password-history
334                                 final PasswordHistory passwordHistory = new UserPasswordHistory(randomPassword, user);
335
336                                 // Fire event
337                                 this.userPasswordChangedEvent.fire(new UpdatedUserPasswordEvent(passwordHistory, randomPassword));
338                         }
339                 }
340
341                 // Create half contact instance with email address
342                 final Contact contact = new UserContact();
343                 contact.setContactEmailAddress(this.contactController.getEmailAddress());
344
345                 // Set contact in user
346                 user.setUserContact(contact);
347
348                 // Check if email address is registered
349                 if (this.contactController.isEmailAddressRegistered(user.getUserContact())) {
350                         // Email address has already been taken, clear both
351                         this.contactController.clearEmailAddresses();
352                         this.showFacesMessage("form_register_page1:emailAddress", "ERROR_EMAIL_ADDRESS_ALREADY_USED", FacesMessage.SEVERITY_WARN); //NOI18N
353                         return ""; //NOI18N
354                 }
355
356                 // Now only redirect to next page as the JSF does it
357                 return "user_register_page2"; //NOI18N
358         }
359
360         /**
361          * Getter for user name
362          * <p>
363          * @return User name
364          */
365         public String getUserName () {
366                 return this.userName;
367         }
368
369         /**
370          * Setter for user name
371          * <p>
372          * @param userName User name
373          */
374         public void setUserName (final String userName) {
375                 this.userName = userName;
376         }
377
378         /**
379          * Getter for clear-text user password
380          * <p>
381          * @return Clear-text user password
382          */
383         public String getUserPassword () {
384                 return this.userPassword;
385         }
386
387         /**
388          * Setter for clear-text user password
389          * <p>
390          * @param userPassword Clear-text user password
391          */
392         public void setUserPassword (final String userPassword) {
393                 this.userPassword = userPassword;
394         }
395
396         /**
397          * Getter for clear-text user password repeated
398          * <p>
399          * @return Clear-text user password repeated
400          */
401         public String getUserPasswordRepeat () {
402                 return this.userPasswordRepeat;
403         }
404
405         /**
406          * Setter for clear-text user password repeated
407          * <p>
408          * @param userPasswordRepeat Clear-text user password repeated
409          */
410         public void setUserPasswordRepeat (final String userPasswordRepeat) {
411                 this.userPasswordRepeat = userPasswordRepeat;
412         }
413
414         /**
415          * Getter for user profile mode
416          * <p>
417          * @return User profile mode
418          */
419         public ProfileMode getUserProfileMode () {
420                 return this.userProfileMode;
421         }
422
423         /**
424          * Setter for user profile mode
425          * <p>
426          * @param userProfileMode User profile mode
427          */
428         public void setUserProfileMode (final ProfileMode userProfileMode) {
429                 this.userProfileMode = userProfileMode;
430         }
431
432         @Override
433         public boolean isRequiredChangePersonalDataSet () {
434                 return ((this.getUserProfileMode() != null) &&
435                                 (this.getUserName() != null) &&
436                                 (!this.getUserName().isEmpty()) &&
437                                 (this.contactController.isRequiredChangePersonalDataSet()));
438         }
439
440         /**
441          * Clears user name
442          */
443         private void clearUserName () {
444                 // Clear it
445                 this.setUserName(null);
446         }
447
448         /**
449          * Clears both user passwords
450          */
451         private void clearUserPasswords () {
452                 // Clear both
453                 this.setUserPassword(null);
454                 this.setUserPasswordRepeat(null);
455         }
456
457         /**
458          * Creates an instance from all properties
459          * <p>
460          * @param createContactData Whether contact data should be created
461          * <p>
462          * @return A user instance
463          */
464         private User createUserInstance (final boolean createContactData) {
465                 // Required personal data must be set
466                 assert (this.isRequiredPersonalDataSet()) : "All required personal data must be set before invoking this method."; //NOI18N
467
468                 // Is user name required?
469                 if (!this.featureController.isFeatureEnabled("user_login_require_username")) {
470                         // Init variables
471                         String randomName = null;
472                         boolean isUsernameFree = false;
473
474                         // Get full list
475                         for (final User user : this.userListController.getAllUsers()) {
476                                 // Loop until a user name is found
477                                 while ((randomName == null) || (randomName.equals(user.getUserName()))) {
478                                         // Generate random name
479                                         randomName = Users.generateRandomUserName();
480                                         isUsernameFree = true;
481                                 }
482
483                                 // Is non-existing username found
484                                 if (isUsernameFree) {
485                                         // Also stop looping here
486                                         break;
487                                 }
488                         }
489
490                         // Set it and inivisible profile
491                         this.setUserName(randomName);
492                         this.setUserProfileMode(ProfileMode.INVISIBLE);
493
494                         // Generate random password
495                         final String randomPassword = UserLoginUtils.createRandomPassword(FinancialsUserWebRequestController.MINIMUM_PASSWORD_LENGTH);
496
497                         // Set random password
498                         this.setUserPassword(randomPassword);
499                         this.setUserPasswordRepeat(randomPassword);
500                 }
501
502                 // Create new user instance
503                 final User user = new LoginUser();
504
505                 // Set user name profile mode and locale
506                 user.setUserName(this.getUserName());
507                 user.setUserProfileMode(this.getUserProfileMode());
508                 user.setUserLocale(this.localizationController.getLocale());
509
510                 // Is multiple registration page
511                 if ((createContactData) || (!this.featureController.isFeatureEnabled("user_register_multiple_page"))) { //NOI18N
512                         // Create contact instance
513                         final Contact contact = this.contactController.createContactInstance();
514
515                         // Set contact in user
516                         user.setUserContact(contact);
517                 }
518
519                 // Return it
520                 return user;
521         }
522
523         /**
524          * Checks if both user passwords are left empty and if this is enabled
525          * (allowed) in context parameter. If true, the calling bean should create a
526          * random password (preferable with UserUtils.createRandomPassword() and set
527          * it in both user password fields.
528          * <p>
529          * @return Whether empty passwords are allowed
530          */
531         private boolean ifBothPasswordsEmptyAllowed () {
532                 // Check feature first
533                 return ((this.featureController.isFeatureEnabled("allow_user_registration_empty_password")) && //NOI18N
534                                 ((this.getUserPassword() == null) || (this.getUserPassword().isEmpty())) &&
535                                 ((this.getUserPasswordRepeat() == null) || (this.getUserPasswordRepeat().isEmpty())));
536         }
537
538         /**
539          * Checks whether all required personal data is set
540          * <p>
541          * @return Whether the required personal data is set
542          */
543         private boolean isRequiredPersonalDataSet () {
544                 // Check conditions based on of multi-page registration is enabled
545                 if (this.featureController.isFeatureEnabled("user_register_multiple_page")) { //NOI18N
546                         // Multiple registration page
547                         return this.contactController.isRequiredPersonalDataSet();
548                 } else {
549                         // Single registration page
550                         return (((this.getUserName() != null) || (!this.featureController.isFeatureEnabled("user_login_require_username"))) && //NOI18N
551                                         (this.getUserProfileMode() != null) &&
552                                         (this.contactController.isRequiredPersonalDataSet()) &&
553                                         (this.getUserPassword() != null) &&
554                                         (this.getUserPasswordRepeat() != null));
555                 }
556         }
557
558         /**
559          * Checks whether same passwords has been entered
560          * <p>
561          * @return Whether same passwords has been entered
562          */
563         private boolean isSamePasswordEntered () {
564                 return ((!this.getUserPassword().isEmpty()) && (Objects.equals(this.getUserPassword(), this.getUserPasswordRepeat())));
565         }
566
567 }