diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..feca8613 Binary files /dev/null and b/.DS_Store differ diff --git a/README-Jodi.md b/README-Jodi.md new file mode 100644 index 00000000..63b6d5ac --- /dev/null +++ b/README-Jodi.md @@ -0,0 +1,3 @@ +# Jodi Mitchell + +This is my Readme for my first commit. diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 00000000..7b0d3672 Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/main/.DS_Store b/src/main/.DS_Store new file mode 100644 index 00000000..508c44cb Binary files /dev/null and b/src/main/.DS_Store differ diff --git a/src/main/java/.DS_Store b/src/main/java/.DS_Store new file mode 100644 index 00000000..8ee47d97 Binary files /dev/null and b/src/main/java/.DS_Store differ diff --git a/src/main/java/edu/.DS_Store b/src/main/java/edu/.DS_Store new file mode 100644 index 00000000..293351a5 Binary files /dev/null and b/src/main/java/edu/.DS_Store differ diff --git a/src/main/java/edu/uark/.DS_Store b/src/main/java/edu/uark/.DS_Store new file mode 100644 index 00000000..f7da2170 Binary files /dev/null and b/src/main/java/edu/uark/.DS_Store differ diff --git a/src/main/java/edu/uark/registerapp/.DS_Store b/src/main/java/edu/uark/registerapp/.DS_Store new file mode 100644 index 00000000..0e5ff945 Binary files /dev/null and b/src/main/java/edu/uark/registerapp/.DS_Store differ diff --git a/src/main/java/edu/uark/registerapp/commands/activeUsers/ActiveUserDeleteCommand.java b/src/main/java/edu/uark/registerapp/commands/activeUsers/ActiveUserDeleteCommand.java new file mode 100644 index 00000000..ccd22837 --- /dev/null +++ b/src/main/java/edu/uark/registerapp/commands/activeUsers/ActiveUserDeleteCommand.java @@ -0,0 +1,38 @@ +package edu.uark.registerapp.commands.activeUsers; + +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import edu.uark.registerapp.commands.VoidCommandInterface; +import edu.uark.registerapp.models.entities.ActiveUserEntity; +import edu.uark.registerapp.models.repositories.ActiveUserRepository; + +@Service +public class ActiveUserDeleteCommand implements VoidCommandInterface { + @Transactional + @Override + public void execute() { + final Optional activeUserEntity = + this.activeUserRepository.findBySessionKey(this.sessionKey); + + if (activeUserEntity.isPresent()) { + this.activeUserRepository.delete(activeUserEntity.get()); + } + } + + // Properties + private String sessionKey; + public String getSessionKey() { + return this.sessionKey; + } + public ActiveUserDeleteCommand setSessionKey(final String sessionKey) { + this.sessionKey = sessionKey; + return this; + } + + @Autowired + private ActiveUserRepository activeUserRepository; +} diff --git a/src/main/java/edu/uark/registerapp/commands/activeUsers/ValidateActiveUserCommand.java b/src/main/java/edu/uark/registerapp/commands/activeUsers/ValidateActiveUserCommand.java new file mode 100644 index 00000000..d04784cb --- /dev/null +++ b/src/main/java/edu/uark/registerapp/commands/activeUsers/ValidateActiveUserCommand.java @@ -0,0 +1,41 @@ +package edu.uark.registerapp.commands.activeUsers; + +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import edu.uark.registerapp.commands.ResultCommandInterface; +import edu.uark.registerapp.commands.exceptions.UnauthorizedException; +import edu.uark.registerapp.models.entities.ActiveUserEntity; +import edu.uark.registerapp.models.repositories.ActiveUserRepository; + +@Service +public class ValidateActiveUserCommand implements ResultCommandInterface { + @Override + public ActiveUserEntity execute() { + final Optional activeUserEntity = + this.activeUserRepository.findBySessionKey(this.sessionKey); + + if (!activeUserEntity.isPresent()) { + throw new UnauthorizedException(); + } + + return activeUserEntity.get(); + } + + // Properties + private String sessionKey; + + public String getSessionKey() { + return this.sessionKey; + } + + public ValidateActiveUserCommand setSessionKey(final String sessionKey) { + this.sessionKey = sessionKey; + return this; + } + + @Autowired + private ActiveUserRepository activeUserRepository; +} diff --git a/src/main/java/edu/uark/registerapp/commands/employees/ActiveEmployeeExistsQuery.java b/src/main/java/edu/uark/registerapp/commands/employees/ActiveEmployeeExistsQuery.java new file mode 100644 index 00000000..9581f662 --- /dev/null +++ b/src/main/java/edu/uark/registerapp/commands/employees/ActiveEmployeeExistsQuery.java @@ -0,0 +1,21 @@ +package edu.uark.registerapp.commands.employees; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import edu.uark.registerapp.commands.VoidCommandInterface; +import edu.uark.registerapp.commands.exceptions.NotFoundException; +import edu.uark.registerapp.models.repositories.EmployeeRepository; + +@Service +public class ActiveEmployeeExistsQuery implements VoidCommandInterface { + @Override + public void execute() { + if (!this.employeeRepository.existsByIsActive(true)) { + throw new NotFoundException("Employee"); + } + } + + @Autowired + private EmployeeRepository employeeRepository; +} diff --git a/src/main/java/edu/uark/registerapp/commands/employees/EmployeeCreateCommand.java b/src/main/java/edu/uark/registerapp/commands/employees/EmployeeCreateCommand.java new file mode 100644 index 00000000..5471dfa5 --- /dev/null +++ b/src/main/java/edu/uark/registerapp/commands/employees/EmployeeCreateCommand.java @@ -0,0 +1,97 @@ +// This will create a new employee + +package edu.uark.registerapp.commands.employees; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import edu.uark.registerapp.commands.ResultCommandInterface; +import edu.uark.registerapp.commands.employees.helpers.EmployeeHelper; +import edu.uark.registerapp.commands.exceptions.UnprocessableEntityException; +import edu.uark.registerapp.models.api.Employee; +import edu.uark.registerapp.models.entities.EmployeeEntity; +import edu.uark.registerapp.models.enums.EmployeeClassification; +import edu.uark.registerapp.models.repositories.EmployeeRepository; + +@Service +public class EmployeeCreateCommand implements ResultCommandInterface { + @Override + public Employee execute() { + this.validateProperties(); + + // If this is the first employee to be added and make them the general manager + if (this.isInitialEmployee) { + this.apiEmployee.setClassification( + EmployeeClassification.GENERAL_MANAGER.getClassification()); + } + + // Create a new ENTITY object from the API object details. + final EmployeeEntity employeeEntity = + this.employeeRepository.save(new EmployeeEntity(this.apiEmployee)); + + // Synchronize information generated by the database upon INSERT. + this.apiEmployee.setId(employeeEntity.getId()); + // Only send the password over the network when modifying the database. + this.apiEmployee.setPassword(StringUtils.EMPTY); + // Only send the password over the network when modifying the database. + this.apiEmployee.setCreatedOn(employeeEntity.getCreatedOn()); + this.apiEmployee.setEmployeeId( + EmployeeHelper.padEmployeeId( + employeeEntity.getEmployeeId())); + + return this.apiEmployee; + } + + // Helper methods + // This checks the fields on the view. + // Will not accept if any of the fields are blank. + private void validateProperties() { + if (StringUtils.isBlank(this.apiEmployee.getFirstName())) { + throw new UnprocessableEntityException("first name"); + } + if (StringUtils.isBlank(this.apiEmployee.getLastName())) { + throw new UnprocessableEntityException("last name"); + } + if (StringUtils.isBlank(this.apiEmployee.getPassword())) { + throw new UnprocessableEntityException("password"); + } + + // If there is a single employee in the DB then select a position for the new addition + if (!this.isInitialEmployee + && (EmployeeClassification.map(this.apiEmployee.getClassification()) == EmployeeClassification.NOT_DEFINED)) { + + throw new UnprocessableEntityException("classification"); + } + } + + // Getters and Setters for the new employee + private Employee apiEmployee; + public Employee getApiEmployee() { + return this.apiEmployee; + } + public EmployeeCreateCommand setApiEmployee(final Employee apiEmployee) { + this.apiEmployee = apiEmployee; + return this; + } + + // Getters and Setters for the first employee, the general manager. + private boolean isInitialEmployee; + public boolean getIsInitialEmployee() { + return this.isInitialEmployee; + } + public EmployeeCreateCommand setIsInitialEmployee( + final boolean isInitialEmployee + ) { + + this.isInitialEmployee = isInitialEmployee; + return this; + } + + @Autowired + private EmployeeRepository employeeRepository; + + public EmployeeCreateCommand() { + this.isInitialEmployee = false; + } +} diff --git a/src/main/java/edu/uark/registerapp/commands/employees/EmployeeDeleteCommand.java b/src/main/java/edu/uark/registerapp/commands/employees/EmployeeDeleteCommand.java new file mode 100644 index 00000000..0e750082 --- /dev/null +++ b/src/main/java/edu/uark/registerapp/commands/employees/EmployeeDeleteCommand.java @@ -0,0 +1,44 @@ +// This will delete an employee by their employee ID + +package edu.uark.registerapp.commands.employees; + +import java.util.Optional; +import java.util.UUID; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import edu.uark.registerapp.commands.VoidCommandInterface; +import edu.uark.registerapp.commands.exceptions.NotFoundException; +import edu.uark.registerapp.models.entities.EmployeeEntity; +import edu.uark.registerapp.models.repositories.EmployeeRepository; + +@Service +public class EmployeeDeleteCommand implements VoidCommandInterface { + @Transactional + @Override + public void execute() { + final Optional employeeEntity = + this.employeeRepository.findById(this.employeeId);// Find the employee first + + if (!employeeEntity.isPresent()) { // No record with the associated record ID exists in the database. + throw new NotFoundException("Product"); + } + + this.employeeRepository.delete(employeeEntity.get()); // Delete the employee if found + } + + // Getters and Setters + private UUID employeeId; + public UUID getEmployeeId() { + return this.employeeId; + } + public EmployeeDeleteCommand setEmployeeId(final UUID productId) { + this.employeeId = productId; + return this; + } + + @Autowired + private EmployeeRepository employeeRepository; +} diff --git a/src/main/java/edu/uark/registerapp/commands/employees/EmployeeQuery.java b/src/main/java/edu/uark/registerapp/commands/employees/EmployeeQuery.java new file mode 100644 index 00000000..335f375b --- /dev/null +++ b/src/main/java/edu/uark/registerapp/commands/employees/EmployeeQuery.java @@ -0,0 +1,43 @@ +// Find employee by Id + +package edu.uark.registerapp.commands.employees; + +import java.util.Optional; +import java.util.UUID; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import edu.uark.registerapp.commands.ResultCommandInterface; +import edu.uark.registerapp.commands.exceptions.NotFoundException; +import edu.uark.registerapp.models.api.Employee; +import edu.uark.registerapp.models.entities.EmployeeEntity; +import edu.uark.registerapp.models.repositories.EmployeeRepository; + +@Service +public class EmployeeQuery implements ResultCommandInterface { + @Override + public Employee execute() { + final Optional employeeEntity = + this.employeeRepository.findById(this.employeeId); + + if (employeeEntity.isPresent()) { + return new Employee(employeeEntity.get()); + } else { + throw new NotFoundException("Employee"); + } + } + + // Getters and setters + private UUID employeeId; + public UUID getEmployeeId() { + return this.employeeId; + } + public EmployeeQuery setEmployeeId(final UUID employeeId) { + this.employeeId = employeeId; + return this; + } + + @Autowired + private EmployeeRepository employeeRepository; +} diff --git a/src/main/java/edu/uark/registerapp/commands/employees/EmployeeSignInCommand.java b/src/main/java/edu/uark/registerapp/commands/employees/EmployeeSignInCommand.java new file mode 100644 index 00000000..ad757154 --- /dev/null +++ b/src/main/java/edu/uark/registerapp/commands/employees/EmployeeSignInCommand.java @@ -0,0 +1,108 @@ +package edu.uark.registerapp.commands.employees; + +import java.util.Arrays; +import java.util.Optional; + +import javax.transaction.Transactional; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import edu.uark.registerapp.commands.ResultCommandInterface; +import edu.uark.registerapp.commands.employees.helpers.EmployeeHelper; +import edu.uark.registerapp.commands.exceptions.UnauthorizedException; +import edu.uark.registerapp.commands.exceptions.UnprocessableEntityException; +import edu.uark.registerapp.models.api.Employee; +import edu.uark.registerapp.models.api.EmployeeSignIn; +import edu.uark.registerapp.models.entities.ActiveUserEntity; +import edu.uark.registerapp.models.entities.EmployeeEntity; +import edu.uark.registerapp.models.repositories.ActiveUserRepository; +import edu.uark.registerapp.models.repositories.EmployeeRepository; + +@Service +public class EmployeeSignInCommand implements ResultCommandInterface { + @Override + public Employee execute() { + this.validateProperties(); + + return new Employee(this.SignInEmployee()); + } + + // Helper methods + private void validateProperties() { + if (StringUtils.isBlank(this.employeeSignIn.getEmployeeId())) { + throw new UnprocessableEntityException("employee ID"); + } + try { + Integer.parseInt(this.employeeSignIn.getEmployeeId()); + } catch (final NumberFormatException e) { + throw new UnprocessableEntityException("employee ID"); + } + if (StringUtils.isBlank(this.employeeSignIn.getPassword())) { + throw new UnprocessableEntityException("password"); + } + } + + @Transactional + private EmployeeEntity SignInEmployee() { + final Optional employeeEntity = + this.employeeRepository.findByEmployeeId( + Integer.parseInt(this.employeeSignIn.getEmployeeId())); + + if (!employeeEntity.isPresent() + || !Arrays.equals( + employeeEntity.get().getPassword(), + EmployeeHelper.hashPassword(this.employeeSignIn.getPassword())) + ) { + + throw new UnauthorizedException(); + } + + final Optional activeUserEntity = + this.activeUserRepository + .findByEmployeeId(employeeEntity.get().getId()); + + if (!activeUserEntity.isPresent()) { + this.activeUserRepository.save( + (new ActiveUserEntity()) + .setSessionKey(this.sessionId) + .setEmployeeId(employeeEntity.get().getId()) + .setClassification( + employeeEntity.get().getClassification()) + .setName( + employeeEntity.get().getFirstName() + .concat(" ") + .concat(employeeEntity.get().getLastName()))); + } else { + this.activeUserRepository.save( + activeUserEntity.get().setSessionKey(this.sessionId)); + } + + return employeeEntity.get(); + } + + // Properties + private EmployeeSignIn employeeSignIn; + public EmployeeSignIn getEmployeeSignIn() { + return this.employeeSignIn; + } + public EmployeeSignInCommand setEmployeeSignIn(final EmployeeSignIn employeeSignIn) { + this.employeeSignIn = employeeSignIn; + return this; + } + + private String sessionId; + public String getSessionId() { + return this.sessionId; + } + public EmployeeSignInCommand setSessionId(final String sessionId) { + this.sessionId = sessionId; + return this; + } + + @Autowired + private EmployeeRepository employeeRepository; + @Autowired + private ActiveUserRepository activeUserRepository; +} diff --git a/src/main/java/edu/uark/registerapp/commands/employees/EmployeeUpdateCommand.java b/src/main/java/edu/uark/registerapp/commands/employees/EmployeeUpdateCommand.java new file mode 100644 index 00000000..9919dc2c --- /dev/null +++ b/src/main/java/edu/uark/registerapp/commands/employees/EmployeeUpdateCommand.java @@ -0,0 +1,83 @@ +// This will update an employee + +package edu.uark.registerapp.commands.employees; + +import java.util.Optional; +import java.util.UUID; + +import javax.transaction.Transactional; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import edu.uark.registerapp.commands.ResultCommandInterface; +import edu.uark.registerapp.commands.exceptions.NotFoundException; +import edu.uark.registerapp.commands.exceptions.UnprocessableEntityException; +import edu.uark.registerapp.models.api.Employee; +import edu.uark.registerapp.models.entities.EmployeeEntity; +import edu.uark.registerapp.models.enums.EmployeeClassification; +import edu.uark.registerapp.models.repositories.EmployeeRepository; + +@Service +public class EmployeeUpdateCommand implements ResultCommandInterface { + @Override + public Employee execute() { + this.validateProperties(); + + this.updateEmployeeEntity(); + + return this.apiEmployee; + } + + // Exceptions for empty fields + private void validateProperties() { + if (StringUtils.isBlank(this.apiEmployee.getFirstName())) { + throw new UnprocessableEntityException("first name"); + } + if (StringUtils.isBlank(this.apiEmployee.getLastName())) { + throw new UnprocessableEntityException("last name"); + } + if (EmployeeClassification.map(this.apiEmployee.getClassification()) == EmployeeClassification.NOT_DEFINED) { + throw new UnprocessableEntityException("classification"); + } + } + + @Transactional + private void updateEmployeeEntity() { + final Optional queriedEmployeeEntity = + this.employeeRepository.findById(this.employeeId); + + if (!queriedEmployeeEntity.isPresent()) { + throw new NotFoundException("Employee"); // No record with the associated record ID exists in the database. + } + + this.apiEmployee = queriedEmployeeEntity.get() + .synchronize(this.apiEmployee); // Synchronize any incoming changes for UPDATE to the database. + + this.employeeRepository.save(queriedEmployeeEntity.get()); // Write, via an UPDATE, any changes to the database. + } + + // Getter and Setters for the universally unique Identifies that tuple + private UUID employeeId; + public UUID getEmployeeId() { + return this.employeeId; + } + public EmployeeUpdateCommand setEmployeeId(final UUID employeeId) { + this.employeeId = employeeId; + return this; + } + + // Getters and Setters for the API + private Employee apiEmployee; + public Employee getApiEmployee() { + return this.apiEmployee; + } + public EmployeeUpdateCommand setApiEmployee(final Employee apiEmployee) { + this.apiEmployee = apiEmployee; + return this; + } + + @Autowired + private EmployeeRepository employeeRepository; +} diff --git a/src/main/java/edu/uark/registerapp/commands/employees/helpers/EmployeeHelper.java b/src/main/java/edu/uark/registerapp/commands/employees/helpers/EmployeeHelper.java new file mode 100644 index 00000000..09a42fd1 --- /dev/null +++ b/src/main/java/edu/uark/registerapp/commands/employees/helpers/EmployeeHelper.java @@ -0,0 +1,35 @@ +package edu.uark.registerapp.commands.employees.helpers; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.apache.commons.lang3.StringUtils; + +public class EmployeeHelper { + public static String padEmployeeId(final int employeeId) { + final String employeeIdAsString = Integer.toString(employeeId); + + return ((employeeIdAsString.length() < EMPLOYEE_ID_MAXIMUM_LENGTH) + ? StringUtils.leftPad( + employeeIdAsString, + EMPLOYEE_ID_MAXIMUM_LENGTH, + "0") + : employeeIdAsString); + } + + // Hash password using message digest + public static byte[] hashPassword(final String password) { + try { + final MessageDigest messageDigest = + MessageDigest.getInstance("SHA-256"); + + messageDigest.update(password.getBytes()); + + return messageDigest.digest(); + } catch (final NoSuchAlgorithmException e) { + return new byte[0]; + } + } + + private static final int EMPLOYEE_ID_MAXIMUM_LENGTH = 5; +} \ No newline at end of file diff --git a/src/main/java/edu/uark/registerapp/controllers/.DS_Store b/src/main/java/edu/uark/registerapp/controllers/.DS_Store new file mode 100644 index 00000000..741eaa87 Binary files /dev/null and b/src/main/java/edu/uark/registerapp/controllers/.DS_Store differ diff --git a/src/main/java/edu/uark/registerapp/controllers/BaseRestController.java b/src/main/java/edu/uark/registerapp/controllers/BaseRestController.java new file mode 100644 index 00000000..2dee66e1 --- /dev/null +++ b/src/main/java/edu/uark/registerapp/controllers/BaseRestController.java @@ -0,0 +1,89 @@ +package edu.uark.registerapp.controllers; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; + +import edu.uark.registerapp.commands.activeUsers.ValidateActiveUserCommand; +import edu.uark.registerapp.commands.exceptions.ConflictException; +import edu.uark.registerapp.commands.exceptions.NotFoundException; +import edu.uark.registerapp.commands.exceptions.UnauthorizedException; +import edu.uark.registerapp.commands.exceptions.UnprocessableEntityException; +import edu.uark.registerapp.controllers.enums.QueryParameterMessages; +import edu.uark.registerapp.controllers.enums.QueryParameterNames; +import edu.uark.registerapp.controllers.enums.ViewNames; +import edu.uark.registerapp.models.api.ApiResponse; +import edu.uark.registerapp.models.entities.ActiveUserEntity; +import edu.uark.registerapp.models.enums.EmployeeClassification; + +public class BaseRestController extends BaseController { + protected ApiResponse redirectSessionNotActive( + final HttpServletResponse response + ) { + + response.setStatus(HttpStatus.FOUND.value()); + return (new ApiResponse()) + .setRedirectUrl( + ViewNames.SIGN_IN.getRoute().concat( + this.buildInitialQueryParameter( + QueryParameterNames.ERROR_CODE.getValue(), + QueryParameterMessages.SESSION_NOT_ACTIVE.getKeyAsString()))); + } + + protected ApiResponse redirectUserNotElevated( + final HttpServletRequest request, + final HttpServletResponse response + ) { + + return this.redirectUserNotElevated(request, response, ViewNames.MAIN_MENU.getRoute()); + } + + protected ApiResponse redirectUserNotElevated( + final HttpServletRequest request, + final HttpServletResponse response, + final String redirectRoute + ) { + + try { + final ActiveUserEntity activeUserEntity = + this.validateActiveUserCommand + .setSessionKey(request.getSession().getId()) + .execute(); + + if (activeUserEntity == null) { + return this.redirectSessionNotActive(response); + } else if (!EmployeeClassification.isElevatedUser(activeUserEntity.getClassification())) { + response.setStatus(HttpStatus.FOUND.value()); + + return (new ApiResponse()) + .setRedirectUrl( + redirectRoute.concat( + this.buildInitialQueryParameter( + QueryParameterNames.ERROR_CODE.getValue(), + QueryParameterMessages.NO_PERMISSIONS_FOR_ACTION.getKeyAsString()))); + } + } catch (final UnauthorizedException e) { + return this.redirectSessionNotActive(response); + } + + return new ApiResponse(); + } + + @ExceptionHandler({ + ConflictException.class, + NotFoundException.class, + UnauthorizedException.class, + UnprocessableEntityException.class + }) + public @ResponseBody ApiResponse handleError(final Exception e) { + return (new ApiResponse()).setErrorMessage(e.getMessage()); + } + + // Properties + @Autowired + private ValidateActiveUserCommand validateActiveUserCommand; +} diff --git a/src/main/java/edu/uark/registerapp/controllers/BaseRouteController.java b/src/main/java/edu/uark/registerapp/controllers/BaseRouteController.java new file mode 100644 index 00000000..58774f84 --- /dev/null +++ b/src/main/java/edu/uark/registerapp/controllers/BaseRouteController.java @@ -0,0 +1,117 @@ +package edu.uark.registerapp.controllers; + +import java.util.Map; +import java.util.Optional; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.servlet.ModelAndView; + +import edu.uark.registerapp.commands.activeUsers.ValidateActiveUserCommand; +import edu.uark.registerapp.commands.exceptions.UnauthorizedException; +import edu.uark.registerapp.controllers.enums.ViewModelNames; +import edu.uark.registerapp.controllers.enums.QueryParameterMessages; +import edu.uark.registerapp.controllers.enums.QueryParameterNames; +import edu.uark.registerapp.controllers.enums.ViewNames; +import edu.uark.registerapp.models.entities.ActiveUserEntity; +import edu.uark.registerapp.models.enums.EmployeeClassification; + +public abstract class BaseRouteController extends BaseController { + protected ModelAndView setErrorMessageFromQueryString( + ModelAndView modelAndView, + final Map queryParameters + ) { + + if (!queryParameters.containsKey(QueryParameterNames.ERROR_CODE.getValue())) { + return modelAndView; + } + + try { + modelAndView = + this.setErrorMessageFromQueryString( + modelAndView, + Integer.parseInt( + queryParameters.get( + QueryParameterNames.ERROR_CODE.getValue()))); + } catch (final NumberFormatException e) { } + + return modelAndView; + } + protected ModelAndView setErrorMessageFromQueryString( + final ModelAndView modelAndView, + final Optional errorCode + ) { + + if (!errorCode.isPresent()) { + return modelAndView; + } + + return this.setErrorMessageFromQueryString(modelAndView, errorCode.get()); + } + + protected Optional getCurrentUser( + final HttpServletRequest request + ) { + + try { + return Optional.of( + this.validateActiveUserCommand + .setSessionKey(request.getSession().getId()) + .execute()); + } catch (final UnauthorizedException e) { + return Optional.ofNullable(null); + } + } + + protected ModelAndView buildInvalidSessionResponse() { + return new ModelAndView( + REDIRECT_PREPEND.concat( + ViewNames.SIGN_IN.getRoute().concat( + this.buildInitialQueryParameter( + QueryParameterNames.ERROR_CODE.getValue(), + QueryParameterMessages.SESSION_NOT_ACTIVE.getKeyAsString())))); + } + + protected boolean isElevatedUser(final ActiveUserEntity activeUserEntity) { + return EmployeeClassification.isElevatedUser( + activeUserEntity.getClassification()); + } + + protected ModelAndView buildNoPermissionsResponse() { + return this.buildNoPermissionsResponse(ViewNames.MAIN_MENU.getRoute()); + } + + protected ModelAndView buildNoPermissionsResponse(final String redirectRoute) { + return new ModelAndView( + REDIRECT_PREPEND.concat( + redirectRoute.concat( + this.buildInitialQueryParameter( + QueryParameterNames.ERROR_CODE.getValue(), + QueryParameterMessages.NO_PERMISSIONS_TO_VIEW.getKeyAsString())))); + } + + protected static final String REDIRECT_PREPEND = "redirect:"; + + // Helper methods + private ModelAndView setErrorMessageFromQueryString( + final ModelAndView modelAndView, + final int errorCode + ) { + + final String errorMessage = QueryParameterMessages.mapMessage(errorCode); + + if (!StringUtils.isBlank(errorMessage)) { + modelAndView.addObject( + ViewModelNames.ERROR_MESSAGE.getValue(), + errorMessage); + } + + return modelAndView; + } + + // Properties + @Autowired + private ValidateActiveUserCommand validateActiveUserCommand; +} diff --git a/src/main/java/edu/uark/registerapp/controllers/EmployeeDetailRouteController.java b/src/main/java/edu/uark/registerapp/controllers/EmployeeDetailRouteController.java new file mode 100644 index 00000000..90ba211d --- /dev/null +++ b/src/main/java/edu/uark/registerapp/controllers/EmployeeDetailRouteController.java @@ -0,0 +1,148 @@ +package edu.uark.registerapp.controllers; + +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.ModelAndView; + +import edu.uark.registerapp.commands.employees.ActiveEmployeeExistsQuery; +import edu.uark.registerapp.commands.employees.EmployeeQuery; +import edu.uark.registerapp.commands.exceptions.NotFoundException; +import edu.uark.registerapp.controllers.enums.ViewModelNames; +import edu.uark.registerapp.controllers.enums.ViewNames; +import edu.uark.registerapp.models.api.Employee; +import edu.uark.registerapp.models.api.EmployeeType; +import edu.uark.registerapp.models.entities.ActiveUserEntity; + +@Controller +@RequestMapping(value = "/employeeDetail") +public class EmployeeDetailRouteController extends BaseRouteController { + @RequestMapping(method = RequestMethod.GET) + public ModelAndView start( + @RequestParam final Map queryParameters, + final HttpServletRequest request + ) { + + final boolean activeUserExists = this.activeUserExists(); + + //see if active user exists + if (activeUserExists) { + final Optional activeUserEntity = + this.getCurrentUser(request); + + if (!activeUserEntity.isPresent()) + { + return this.buildInvalidSessionResponse(); + } else if (!this.isElevatedUser(activeUserEntity.get())) + { + return this.buildNoPermissionsResponse(); + } + } + + return this.buildStartResponse(!activeUserExists, queryParameters); + } + + @RequestMapping(value = "/{employeeId}", method = RequestMethod.GET) + public ModelAndView startWithEmployee( + @PathVariable final UUID employeeId, + @RequestParam final Map queryParameters, + final HttpServletRequest request + ) { + + final Optional activeUserEntity = + this.getCurrentUser(request); + + if (!activeUserEntity.isPresent()) { + return this.buildInvalidSessionResponse(); + } else if (!this.isElevatedUser(activeUserEntity.get())) { + return this.buildNoPermissionsResponse(); + } + + return this.buildStartResponse(employeeId, queryParameters); + } + + // Helper methods + private boolean activeUserExists() { + try { + this.activeEmployeeExistsQuery.execute(); + return true; + } catch (final NotFoundException e) { + return false; + } + } + + private ModelAndView buildStartResponse( + final boolean isInitialEmployee, + final Map queryParameters + ) { + + return this.buildStartResponse( + isInitialEmployee, + (new UUID(0, 0)), + queryParameters); + } + + private ModelAndView buildStartResponse( + final UUID employeeId, + final Map queryParameters + ) { + + return this.buildStartResponse(false, employeeId, queryParameters); + } + + private ModelAndView buildStartResponse( + final boolean isInitialEmployee, + final UUID employeeId, + final Map queryParameters + ) { + + ModelAndView modelAndView = + this.setErrorMessageFromQueryString( + new ModelAndView(ViewNames.EMPLOYEE_DETAIL.getViewName()), + queryParameters); + + if (employeeId.equals(new UUID(0, 0))) { + modelAndView.addObject( + ViewModelNames.EMPLOYEE.getValue(), + (new Employee()).setIsInitialEmployee(isInitialEmployee)); + } else { + try { + modelAndView.addObject( + ViewModelNames.EMPLOYEE.getValue(), + this.employeeQuery + .setEmployeeId(employeeId) + .execute() + .setIsInitialEmployee(isInitialEmployee)); + } catch (final Exception e) { + modelAndView.addObject( + ViewModelNames.ERROR_MESSAGE.getValue(), + e.getMessage()); + modelAndView.addObject( + ViewModelNames.EMPLOYEE.getValue(), + (new Employee()).setIsInitialEmployee(isInitialEmployee)); + } + } + + modelAndView.addObject( + ViewModelNames.EMPLOYEE_TYPES.getValue(), + EmployeeType.allEmployeeTypes()); + + return modelAndView; + } + + // Properties + @Autowired + private EmployeeQuery employeeQuery; + + @Autowired + private ActiveEmployeeExistsQuery activeEmployeeExistsQuery; +} diff --git a/src/main/java/edu/uark/registerapp/controllers/EmployeeRestController.java b/src/main/java/edu/uark/registerapp/controllers/EmployeeRestController.java new file mode 100644 index 00000000..236a0291 --- /dev/null +++ b/src/main/java/edu/uark/registerapp/controllers/EmployeeRestController.java @@ -0,0 +1,100 @@ +package edu.uark.registerapp.controllers; + +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import edu.uark.registerapp.commands.employees.ActiveEmployeeExistsQuery; +import edu.uark.registerapp.commands.employees.EmployeeCreateCommand; +import edu.uark.registerapp.commands.employees.EmployeeUpdateCommand; +import edu.uark.registerapp.commands.exceptions.NotFoundException; +import edu.uark.registerapp.controllers.enums.QueryParameterNames; +import edu.uark.registerapp.controllers.enums.ViewNames; +import edu.uark.registerapp.models.api.ApiResponse; +import edu.uark.registerapp.models.api.Employee; + +@RestController +@RequestMapping(value = "/api/employee") +public class EmployeeRestController extends BaseRestController { + @RequestMapping(value = "/", method = RequestMethod.POST) + public @ResponseBody ApiResponse createEmployee( + @RequestBody final Employee employee, + final HttpServletRequest request, + final HttpServletResponse response + ) { + + boolean isInitialEmployee = false; + ApiResponse canCreateEmployeeResponse; + + try { + this.activeEmployeeExistsQuery.execute(); + + canCreateEmployeeResponse = + this.redirectUserNotElevated(request, response); + } catch (final NotFoundException e) { + isInitialEmployee = true; + canCreateEmployeeResponse = new ApiResponse(); + } + + if (!canCreateEmployeeResponse.getRedirectUrl().equals(StringUtils.EMPTY)) { + return canCreateEmployeeResponse; + } + + final Employee createdEmployee = + this.employeeCreateCommand + .setApiEmployee(employee) + .setIsInitialEmployee(isInitialEmployee) + .execute(); + + if (isInitialEmployee) { + createdEmployee + .setRedirectUrl( + ViewNames.SIGN_IN.getRoute().concat( + this.buildInitialQueryParameter( + QueryParameterNames.EMPLOYEE_ID.getValue(), + createdEmployee.getEmployeeId()))); + } + + return createdEmployee.setIsInitialEmployee(isInitialEmployee); + } + + @RequestMapping(value = "/{employeeId}", method = RequestMethod.PATCH) + public @ResponseBody ApiResponse updateEmployee( + @PathVariable final UUID employeeId, + @RequestBody final Employee employee, + final HttpServletRequest request, + final HttpServletResponse response + ) { + + final ApiResponse elevatedUserResponse = + this.redirectUserNotElevated(request, response); + if (!elevatedUserResponse.getRedirectUrl().equals(StringUtils.EMPTY)) { + return elevatedUserResponse; + } + + return this.employeeUpdateCommand + .setEmployeeId(employeeId) + .setApiEmployee(employee) + .execute(); + } + + // Properties + @Autowired + private EmployeeCreateCommand employeeCreateCommand; + + @Autowired + private EmployeeUpdateCommand employeeUpdateCommand; + + @Autowired + private ActiveEmployeeExistsQuery activeEmployeeExistsQuery; +} diff --git a/src/main/java/edu/uark/registerapp/controllers/MainMenuRouteController.java b/src/main/java/edu/uark/registerapp/controllers/MainMenuRouteController.java new file mode 100644 index 00000000..90cd6724 --- /dev/null +++ b/src/main/java/edu/uark/registerapp/controllers/MainMenuRouteController.java @@ -0,0 +1,52 @@ +package edu.uark.registerapp.controllers; + +//HttpServletRequest allows a servlet to get info about a client request +import javax.servlet.http.HttpServletRequest; +import java.util.Map; +import java.util.Optional; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.ModelAndView; + +import edu.uark.registerapp.controllers.enums.ViewModelNames; +import edu.uark.registerapp.controllers.enums.ViewNames; +import edu.uark.registerapp.models.entities.ActiveUserEntity; + +@Controller +@RequestMapping(value = "/mainMenu") +public class MainMenuRouteController extends BaseRouteController{ + //GET request with /mainMenu route/endpoint path + @RequestMapping(method = RequestMethod.GET) + //@RequestParam reads form data and binds it to the specified parameters; maps the request parameter to query parameter + //parameters for get request: Map and HttpServletRequest + //Map object is a collection of keyed-in elements using any type of key + public ModelAndView start( + @RequestParam final Map queryParameters, + final HttpServletRequest request) { + //if there's an active user in the current session, add any error messages received in requestParam to the view + //serve up the main menu view/doc + //ELSE: immediately redirect to the Sign-In view document with an appropriate error message + final Optional + activeUserEntity = + this.getCurrentUser(request); + if (!activeUserEntity.isPresent() + ) { + return this.buildInvalidSessionResponse(); + } + + ModelAndView modelAndView = + this.setErrorMessageFromQueryString( + new ModelAndView(ViewNames.MAIN_MENU.getViewName()), + queryParameters); + + modelAndView.addObject( + ViewModelNames.IS_ELEVATED_USER.getValue(), + this.isElevatedUser(activeUserEntity.get())); + + return modelAndView; + } +} + diff --git a/src/main/java/edu/uark/registerapp/controllers/ProductDetailRouteController.java b/src/main/java/edu/uark/registerapp/controllers/ProductDetailRouteController.java index f6f35713..96b28f7a 100644 --- a/src/main/java/edu/uark/registerapp/controllers/ProductDetailRouteController.java +++ b/src/main/java/edu/uark/registerapp/controllers/ProductDetailRouteController.java @@ -1,50 +1,94 @@ package edu.uark.registerapp.controllers; +import java.util.Map; // added +import java.util.Optional; // added import java.util.UUID; +import javax.servlet.http.HttpServletRequest; // added + import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; //added import org.springframework.web.servlet.ModelAndView; import edu.uark.registerapp.commands.products.ProductQuery; import edu.uark.registerapp.controllers.enums.ViewModelNames; import edu.uark.registerapp.controllers.enums.ViewNames; import edu.uark.registerapp.models.api.Product; +import edu.uark.registerapp.models.entities.ActiveUserEntity; // added +import edu.uark.registerapp.models.enums.EmployeeClassification; // added @Controller @RequestMapping(value = "/productDetail") -public class ProductDetailRouteController { +public class ProductDetailRouteController extends BaseRouteController { + // added extend BaseRouteController @RequestMapping(method = RequestMethod.GET) - public ModelAndView start() { - return (new ModelAndView(ViewNames.PRODUCT_DETAIL.getViewName())) - .addObject( - ViewModelNames.PRODUCT.getValue(), - (new Product()).setLookupCode(StringUtils.EMPTY).setCount(0)); + // added parameters to start + public ModelAndView start( + @RequestParam final Map queryParameters, + final HttpServletRequest request + ) { + final Optional activeUserEntity = + this.getCurrentUser(request); + if (!activeUserEntity.isPresent()) { + return this.buildInvalidSessionResponse(); + } else if (!this.isElevatedUser(activeUserEntity.get())) { + return this.buildNoPermissionsResponse( + ViewNames.PRODUCT_LISTING.getRoute()); + } + + final ModelAndView modelAndView = + this.setErrorMessageFromQueryString( + new ModelAndView(ViewNames.PRODUCT_DETAIL.getViewName()), + queryParameters); + + modelAndView.addObject( + ViewModelNames.IS_ELEVATED_USER.getValue(), + true); + modelAndView.addObject( + ViewModelNames.PRODUCT.getValue(), + (new Product()).setLookupCode(StringUtils.EMPTY).setCount(0)); + + return modelAndView; } @RequestMapping(value = "/{productId}", method = RequestMethod.GET) - public ModelAndView startWithProduct(@PathVariable final UUID productId) { - final ModelAndView modelAndView = - new ModelAndView(ViewNames.PRODUCT_DETAIL.getViewName()); - - try { - modelAndView.addObject( - ViewModelNames.PRODUCT.getValue(), - this.productQuery.setProductId(productId).execute()); - } catch (final Exception e) { - modelAndView.addObject( - ViewModelNames.ERROR_MESSAGE.getValue(), - e.getMessage()); - modelAndView.addObject( - ViewModelNames.PRODUCT.getValue(), - (new Product()) - .setCount(0) - .setLookupCode(StringUtils.EMPTY)); - } + public ModelAndView startWithProduct( + @PathVariable final UUID productId, + @RequestParam final Map queryParameters, + final HttpServletRequest request + ){ + final Optional activeUserEntity = this.getCurrentUser(request); + if(!activeUserEntity.isPresent()) + { + return this.buildInvalidSessionResponse(); + } + + final ModelAndView modelAndView = + this.setErrorMessageFromQueryString( + new ModelAndView(ViewNames.PRODUCT_DETAIL.getViewName()), queryParameters); + + modelAndView.addObject(ViewModelNames.IS_ELEVATED_USER.getValue(), + EmployeeClassification.isElevatedUser(activeUserEntity.get().getClassification())); + + try { + modelAndView.addObject( + ViewModelNames.PRODUCT.getValue(), + this.productQuery.setProductId(productId).execute()); + } catch (final Exception e) { + modelAndView.addObject( + ViewModelNames.ERROR_MESSAGE.getValue(), + e.getMessage()); + modelAndView.addObject( + ViewModelNames.PRODUCT.getValue(), + (new Product()) + .setCount(0) + .setLookupCode(StringUtils.EMPTY)); + } return modelAndView; } diff --git a/src/main/java/edu/uark/registerapp/controllers/ProductListingRouteController.java b/src/main/java/edu/uark/registerapp/controllers/ProductListingRouteController.java index 3c2a1178..e4e8164a 100644 --- a/src/main/java/edu/uark/registerapp/controllers/ProductListingRouteController.java +++ b/src/main/java/edu/uark/registerapp/controllers/ProductListingRouteController.java @@ -1,23 +1,46 @@ package edu.uark.registerapp.controllers; +import java.util.Map; +import java.util.Optional; + +import javax.servlet.http.HttpServletRequest; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import edu.uark.registerapp.commands.products.ProductsQuery; import edu.uark.registerapp.controllers.enums.ViewModelNames; import edu.uark.registerapp.controllers.enums.ViewNames; import edu.uark.registerapp.models.api.Product; +import edu.uark.registerapp.models.entities.ActiveUserEntity; @Controller -@RequestMapping(value = "/") -public class ProductListingRouteController { +@RequestMapping(value = "/productListing") +public class ProductListingRouteController extends BaseRouteController { @RequestMapping(method = RequestMethod.GET) - public ModelAndView showProductListing() { + public ModelAndView showProductListing( + @RequestParam final Map queryParameters, + final HttpServletRequest request + ) { + + final Optional activeUserEntity = + this.getCurrentUser(request); + if (!activeUserEntity.isPresent()) { + return buildInvalidSessionResponse(); + } + ModelAndView modelAndView = - new ModelAndView(ViewNames.PRODUCT_LISTING.getViewName()); + this.setErrorMessageFromQueryString( + new ModelAndView(ViewNames.PRODUCT_LISTING.getViewName()), + queryParameters); + + modelAndView.addObject( + ViewModelNames.IS_ELEVATED_USER.getValue(), + this.isElevatedUser(activeUserEntity.get())); try { modelAndView.addObject( @@ -38,4 +61,4 @@ public ModelAndView showProductListing() { // Properties @Autowired private ProductsQuery productsQuery; -} +} \ No newline at end of file diff --git a/src/main/java/edu/uark/registerapp/controllers/SignInRestController.java b/src/main/java/edu/uark/registerapp/controllers/SignInRestController.java new file mode 100644 index 00000000..96741f18 --- /dev/null +++ b/src/main/java/edu/uark/registerapp/controllers/SignInRestController.java @@ -0,0 +1,35 @@ +// Task 4 - Assigned to Ben Thiele +package edu.uark.registerapp.controllers; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import edu.uark.registerapp.commands.activeUsers.ActiveUserDeleteCommand; +import edu.uark.registerapp.controllers.enums.ViewNames; +import edu.uark.registerapp.models.api.ApiResponse; + +@RestController +@RequestMapping(value = "/api") +public class SignInRestController extends BaseRestController { + @RequestMapping(value="/signOut", method = RequestMethod.DELETE) + public @ResponseBody ApiResponse removeActiveUser( + final HttpServletRequest request + ) { + + this.activeUserDeleteCommand + .setSessionKey(request.getSession().getId()) + .execute(); + + return (new ApiResponse()) + .setRedirectUrl(ViewNames.SIGN_IN.getRoute()); + } + + // Properties + @Autowired + private ActiveUserDeleteCommand activeUserDeleteCommand; +} diff --git a/src/main/java/edu/uark/registerapp/controllers/SignInRouteController.java b/src/main/java/edu/uark/registerapp/controllers/SignInRouteController.java new file mode 100644 index 00000000..ec374a9b --- /dev/null +++ b/src/main/java/edu/uark/registerapp/controllers/SignInRouteController.java @@ -0,0 +1,95 @@ +// Task 4 - Assigned to Ben Thiele +package edu.uark.registerapp.controllers; + +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.ModelAndView; + +import edu.uark.registerapp.commands.employees.ActiveEmployeeExistsQuery; +import edu.uark.registerapp.commands.employees.EmployeeSignInCommand; +import edu.uark.registerapp.commands.exceptions.NotFoundException; +import edu.uark.registerapp.controllers.enums.QueryParameterNames; +import edu.uark.registerapp.controllers.enums.ViewModelNames; +import edu.uark.registerapp.controllers.enums.ViewNames; +import edu.uark.registerapp.models.api.EmployeeSignIn; + +@Controller // Defines Class as route handler +@RequestMapping(value = "/") // Maps class to url address +public class SignInRouteController extends BaseRouteController { + @RequestMapping(method = RequestMethod.GET) // Method responds to GET request + // Show sign in screen + public ModelAndView showSignIn( + @RequestParam final Map queryParameters // Extract query string + ) { + // Check if active employees exist, redirect to employee detail page if not + try { + this.activeEmployeeExistsQuery.execute(); + } catch (NotFoundException e) { + return new ModelAndView( + REDIRECT_PREPEND.concat( + ViewNames.EMPLOYEE_DETAIL.getRoute())); + } + //If active employees exist go to sign in + ModelAndView modelAndView = + this.setErrorMessageFromQueryString( + new ModelAndView(ViewNames.SIGN_IN.getViewName()), //Set view + queryParameters); + + if (queryParameters.containsKey(QueryParameterNames.EMPLOYEE_ID.getValue())) { + modelAndView.addObject( + ViewModelNames.EMPLOYEE_ID.getValue(), // Set model + queryParameters.get(QueryParameterNames.EMPLOYEE_ID.getValue())); + } + + return modelAndView; + } + + // Respond to POST request + @RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + public ModelAndView performSignIn( + EmployeeSignIn employeeSignIn, // Object to hold employee credentials + HttpServletRequest request + ) { + + try { + // Object validates employee information and session + // If fails, error message is displayed + this.employeeSignInCommand + .setSessionId(request.getSession().getId()) + .setEmployeeSignIn(employeeSignIn) + .execute(); + } catch (Exception e) { + ModelAndView modelAndView = + new ModelAndView(ViewNames.SIGN_IN.getViewName()); + + modelAndView.addObject( + ViewModelNames.ERROR_MESSAGE.getValue(), + e.getMessage()); + modelAndView.addObject( + ViewModelNames.EMPLOYEE_ID.getValue(), + employeeSignIn.getEmployeeId()); + + return modelAndView; + } + + // Successful login moves user to main menu + return new ModelAndView( + REDIRECT_PREPEND.concat( + ViewNames.MAIN_MENU.getRoute())); + } + + // Properties + @Autowired + private EmployeeSignInCommand employeeSignInCommand; + + @Autowired + private ActiveEmployeeExistsQuery activeEmployeeExistsQuery; +} diff --git a/src/main/java/edu/uark/registerapp/controllers/enums/QueryParameterMessages.java b/src/main/java/edu/uark/registerapp/controllers/enums/QueryParameterMessages.java new file mode 100644 index 00000000..3f1bed87 --- /dev/null +++ b/src/main/java/edu/uark/registerapp/controllers/enums/QueryParameterMessages.java @@ -0,0 +1,45 @@ +package edu.uark.registerapp.controllers.enums; + +import java.util.HashMap; +import java.util.Map; + +public enum QueryParameterMessages { + NOT_DEFINED(-1, ""), + SESSION_NOT_ACTIVE(1001, "The current user's session is no longer active."), + NO_PERMISSIONS_TO_VIEW(1101, "You do not have permission to view this resource."), + NO_PERMISSIONS_FOR_ACTION(1102, "You do not have permission to perform this action."); + + public int getKey() { + return this.key; + } + public String getKeyAsString() { + return Integer.toString(this.key); + } + public String getMessage() { + return this.message; + } + + public static String mapMessage(final int key) { + if (valueMap == null) { + valueMap = new HashMap(); + + for (final QueryParameterMessages status : QueryParameterMessages.values()) { + valueMap.put(status.getKey(), status.getMessage()); + } + } + + return (valueMap.containsKey(key) + ? valueMap.get(key) + : QueryParameterMessages.NOT_DEFINED.getMessage()); + } + + private int key; + private String message; + + private static Map valueMap = null; + + private QueryParameterMessages(final int key, final String message) { + this.key = key; + this.message = message; + } +} diff --git a/src/main/java/edu/uark/registerapp/controllers/enums/QueryParameterNames.java b/src/main/java/edu/uark/registerapp/controllers/enums/QueryParameterNames.java index 988a9c79..d20b0100 100644 --- a/src/main/java/edu/uark/registerapp/controllers/enums/QueryParameterNames.java +++ b/src/main/java/edu/uark/registerapp/controllers/enums/QueryParameterNames.java @@ -2,7 +2,8 @@ public enum QueryParameterNames { NOT_DEFINED(""), - ERROR_CODE("errorCode"); + ERROR_CODE("errorCode"), + EMPLOYEE_ID("employeeId"); public String getValue() { return value; diff --git a/src/main/java/edu/uark/registerapp/controllers/enums/ViewModelNames.java b/src/main/java/edu/uark/registerapp/controllers/enums/ViewModelNames.java index 7c39b102..fefde2fd 100644 --- a/src/main/java/edu/uark/registerapp/controllers/enums/ViewModelNames.java +++ b/src/main/java/edu/uark/registerapp/controllers/enums/ViewModelNames.java @@ -3,8 +3,12 @@ public enum ViewModelNames { NOT_DEFINED(""), ERROR_MESSAGE("errorMessage"), + IS_ELEVATED_USER("isElevatedUser"), PRODUCTS("products"), // Product listing - PRODUCT("product"); // Product detail + PRODUCT("product"), // Product detail + EMPLOYEE_ID("employeeId"), // Sign in + EMPLOYEE("employee"), // Employee detail + EMPLOYEE_TYPES("employeeTypes"); public String getValue() { return value; diff --git a/src/main/java/edu/uark/registerapp/controllers/enums/ViewNames.java b/src/main/java/edu/uark/registerapp/controllers/enums/ViewNames.java index cd1a1246..3e3e2ca2 100644 --- a/src/main/java/edu/uark/registerapp/controllers/enums/ViewNames.java +++ b/src/main/java/edu/uark/registerapp/controllers/enums/ViewNames.java @@ -1,8 +1,11 @@ package edu.uark.registerapp.controllers.enums; public enum ViewNames { + SIGN_IN("signIn", "/"), + MAIN_MENU("mainMenu"), PRODUCT_DETAIL("productDetail"), - PRODUCT_LISTING("productListing", "/"); + EMPLOYEE_DETAIL("employeeDetail"), + PRODUCT_LISTING("productListing"); public String getRoute() { return this.route; diff --git a/src/main/java/edu/uark/registerapp/models/api/Employee.java b/src/main/java/edu/uark/registerapp/models/api/Employee.java new file mode 100644 index 00000000..e05e76ca --- /dev/null +++ b/src/main/java/edu/uark/registerapp/models/api/Employee.java @@ -0,0 +1,149 @@ +// The API that talks to DB about the entity employee and gives back the data to the user. +package edu.uark.registerapp.models.api; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; + +import org.apache.commons.lang3.StringUtils; + +import edu.uark.registerapp.commands.employees.helpers.EmployeeHelper; +import edu.uark.registerapp.models.entities.EmployeeEntity; + +public class Employee extends ApiResponse { + private UUID id; + public UUID getId() { + return this.id; + } + + public Employee setId(final UUID id) { + this.id = id; + return this; + } + + private String employeeId; + public String getEmployeeId() { + return this.employeeId; + } + + //Part of task 3 + public Employee setEmployeeId(final int employeeId) { + this.employeeId = EmployeeHelper.padEmployeeId(employeeId); + return this; + } + public Employee setEmployeeId(final String employeeId) { + this.employeeId = employeeId; + return this; + } + + private String firstName; + public String getFirstName() { + return this.firstName; + } + public Employee setFirstName(final String firstName) { + this.firstName = firstName; + return this; + } + + private String lastName; + public String getLastName() { + return this.lastName; + } + public Employee setLastName(final String lastName) { + this.lastName = lastName; + return this; + } + + private String password; + public String getPassword() { + return this.password; + } + public Employee setPassword(final String password) { + this.password = password; + return this; + } + + private boolean isActive; + public boolean getIsActive() { + return this.isActive; + } + public Employee setIsActive(final boolean isActive) { + this.isActive = isActive; + return this; + } + + private int classification; + public int getClassification() { + return this.classification; + } + public Employee setClassification(final int classification) { + this.classification = classification; + return this; + } + + private UUID managerId; + public UUID getManagerId() { + return this.managerId; + } + public Employee setManagerId(final UUID managerId) { + this.managerId = managerId; + return this; + } + + private String createdOn; + public String getCreatedOn() { + return this.createdOn; + } + public Employee setCreatedOn(final String createdOn) { + this.createdOn = createdOn; + return this; + } + public Employee setCreatedOn(final LocalDateTime createdOn) { + this.createdOn = + createdOn.format(DateTimeFormatter.ofPattern("MM/dd/yyyy")); + + return this; + } + + private boolean isInitialEmployee; + public boolean getIsInitialEmployee() { + return this.isInitialEmployee; + } + public Employee setIsInitialEmployee(final boolean isInitialEmployee) { + this.isInitialEmployee = isInitialEmployee; + return this; + } + + public Employee() { + super(); + + this.isActive = true; + this.id = new UUID(0, 0); + this.classification = -1; + this.isInitialEmployee = false; + this.managerId = new UUID(0, 0); + this.lastName = StringUtils.EMPTY; + this.password = StringUtils.EMPTY; + this.firstName = StringUtils.EMPTY; + this.employeeId = StringUtils.EMPTY; + + this.setCreatedOn(LocalDateTime.now()); + } + + public Employee(final edu.uark.registerapp.models.entities.EmployeeEntity employeeEntity) { + super(false); + + this.isInitialEmployee = false; + this.id = employeeEntity.getId(); + this.password = StringUtils.EMPTY; + this.isActive = employeeEntity.getIsActive(); + this.lastName = employeeEntity.getLastName(); + this.firstName = employeeEntity.getFirstName(); + this.managerId = employeeEntity.getManagerId(); + this.classification = employeeEntity.getClassification(); + this.employeeId = + EmployeeHelper.padEmployeeId(employeeEntity.getEmployeeId()); + + this.setCreatedOn(employeeEntity.getCreatedOn()); + } +} \ No newline at end of file diff --git a/src/main/java/edu/uark/registerapp/models/api/EmployeeSignIn.java b/src/main/java/edu/uark/registerapp/models/api/EmployeeSignIn.java new file mode 100644 index 00000000..fa2a9279 --- /dev/null +++ b/src/main/java/edu/uark/registerapp/models/api/EmployeeSignIn.java @@ -0,0 +1,35 @@ +// Sprint 2 - Task 4. Assigned to Ben Thiele. Taken from sprint 2 example with slight reorganization. +package edu.uark.registerapp.models.api; + +import org.apache.commons.lang3.StringUtils; + +public class EmployeeSignIn { + // Instance Variables + private String employeeId; + private String password; + + // Constructor - Sets strings to empty. + public EmployeeSignIn() { + this.password = StringUtils.EMPTY; + this.employeeId = StringUtils.EMPTY; + } + + // Setters and Getters + public String getEmployeeId() { + return this.employeeId; + } + + public EmployeeSignIn setEmployeeId(final String employeeId) { + this.employeeId = employeeId; + return this; + } + + public String getPassword() { + return this.password; + } + + public EmployeeSignIn setPassword(final String password) { + this.password = password; + return this; + } +} diff --git a/src/main/java/edu/uark/registerapp/models/api/EmployeeType.java b/src/main/java/edu/uark/registerapp/models/api/EmployeeType.java new file mode 100644 index 00000000..f26c5f0e --- /dev/null +++ b/src/main/java/edu/uark/registerapp/models/api/EmployeeType.java @@ -0,0 +1,55 @@ +package edu.uark.registerapp.models.api; + +import org.apache.commons.lang3.StringUtils; + +import edu.uark.registerapp.models.enums.EmployeeClassification; + +public class EmployeeType { + private int classification; + public int getClassification() { + return this.classification; + } + public EmployeeType setClassification(final int classification) { + this.classification = classification; + return this; + } + + private String displayLabel; + + public String getDisplayLabel() { + return this.displayLabel; + } + + public EmployeeType setDisplayLabel(final String displayLabel) { + this.displayLabel = displayLabel; + return this; + } + + public static EmployeeType[] allEmployeeTypes() { + final EmployeeClassification[] employeeClassifications = + EmployeeClassification.values(); + final EmployeeType[] employeeTypes = + new EmployeeType[employeeClassifications.length]; + + for (int i = 0; i < employeeClassifications.length; i++) { + employeeTypes[i] = new EmployeeType(employeeClassifications[i]); + } + + return employeeTypes; + } + + public EmployeeType() { + this(-1, StringUtils.EMPTY); + } + + public EmployeeType(final EmployeeClassification employeeClassification) { + this( + employeeClassification.getClassification(), + employeeClassification.getDisplayLabel()); + } + + public EmployeeType(final int classification, final String displayLabel) { + this.displayLabel = displayLabel; + this.classification = classification; + } +} diff --git a/src/main/java/edu/uark/registerapp/models/entities/ActiveUserEntity.java b/src/main/java/edu/uark/registerapp/models/entities/ActiveUserEntity.java new file mode 100644 index 00000000..00b509ac --- /dev/null +++ b/src/main/java/edu/uark/registerapp/models/entities/ActiveUserEntity.java @@ -0,0 +1,92 @@ +// This is how we talk to the DB in the relation useractive +package edu.uark.registerapp.models.entities; + +import java.time.LocalDateTime; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.apache.commons.lang3.StringUtils; +import org.hibernate.annotations.Generated; +import org.hibernate.annotations.GenerationTime; + +@Entity +@Table(name="activeuser") // In the acitveuser relation +public class ActiveUserEntity { + @Id + @Column(name="id", updatable = false) // The id can not be changed + @GeneratedValue(strategy=GenerationType.AUTO) + private final UUID id; + + public UUID getId() { + return this.id; + } + + @Column(name = "employeeid") + private UUID employeeId; + + public UUID getEmployeeId() { + return this.employeeId; + } + + public ActiveUserEntity setEmployeeId(final UUID employeeId) { + this.employeeId = employeeId; + return this; + } + + @Column(name = "name") + private String name; + + public String getName() { + return this.name; + } + + public ActiveUserEntity setName(final String name) { + this.name = name; + return this; + } + + @Column(name = "classification") + private int classification; + + public int getClassification() { + return this.classification; + } + + public ActiveUserEntity setClassification(final int classification) { + this.classification = classification; + return this; + } + + @Column(name = "sessionkey") + private String sessionKey; + + public String getSessionKey() { + return this.sessionKey; + } + + public ActiveUserEntity setSessionKey(final String sessionKey) { + this.sessionKey = sessionKey; + return this; + } + + @Column(name="createdon", insertable=false, updatable = false) + @Generated(GenerationTime.INSERT) + private LocalDateTime createdOn; + public LocalDateTime getCreatedOn() { + return this.createdOn; + } + + public ActiveUserEntity() { + this.id = new UUID(0, 0); + this.classification = -1; + this.name = StringUtils.EMPTY; + this.employeeId = new UUID(0, 0); + this.sessionKey = StringUtils.EMPTY; + } +} \ No newline at end of file diff --git a/src/main/java/edu/uark/registerapp/models/entities/EmployeeEntity.java b/src/main/java/edu/uark/registerapp/models/entities/EmployeeEntity.java new file mode 100644 index 00000000..7b8194ce --- /dev/null +++ b/src/main/java/edu/uark/registerapp/models/entities/EmployeeEntity.java @@ -0,0 +1,165 @@ +package edu.uark.registerapp.models.entities; + +import java.time.LocalDateTime; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.apache.commons.lang3.StringUtils; +import org.hibernate.annotations.Generated; +import org.hibernate.annotations.GenerationTime; +import edu.uark.registerapp.commands.employees.helpers.EmployeeHelper; +import edu.uark.registerapp.models.api.Employee; + +@Entity +@Table(name="employee") +public class EmployeeEntity { + @Id + @Column(name="id", updatable = false) + @GeneratedValue(strategy=GenerationType.AUTO) + private final UUID id; + + public UUID getId() { + return this.id; + } + + @Column(name = "employeeid", insertable = false, updatable = false) + @Generated(GenerationTime.INSERT) + private int employeeId; + + public int getEmployeeId() { + return this.employeeId; + } + + @Column(name = "firstname") + private String firstName; + + public String getFirstName() { + return this.firstName; + } + + public EmployeeEntity setFirstName(final String firstName) { + this.firstName = firstName; + return this; + } + + @Column(name = "lastname") + private String lastName; + + public String getLastName() { + return this.lastName; + } + + public EmployeeEntity setLastName(final String lastName) { + this.lastName = lastName; + return this; + } + + @Column(name = "password") + private byte[] password; + + public byte[] getPassword() { + return this.password; + } + + public EmployeeEntity setPassword(final byte[] password) { + this.password = password; + return this; + } + + @Column(name = "active") + private boolean isActive; + + public boolean getIsActive() { + return this.isActive; + } + + public EmployeeEntity setIsActive(final boolean isActive) { + this.isActive = isActive; + return this; + } + + @Column(name = "classification") + private int classification; + + public int getClassification() { + return this.classification; + } + + public EmployeeEntity setClassification(final int classification) { + this.classification = classification; + return this; + } + + @Column(name = "managerid") + private UUID managerId; + + public UUID getManagerId() { + return this.managerId; + } + + public EmployeeEntity setManagerId(final UUID managerId) { + this.managerId = managerId; + return this; + } + + @Column(name = "createdon", insertable = false, updatable = false) + @Generated(GenerationTime.INSERT) + private LocalDateTime createdOn; + + public LocalDateTime getCreatedOn() { + return this.createdOn; + } + + public Employee synchronize(final Employee apiEmployee) { + this.setIsActive(apiEmployee.getIsActive()); + this.setLastName(apiEmployee.getLastName()); + this.setFirstName(apiEmployee.getFirstName()); + this.setClassification(apiEmployee.getClassification()); + if (apiEmployee.getManagerId() != null) { + this.setManagerId(apiEmployee.getManagerId()); + } + + //part of task 3 + if (!StringUtils.isBlank(apiEmployee.getPassword())) { + this.setPassword( + EmployeeHelper.hashPassword( + apiEmployee.getPassword())); + } + + apiEmployee.setId(this.getId()); + apiEmployee.setCreatedOn(this.getCreatedOn()); + apiEmployee.setEmployeeId(this.getEmployeeId()); + + return apiEmployee; + } + + public EmployeeEntity() { + this.employeeId = -1; + this.isActive = false; + this.id = new UUID(0, 0); + this.classification = -1; + this.password = new byte[0]; + this.managerId = new UUID(0, 0); + this.lastName = StringUtils.EMPTY; + this.firstName = StringUtils.EMPTY; + } + + public EmployeeEntity(final Employee apiEmployee) { + this.id = new UUID(0, 0); + this.isActive = apiEmployee.getIsActive(); + this.lastName = apiEmployee.getLastName(); + this.firstName = apiEmployee.getFirstName(); + this.classification = apiEmployee.getClassification(); + this.password = EmployeeHelper.hashPassword(apiEmployee.getPassword()); + this.managerId = ( + (apiEmployee.getManagerId() != null) + ? apiEmployee.getManagerId() + : new UUID(0, 0)); + } +} \ No newline at end of file diff --git a/src/main/java/edu/uark/registerapp/models/enums/EmployeeClassification.java b/src/main/java/edu/uark/registerapp/models/enums/EmployeeClassification.java new file mode 100644 index 00000000..7ff08f1c --- /dev/null +++ b/src/main/java/edu/uark/registerapp/models/enums/EmployeeClassification.java @@ -0,0 +1,58 @@ +package edu.uark.registerapp.models.enums; + +import java.util.HashMap; +import java.util.Map; + +public enum EmployeeClassification { + NOT_DEFINED(-1, "Not Selected"), + CASHIER(101, "Cashier"), + SHIFT_MANAGER(501, "Shift Manager"), + GENERAL_MANAGER(701, "General Manager"); + + public int getClassification() { + return this.classification; + } + + public String getDisplayLabel() { + return this.displayLabel; + } + + public static EmployeeClassification map(final int key) { + if (valueMap == null) { + valueMap = new HashMap(); + + for (final EmployeeClassification employeeClassification : EmployeeClassification.values()) { + valueMap.put( + employeeClassification.getClassification(), + employeeClassification); + } + } + + return ((valueMap.containsKey(key) + ? valueMap.get(key) + : EmployeeClassification.NOT_DEFINED)); + } + + public static boolean isElevatedUser(final int classification) { + final EmployeeClassification employeeClassification = + EmployeeClassification.map(classification); + + return ( + (employeeClassification == EmployeeClassification.GENERAL_MANAGER) + || (employeeClassification == EmployeeClassification.SHIFT_MANAGER)); + } + + private int classification; + private String displayLabel; + + private static Map valueMap = null; + + private EmployeeClassification( + final int classification, + final String displayLabel + ) { + + this.displayLabel = displayLabel; + this.classification = classification; + } +} \ No newline at end of file diff --git a/src/main/java/edu/uark/registerapp/models/repositories/ActiveUserRepository.java b/src/main/java/edu/uark/registerapp/models/repositories/ActiveUserRepository.java new file mode 100644 index 00000000..baece09b --- /dev/null +++ b/src/main/java/edu/uark/registerapp/models/repositories/ActiveUserRepository.java @@ -0,0 +1,15 @@ +// We will need this for the CRUD operations to find the employee Id and the session key of the acitve user + +package edu.uark.registerapp.models.repositories; + +import java.util.Optional; +import java.util.UUID; + +import org.springframework.data.repository.CrudRepository; + +import edu.uark.registerapp.models.entities.ActiveUserEntity; + +public interface ActiveUserRepository extends CrudRepository { + Optional findByEmployeeId(UUID employeeId); + Optional findBySessionKey(String sessionKey); +} \ No newline at end of file diff --git a/src/main/java/edu/uark/registerapp/models/repositories/EmployeeRepository.java b/src/main/java/edu/uark/registerapp/models/repositories/EmployeeRepository.java new file mode 100644 index 00000000..9575faa3 --- /dev/null +++ b/src/main/java/edu/uark/registerapp/models/repositories/EmployeeRepository.java @@ -0,0 +1,15 @@ +package edu.uark.registerapp.models.repositories; + +import java.util.Optional; +import java.util.UUID; + +import org.springframework.data.repository.CrudRepository; + +import edu.uark.registerapp.models.entities.EmployeeEntity; + +public interface EmployeeRepository extends CrudRepository { + boolean existsByIsActive(boolean isActive); + boolean existsByEmployeeId(int employeeId); + Optional findById(UUID id); + Optional findByEmployeeId(int employeeId); +} \ No newline at end of file diff --git a/src/main/resources/.DS_Store b/src/main/resources/.DS_Store new file mode 100644 index 00000000..0cb76803 Binary files /dev/null and b/src/main/resources/.DS_Store differ diff --git a/src/main/resources/static/.DS_Store b/src/main/resources/static/.DS_Store new file mode 100644 index 00000000..c71596a8 Binary files /dev/null and b/src/main/resources/static/.DS_Store differ diff --git a/src/main/resources/static/images/Sign-Out.png b/src/main/resources/static/images/Sign-Out.png new file mode 100644 index 00000000..82fe8695 Binary files /dev/null and b/src/main/resources/static/images/Sign-Out.png differ diff --git a/src/main/resources/static/images/signout-img.svg b/src/main/resources/static/images/signout-img.svg new file mode 100644 index 00000000..0c8c0350 --- /dev/null +++ b/src/main/resources/static/images/signout-img.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/static/scripts/employeeDetail.js b/src/main/resources/static/scripts/employeeDetail.js new file mode 100644 index 00000000..b8e22393 --- /dev/null +++ b/src/main/resources/static/scripts/employeeDetail.js @@ -0,0 +1,207 @@ +let hideEmployeeSavedAlertTimer = undefined; + +document.addEventListener("DOMContentLoaded", () => { + document.getElementById("saveButton") + .addEventListener("click", saveActionClick); + + const employeeFirstNameEditElement = + getEmployeeFirstNameEditElement(); + employeeFirstNameEditElement.focus(); + employeeFirstNameEditElement.select(); +}); + +// Save +function saveActionClick(event) { + if (!validateSave()) { + return; + } + + const saveActionElement = event.target; + saveActionElement.disabled = true; + + const employeeId = getEmployeeId(); + const employeeIdIsDefined = (employeeId.trim() !== ""); + const saveActionUrl = ("/api/employee/" + + (employeeIdIsDefined ? employeeId : "")); + const saveEmployeeRequest = { + id: employeeId, + managerId: getEmployeeManagerId(), + lastName: getEmployeeLastNameEditElement().value, + password: getEmployeePasswordEditElement().value, + firstName: getEmployeeFirstNameEditElement().value, + classification: getEmployeeTypeSelectElement().value + }; + + if (employeeIdIsDefined) { + ajaxPatch(saveActionUrl, saveEmployeeRequest, (callbackResponse) => { + saveActionElement.disabled = false; + + if (isSuccessResponse(callbackResponse)) { + completeSaveAction(callbackResponse); + } + }); + } else { + ajaxPost(saveActionUrl, saveEmployeeRequest, (callbackResponse) => { + saveActionElement.disabled = false; + + if (isSuccessResponse(callbackResponse)) { + completeSaveAction(callbackResponse); + } + }); + } +} + + +//task 10 validation of client info +function validateSave() { + const firstNameEditElement = getEmployeeFirstNameEditElement(); + + //error display for first name + if (firstNameEditElement.value.trim() === "") + { + displayError("Please provide a valid employee first name."); + //focus and reset + firstNameEditElement.focus(); + firstNameEditElement.select(); + return false; + } + + //error display for last name + const lastNameEditElement = getEmployeeLastNameEditElement(); + if (lastNameEditElement.value.trim() === "") + { + displayError("Please provide a valid employee last name."); + //focus and select + lastNameEditElement.focus(); + lastNameEditElement.select(); + return false; + } + + //error display for password if blank + const passwordEditElement = getEmployeePasswordEditElement(); + if (passwordEditElement.value.trim() === "") + { + displayError("Please provide a valid employee password."); + //focus and select + passwordEditElement.focus(); + passwordEditElement.select(); + return false; + } + + //error display for password + if (passwordEditElement.value !== getEmployeeConfirmPassword()) + { + displayError("Passwords do not match."); + //focus and select + passwordEditElement.focus() + passwordEditElement.select(); + return false; + } + + const employeeTypeSelectElement = getEmployeeTypeSelectElement(); + + //error display for employee type + if (!employeeTypeSelectElement.closest("tr").classList.contains("hidden")) + { + if (employeeTypeSelectElement.value <= 0) + { + displayError("Please provide a valid employee Type."); + //focus + employeeTypeSelectElement.focus(); + return false; + } + } + + return true; +} + +//Save employee info and flag it so there's no more editing +function completeSaveAction(callbackResponse) { + if (callbackResponse.data == null) { + return; + } + + if ((callbackResponse.data.redirectUrl != null) + && (callbackResponse.data.redirectUrl !== "")) { + + window.location.replace(callbackResponse.data.redirectUrl); + return; + } + + displayEmployeeSavedAlertModal(); + + const employeeEmployeeIdElement = getEmployeeEmployeeIdElement(); + const employeeEmployeeIdRowElement = employeeEmployeeIdElement.closest("tr"); + if (employeeEmployeeIdRowElement.classList.contains("hidden")) + { + setEmployeeId(callbackResponse.data.id); + employeeEmployeeIdElement.value = callbackResponse.data.employeeId; + employeeEmployeeIdRowElement.classList.remove("hidden"); + } +} + +function displayEmployeeSavedAlertModal() { + if (hideEmployeeSavedAlertTimer) { + clearTimeout(hideEmployeeSavedAlertTimer); + } + + const savedAlertModalElement = getSavedAlertModalElement(); + savedAlertModalElement.style.display = "none"; + savedAlertModalElement.style.display = "block"; + + hideEmployeeSavedAlertTimer = setTimeout(hideEmployeeSavedAlertModal, 1200); +} + +//hide after saving +function hideEmployeeSavedAlertModal() { + if (hideEmployeeSavedAlertTimer) { + clearTimeout(hideEmployeeSavedAlertTimer); + } + + getSavedAlertModalElement().style.display = "none"; +} +// End save + +//Getters and setters +function getEmployeeId() { + return document.getElementById("employeeId").value; +} +function setEmployeeId(employeeId) { + document.getElementById("employeeId").value = employeeId; +} + +function getEmployeeManagerId() { + return document.getElementById("employeeManagerId").value; +} + +function getEmployeeEmployeeId() { + return getEmployeeEmployeeIdElement().value; +} +function getEmployeeEmployeeIdElement() { + return document.getElementById("employeeEmployeeId"); +} + +function getSavedAlertModalElement() { + return document.getElementById("employeeSavedAlertModal"); +} + +function getEmployeeFirstNameEditElement() { + return document.getElementById("employeeFirstName"); +} + +function getEmployeeLastNameEditElement() { + return document.getElementById("employeeLastName"); +} + +function getEmployeePasswordEditElement() { + return document.getElementById("employeePassword"); +} + +function getEmployeeConfirmPassword() { + return document.getElementById("employeeConfirmPassword").value; +} + +function getEmployeeTypeSelectElement() { + return document.getElementById("employeeType"); +} +//End getters and setters diff --git a/src/main/resources/static/scripts/mainMenu.js b/src/main/resources/static/scripts/mainMenu.js new file mode 100644 index 00000000..e3777091 --- /dev/null +++ b/src/main/resources/static/scripts/mainMenu.js @@ -0,0 +1,43 @@ +document.addEventListener("DOMContentLoaded", function(event) { + getStartTransactionActionElement().addEventListener( + "click", + () => { displayError("Functionality has not yet been implemented."); }); + + getViewProductsActionElement().addEventListener( + "click", + () => { window.location.assign("/productListing"); }); + + getCreateEmployeeActionElement().addEventListener( + "click", + () => { window.location.assign("/employeeDetail"); }); + + getProductSalesReportActionElement().addEventListener( + "click", + () => { displayError("Functionality has not yet been implemented."); }); + + getCashierSalesReportActionElement().addEventListener( + "click", + () => { displayError("Functionality has not yet been implemented."); }); + +}); + +// Getters and setters +function getViewProductsActionElement() { + return document.getElementById("viewProducts"); +} + +function getCreateEmployeeActionElement() { + return document.getElementById("createEmployee"); +} + +function getStartTransactionActionElement() { + return document.getElementById("startTransaction"); +} + +function getProductSalesReportActionElement() { + return document.getElementById("salesReport"); +} + +function getCashierSalesReportActionElement() { + return document.getElementById("cashiersReport"); +} \ No newline at end of file diff --git a/src/main/resources/static/scripts/master.js b/src/main/resources/static/scripts/master.js index 88b039d0..a990676c 100644 --- a/src/main/resources/static/scripts/master.js +++ b/src/main/resources/static/scripts/master.js @@ -1,3 +1,10 @@ +document.addEventListener("DOMContentLoaded", () => { + const signOutActionElement = getSignOutActionElement(); + if (signOutActionElement != null) { + signOutActionElement.addEventListener("click", signOutActionClickHandler); + } +}); + // AJAX function ajaxGet(resourceRelativeUri, callback) { return ajax(resourceRelativeUri, "GET", null, callback); @@ -19,10 +26,12 @@ function ajaxDelete(resourceRelativeUri, callback) { return ajax(resourceRelativeUri, "DELETE", null, callback); } +//ajax method to use in saving employee details function ajax(resourceRelativeUri, verb, data, callback) { const httpRequest = new XMLHttpRequest(); - if (httpRequest == null) { + if (httpRequest == null) + { return httpRequest; } @@ -158,6 +167,10 @@ function displayError(errorMessage) { // End display error message //Getters and setters +function getSignOutActionElement() { + return document.getElementById("signOutImage"); +} + function getErrorMessageContainerElement() { return document.getElementById("error"); } @@ -166,3 +179,30 @@ function getErrorMessageDisplayElement() { return document.getElementById("errorMessage"); } // End getters and setters + +//Sign out +function signOutActionClickHandler() { + ajaxDelete("/api/signOut", (callbackResponse) => { + if ((callbackResponse.data != null) + && (callbackResponse.data.redirectUrl != null) + && (callbackResponse.data.redirectUrl !== "")) { + + window.location.replace(callbackResponse.data.redirectUrl); + } else { + window.location.replace("/"); + } + }); +} +//End sign out + +// Menu button function +document.addEventListener("DOMContentLoaded", function(event) { + goToMenu().addEventListener( + "click", + () => { window.location.assign("/mainMenu"); }); +}); + +function goToMenu() +{ + return document.getElementById("menuButton"); +} \ No newline at end of file diff --git a/src/main/resources/static/scripts/signin.js b/src/main/resources/static/scripts/signin.js new file mode 100644 index 00000000..88b2a2ee --- /dev/null +++ b/src/main/resources/static/scripts/signin.js @@ -0,0 +1,90 @@ +//Task 3 - Sign in verification + +document.addEventListener("DOMContentLoaded", function(event) { + + const employeeIdEditElement = getEmployeeIdEditElement(); + + employeeIdEditElement.focus(); + + employeeIdEditElement.select(); + +}); + + + +function validateForm() { + + const employeeIdEditElement = getEmployeeIdEditElement(); + + //Check the id + if (isNaN(Number(employeeIdEditElement.value)) + + || (Number(employeeIdEditElement.value) <= 0)) { + + + + displayError("Please provide a valid employee ID. Please try again."); + + + + employeeIdEditElement.focus(); + + employeeIdEditElement.select(); + + + + return false; + + } + + + + const passwordEditElement = getPasswordEditElement(); + + //check to see if password is equal to null + + if ((passwordEditElement.value == null) + + || (passwordEditElement.value.trim() === "")) { + + + + displayError("Please provide a valid password. It may not be blank. Please try again."); + + + + passwordEditElement.focus(); + + passwordEditElement.select(); + + + + return false; + + } + + + + return true; + +} + + + +//Getters and setters + +function getPasswordEditElement() { + + return document.getElementById("password"); + +} + + + +function getEmployeeIdEditElement() { + + return document.getElementById("employeeId"); + +} + +//End getters and setters diff --git a/src/main/resources/static/styles/master.css b/src/main/resources/static/styles/master.css index 2b060e6d..585a4a08 100644 --- a/src/main/resources/static/styles/master.css +++ b/src/main/resources/static/styles/master.css @@ -1,3 +1,36 @@ +/* Beginning of menu style */ +.container { + display: inline-block; + cursor: pointer; + } + + .bar1, .bar2, .bar3 { + width: 35px; + height: 5px; + background-color: #333; + margin: 6px 0; + transition: 0.4s; + } + /* End of menu style */ + +div.footer { + left: 0; + right: 0; + bottom: 0; + position: absolute; +} + +img.footer { + z-index: 1; + height: 50px; + text-decoration: none; + display: inline-block; + cursor: pointer; + position: fixed; + right: 20; + bottom: 20; +} + div.header { padding-top: 1px; text-align: right; diff --git a/src/main/resources/templates/employeeDetail.html b/src/main/resources/templates/employeeDetail.html new file mode 100644 index 00000000..f5f7bde7 --- /dev/null +++ b/src/main/resources/templates/employeeDetail.html @@ -0,0 +1,121 @@ + + + + Register - Employee + + + + + + + + + + + +
+

