Cambios al buscador_alumno y creacion de listas separadas par bajar mas la posibilidad de accesso no autorizado a funciones de crud de administrador.

Creacion de un triger para que cuando añaden un alumno por heidi, inert directo que crea un usuario. Tambien esta creado por defecto al iniciar la aplicacion por primera vez
master
vicsash 5 months ago
parent 805466f4ae
commit 0a26208f41

@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@ -83,7 +84,6 @@ public class SecurityConfig{
// If the table is empty, insert 'READ', 'WRITE', and 'DELETE'
jdbcTemplate.execute("INSERT INTO autoridad (nombre) VALUES ('READ'), ('WRITE'), ('DELETE')");
}
// Check if the rol table is empty
Integer rolCount = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM rol", Integer.class);
if (rolCount != null && rolCount == 0) {
@ -106,21 +106,10 @@ public class SecurityConfig{
String sql = "INSERT INTO usuario (nombre_usuario, nombre_log_in, email, password, fk_rol) VALUES (?, ?, ?, ?, ?)";
jdbcTemplate.update(sql, "admin", "admin", "admin@example.com", "$2a$10$3B5KqGe7WIYVYmLBqGAHOuT0SrWgI1.J1kDj3v7TrJC65bU6P49cC", 1);
createDefaultData();
triggerCreate();
}
}
/* public void createDefaultRolesAuthoritiesAndAdmin() {
try {
if (usuarioService.findByNombreUsuario("admin").isEmpty()) {
Rol adminRole = rolService.findByName("ADMIN");
usuarioService.createUsuario("admin", "admin",
"admin@example.com",
"1234",
false, adminRole.getId());
}
} catch (Exception e) {
logger.error("Exception in createDefaultRolesAuthoritiesAndAdmin: ", e);
}
}*/
private void createDefaultData(){
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('Java')");
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('Microsoft XL')");
@ -179,4 +168,24 @@ public class SecurityConfig{
jdbcTemplate.execute("INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('G.S. ADMINISTRACIÓN Y FINANZAS','GSADMFIN', 3)");
jdbcTemplate.execute("INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('G.M. GESTIÓN ADMINISTRATIVA SEMIPRESENCIAL','GMGADMSEMI', 3)");
}
private void triggerCreate() {
String createTriggerSql = "CREATE DEFINER=`projfin`@`%` TRIGGER `new_user` AFTER INSERT ON `alumnos` " +
"FOR EACH ROW " +
"BEGIN " +
" INSERT INTO usuario (email, nombre_log_in, nombre_usuario, password, fk_rol) " +
" VALUES ( " +
" NEW.correo, " +
" NEW.correo, " +
" CONCAT_WS(' ', NEW.nombre, NEW.apellido, NEW.apellido2), " +
" '$2a$10$1OSyk1wLCHMKQ9yjnB4pkOxQzsjo1dSpixbVoJrpqWlYq4wQBRs9e', " +
" 2 " +
" ); " +
"END;";
try {
jdbcTemplate.execute(createTriggerSql);
} catch (DataAccessException ex) {
logger.error("Error creating trigger: ", ex);
}
}
}

