Commit dc1fcd80 by Joel Florentin

adjuntar archivo cv en form postulante

parent a5523490
...@@ -49,13 +49,13 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { ...@@ -49,13 +49,13 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
http http
// .csrf().disable() // .csrf().disable()
.authorizeRequests() .authorizeRequests()
.antMatchers("/").authenticated() .mvcMatchers("/").authenticated()
.antMatchers("/home").authenticated() .mvcMatchers("/home").authenticated()
.antMatchers("/cargo*").authenticated() .mvcMatchers("/cargo*").authenticated()
.antMatchers("/convocatoria*").authenticated() .mvcMatchers("/convocatoria*").authenticated()
.antMatchers("/tecnologia*").authenticated() .mvcMatchers("/tecnologia*").authenticated()
.antMatchers("/postulantes").authenticated() .mvcMatchers("/postulantes","/postulantes/**").authenticated()
.antMatchers("/edit-user-data").authenticated() .mvcMatchers("/edit-user-data").authenticated()
.anyRequest().permitAll() .anyRequest().permitAll()
.and() .and()
.formLogin() .formLogin()
......
package com.roshka.controller;
import java.util.ArrayList;
import java.util.List;
import com.roshka.DTO.PostulanteListaDTO;
import com.roshka.modelo.*;
import com.roshka.modelo.Disponibilidad;
import com.roshka.modelo.EstadoPostulante;
import com.roshka.modelo.Postulante;
import com.roshka.repositorio.*;
import com.roshka.repositorio.CiudadRepository;
import com.roshka.repositorio.ConvocatoriaRepository;
import com.roshka.repositorio.DepartamentoRepository;
import com.roshka.repositorio.ExperienciaRepository;
import com.roshka.repositorio.InstitucionRepository;
import com.roshka.repositorio.PostulanteRepository;
import com.roshka.repositorio.TecnologiaRepository;
import com.roshka.utils.Helper;
import org.hibernate.jpa.TypedParameterValue;
import org.hibernate.type.StringType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@Controller
public class PostulanteRRHHController {
PostulanteRepository post;
TecnologiaRepository tecRepo;
ExperienciaRepository expRepo;
InstitucionRepository institucionRepository;
DepartamentoRepository depRepo;
CiudadRepository ciuRepo;
EstudioRepository estudioRepository;
PostulanteTecnologiaRepository postulanteTecnologiaRepository;
ConvocatoriaRepository cargoRepo;
CargoRepository carRepo;
DBFileRepository fileRepo;
@Autowired
public PostulanteRRHHController(
PostulanteRepository post, TecnologiaRepository tecRepo, ExperienciaRepository expRepo,
InstitucionRepository institucionRepository, DepartamentoRepository depRepo,
CiudadRepository ciuRepo, EstudioRepository estudioRepository,
PostulanteTecnologiaRepository postulanteTecnologiaRepository,
ConvocatoriaRepository cargoRepo, CargoRepository carRepo, DBFileRepository fileRepo) {
this.post = post;
this.tecRepo = tecRepo;
this.expRepo = expRepo;
this.institucionRepository = institucionRepository;
this.depRepo = depRepo;
this.ciuRepo = ciuRepo;
this.estudioRepository = estudioRepository;
this.postulanteTecnologiaRepository = postulanteTecnologiaRepository;
this.cargoRepo =cargoRepo;
this.carRepo=carRepo;
this.fileRepo = fileRepo;
}
@RequestMapping("/postulantes")
public String postulantes(Model model,
@RequestParam(required = false)Long tecId,
@RequestParam(required = false)String nombre,
@RequestParam(required = false)EstadoPostulante estado,
@RequestParam(required = false)Disponibilidad dispo,
@RequestParam(required = false)Long lvlEng,
@RequestParam(required = false)Long lvlTec,
@RequestParam(required = false)Long instId,
@RequestParam(required = false)Long expInMonths,
@RequestParam(required = false)Long cargoId,
@RequestParam(required = false)Long convId,
@RequestParam(defaultValue = "0")Integer nroPagina
) {
final Integer CANTIDAD_POR_PAGINA = 5;
Pageable page = PageRequest.of(nroPagina,CANTIDAD_POR_PAGINA,Sort.by("id"));
model.addAttribute("tecnologias", tecRepo.findAll());
model.addAttribute("disponibilidades", Disponibilidad.values());
model.addAttribute("institucionesEducativas", institucionRepository.findAll());
model.addAttribute("estadoP", EstadoPostulante.values());
model.addAttribute("convocatoriaC", cargoRepo.findAll());
Page<Postulante> postulantesPag = post.postulantesMultiFiltro(nombre == null || nombre.trim().isEmpty() ? new TypedParameterValue(StringType.INSTANCE,null) : new TypedParameterValue(StringType.INSTANCE,"%"+nombre+"%"),dispo, lvlEng, lvlTec, tecId, instId,cargoId,page,estado,convId);
List<Postulante> postulantes = postulantesPag.getContent();
List<PostulanteListaDTO> postulantesDTO = new ArrayList<>();
for (Postulante postulante : postulantes) {
long expTotal = 0;
//Sumamos el tiempo de experiencia total en meses de cada postulante
//expTotal = postulante.getExperiencias().stream().mapToLong(e -> Helper.getMonthsDifference(e.getFechaDesde(), e.getFechaHasta())).sum();
for (Experiencia experiencia : postulante.getExperiencias()) {
expTotal += Helper.getMonthsDifference(experiencia.getFechaDesde(), experiencia.getFechaHasta());
}
if(expInMonths != null && expInMonths > expTotal) continue;
postulantesDTO.add(new PostulanteListaDTO(postulante.getId(), postulante.getNombre(), postulante.getApellido(), postulante.getDisponibilidad(), postulante.getNivelIngles(), expTotal, postulante.getTecnologias(),postulante.getEstadoPostulante(),postulante.getPostulaciones()));
}
model.addAttribute("pages", postulantesPag.getTotalPages());
model.addAttribute("postulantes", postulantesDTO);
return "postulantes";
}
@GetMapping({"/postulantes/{postulanteId}"})
public String getPostulanteDetalle(Model model, @PathVariable("postulanteId") Long postulanteId) {
Postulante p = post.findById(postulanteId).orElse(null);
model.addAttribute("postulante",p);
model.addAttribute("cvId", fileRepo.getIdByPostulante(p));
model.addAttribute("estadoP", EstadoPostulante.values());
return "detallepostulante";
}
@PostMapping({"/postulantes/{postulanteId}"})
public String setPostulanteEstado(@ModelAttribute Postulante postulante, BindingResult result, @PathVariable("postulanteId") Long postulanteId) {
//post.setPostulanteEstadoAndComentario(postulante.getEstadoPostulante(),postulante.getComentarioRRHH(), postulante.getId());
Postulante postulanteVd = post.getById(postulanteId);
postulanteVd.setEstadoPostulante(postulante.getEstadoPostulante());
postulanteVd.setComentarioRRHH(postulante.getComentarioRRHH());
post.setPostulanteEstadoAndComentario(postulante.getEstadoPostulante(), postulante.getComentarioRRHH(), postulanteId);
//post.save(postulanteVd);
return "redirect:/postulante/"+postulanteId;
}
@GetMapping("/postulantes/cvFile/{fileId}")
public ResponseEntity<Resource> downloadFile(@PathVariable String fileId) {
// Load file from database
DBFile dbFile;
try {
dbFile = fileRepo.findById(fileId)
.orElseThrow(() -> new Exception("File not found with id " + fileId));
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(dbFile.getFileType()))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + dbFile.getFileName() + "\"")
.body(new ByteArrayResource(dbFile.getData()));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return ResponseEntity.notFound().build();
}
}
}
\ No newline at end of file
package com.roshka.modelo;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name = "files")
public class DBFile {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
private String id;
private String fileName;
private String fileType;
@Lob
private byte[] data;
@OneToOne(mappedBy = "cvFile")
private Postulante postulante;
public DBFile() {
}
public DBFile(String fileName, String fileType, byte[] data) {
this.fileName = fileName;
this.fileType = fileType;
this.data = data;
}
public byte[] getData() {
return data;
}
public String getFileName() {
return fileName;
}
public String getFileType() {
return fileType;
}
public void setData(byte[] data) {
this.data = data;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public void setFileType(String fileType) {
this.fileType = fileType;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public Postulante getPostulante() {
return postulante;
}
public void setPostulante(Postulante postulante) {
this.postulante = postulante;
}
}
...@@ -66,8 +66,6 @@ public class Postulante { ...@@ -66,8 +66,6 @@ public class Postulante {
@Max(value = 5) @Max(value = 5)
private Long nivelIngles; private Long nivelIngles;
@Column(name = "curriculum")
private String curriculum;
@Column(name="estado_civil") @Column(name="estado_civil")
@NotNull @NotNull
...@@ -115,6 +113,11 @@ public class Postulante { ...@@ -115,6 +113,11 @@ public class Postulante {
) )
private List<ConvocatoriaCargo> postulaciones; private List<ConvocatoriaCargo> postulaciones;
@OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY)
@JoinColumn(name = "cvfile_id",referencedColumnName = "id")
@JsonIgnore
private DBFile cvFile;
public long getId() { public long getId() {
return id; return id;
...@@ -140,9 +143,6 @@ public class Postulante { ...@@ -140,9 +143,6 @@ public class Postulante {
this.apellido = apellido; this.apellido = apellido;
} }
public String getnroDocument() {
return nroDocument;
}
public void setnroDocument(String nroDocument) { public void setnroDocument(String nroDocument) {
this.nroDocument = nroDocument; this.nroDocument = nroDocument;
...@@ -192,16 +192,6 @@ public class Postulante { ...@@ -192,16 +192,6 @@ public class Postulante {
this.nivelIngles = nivelIngles; this.nivelIngles = nivelIngles;
} }
public String getCurriculum() {
return curriculum;
}
public void setCurriculum(String curriculum) {
this.curriculum = curriculum;
}
public Disponibilidad getDisponibilidad() { public Disponibilidad getDisponibilidad() {
return disponibilidad; return disponibilidad;
} }
...@@ -291,4 +281,13 @@ public class Postulante { ...@@ -291,4 +281,13 @@ public class Postulante {
public void setComentarioRRHH(String comentarioRRHH){ public void setComentarioRRHH(String comentarioRRHH){
this.comentarioRRHH=comentarioRRHH; this.comentarioRRHH=comentarioRRHH;
} }
public DBFile getCvFile() {
return cvFile;
}
public String getNroDocument() {
return nroDocument;
}
public void setCvFile(DBFile cvFile) {
this.cvFile = cvFile;
}
} }
package com.roshka.repositorio;
import com.roshka.modelo.DBFile;
import com.roshka.modelo.Postulante;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
@Repository
public interface DBFileRepository extends JpaRepository<DBFile, String> {
@Query("select db.id from DBFile db where db.postulante = ?1")
public String getIdByPostulante(Postulante postulante);
}
\ No newline at end of file
...@@ -26,3 +26,13 @@ spring.mail.properties.mail.smtp.starttls.enable=true ...@@ -26,3 +26,13 @@ spring.mail.properties.mail.smtp.starttls.enable=true
jsp-inheritance-prefix=/jsp/layouts/ jsp-inheritance-prefix=/jsp/layouts/
jsp-inheritance-suffix=.jsp jsp-inheritance-suffix=.jsp
## MULTIPART (MultipartProperties)
# Enable multipart uploads
spring.servlet.multipart.enabled=true
# Threshold after which files are written to disk.
spring.servlet.multipart.file-size-threshold=2KB
# Max file size.
spring.servlet.multipart.max-file-size=10MB
# Max Request Size
spring.servlet.multipart.max-request-size=10MB
\ No newline at end of file
...@@ -211,6 +211,12 @@ function serializeJSON (form) { ...@@ -211,6 +211,12 @@ function serializeJSON (form) {
return JSON.stringify(pairs, null, 2); return JSON.stringify(pairs, null, 2);
} }
function obtenerCV(){
let input = document.querySelector('#cvFile')
return input.files[0];
}
async function postData(url = '', data = {}) { async function postData(url = '', data = {}) {
var token = document.querySelector("meta[name='_csrf']").content; var token = document.querySelector("meta[name='_csrf']").content;
var headerxs = document.querySelector("meta[name='_csrf_header']").content; var headerxs = document.querySelector("meta[name='_csrf_header']").content;
...@@ -221,7 +227,7 @@ async function postData(url = '', data = {}) { ...@@ -221,7 +227,7 @@ async function postData(url = '', data = {}) {
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit credentials: 'same-origin', // include, *same-origin, omit
headers: { headers: {
'Content-Type': 'application/json', //'Content-Type': undefined//'application/json',
// 'Content-Type': 'application/x-www-form-urlencoded', // 'Content-Type': 'application/x-www-form-urlencoded',
}, },
redirect: 'follow', // manual, *follow, error redirect: 'follow', // manual, *follow, error
...@@ -232,6 +238,16 @@ async function postData(url = '', data = {}) { ...@@ -232,6 +238,16 @@ async function postData(url = '', data = {}) {
const response = await fetch(url, senddata); const response = await fetch(url, senddata);
return response; // parses JSON response into native JavaScript objects return response; // parses JSON response into native JavaScript objects
} }
function formatearJsonWithFile(json, file){
formData = new FormData();
formData.append("file", file);
formData.append('postulante', new Blob([json], {
type: "application/json"
}));
return formData
}
formValidator() formValidator()
form = document.querySelector("form"); form = document.querySelector("form");
form.addEventListener("submit",(evt)=>{ form.addEventListener("submit",(evt)=>{
...@@ -241,7 +257,7 @@ form.addEventListener("submit",(evt)=>{ ...@@ -241,7 +257,7 @@ form.addEventListener("submit",(evt)=>{
// } // }
// form.classList.add('was-validated') // form.classList.add('was-validated')
if(!noValidateFlag){ if(!noValidateFlag){
postData('postulante', serializeJSON(form)) postData('work-with-us', formatearJsonWithFile(serializeJSON(form),obtenerCV()))
.then(response => { .then(response => {
if(response.status==200 || response.status==302){ if(response.status==200 || response.status==302){
location.replace(response.url); location.replace(response.url);
......
...@@ -130,11 +130,18 @@ ...@@ -130,11 +130,18 @@
<hr> <hr>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#estadoModalLong">actualizar</button> <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#estadoModalLong">Actualizar</button>
</div> </div>
<c:choose>
<c:when test = "${cvId != null}">
<div class="col"> <div class="col">
<a class="btn btn-link " href="#">Descargar CV</a> <a class="btn btn-link" target="__blank" href="/postulantes/cvFile/${cvId}">Descargar CV</a>
</div> </div>
</c:when>
</c:choose>
</div> </div>
</div> </div>
</div> </div>
......
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html> <%@ taglib uri="http://kwonnam.pe.kr/jsp/template-inheritance" prefix="layout"%>
<html lang="en"> <layout:extends name="layouts/base.jsp">
<head> <layout:put block="cssDeclaracion" type="REPLACE">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<title>RRHH</title>
<link href="../css/indexStyle.css" rel="stylesheet" type="text/css"/> <link href="../css/indexStyle.css" rel="stylesheet" type="text/css"/>
</layout:put>
</head> </layout:extends>
<body> \ No newline at end of file
<jsp:include page="header.jsp"/>
<jsp:include page="alerts.jsp"/>
<div class="container-xxl my-md-4 bd-layout">
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
</body>
</html>
\ No newline at end of file
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<layout:block name="cssDeclaracion"><link href="../css/cargoStyle.css" rel="stylesheet" type="text/css"/></layout:block> <layout:block name="cssDeclaracion">
<link href="../css/cargoStyle.css" rel="stylesheet" type="text/css"/>
</layout:block>
<title>RRHH</title> <title>RRHH</title>
</head> </head>
...@@ -54,7 +56,7 @@ ...@@ -54,7 +56,7 @@
Postulantes Postulantes
</a> </a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<li><a class="dropdown-item" href="/postulante">Agregar</a></li> <li><a class="dropdown-item" href="/work-with-us">Agregar</a></li>
<li><a class="dropdown-item" href="/postulantes">Listar</a></li> <li><a class="dropdown-item" href="/postulantes">Listar</a></li>
</ul> </ul>
</li> </li>
......
...@@ -145,6 +145,11 @@ ...@@ -145,6 +145,11 @@
</select> </div> </select> </div>
<div class="inputs mb-3 col-md-4">
<label for="formFile" class="form-label">Cargar cv</label>
<input class="form-control" type="file" id="cvFile">
</div>
<div > <div >
<div style="color:blue" class=" inputs d-flex justify-content-between align-items-center experience"><span class="border px-3 p-1 add-experience" data-toggle="modal" data-target="#cargoForm"><i class="fa fa-plus"></i>&nbsp;Cargo al que postulas</span></div><br> <div style="color:blue" class=" inputs d-flex justify-content-between align-items-center experience"><span class="border px-3 p-1 add-experience" data-toggle="modal" data-target="#cargoForm"><i class="fa fa-plus"></i>&nbsp;Cargo al que postulas</span></div><br>
</div> </div>
......
...@@ -99,7 +99,7 @@ ...@@ -99,7 +99,7 @@
</c:forEach> </c:forEach>
</td> </td>
<td>${postulante.estado.getEstado()}</td> <td>${postulante.estado.getEstado()}</td>
<td><a href="/postulante/${postulante.id}">Ver</a></td> <td><a href="/postulantes/${postulante.id}">Ver</a></td>
</tr> </tr>
</c:forEach> </c:forEach>
</tbody> </tbody>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment