package br.gov.servicos.editor.usuarios;
import br.com.caelum.stella.format.CPFFormatter;
import br.gov.servicos.editor.frontend.Siorg;
import br.gov.servicos.editor.security.TipoPermissao;
import br.gov.servicos.editor.security.UserProfiles;
import br.gov.servicos.editor.usuarios.cadastro.FormularioUsuario;
import br.gov.servicos.editor.usuarios.recuperarsenha.RecuperacaoSenhaService;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Marker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.validation.Valid;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import static br.gov.servicos.editor.security.TipoPermissao.CADASTRAR_OUTROS_ORGAOS;
import static lombok.AccessLevel.PRIVATE;
import static net.logstash.logback.marker.Markers.append;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
@Slf4j
@Controller
@FieldDefaults(level = PRIVATE, makeFinal = true)
public class GerenciarUsuarioController {
public static final String COMPLETAR_CADASTRO = "completarCadastro";
public static final String RECUPERAR_SENHA = "recuperarSenha";
UsuarioFactory factory;
UsuarioService usuarioService;
PapelRepository papeis;
RecuperacaoSenhaService tokenService;
Siorg siorg;
UserProfiles userProfiles;
CPFFormatter cpfFormatter = new CPFFormatter();
@Autowired
public GerenciarUsuarioController(UsuarioFactory factory, UsuarioService usuarioService, PapelRepository papeis, RecuperacaoSenhaService tokenService, Siorg siorg, UserProfiles userProfiles) {
this.factory = factory;
this.usuarioService = usuarioService;
this.papeis = papeis;
this.tokenService = tokenService;
this.siorg = siorg;
this.userProfiles = userProfiles;
}
@ModelAttribute("papeis")
public Iterable<Papel> popularPapeis() {
Iterable<Papel> todosPapeis = papeis.findAll();
return StreamSupport.stream(todosPapeis.spliterator(), false)
.filter(papel -> userProfiles.temPermissao(TipoPermissao.CADASTRAR.comPapel(papel.getNome())))
.collect(Collectors.toList());
}
@ModelAttribute("userProfiles")
public UserProfiles getUserProfiles() {
return userProfiles;
}
@ModelAttribute("siorg")
public Siorg getSiorg() {
return siorg;
}
@ModelAttribute("temPermissaoDeGerenciarUsuariosDeOutrosOrgaos")
public boolean temPermissaoDeGerenciarUsuariosDeOutrosOrgaos() {
return userProfiles.temPermissao(CADASTRAR_OUTROS_ORGAOS.getNome());
}
@RequestMapping(value = "/editar/usuarios")
public ModelAndView usuarios() {
Iterable<Usuario> usuarios = usuarioService.findAll();
ModelMap model = new ModelMap();
model.addAttribute("siorg", siorg);
model.addAttribute("usuarios", usuarios);
return new ModelAndView("usuarios", model);
}
@RequestMapping(value = "/editar/usuarios/usuario", method = POST)
public ModelAndView criar(@Valid FormularioUsuario formularioUsuario, BindingResult result) {
if (verificarPermissao(formularioUsuario)) {
throw new AccessDeniedException("Usuário sem permissão");
}
if (!result.hasErrors()) {
Usuario usuarioSalvo = usuarioService.save(factory.criarUsuario(formularioUsuario));
logUsuario("Usuario criado", usuarioSalvo);
return intrucoesParaRecuperarSenha(usuarioSalvo, COMPLETAR_CADASTRO);
} else {
ModelMap model = new ModelMap();
model.addAttribute("metodo", POST);
return new ModelAndView("cadastrar", model);
}
}
@RequestMapping(value = "/editar/usuarios/usuario", method = PUT)
public ModelAndView atualizar(@Valid FormularioUsuario formularioUsuario, BindingResult result) {
if (verificarPermissao(formularioUsuario)) {
throw new AccessDeniedException("Usuário sem permissão");
}
if (!result.hasErrors()) {
// TODO verificar se existe mais de um usuário com o mesmo cpf e lançar erro
Usuario usuario = usuarioService.findByCpf(cpfFormatter.unformat(formularioUsuario.getCpf()));
if (usuario != null) {
usuario = factory.atualizaUsuario(usuario, formularioUsuario);
} else {
throw new UsuarioInexistenteException();
}
Usuario usuarioSalvo = usuarioService.save(usuario);
logUsuario("Usuario atualizado", usuarioSalvo);
return usuarios();
} else {
ModelMap model = new ModelMap();
model.addAttribute("metodo", PUT);
return new ModelAndView("cadastrar", model);
}
}
@RequestMapping("/editar/usuarios/usuario")
public ModelAndView login(FormularioUsuario formularioUsuario) {
ModelMap model = new ModelMap();
model.addAttribute("formularioUsuario", formularioUsuario.withEhInclusaoDeUsuario(Boolean.TRUE));
model.addAttribute("metodo", POST);
return new ModelAndView("cadastrar", model);
}
@RequestMapping(value = "/editar/usuarios/usuario/{usuarioId}/habilitar-desabilitar", method = POST)
public String habilitarDesabilitarUsuario(@PathVariable("usuarioId") String usuarioId) {
Usuario usuario = usuarioService.habilitarDesabilitarUsuario(usuarioId);
logUsuario("Mudança de propriedade habilitado", usuario);
return "redirect:/editar/usuarios";
}
@RequestMapping(value = "/editar/usuarios/usuario/{usuarioId}/recuperar-senha", method = POST)
public ModelAndView requisitarTrocaSenha(@PathVariable("usuarioId") String usuarioId) {
Usuario usuario = usuarioService.findById(usuarioId);
return intrucoesParaRecuperarSenha(usuario, RECUPERAR_SENHA);
}
@RequestMapping(value = "/editar/usuarios/usuario/{usuarioId}/editar", method = POST)
public ModelAndView editarUsuario(@PathVariable("usuarioId") String usuarioId) {
Usuario usuario = usuarioService.findById(usuarioId);
FormularioUsuario formularioUsuario = factory.criaFormulario(usuario);
ModelMap model = new ModelMap();
model.addAttribute("formularioUsuario", formularioUsuario.withEhInclusaoDeUsuario(Boolean.FALSE));
model.addAttribute("metodo", PUT);
return new ModelAndView("cadastrar", model);
}
private boolean verificarPermissao(@Valid FormularioUsuario formularioUsuario) {
Papel papel = papeis.findById(Long.valueOf(formularioUsuario.getPapelId()));
return papel != null && !userProfiles.temPermissaoGerenciarUsuarioOrgaoEPapel(formularioUsuario.getSiorg(), papel.getNome());
}
private ModelAndView intrucoesParaRecuperarSenha(Usuario usuario, String pagina) {
ModelMap model = new ModelMap();
model.addAttribute("usuario", usuario);
model.addAttribute("link", gerarLinkParaRecuperacaoDeSenha(usuario.getId().toString(), pagina));
model.addAttribute("pagina", pagina);
logUsuario("Token gerado para trocar senha", usuario);
return new ModelAndView("instrucoes-recuperar-senha", model);
}
private String gerarLinkParaRecuperacaoDeSenha(String usuarioId, String pagina) {
String token = tokenService.gerarTokenParaUsuario(usuarioId);
return "/editar/recuperar-senha?token=" + token + "&usuarioId=" + usuarioId + "&pagina=" + pagina;
}
private static void logUsuario(String mensagem, Usuario usuario) {
Marker marker = append("usuario.id", usuario.getId())
.and(append("usuario.cpf", usuario.getCpf()))
.and(append("usuario.habilitado", usuario.isHabilitado()))
.and(append("usuario.nome", usuario.getNome()))
.and(append("usuario.papel", usuario.getPapel().getNome()))
.and(append("usuario.siorg", usuario.getSiorg()));
log.debug(marker, mensagem);
}
}