@ -9,6 +9,7 @@ import com.example.proyectofinal.servicios.empresa.*;
import com.example.proyectofinal.servicios.user.UsuarioService;
import jakarta.annotation.security.RolesAllowed;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
@ -21,6 +22,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.server.ResponseStatusException;
import java.text.ParseException;
import java.util.*;
@ -72,7 +74,6 @@ public class BuscadorController {
}
}
@GetMapping("/empresas/page/{pageNum}")
public String searchEmpresasList(@PathVariable int pageNum,
@RequestParam(defaultValue = "") String query,
@ -80,8 +81,8 @@ public class BuscadorController {
@RequestParam(defaultValue = "nombre") String sortField,
@RequestParam(defaultValue = "asc") String sortDir,
@RequestParam String secondaryOption,
Model model){
System.out.println("TEST SORT DIR " + sortDir);
Model model,
Authentication authentication) {
String[] queryMultiWord = query.split(",");
List<String> queryList = new ArrayList<>();
for (String queryForList : queryMultiWord) {
@ -105,6 +106,13 @@ public class BuscadorController {
model.addAttribute("secondaryOption", secondaryOption);
model.addAttribute("isAdmin", usuarioService.isAdmin());
}
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
boolean isAdmin = authorities.stream()
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ADMIN"));
if (!isAdmin) {
return "list_alu/empresas";
}
return "/list/empresas";
}
@ -128,7 +136,6 @@ public class BuscadorController {
return "/list/sectores";
}
@GetMapping("/contactos/page/{pageNum}")
public String searchContactosList(@PathVariable int pageNum,
@RequestParam(defaultValue = "") String query,
@ -136,7 +143,8 @@ public class BuscadorController {
@RequestParam(defaultValue = "nombre") String sortField,
@RequestParam(defaultValue = "asc") String sortDir,
@RequestParam String secondaryOption,
Model model) {
Model model,
Authentication authentication) {
String[] queryMultiWord = query.split(",");
List<String> queryList = new ArrayList<>();
for (String queryForList : queryMultiWord) {
@ -160,10 +168,15 @@ public class BuscadorController {
model.addAttribute("secondaryOption", secondaryOption);
model.addAttribute("isAdmin", usuarioService.isAdmin());
}
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
boolean isAdmin = authorities.stream()
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ADMIN"));
if (!isAdmin) {
return "list_alu/contactos";
}
return "/list/contactos";
}
@GetMapping("/sucursales/page/{pageNum}")
public String searchSucursalesList(@PathVariable int pageNum,
@RequestParam(defaultValue = "") String query,
@ -171,7 +184,8 @@ public class BuscadorController {
@RequestParam(defaultValue = "nombre") String sortField,
@RequestParam(defaultValue = "asc") String sortDir,
@RequestParam String secondaryOption,
Model model) {
Model model,
Authentication authentication) {
String[] queryMultiWord = query.split(",");
List<String> queryList = new ArrayList<>();
for (String queryForList : queryMultiWord) {
@ -196,10 +210,15 @@ public class BuscadorController {
model.addAttribute("secondaryOption", secondaryOption);
model.addAttribute("isAdmin", usuarioService.isAdmin());
}
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
boolean isAdmin = authorities.stream()
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ADMIN"));
if (!isAdmin) {
return "list_alu/sucursales";
}
return "/list/sucursales";
}
@GetMapping("/ofertas/page/{pageNum}")
public String searchOfertasList(@PathVariable int pageNum,
@RequestParam(defaultValue = "") String query,
@ -207,7 +226,8 @@ public class BuscadorController {
@RequestParam(defaultValue = "nombre") String sortField,
@RequestParam(defaultValue = "asc") String sortDir,
@RequestParam(defaultValue = "") String secondaryOption,
Model model) throws ParseException {
Model model,
Authentication authentication) throws ParseException {
String[] queryMultiWord = query.split(",");
List<String> queryList = new ArrayList<>();
for (String queryForList : queryMultiWord) {
@ -232,10 +252,15 @@ public class BuscadorController {
model.addAttribute("secondaryOption", secondaryOption);
model.addAttribute("isAdmin", usuarioService.isAdmin());
}
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
boolean isAdmin = authorities.stream()
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ADMIN"));
if (!isAdmin) {
return "list_alu/ofertas";
}
return "/list/ofertas";
}
@GetMapping("/familias/page/{pageNum}")
public String searchFamiliasList(@PathVariable int pageNum,
@RequestParam(defaultValue = "") String query,
@ -257,7 +282,6 @@ public class BuscadorController {
return "/list/familias";
}
@GetMapping("/ciclos/page/{pageNum}")
public String searchCiclosList(@PathVariable int pageNum,
@RequestParam(defaultValue = "") String query,
@ -265,7 +289,8 @@ public class BuscadorController {
@RequestParam(defaultValue = "nombre") String sortField,
@RequestParam(defaultValue = "asc") String sortDir,
@RequestParam(defaultValue = "") String secondaryOption,
Model model) throws ParseException {
Model model,
Authentication authentication) {
String[] queryMultiWord = query.split(",");
List<String> queryList = new ArrayList<>();
for (String queryForList : queryMultiWord) {
@ -290,10 +315,15 @@ public class BuscadorController {
model.addAttribute("secondaryOption", secondaryOption);
model.addAttribute("isAdmin", usuarioService.isAdmin());
}
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
boolean isAdmin = authorities.stream()
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ADMIN"));
if (!isAdmin) {
return "list_alu/ciclos";
}
return "/list/ciclos";
}
@GetMapping("/alumnos/page/{pageNum}")
public String searchAlumnosList(@PathVariable int pageNum,
@RequestParam(defaultValue = "") String query,
@ -301,8 +331,8 @@ public class BuscadorController {
@RequestParam(defaultValue = "nombre") String sortField,
@RequestParam(defaultValue = "asc") String sortDir,
@RequestParam(defaultValue = "") String secondaryOption,
Model model) {
Model model,
Authentication authentication) {
String[] queryMultiWord = query.split(",");
List<String> queryList = new ArrayList<>();
for (String queryForList : queryMultiWord) {
@ -326,7 +356,6 @@ public class BuscadorController {
model.addAttribute("secondaryOption", secondaryOption);
model.addAttribute("isAdmin", usuarioService.isAdmin());
}
return "/list/alumnos";
}
@ -338,7 +367,6 @@ public class BuscadorController {
@RequestParam(defaultValue = "asc") String sortDir,
@RequestParam(defaultValue = "") String secondaryOption,
Model model) {
String[] word = query.split("\\b(y|o)\\b|[,/]");
List<Integer> itemsPage = Arrays.asList(5, 10, 15, 20, 25, 50);
Map<String, Object> attributes = new HashMap<>();
if (secondaryOption.equalsIgnoreCase("Todo")) {
@ -400,14 +428,12 @@ public class BuscadorController {
}
@GetMapping("/sectores/search")
public ResponseEntity<List<Sector>> searchSectores(@RequestParam String query) {
List<Sector> sectors = sectorService.search(query);
return ResponseEntity.ok(sectors);
}
@GetMapping("/contactos/search")
public ResponseEntity<List<Contacto>> searchContactos(@RequestParam String querySearchBar, @RequestParam String query, @RequestParam String secondaryOption) {
if(secondaryOption.equalsIgnoreCase("Todo")){
@ -419,7 +445,6 @@ public class BuscadorController {
}
}
@GetMapping("/sucursales/search")
public ResponseEntity<List<Sucursal>> searchSucursales(@RequestParam String querySearchBar, @RequestParam String query, @RequestParam String secondaryOption) {
if(secondaryOption.equalsIgnoreCase("Todo")){
@ -431,14 +456,12 @@ public class BuscadorController {
}
}
@GetMapping("/familias/search")
public ResponseEntity<List<Familia>> searchFamilias(@RequestParam String query) {
List<Familia> familias = familiaService.search(query);
return ResponseEntity.ok(familias);
}
@GetMapping("/ciclos/search")
public ResponseEntity<List<Ciclo>> searchCiclos(@RequestParam String querySearchBar, @RequestParam String query, @RequestParam String secondaryOption) {
if(secondaryOption.equalsIgnoreCase("Todo")){
@ -450,14 +473,12 @@ public class BuscadorController {
}
}
@GetMapping("/skills/search")
public ResponseEntity<List<Skill>> searchSkills(@RequestParam String query) {
List<Skill> ciclos = skillService.search(query);
return ResponseEntity.ok(ciclos);
}
@GetMapping("/alumnos/search")
public ResponseEntity<List<Alumno>> searchAlumnos(@RequestParam String querySearchBar, @RequestParam String query, @RequestParam String secondaryOption) {
List<Alumno> alumnos;
@ -482,18 +503,6 @@ public class BuscadorController {
return ResponseEntity.ok(alumnos);
}
private void printTest (List<Alumno> alumnos){
for (Alumno alumno : alumnos) {
System.out.println("----------------------------");
System.out.println(alumno.getNombre());
for(Skill skill : alumno.getSkills()) {
System.out.println(skill.getNombre());
}
System.out.println("----------------------------");
}
}
@GetMapping("/ofertas/search")
public ResponseEntity<List<Oferta>> searchOfertas(@RequestParam String querySearchBar, @RequestParam String query, @RequestParam String secondaryOption) {
List<Oferta> ofertas;

@ -85,9 +85,7 @@ public class AlumnoController {
nombreUsuarioBuilder.append(alumno.getApellido2().toLowerCase());
}
String nombreUsuario = nombreUsuarioBuilder.toString();
String nia = alumno.getNia();
String firstThreeLetters = nia.substring(0, 3);
String nombreLogIn="alu." +alumno.getNombre()+firstThreeLetters;
String nombreLogIn=alumno.getCorreo();
String email = Optional.of(alumno.getCorreo()).orElse(alumno.getCorreo2());
Long newUser = usuarioService.findRolByName("USER");
usuarioService.createUsuario(nombreUsuario, nombreLogIn, email, password, newUser);

@ -107,12 +107,9 @@
<div class="dropdown-container">
<select name="searchOption" id="searchOption">
<option value="empresas">Empresa</option>
<option value="sectores">Sectores</option>
<option value="ofertas">Ofertas</option>
<option value="sucursales">Sucursales</option>
<option value="skills">Skills</option>
<option value="contactos">Contactos</option>
<option value="familias">Familias</option>
<option value="ciclos">Ciclos</option>
</select>
@ -239,9 +236,6 @@
case 'empresas':
options = ['Todo', 'Sector','Keywords'];
break;
case 'sectores':
options = ['Todo'];
break;
case 'contactos':
options = ['Todo', 'Empresa'];
break;
@ -251,18 +245,9 @@
case'sucursales':
options = ['Todo', 'Empresa','Localidad'];
break;
case'skills':
options = ['Todo'];
break;
case'familias':
options = ['Todo'];
break;
case'ciclos':
options = ['Todo','Familia'];
break;
case'alumnos':
options = ['Todo','Ciclo','Keywords'];
break;
default:
options = [];
}

@ -0,0 +1,229 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css">
<link rel="stylesheet" type="text/css" th:href="@{/style.css}">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.23/jspdf.plugin.autotable.min.js"></script>
<meta charset="UTF-8">
<title>Lista: Cilos</title>
<style>
</style>
</head>
<body>
<div class="header">
<h1>
<i class="fas fa-arrow-left" onclick="goBack()" style="cursor:pointer;"></i>
Listado de Ciclos
</h1>
<a href="/logout" class="logout-button"><i class="fas fa-door-open "></i></a>
</div>
<div class="toolbar">
<div>
<input type="text" id="myInput" placeholder="Buscar por....">
</div>
<div class="button-group">
<button class="pdfButton" onclick="generatePDF()">Generar PDF de esta pagina</button>
<button class="pdfButton" onclick="generatePDF_All()">Generar PDF de todas entradas</button>
</div>
</div>
<div class="table-container">
<table class="table" id="table">
<thead class="thread-light">
<tr>
<th class="table-header">
<a th:href="@{'/buscador/ciclos/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=nombre&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Nombre
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/ciclos/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=codigo&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Codigo
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/ciclos/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=familia.nombre&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Familia
</a>
</th>
</thead>
<tbody>
<tr class="cell" th:each="ciclo :${ciclos}" th:data-id="${ciclo.id}">
<td>
[[${ciclo.nombre}]]
</td>
<td>[[${ciclo.codigo}]]</td>
<td>[[${ciclo.familia.nombre}]]</td>
</tr>
</tbody>
</table>
</div>
<div class="page">
<nav aria-label="Page navigation" id="paginationControls">
<ul class="pagination">
<input type="hidden" name="secondaryOption" id="hiddenSecondaryOption" th:value="${secondaryOption}">
<li class="page-item" th:classappend="${currentPage == 1 ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/ciclos/page/' + ${1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Prim</a>
</li>
<li class="page-item" th:classappend="${currentPage == 1 ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/ciclos/page/' + ${currentPage - 1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Ant</a>
</li>
<li class="page-item" th:each="pageNum : ${#numbers.sequence(1, totalPages)}" th:classappend="${pageNum eq currentPage ? 'active' : ''}">
<a class="page-link" th:href="@{'/buscador/ciclos/page/' + ${pageNum} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">[[${pageNum}]]</a>
</li>
<li class="page-item" th:classappend="${currentPage == totalPages ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/ciclos/page/' + ${currentPage + 1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Sig</a>
</li>
<li class="page-item" th:classappend="${currentPage == totalPages ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/ciclos/page/' + ${totalPages} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Ult</a>
</li>
</ul>
</nav>
</div>
<select id="entriesCount">
<option th:each="item : ${itemsPage}" th:value="${item}" th:text="${item}" th:selected="${item == currentSize}"></option>
</select>
<script src="/orderTable.js"></script>
<script th:inline="javascript">
function goBack() {
window.location.href = '/buscador';
}
var $table = $('#table');
var $myInput = $('#myInput');
var isSearchBarUsed = false;
$myInput.on('input', function() {
var querySearchBar = document.querySelector('#myInput').value;
var paginationControls = document.querySelector('#paginationControls');
var entriesCountDropdown = document.querySelector('#entriesCount');
if (querySearchBar === '') {
isSearchBarUsed = false;
paginationControls.style.display = '';
entriesCountDropdown.style.display = '';
table.style.pointerEvents = '';
location.reload();
} else {
isSearchBarUsed = true;
paginationControls.style.display = 'none';
entriesCountDropdown.style.display = 'none';
table.style.pointerEvents = 'none';
/*<![CDATA[*/
var query = /*[[${query}]]*/ 'defaultQuery';
var secondaryOption = /*[[${secondaryOption}]]*/ 'defaultSecondaryOption';
/* rest of your JavaScript code */
/*]]>*/
fetch('/buscador/ciclos/search?querySearchBar=' + querySearchBar + '&query=' + query + '&secondaryOption=' + secondaryOption)
.then(response => response.json())
.then(data => {
var tableBody = document.querySelector('#table tbody');
tableBody.innerHTML = '';
data.forEach(ciclo => {
var row = document.createElement('tr');
row.dataset.id = ciclo.id;
row.innerHTML = `
<td>
${ciclo.nombre}
</td>
<td>${ciclo.codigo}</td>
<td>${ciclo.familia.nombre}</td>
`;
tableBody.appendChild(row);
});
table.style.pointerEvents = 'auto';
});
}
});
document.querySelector('#table').addEventListener('click', function(event) {
if (event.target.matches('.edit-icon')) {
handleEdit(event);
} else if (event.target.matches('.delete-icon')) {
handleDelete(event);
}
});
var tableHeaders = document.querySelectorAll('.table-header');
tableHeaders.forEach(function(header) {
header.addEventListener('click', function(event) {
// If the search bar is currently being used, prevent the default action of the click event
if (isSearchBarUsed) {
event.preventDefault();
}
});
});
function generatePDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('l', 'pt'); // 'l' for landscape mode, 'pt' for points as unit
// Add a title to the PDF
doc.setFontSize(20); // Set the font size
doc.text('Lista de ciclos', 40, 40); // Add the title
// Get the HTML table
const tableElement = document.getElementById("table");
// Use jsPDF-AutoTable to convert the table to PDF
doc.autoTable({ html: tableElement, startY: 60 }); // Start the table below the title
// Save the PDF
doc.save('lista_ciclos.pdf');
}
function generatePDF_All() {
var querySearchBar = document.querySelector('#myInput').value;
var query = /*[[${query}]]*/ 'defaultQuery';
var secondaryOption = /*[[${secondaryOption}]]*/ 'defaultSecondaryOption';
fetch('/ciclos_pdf/search/all?query=' + query + '&secondaryOption=' + secondaryOption)
.then(response => response.json())
.then(data => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('l', 'pt');
doc.setFontSize(20);
doc.text('Lista de ciclos', 40, 40);
// Create a new table for the PDF
var table = document.createElement('table');
// Create table headers
var tableHead = document.createElement('thead');
var headerRow = document.createElement('tr');
headerRow.innerHTML = `
<th>Nombre</th>
<th>Codigo</th>
<th>Familia</th>
`;
tableHead.appendChild(headerRow);
table.appendChild(tableHead);
// Create table body
var tableBody = document.createElement('tbody');
data.forEach(ciclo => {
var row = document.createElement('tr');
row.dataset.id = ciclo.id;
row.innerHTML = `
<td>${ciclo.nombre}</td>
<td>${ciclo.codigo}</td>
<td>${ciclo.familia.nombre}</td>
`;
tableBody.appendChild(row);
});
table.appendChild(tableBody);
doc.autoTable({ html: table, startY: 60 });
doc.save('lista_ciclos.pdf');
});
}
</script>
</body>
</html>

@ -0,0 +1,255 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css">
<link rel="stylesheet" type="text/css" th:href="@{/style.css}">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.23/jspdf.plugin.autotable.min.js"></script>
<meta charset="UTF-8">
<title>Lista: Contactos</title>
<style>
</style>
</head>
<body>
<div class="header">
<h1>
<i class="fas fa-arrow-left" onclick="goBack()" style="cursor:pointer;"></i>
Listado de Contactos
</h1>
<a href="/logout" class="logout-button"><i class="fas fa-door-open "></i></a>
</div>
<div class="toolbar">
<div>
<input type="text" id="myInput" placeholder="Buscar por....">
</div>
<div class="button-group">
<button class="pdfButton" onclick="generatePDF()">Generar PDF de esta pagina</button>
<button class="pdfButton" onclick="generatePDF_All()">Generar PDF de todas entradas</button>
</div>
</div>
<div class="table-container">
<table class="table" id="table">
<thead class="thread-light">
<tr>
<th class="table-header">
<a th:href="@{'/buscador/contactos/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=nombre&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Nombre
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/contactos/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=apellido&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Apellido
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/contactos/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=apellido2&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Apellido2
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/contactos/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=correo&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Correo
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/contactos/page/' + ${currentPage} + '?query=' + ${query} + '&ortField=telefono&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Telefono
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/contactos/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=empresa.nombre&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Empresa
</a>
</th>
</tr>
</thead>
<tbody>
<tr class="cell" th:each="contacto :${contactos}" th:data-id="${contacto.id}">
<td>
[[${contacto.nombre}]]
</td>
<td>[[${contacto.apellido}]]</td>
<td>[[${contacto.apellido2}]]</td>
<td>[[${contacto.correo}]]</td>
<td>[[${contacto.telefono}]]</td>
<td>[[${contacto.empresa.nombre}]]</td>
</tr>
</tbody>
</table>
</div>
<div class="page">
<nav aria-label="Page navigation" id="paginationControls">
<ul class="pagination">
<input type="hidden" name="secondaryOption" id="hiddenSecondaryOption" th:value="${secondaryOption}">
<li class="page-item" th:classappend="${currentPage == 1 ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/contactos/page/' + ${1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Prim</a>
</li>
<li class="page-item" th:classappend="${currentPage == 1 ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/contactos/page/' + ${currentPage - 1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Ant</a>
</li>
<li class="page-item" th:each="pageNum : ${#numbers.sequence(1, totalPages)}" th:classappend="${pageNum eq currentPage ? 'active' : ''}">
<a class="page-link" th:href="@{'/buscador/contactos/page/' + ${pageNum} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">[[${pageNum}]]</a>
</li>
<li class="page-item" th:classappend="${currentPage == totalPages ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/contactos/page/' + ${currentPage + 1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Sig</a>
</li>
<li class="page-item" th:classappend="${currentPage == totalPages ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/contactos/page/' + ${totalPages} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Ult</a>
</li>
</ul>
</nav>
</div>
<select id="entriesCount">
<option th:each="item : ${itemsPage}" th:value="${item}" th:text="${item}" th:selected="${item == currentSize}"></option>
</select>
<script src="/orderTable.js"></script>
<script th:inline="javascript">
function goBack() {
window.location.href = '/buscador';
}
var $table = $('#table');
var $myInput = $('#myInput');
var isSearchBarUsed = false;
$myInput.on('input', function() {
var querySearchBar = document.querySelector('#myInput').value;
var paginationControls = document.querySelector('#paginationControls');
var entriesCountDropdown = document.querySelector('#entriesCount');
if (querySearchBar === '') {
isSearchBarUsed = false;
paginationControls.style.display = '';
entriesCountDropdown.style.display = '';
table.style.pointerEvents = '';
location.reload();
} else {
isSearchBarUsed = true;
paginationControls.style.display = 'none';
entriesCountDropdown.style.display = 'none';
table.style.pointerEvents = 'none';
/*<![CDATA[*/
var query = /*[[${query}]]*/ 'defaultQuery';
var secondaryOption = /*[[${secondaryOption}]]*/ 'defaultSecondaryOption';
/* rest of your JavaScript code */
/*]]>*/
fetch('/buscador/contactos/search?querySearchBar=' + querySearchBar+ '&query=' + query + '&secondaryOption=' + secondaryOption)
.then(response => response.json())
.then(data => {
var tableBody = document.querySelector('#table tbody');
tableBody.innerHTML = '';
data.forEach(contacto => {
var row = document.createElement('tr');
row.dataset.id = contacto.id;
row.innerHTML = `
<td>
${contacto.nombre}
</td>
<td>${contacto.apellido}</td>
<td>${contacto.apellido2}</td>
<td>${contacto.correo}</td>
<td>${contacto.telefono}</td>
<td>${contacto.empresa.nombre}</td>
`;
tableBody.appendChild(row);
});
table.style.pointerEvents = 'auto';
});
}
});
var tableHeaders = document.querySelectorAll('.table-header');
tableHeaders.forEach(function(header) {
header.addEventListener('click', function(event) {
// If the search bar is currently being used, prevent the default action of the click event
if (isSearchBarUsed) {
event.preventDefault();
}
});
});
function generatePDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('l', 'pt'); // 'l' for landscape mode, 'pt' for points as unit
// Add a title to the PDF
doc.setFontSize(20); // Set the font size
doc.text('Lista de contactos', 40, 40); // Add the title
// Get the HTML table
const tableElement = document.getElementById("table");
// Use jsPDF-AutoTable to convert the table to PDF
doc.autoTable({ html: tableElement, startY: 60 }); // Start the table below the title
// Save the PDF
doc.save('lista_contactos.pdf');
}
function generatePDF_All() {
var querySearchBar = document.querySelector('#myInput').value;
var query = /*[[${query}]]*/ 'defaultQuery';
var secondaryOption = /*[[${secondaryOption}]]*/ 'defaultSecondaryOption';
fetch('/contactos_pdf/search/all?querySearchBar=' + querySearchBar + '&query=' + query + '&secondaryOption=' + secondaryOption)
.then(response => response.json())
.then(data => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('l', 'pt');
doc.setFontSize(20);
doc.text('Lista de contactos', 40, 40);
// Create a new table for the PDF
var table = document.createElement('table');
// Create table headers
var tableHead = document.createElement('thead');
var headerRow = document.createElement('tr');
headerRow.innerHTML = `
<th>Nombre</th>
<th>Apellido</th>
<th>Apellido2</th>
<th>Correo</th>
<th>Telefono</th>
<th>Empresa</th>
`;
tableHead.appendChild(headerRow);
table.appendChild(tableHead);
// Create table body
var tableBody = document.createElement('tbody');
data.forEach(contacto => {
var row = document.createElement('tr');
row.dataset.id = contacto.id;
row.innerHTML = `
<td>${contacto.nombre}</td>
<td>${contacto.apellido}</td>
<td>${contacto.apellido2}</td>
<td>${contacto.correo}</td>
<td>${contacto.telefono}</td>
<td>${contacto.empresa.nombre}</td>
`;
tableBody.appendChild(row);
});
table.appendChild(tableBody);
doc.autoTable({ html: table, startY: 60 });
doc.save('lista_contactos.pdf');
});
}
</script>
</body>
</html>

@ -0,0 +1,280 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css">
<link rel="stylesheet" type="text/css" th:href="@{/style.css}">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.23/jspdf.plugin.autotable.min.js"></script>
<meta charset="UTF-8">
<title>Lista Empresas</title>
<style>
.table td.scrollable-cell .skill-cell {
width: 300px;
min-height: 50px;
}
</style>
</head>
<body>
<div class="header">
<h1>
<i class="fas fa-arrow-left" onclick="goBack()" style="cursor:pointer;"></i>
Listado de Empresas
</h1>
<a href="/logout" class="logout-button"><i class="fas fa-door-open "></i></a>
</div>
<div class="toolbar">
<div>
<input type="text" id="myInput" placeholder="Buscar por....">
</div>
<div class="button-group">
<button class="pdfButton" onclick="generatePDF()">Generar PDF de esta pagina</button>
<button class="pdfButton" onclick="generatePDF_All()">Generar PDF de todas entradas</button>
</div>
</div>
<div class="table-container">
<table class="table" id="table">
<thead class="thread-light">
<tr>
<th class="table-header">
<a th:href="@{'/buscador/empresas/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=nombre&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Nombre
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/empresas/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=cif&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Cif
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/empresas/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=correo&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Correo
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/empresas/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=telefono&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Telefono
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/empresas/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=keywords&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Keywords
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/empresas/page/' + ${currentPage} +'?query=' + ${query} + '&sortField=sector.nombre&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Sector
</a>
</th>
</tr>
</thead>
<tbody>
<tr class="cell" th:each="empresa :${empresas}" th:data-id="${empresa.id}">
<td>
[[${empresa.nombre}]]
</td>
<td>[[${empresa.cif}]]</td>
<td>[[${empresa.correo}]]</td>
<td>[[${empresa.telefono}]]</td>
<td class="scrollable-cell">
<div class="scrollable-content skill-cell">
[[${empresa.keywords}]]
</div>
</td>
<td class="scrollable-cell">
<div class="scrollable-content skill-cell">
[[${empresa.sector.nombre}]]
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="page">
<nav aria-label="Page navigation" id="paginationControls">
<ul class="pagination">
<input type="hidden" name="secondaryOption" id="hiddenSecondaryOption" th:value="${secondaryOption}">
<li class="page-item" th:classappend="${currentPage == 1 ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/empresas/page/' + ${1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Prim</a>
</li>
<li class="page-item" th:classappend="${currentPage == 1 ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/empresas/page/' + ${currentPage - 1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Ant</a>
</li>
<li class="page-item" th:each="pageNum : ${#numbers.sequence(1, totalPages)}" th:classappend="${pageNum eq currentPage ? 'active' : ''}">
<a class="page-link" th:href="@{'/buscador/empresas/page/' + ${pageNum} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">[[${pageNum}]]</a>
</li>
<li class="page-item" th:classappend="${currentPage == totalPages ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/empresas/page/' + ${currentPage + 1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Sig</a>
</li>
<li class="page-item" th:classappend="${currentPage == totalPages ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/empresas/page/' + ${totalPages} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Ult</a>
</li>
</ul>
</nav>
</div>
<select id="entriesCount">
<option th:each="item : ${itemsPage}" th:value="${item}" th:text="${item}" th:selected="${item == currentSize}"></option>
</select>
<script src="/orderTable.js"></script>
<script th:inline="javascript">
function goBack() {
window.location.href = '/buscador';
}
var $table = $('#table');
var $myInput = $('#myInput');
var isSearchBarUsed = false;
$myInput.on('input', function() {
var querySearchBar = document.querySelector('#myInput').value;
var paginationControls = document.querySelector('#paginationControls');
var entriesCountDropdown = document.querySelector('#entriesCount');
if (querySearchBar === '') {
isSearchBarUsed = false;
paginationControls.style.display = '';
entriesCountDropdown.style.display = '';
table.style.pointerEvents = '';
location.reload();
} else {
isSearchBarUsed = true;
paginationControls.style.display = 'none';
entriesCountDropdown.style.display = 'none';
table.style.pointerEvents = 'none';
/*<![CDATA[*/
var query = /*[[${query}]]*/ 'defaultQuery';
var secondaryOption = /*[[${secondaryOption}]]*/ 'defaultSecondaryOption';
/* rest of your JavaScript code */
/*]]>*/
//console.log("Query: " + query);
//console.log("Secondary Option: " + secondaryOption);
fetch('/buscador/empresas/search?querySearchBar=' + querySearchBar + '&query=' + query + '&secondaryOption=' + secondaryOption)
.then(response => response.json())
.then(data => {
var tableBody = document.querySelector('#table tbody');
tableBody.innerHTML = '';
data.forEach(empresa => {
var row = document.createElement('tr');
row.dataset.id = empresa.id;
row.innerHTML = `
<td>
${empresa.nombre}
</td>
<td>${empresa.cif}</td>
<td>${empresa.correo}</td>
<td>${empresa.telefono}</td>
<td class="keywords-cell">
<div class="scrollable-content">
${empresa.keywords}
</div>
</td>
<td>${empresa.sector.nombre}</td>
`;
tableBody.appendChild(row);
});
table.style.pointerEvents = 'auto';
});
}
});
var tableHeaders = document.querySelectorAll('.table-header');
tableHeaders.forEach(function (header) {
header.addEventListener('click', function (event) {
if (isSearchBarUsed) {
event.preventDefault();
}
});
});
/////////////////PDF FOR CURRENT ITEMS//////////////////////
function generatePDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('l', 'pt'); // 'l' for landscape mode, 'pt' for points as unit
// Add a title to the PDF
doc.setFontSize(20); // Set the font size
doc.text('Lista de empresas', 40, 40); // Add the title
// Get the HTML table
const tableElement = document.getElementById("table");
// Use jsPDF-AutoTable to convert the table to PDF
doc.autoTable({ html: tableElement, startY: 60 }); // Start the table below the title
// Save the PDF
doc.save('lista_empresas.pdf');
}
/////////////////PDF FOR ALL SEARCHED ITEMS//////////////////////
function generatePDF_All() {
var querySearchBar = document.querySelector('#myInput').value;
var query = /*[[${query}]]*/ 'defaultQuery';
var secondaryOption = /*[[${secondaryOption}]]*/ 'defaultSecondaryOption';
fetch('/empresas_pdf/search/all?query=' + query + '&secondaryOption=' + secondaryOption)
.then(response => response.json())
.then(data => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('l', 'pt');
doc.setFontSize(20);
doc.text('Lista de empresas', 40, 40);
// Create a new table for the PDF
var table = document.createElement('table');
// Create table headers
var tableHead = document.createElement('thead');
var headerRow = document.createElement('tr');
headerRow.innerHTML = `
<th>Nombre</th>
<th>Cif</th>
<th>Correo</th>
<th>Telefono</th>
<th>Keywords</th>
<th>Sector</th>
`;
tableHead.appendChild(headerRow);
table.appendChild(tableHead);
// Create table body
var tableBody = document.createElement('tbody');
data.forEach(empresa => {
var row = document.createElement('tr');
row.dataset.id = empresa.id;
row.innerHTML = `
<td>${empresa.nombre}</td>
<td>${empresa.cif}</td>
<td>${empresa.correo}</td>
<td>${empresa.telefono}</td>
<td class="scrollable-cell">
<div class="scrollable-content skill-cell">
${empresa.keywords}
</div>
</td>
<td class="scrollable-cell">
<div class="scrollable-content skill-cell">
${empresa.sector.nombre}
</div>
</td>
`;
tableBody.appendChild(row);
});
table.appendChild(tableBody);
doc.autoTable({ html: table, startY: 60 });
doc.save('lista_empresas.pdf');
});
}
</script>
</body>
</html>

@ -0,0 +1,280 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css">
<link rel="stylesheet" type="text/css" th:href="@{/style.css}">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.23/jspdf.plugin.autotable.min.js"></script>
<meta charset="UTF-8">
<title>Lista Ofertas</title>
<style>
.table td.scrollable-cell .skill-cell {
width: 250px;
min-height: 50px;
}
</style>
</head>
<body>
<div class="header">
<h1>
<i class="fas fa-arrow-left" onclick="goBack()" style="cursor:pointer;"></i>
Listado de Ofertas
</h1>
<a href="/logout" class="logout-button"><i class="fas fa-door-open "></i></a>
</div>
<div class="toolbar">
<div>
<input type="text" id="myInput" placeholder="Buscar por....">
</div>
<div class="button-group">
<button class="pdfButton" onclick="generatePDF()">Generar PDF de esta pagina</button>
<button class="pdfButton" onclick="generatePDF_All()">Generar PDF de todas entradas</button>
</div>
</div>
<div class="scrollable-table">
<table class="table" id="table">
<thead class="thread-light">
<tr>
<th class="table-header">
<a th:href="@{'/buscador/ofertas/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=nombre&sortDir=' + ${reverseSortDir} + '&secondaryOption=' + ${secondaryOption}}">
Nombre
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/ofertas/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=fecha&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Fecha
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/ofertas/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=descripcion&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Descripcion
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/ofertas/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=sucursal.nombre&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Sucursal
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/ofertas/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=ciclo.nombre&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Ciclo
</a>
</th>
<th class="table-header">
Skills
</th>
</tr>
</thead>
<tbody>
<tr class="cell" th:each="oferta :${ofertas}" th:data-id="${oferta.id}">
<td>
[[${oferta.nombre}]]
</td>
<td>[[${oferta.fecha}]]</td>
<td>[[${oferta.descripcion}]]</td>
<td>[[${oferta.sucursal.nombre}]]</td>
<td class="scrollable-cell">
<div class="scrollable-content skill-cell">
[[${oferta.ciclo.nombre}]]
</div>
</td>
<td class="scrollable-cell">
<div class="scrollable-content skill-cell">
<span th:each="skill : ${oferta.skills}" th:text="${skill.nombre} + ' '"></span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="page">
<nav aria-label="Page navigation" id="paginationControls">
<ul class="pagination">
<input type="hidden" name="secondaryOption" id="hiddenSecondaryOption" th:value="${secondaryOption}">
<li class="page-item" th:classappend="${currentPage == 1 ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/ofertas/page/' + ${1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Prim</a>
</li>
<li class="page-item" th:classappend="${currentPage == 1 ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/ofertas/page/' + ${currentPage - 1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Ant</a>
</li>
<li class="page-item" th:each="pageNum : ${#numbers.sequence(1, totalPages)}" th:classappend="${pageNum eq currentPage ? 'active' : ''}">
<a class="page-link" th:href="@{'/buscador/ofertas/page/' + ${pageNum} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">[[${pageNum}]]</a>
</li>
<li class="page-item" th:classappend="${currentPage == totalPages ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/ofertas/page/' + ${currentPage + 1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Sig</a>
</li>
<li class="page-item" th:classappend="${currentPage == totalPages ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/ofertas/page/' + ${totalPages} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Ult</a>
</li>
</ul>
</nav>
</div>
<select id="entriesCount">
<option th:each="item : ${itemsPage}" th:value="${item}" th:text="${item}" th:selected="${item == currentSize}"></option>
</select>
<script src="/orderTable.js"></script>
<script th:inline="javascript">
function goBack() {
window.location.href = '/buscador';
}
var $table = $('#table');
var $myInput = $('#myInput');
var isSearchBarUsed = false;
$myInput.on('input', function() {
var querySearchBar = document.querySelector('#myInput').value;
var paginationControls = document.querySelector('#paginationControls');
var entriesCountDropdown = document.querySelector('#entriesCount');
/*<![CDATA[*/
var query = /*[[${query}]]*/ 'defaultQuery';
var secondaryOption = /*[[${secondaryOption}]]*/ 'defaultSecondaryOption';
/* rest of your JavaScript code */
/*]]>*/
if (querySearchBar === '') {
isSearchBarUsed = false;
paginationControls.style.display = '';
entriesCountDropdown.style.display = '';
table.style.pointerEvents = '';
location.reload();
} else {
isSearchBarUsed = true;
paginationControls.style.display = 'none';
entriesCountDropdown.style.display = 'none';
table.style.pointerEvents = 'none';
fetch('/buscador/ofertas/search?querySearchBar=' + querySearchBar + '&query=' + query + '&secondaryOption=' + secondaryOption)
.then(response => response.json())
.then(data => {
var tableBody = document.querySelector('#table tbody');
tableBody.innerHTML = '';
data.forEach(oferta => {
var row = document.createElement('tr');
row.dataset.id = oferta.id;
row.innerHTML = `
<td>
${oferta.nombre}
</td>
<td>${oferta.fecha}</td>
<td>${oferta.descripcion}</td>
<td>${oferta.sucursal.nombre}</td>
<td class="scrollable-cell">
<div class="scrollable-content skill-cell">
${oferta.ciclo.nombre}</td>
</div>
</td>
<td class="scrollable-cell">
<div class="scrollable-content skill-cell">
${oferta.skills.map(skill => skill.nombre).join(', ')}
</div>
</td>
`;
tableBody.appendChild(row);
});
table.style.pointerEvents = 'auto';
});
}
});
var tableHeaders = document.querySelectorAll('.table-header');
tableHeaders.forEach(function(header) {
header.addEventListener('click', function(event) {
// If the search bar is currently being used, prevent the default action of the click event
if (isSearchBarUsed) {
event.preventDefault();
}
});
});/*
/////////////////MOUSE SROLL FOR KEYWORD AND SKILLS//////////////////////
const cells = document.querySelectorAll('.keywords-cell');
cells.forEach(cell => {
cell.addEventListener('wheel', function(e) {
e.preventDefault();
this.scrollLeft += e.deltaY;
}, { passive: false });
});*/
function generatePDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('l', 'pt'); // 'l' for landscape mode, 'pt' for points as unit
// Add a title to the PDF
doc.setFontSize(20); // Set the font size
doc.text('Lista de ofertas', 40, 40); // Add the title
// Get the HTML table
const tableElement = document.getElementById("table");
// Use jsPDF-AutoTable to convert the table to PDF
doc.autoTable({ html: tableElement, startY: 60 }); // Start the table below the title
// Save the PDF
doc.save('lista_ofertas.pdf');
}
function generatePDF_All() {
var querySearchBar = document.querySelector('#myInput').value;
var query = /*[[${query}]]*/ 'defaultQuery';
var secondaryOption = /*[[${secondaryOption}]]*/ 'defaultSecondaryOption';
fetch('/ofertas_pdf/search/all?query=' + query + '&secondaryOption=' + secondaryOption)
.then(response => response.json())
.then(data => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('l', 'pt');
doc.setFontSize(20);
doc.text('Lista de ofertas', 40, 40);
// Create a new table for the PDF
var table = document.createElement('table');
// Create table headers
var tableHead = document.createElement('thead');
var headerRow = document.createElement('tr');
headerRow.innerHTML = `
<th>Nombre</th>
<th>Fecha</th>
<th>Descripcion</th>
<th>Sucursal</th>
<th>Ciclo</th>
<th>Skills</th>
// Add more headers as per your data structure
`;
tableHead.appendChild(headerRow);
table.appendChild(tableHead);
// Create table body
var tableBody = document.createElement('tbody');
data.forEach(oferta => {
var row = document.createElement('tr');
row.dataset.id = oferta.id;
row.innerHTML = `
<td>${oferta.nombre}</td>
<td>${oferta.fecha}</td>
<td>${oferta.descripcion}</td>
<td>${oferta.sucursal.nombre}</td>
<td>${oferta.ciclo.nombre}</td>
<td>${oferta.skills.map(skill => skill.nombre).join(', ')}</td>
`;
tableBody.appendChild(row);
});
table.appendChild(tableBody);
doc.autoTable({ html: table, startY: 60 });
doc.save('lista_ofertas.pdf');
});
}
</script>
</body>
</html>

@ -0,0 +1,241 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css">
<link rel="stylesheet" type="text/css" th:href="@{/style.css}">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.23/jspdf.plugin.autotable.min.js"></script>
<meta charset="UTF-8">
<title>Lista Sucursales</title>
<style>
</style>
</head>
<body>
<div class="header">
<h1>
<i class="fas fa-arrow-left" onclick="goBack()" style="cursor:pointer;"></i>
Listado de Sucursales
</h1>
<a href="/logout" class="logout-button"><i class="fas fa-door-open "></i></a>
</div>
<div class="toolbar">
<div>
<input type="text" id="myInput" placeholder="Buscar por....">
</div>
<div class="button-group">
<button class="pdfButton" onclick="generatePDF()">Generar PDF de esta pagina</button>
<button class="pdfButton" onclick="generatePDF_All()">Generar PDF de todas entradas</button>
</div>
</div>
<div class="table-container">
<table class="table" id="table">
<thead class="thread-light">
<tr>
<th class="table-header">
<a th:href="@{'/buscador/sucursales/page/' + ${currentPage} +'?query=' + ${query} + '&sortField=nombre&sortDir=' + ${reverseSortDir} + '&secondaryOption=' + ${secondaryOption}}">
Nombre
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/sucursales/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=localidad&sortDir=' + ${reverseSortDir} + '&secondaryOption=' + ${secondaryOption}}">
Localidad
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/sucursales/page/' + ${currentPage} +'?query=' + ${query} + '&sortField=direccion&sortDir=' + ${reverseSortDir} + '&secondaryOption=' + ${secondaryOption}}">
Direccion
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/sucursales/page/' + ${currentPage} + '?query=' + ${query} + '&sortField=sedeCentral&sortDir=' + ${reverseSortDir} + '&secondaryOption=' + ${secondaryOption}}">
Sede Central
</a>
</th>
<th class="table-header">
<a th:href="@{'/buscador/sucursales/page/' + ${currentPage} +'?query=' + ${query} + '&sortField=empresa.nombre&sortDir=' + ${reverseSortDir} + '&secondaryOption=' + ${secondaryOption}}">
Empresa
</a>
</th>
</tr>
</thead>
<tbody>
<tr class="cell" th:each="sucursal :${sucursales}" th:data-id="${sucursal.id}">
<td>
[[${sucursal.nombre}]]
</td>
<td>[[${sucursal.localidad}]]</td>
<td>[[${sucursal.direccion}]]</td>
<td th:text="${sucursal.sedeCentral} ? 'Si' : 'No'"></td>
<td>[[${sucursal.empresa.nombre}]]</td>
</tr>
</tbody>
</table>
</div>
<div class="page">
<nav aria-label="Page navigation" id="paginationControls">
<ul class="pagination">
<input type="hidden" name="secondaryOption" id="hiddenSecondaryOption" th:value="${secondaryOption}">
<li class="page-item" th:classappend="${currentPage == 1 ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/sucursales/page/' + ${1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Prim</a>
</li>
<li class="page-item" th:classappend="${currentPage == 1 ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/sucursales/page/' + ${currentPage - 1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Ant</a>
</li>
<li class="page-item" th:each="pageNum : ${#numbers.sequence(1, totalPages)}" th:classappend="${pageNum eq currentPage ? 'active' : ''}">
<a class="page-link" th:href="@{'/buscador/sucursales/page/' + ${pageNum} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">[[${pageNum}]]</a>
</li>
<li class="page-item" th:classappend="${currentPage == totalPages ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/sucursales/page/' + ${currentPage + 1} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Sig</a>
</li>
<li class="page-item" th:classappend="${currentPage == totalPages ? 'disabled' : ''}">
<a class="page-link" th:href="@{'/buscador/sucursales/page/' + ${totalPages} + '?query=' + ${query} + '&size=' + ${currentSize} + '&secondaryOption=' + ${secondaryOption}}">Ult</a>
</li>
</ul>
</nav>
</div>
<select id="entriesCount">
<option th:each="item : ${itemsPage}" th:value="${item}" th:text="${item}" th:selected="${item == currentSize}"></option>
</select>
<script src="/orderTable.js"></script>
<script th:inline="javascript">
function goBack() {
window.location.href = '/buscador';
}
var $table = $('#table');
var $myInput = $('#myInput');
var isSearchBarUsed = false;
$myInput.on('input', function() {
var querySearchBar = document.querySelector('#myInput').value;
var paginationControls = document.querySelector('#paginationControls');
var entriesCountDropdown = document.querySelector('#entriesCount');
if (querySearchBar === '') {
isSearchBarUsed = false;
paginationControls.style.display = '';
entriesCountDropdown.style.display = '';
table.style.pointerEvents = '';
location.reload();
} else {
isSearchBarUsed = true;
paginationControls.style.display = 'none';
entriesCountDropdown.style.display = 'none';
table.style.pointerEvents = 'none';
/*<![CDATA[*/
var query = /*[[${query}]]*/ 'defaultQuery';
var secondaryOption = /*[[${secondaryOption}]]*/ 'defaultSecondaryOption';
/* rest of your JavaScript code */
/*]]>*/
fetch('/buscador/sucursales/search?querySearchBar=' + querySearchBar + '&query=' + query + '&secondaryOption=' + secondaryOption)
.then(response => response.json())
.then(data => {
var tableBody = document.querySelector('#table tbody');
tableBody.innerHTML = '';
data.forEach(sucursal => {
var row = document.createElement('tr');
row.dataset.id = sucursal.id;
var sedeCentralText = sucursal.sedeCentral ? 'Si' : 'No'; // Add this line
row.innerHTML = `
<td>
${sucursal.nombre}
</td>
<td>${sucursal.localidad}</td>
<td>${sucursal.direccion}</td>
<td>${sedeCentralText}
<td>${sucursal.empresa.nombre}</td>
`;
tableBody.appendChild(row);
});
table.style.pointerEvents = 'auto';
});
}
});
var tableHeaders = document.querySelectorAll('.table-header');
tableHeaders.forEach(function(header) {
header.addEventListener('click', function(event) {
// If the search bar is currently being used, prevent the default action of the click event
if (isSearchBarUsed) {
event.preventDefault();
}
});
});
function generatePDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('l', 'pt'); // 'l' for landscape mode, 'pt' for points as unit
// Add a title to the PDF
doc.setFontSize(20); // Set the font size
doc.text('Lista de sucursales', 40, 40); // Add the title
// Get the HTML table
const tableElement = document.getElementById("table");
// Use jsPDF-AutoTable to convert the table to PDF
doc.autoTable({ html: tableElement, startY: 60 }); // Start the table below the title
// Save the PDF
doc.save('lista_sucursales.pdf');
}
function generatePDF_All() {
var querySearchBar = document.querySelector('#myInput').value;
var query = /*[[${query}]]*/ 'defaultQuery';
var secondaryOption = /*[[${secondaryOption}]]*/ 'defaultSecondaryOption';
fetch('/sucursales_pdf/search/all?query=' + query + '&secondaryOption=' + secondaryOption)
.then(response => response.json())
.then(data => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('l', 'pt');
doc.setFontSize(20);
doc.text('Lista de Sucursales', 40, 40);
// Create a new table for the PDF
var table = document.createElement('table');
// Create table headers
var tableHead = document.createElement('thead');
var headerRow = document.createElement('tr');
headerRow.innerHTML = `
<th>Nombre</th>
<th>Direccion</th>
<th>Empresa</th>
`;
tableHead.appendChild(headerRow);
table.appendChild(tableHead);
// Create table body
var tableBody = document.createElement('tbody');
data.forEach(sucursal => {
var row = document.createElement('tr');
row.dataset.id = sucursal.id;
row.innerHTML = `
<td>${sucursal.nombre}</td>
<td>${sucursal.direccion}</td>
<td>${sucursal.empresa.nombre}</td>
`;
tableBody.appendChild(row);
});
table.appendChild(tableBody);
doc.autoTable({ html: table, startY: 60 });
doc.save('lista_sucursales.pdf');
});
}
</script>
</body>
</html>
Loading…
Cancel
Save

Powered by INFORMATICA.FP.EDU.ES.