/**
* Personalfragebogen 2.0. Revolutionize form data entry for taxation and
* other purposes.
* Copyright (C) 2015 Attila Bujaki, Werner Sembach, Jonas Gröger, Oswaldo
* Bejarano, Ardhi Sutadi, Nikitha Mohan, Benedikt Rauh
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.fau.amos4.web;
import java.io.IOException;
import java.security.Principal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import de.fau.amos4.configuration.AppContext;
import de.fau.amos4.model.Client;
import de.fau.amos4.model.Employee;
import de.fau.amos4.model.fields.Denomination;
import de.fau.amos4.model.fields.HealthInsurance;
import de.fau.amos4.model.fields.MaritalStatus;
import de.fau.amos4.model.fields.NursingCareInsurance;
import de.fau.amos4.model.fields.Parenthood;
import de.fau.amos4.model.fields.PensionInsurance;
import de.fau.amos4.model.fields.Sex;
import de.fau.amos4.model.fields.TypeOfFixedTermContract;
import de.fau.amos4.model.fields.UnemploymentInsurance;
import de.fau.amos4.model.fields.YesNo;
import de.fau.amos4.service.ClientRepository;
import de.fau.amos4.service.ClientService;
import de.fau.amos4.service.EmployeeRepository;
import de.fau.amos4.service.EmployeeService;
import de.fau.amos4.util.CheckDataInput;
import de.fau.amos4.util.FormGenerator;
import de.fau.amos4.util.TokenGenerator;
@Controller
public class EmployeeFormController
{
private final EmployeeRepository employeeRepository;
private final ClientRepository clientRepository;
private final ClientService clientService;
private final EmployeeService employeeService;
/*
Constructor called at program start.
*/
@Autowired
public EmployeeFormController(EmployeeRepository employeeRepository, ClientRepository clientRepository, ClientService clientService, EmployeeService employeeService)
{
this.clientService = clientService;
this.employeeRepository = employeeRepository;
this.clientRepository = clientRepository;
this.employeeService = employeeService;
}
/*
EmployeeEdit handles employee/edit.html
It is invoked by the edit button in the client/dashboard.html
The client can edit the prefilled fields of one respective employee entry in the dashboard.
*/
@RequestMapping("/employee/edit")
public ModelAndView EmployeeEdit(HttpServletResponse response, @RequestParam(value = "id") long employeeId, Principal principal, Model model) throws IOException
{
ModelAndView mav = new ModelAndView();
mav.setViewName("employee/edit");
Employee employee = employeeRepository.findOne(employeeId);
FormGenerator generator = new FormGenerator();
mav.addObject("formInfo", generator.Generate(Employee.class, employee));
mav.addObject("id", employeeId);
mav.addObject("employee", employee);
// TODO: Move these 'enum' fields to a method with @ModelAttribute so that its available in the whole controller
// TODO: Consider if it makes sense to add that as an advice so that its available to all controllers application-wide
mav.addObject("allDisabled", YesNo.values());
mav.addObject("allMarital", MaritalStatus.values());
mav.addObject("allSex", Sex.values());
mav.addObject("allDenomination", Denomination.values());
mav.addObject("allTypeOfContract", TypeOfFixedTermContract.values());
mav.addObject("allHealthInsurance", HealthInsurance.values());
mav.addObject("allNursingCareInsurance", NursingCareInsurance.values());
mav.addObject("allPensionInsurance", PensionInsurance.values());
mav.addObject("allParenthood", Parenthood.values());
mav.addObject("addUnemploymentInsurance", UnemploymentInsurance.values());
return mav;
}
/*
EmployeeEditSubmit is invoked by the submit button in the employee/edit.html page.
Changes made there are stored in the database and the client gets redirected to client/dashboard.html.
*/
@RequestMapping("/employee/edit/submit")
public ModelAndView EmployeeEditSubmit(@ModelAttribute Employee employee, Principal principal)
{
ModelAndView mav = new ModelAndView();
FormGenerator generator = new FormGenerator();
mav.addObject("formInfo", generator.Generate(Employee.class, employee));
CheckDataInput cdi = new CheckDataInput();
// Fields with ValidFormat annotation and no content.
List<String> emptyFields = cdi.listEmptyFields(employee);
// Fields with ValidFormat annotation and not valid content based on the annotation regex.
List<String> invalidFields = cdi.listInvalidFields(employee);
// List of invalid and not empty fields
List<String> invalidNonEmptyFields = new ArrayList<String>();
invalidNonEmptyFields.addAll(invalidFields);
invalidNonEmptyFields.removeAll(emptyFields);
// If there is a not empty, invalid field, can't accept input.
if(invalidNonEmptyFields.size() > 0)
{
mav.addObject("invalidFieldErrorMessages", invalidNonEmptyFields);
mav.setViewName("employee/edit");
mav.addObject("preview", false);
return mav; // Display "/employee/edit" with error messages
}
else
{
// There is no invalid and non empty field. -> Accept input.
// Display warnings because of empty fields:
mav.addObject("emptyFields", emptyFields);
if (principal == null) {
mav.addObject("allDisabled", YesNo.values());
mav.addObject("allMarital", MaritalStatus.values());
mav.addObject("allSex", Sex.values());
mav.addObject("allDenomination", Denomination.values());
mav.addObject("allTypeOfContract", TypeOfFixedTermContract.values());
mav.addObject("allHealthInsurance", HealthInsurance.values());
mav.addObject("allNursingCareInsurance", NursingCareInsurance.values());
mav.addObject("allPensionInsurance", PensionInsurance.values());
mav.addObject("addUnemploymentInsurance", UnemploymentInsurance.values());
mav.addObject("allParenthood", Parenthood.values());;
mav.addObject("preview", true);
mav.setViewName("employee/edit");
return mav;
} else {
final String currentUser = principal.getName();
System.out.println("not null");
Client client = clientService.getClientByEmail(currentUser);
employee.setClient(client);
client.getEmployees().add(employee);
employeeRepository.save(employee);
clientRepository.save(client);
mav.setViewName("redirect:/client/dashboard");
// Redirect to AccountPage page
return mav;
}
}
}
/*
EmployeeTokenSubmit is invoked on click of the submit botton on employee/token.html
If the token is valid, the employee gets redirected to the prefilled employee/form.html to make changes on
the data associated with the token.
If the token is invalid, an error message shows up on the screen.
After a token is used, it becomes invalid.
*/
@RequestMapping("/employee/token/submit")
public ModelAndView EmployeeTokenSubmit(HttpServletResponse response, @RequestParam(value = "token", required = true) String token, Model model) throws IOException
{
long employeeId = 0;
Iterable<Employee> allEmployees = employeeRepository.findAll();
for (Iterator<Employee> i = allEmployees.iterator(); i.hasNext(); ) {
Employee currEmployee = i.next();
if( currEmployee.getToken().equals(token)) {
employeeId = currEmployee.getId();
}
}
ModelAndView mav = new ModelAndView();
if (employeeId != 0) {
mav.setViewName("employee/edit");
Employee employee = employeeRepository.findOne(employeeId);
FormGenerator generator = new FormGenerator();
mav.addObject("formInfo", generator.Generate(Employee.class, employee));
mav.addObject("id", employeeId);
mav.addObject("employee", employee);
mav.addObject("allDisabled", YesNo.values());
mav.addObject("allMarital", MaritalStatus.values());
mav.addObject("allSex", Sex.values());
mav.addObject("allDenomination", Denomination.values());
mav.addObject("allTypeOfContract", TypeOfFixedTermContract.values());
mav.addObject("allHealthInsurance", HealthInsurance.values());
mav.addObject("allNursingCareInsurance", NursingCareInsurance.values());
mav.addObject("allPensionInsurance", PensionInsurance.values());
mav.addObject("addUnemploymentInsurance", UnemploymentInsurance.values());
mav.addObject("allParenthood", Parenthood.values());
}
else {
mav.addObject("m", "invalid");
mav.setViewName("employee/token");
}
return mav;
}
@InitBinder
public void initBinder(WebDataBinder binder)
{
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("dd/MM/yyyy"), true, 10));
}
/*
EmployeeConfirm handles employee/confirm.html
Invoked by: Submit button in employee/preview.html
Apart from providing the opportunity to download the data as text file or pdf, the
previously entered data is stored in the database.
*/
@RequestMapping("/employee/confirm")
public String EmployeeConfirm(@ModelAttribute("employee") Employee employee,
BindingResult result, Model model) throws Exception
{
Employee e = employeeService.getEmployeeByToken(employee.getToken());
try
{
Client client = e.getClient();
if(client != null)
{
employee.setClient(client);
client.getEmployees().add(employee);
clientRepository.save(client);
}
}
catch(Exception ex)
{
System.out.println(ex.getMessage());
}
String token = TokenGenerator.getInstance().createUniqueToken(employeeRepository);
employee.setToken(token);
// If the employee is new: Create
// If the employee already has a primary key: Update
employeeRepository.save(employee);
// Setup model and return view
model.addAttribute("EmployeeId", employee.getId());
return "employee/confirm";
}
// Exception handling - Display exception information
@ExceptionHandler(Exception.class)
public ModelAndView handleError(HttpServletRequest req, Exception exception)
{
// TODO: Add logging!
ModelAndView mav = new ModelAndView();
mav.addObject("url", req.getRequestURL());
mav.addObject("message", exception.getMessage());
// TODO: Implement stacktrace display function.
return mav;
}
/*
Invoked by: Delete button on client/dashboard.html
The respective employee is deleted in the database, recovery is not possible
*/
@RequestMapping("/employee/delete")
public String EmployeeDelete(@RequestParam(value = "id", required = true) long employeeId)
{
//TODO: Security, allow deletion only for employees assigned to respective client.
// Remove employee with passed id
this.employeeRepository.delete(employeeId);
// Redirect to AccountPage page
return "redirect:/client/dashboard";
}
/*
Invoked by: New Employee link on client/dashboard.html
Creates a new employee in the database.
*/
@RequestMapping("/employee/new")
public String EmployeeNew(Principal principal)
{
// Create a new employee with default name
Employee employee = new Employee();
final String currentUser = principal.getName();
Client client = clientService.getClientByEmail(currentUser);
Locale locale = LocaleContextHolder.getLocale();
String newEmployee = AppContext.getApplicationContext().getMessage("EmployeeFormController.newEmployee", null, locale);
employee.setFamilyName(newEmployee);
employee.setClient(client);
String token = TokenGenerator.getInstance().createUniqueToken(employeeRepository);
employee.setToken(token);
client.getEmployees().add(employee);
employeeRepository.save(employee);
clientRepository.save(client);
// Redirect to AccountPage page
return "redirect:/client/dashboard";
}
@RequestMapping({"/employee/token", "/FrontPage"}) //FrontPage mapping is required by user story TODO ask PO's about this?
public String EmployeeToken(Model model) throws Exception
{
return "employee/token";
}
}