Employee Detail

+
+ +
+ +
+

+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Employee ID: + + +
First Name: + +
Last Name: + + +
Password: + + +
Confirm Password: + + +
Employee Type: + + +
+
+ +
+
+ + +
+ + + +
+ + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/mainMenu.html b/src/main/resources/templates/mainMenu.html new file mode 100644 index 00000000..a07afacc --- /dev/null +++ b/src/main/resources/templates/mainMenu.html @@ -0,0 +1,62 @@ + + + + Register - Main Menu + + + + + + + + + + +
+

Main Menu

+
+ +
+
+

+
+ + +
+ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/productDetail.html b/src/main/resources/templates/productDetail.html index ac183115..4b3e5248 100644 --- a/src/main/resources/templates/productDetail.html +++ b/src/main/resources/templates/productDetail.html @@ -12,6 +12,11 @@ +

Product Detail

@@ -34,27 +39,27 @@

Lookup Code: - + Count: - +
-
+

- +

- +
+ + diff --git a/src/main/resources/templates/productListing.html b/src/main/resources/templates/productListing.html index c4b758ae..6fd1a6db 100644 --- a/src/main/resources/templates/productListing.html +++ b/src/main/resources/templates/productListing.html @@ -12,6 +12,12 @@ + +

Products Listing

@@ -22,7 +28,7 @@

-
+ @@ -54,6 +60,10 @@

+ + diff --git a/src/main/resources/templates/signIn.html b/src/main/resources/templates/signIn.html new file mode 100644 index 00000000..6f4c3994 --- /dev/null +++ b/src/main/resources/templates/signIn.html @@ -0,0 +1,41 @@ + + + + Register - Sign In + + + + + + + + + + +
+

Sign In

+
+ +
+
+

+
+ +
+
+ +
+
+
+ +
+

+
+ +
+
+
+ + + + \ No newline at end of file diff --git a/src/test/java/edu/uark/registerapp/RegisterappApplicationTests.java b/src/main/test/java/edu/uark/registerapp/RegisterappApplicationTests.java similarity index 100% rename from src/test/java/edu/uark/registerapp/RegisterappApplicationTests.java rename to src/main/test/java/edu/uark/registerapp/RegisterappApplicationTests.java