Acabando pruebas y ajustando css yarreglado fallos. Revisando creacion dl usuario inicial adinistrador

master
vicsash 4 months ago
parent a287df1ab8
commit 1d65f92f3e

@ -56,10 +56,7 @@ public class SecurityConfig{
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.addLogoutHandler((request, response, authentication) -> {
if (authentication != null) {
String nombreLogIn = authentication.getName();
usuarioService.logout(nombreLogIn);
}
logger.info("User logged out: " + authentication.getName());
})
);
return http.build();
@ -97,10 +94,12 @@ public class SecurityConfig{
// Manually insert authorities for 'ALU' role
jdbcTemplate.update("INSERT INTO rol_autoridad (fk_rol, fk_autoridad) VALUES (2, 1)"); // 'ALU' - 'READ'
jdbcTemplate.update("INSERT INTO rol_autoridad (fk_rol, fk_autoridad) VALUES (2, 2)"); // 'ALU' - 'EDIT'
createDefaultRolesAuthoritiesAndAdmin();
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();
}
}
public void createDefaultRolesAuthoritiesAndAdmin() {
/* public void createDefaultRolesAuthoritiesAndAdmin() {
try {
if (usuarioService.findByNombreUsuario("admin").isEmpty()) {
Rol adminRole = rolService.findByName("ADMIN");
@ -112,5 +111,63 @@ public class SecurityConfig{
} 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')");
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('Ruso')");
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('Aleman')");
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('Ingles')");
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('Python')");
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('C++')");
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('C#')");
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('HTML')");
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('CSS')");
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('JavaScript')");
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('PHP')");
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('SQL')");
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('Marketing')");
jdbcTemplate.execute("INSERT INTO skills (nombre) VALUES ('Frances')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Agricultura')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Tecnologías de la información y la comunicación')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Ganadería')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Pesca')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Silvicultura')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Turismo')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Minería')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Industria manufacturera')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Construcción')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Industria energética')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Industria química')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Transporte y logística')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Turismo y hostelería')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Salud')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Finanzas')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Telecomunicaciones')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Entretenimiento y medios')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Servicios profesionales')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Investigación y desarrollo (I+D)')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Tecnologías de la información y la comunicación (TIC)')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Servicios de información')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Servicios gubernamentales')");
jdbcTemplate.execute("INSERT INTO sectores (nombre) VALUES ('Servicios sin ánimo de lucro')");
jdbcTemplate.execute("INSERT INTO familias (nombre) VALUES ('INFORMÁTICA Y COMUNICACIONES')");
jdbcTemplate.execute("INSERT INTO familias (nombre) VALUES ('SANIDAD')");
jdbcTemplate.execute("INSERT INTO familias (nombre) VALUES ('ADMINISTRACION Y GESTION')");
jdbcTemplate.execute("INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('G.S. DESARROLLO DE APLICACIONES MULTIPLATAFORMA','GSDAM', 1)");
jdbcTemplate.execute("INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('G.S. DESARROLLO DE APLICACIONES WEB','GSDAW', 1)");
jdbcTemplate.execute("INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('G.S. ADMINISTRACIÓN DE SISTEMAS INFORMÁTICOS EN RED','GSASIX', 1)");
jdbcTemplate.execute("INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('G.M. SISTEMAS MICROINFORMÁTICOS Y REDES','GMSMX', 1)");
jdbcTemplate.execute("INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('G.M. EMERGENCIAS SANITARIAS','GMES', 2)");
jdbcTemplate.execute("INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('G.M. CUIDADOS AUXILIARES DE ENFERMERÍA','GMAE', 2)");
jdbcTemplate.execute("INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('G.S. DIETÉTICA','GSDIE', 2)");
jdbcTemplate.execute("INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('G.M. Emergencias Sanitarias (SEMIPRESENCIAL)','GMESSEMI', 2)");
jdbcTemplate.execute("INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('F.P. BÁSICA - SERVICIOS ADMINISTRATIVOS','FPBSA', 3)");
jdbcTemplate.execute("INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('G.M. GESTIÓN ADMINISTRATIVA','GMGADM', 3)");
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)");
}
}

@ -20,6 +20,7 @@ import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.util.Collection;
import java.util.List;
@ -60,7 +61,7 @@ public class AdminController {
usuario.setRol(usuarioService.getRolById(1));
if(usuarioService.getUserByLogInName(usuario.getNombreLogIn()) == null){
usuarioService.createUsuario(usuario.getNombreUsuario(), usuario.getNombreLogIn(), usuario.getEmail(), usuario.getPassword(), usuario.isLogedIn(), usuario.getRol().getId());
usuarioService.createUsuario(usuario.getNombreUsuario(), usuario.getNombreLogIn(), usuario.getEmail(), usuario.getPassword(), usuario.getRol().getId());
return "redirect:/buscador?userCreated=true";
}else {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Este usuario ya existe");
@ -170,7 +171,20 @@ public class AdminController {
return ResponseEntity.ok("userDeleted");
}
@GetMapping("/admin/firstUser")
public String showAlterUserForm(Model model, Authentication authentication) {
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
boolean isAdmin = authorities.stream()
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ADMIN"));
if (!isAdmin) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "No tienes permisos para acceder a esta página");
}
String username = authentication.getName();
Usuario usuario = usuarioService.findByLogInName(username);
model.addAttribute("usuario", usuario);
model.addAttribute("newPassword", "");
return "admin/usuario/first_login_admin";
}

@ -2,6 +2,7 @@ package com.example.proyectofinal.controllers;
import com.example.proyectofinal.models.empresas.*;
import com.example.proyectofinal.models.login.Usuario;
import com.example.proyectofinal.repositories.empresas.*;
import com.example.proyectofinal.interfaces.IPagination;
import com.example.proyectofinal.servicios.empresa.*;
@ -12,6 +13,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.ui.Model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@ -26,7 +28,8 @@ import java.util.*;
@Controller
@RequestMapping("/buscador")
public class BuscadorController {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private AlumnoService alumnoService;
@Autowired
@ -58,6 +61,11 @@ public class BuscadorController {
boolean isAdmin = authorities.stream()
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ADMIN"));
if (isAdmin) {
String username = authentication.getName();
Usuario usuario = usuarioService.findByLogInName(username);
if (passwordEncoder.matches("1234", usuario.getPassword())) {
return "redirect:/admin/firstUser";
}
return "buscador_admin";
} else {
return "buscador_alumno";
@ -302,16 +310,13 @@ public class BuscadorController {
queryList.add(trimmedQuery);
}
}
List<Integer> itemsPage = Arrays.asList(5, 10, 15, 20, 25, 50);
Page<Alumno> page = null;
if(queryMultiWord.length>1){
page = alumnoService.getPageMultiWord(pageNum, size, sortField, sortDir, queryList, secondaryOption);
}else{
page = alumnoService.getPage(pageNum, size, sortField, sortDir, query, secondaryOption);
}
if(page!=null){
List<Alumno> alumnos = page.getContent();
addPaginationAttributes(model, pageNum, page, sortField, sortDir, itemsPage, size);

@ -91,9 +91,8 @@ public class AlumnoController {
String firstThreeLetters = nia.substring(0, 3);
String nombreLogIn="alu." +alumno.getNombre()+firstThreeLetters;
String email = Optional.of(alumno.getCorreo()).orElse(alumno.getCorreo2());
boolean isLogged = false;
Long newUser = usuarioService.findRolByName("USER");
usuarioService.createUsuario(nombreUsuario, nombreLogIn, email, password, isLogged, newUser);
usuarioService.createUsuario(nombreUsuario, nombreLogIn, email, password, newUser);
alumnoService.save(alumno);
return new ResponseEntity<>("El alumno fue guardado con exito", HttpStatus.OK);
}catch (Exception e) {

@ -61,7 +61,7 @@ public class SucursalController {
ArrayList<Sucursal> sucursales;
sucursales = (ArrayList<Sucursal>) sucursalService.findAll();
for (Sucursal s : sucursales) {
if (s.getSedeCentral()) {
if (s.getSedeCentral() && sedeCentral) {
return new ResponseEntity<>("Ya existe una sede central", HttpStatus.BAD_REQUEST);
}
}
@ -102,7 +102,7 @@ public class SucursalController {
ArrayList<Sucursal> sucursales;
sucursales = (ArrayList<Sucursal>) sucursalService.findAll();
for (Sucursal s : sucursales) {
if (s.getSedeCentral()) {
if (s.getSedeCentral() && sedeCentral) {
return new ResponseEntity<>("Ya existe una sede central", HttpStatus.BAD_REQUEST);
}
}

@ -1,36 +1,19 @@
INSERT INTO familias (nombre) VALUES ('Informatica');
INSERT INTO familias (nombre) VALUES ('Sanidad');
INSERT INTO familias (nombre) VALUES ('Economia');
INSERT INTO familias (nombre) VALUES ('Deporte');
INSERT INTO familias (nombre) VALUES ('Tourismo');
-- Insert into Ciclo table
INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('Dessarrollo de aplicaciones multiplataforma','DAM2', 1);
INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('Dessarrollo de aplicaciones web','DAW2', 1);
INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('Gestion de servidores ANCII','ANCI2', 1);
INSERT INTO Ciclos (nombre, codigo, fk_familia) VALUES ('Tourismo','TOUR', 5);
INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('Deporte','DEP', 4);
INSERT INTO ciclos (nombre, codigo, fk_familia) VALUES ('Contabilidad','Cont', 3);
-- Insert into Alumno table
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Jorge', 'Doe', NULL , '2000-01-01', 'Masculino', '11345678', '123456A', 'john.doe@example.com', 'john.smith@example.com', 'American', 'Java, Python', 1);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Jane', 'Doe', 'Johnson', '2000-02-02', 'Femenino', '12345678', '123456B', 'jane.doe@example.com', 'jane.johnson@example.com', 'American', 'Guitara', 2);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Robert', 'Smith', NULL , '2000-03-03', 'Masculino', '13345679', '123458C', 'robert.smith@example.com', NULL , 'British', 'Eletricista', 3);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Emily', 'Johnson', 'Smith', '2000-04-04', 'Femenino', '14345676', '123678D', 'emily.johnson@example.com', 'emily.smith@example.com', 'British', 'Moviles', 4);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('James', 'Brown', 'Johnson', '2000-05-05', 'Masculino', '1534567', '123478E', 'james.brown@example.com', NULL, 'Australian', 'Deportista', 5);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Michael', 'Jackson', 'Smith', '2000-06-06', 'Masculino', '1634567', '125678F', 'michael.jackson@example.com', 'michael.smith@example.com', 'American', 'Music, Dance', 1);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Emma', 'Watson', 'Johnson', '2000-07-07', 'Femenino', '1734567', '123458G', 'emma.watson@example.com', 'emma.johnson@example.com', 'British', 'Acting, French', 2);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Tom', 'Cruise',NULL , '2000-08-08', 'Masculino', '1834567', '1234567', 'tom.cruise@example.com',NULL, 'American', 'Acting, Stunts', 3);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Jennifer', 'Lawrence', 'Smith', '2000-09-09', 'Femenino', '1934567', '123478I', 'jennifer.lawrence@example.com', 'jennifer.smith@example.com', 'American', 'Acting, Archery', 4);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Chris', 'Hemsworth', 'Johnson', '2000-10-10', 'Masculino', '1104567', '123678J', 'chris.hemsworth@example.com',NULL , 'Australian', 'Acting, Fitness', 5);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Brad', 'Pitt', 'Johnson', '2000-11-11', 'Masculino', '1114567', '123678K', 'brad.pitt@example.com', 'brad.johnson@example.com', 'American', 'Acting, Production', 1);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Angelina', 'Jolie', 'Smith', '2000-12-12', 'Femenino', '1124567', '123678L', 'angelina.jolie@example.com', 'angelina.smith@example.com', 'American', 'Acting, Humanitarian', 2);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Leonardo', 'DiCaprio', NULL , '2001-01-01', 'Masculino', '1134567', '123678M', 'leonardo.dicaprio@example.com',NULL , 'American', 'Acting, Environmental activism', 3);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Scarlett', 'Johansson', 'Johnson', '2001-02-02', 'Femenino', '1144567', '123678N', 'scarlett.johansson@example.com', 'scarlett.johnson@example.com', 'American', 'Acting, Singing', 4);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Michael', 'Jackson', 'Smith', '2000-06-06', 'Masculino', '1634567', '125678F', 'michael.jackson@example.com', 'michael.smith@example.com', 'American', 'Music, Dance', 6);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Emma', 'Watson', 'Johnson', '2000-07-07', 'Femenino', '1734567', '123458G', 'emma.watson@example.com', 'emma.johnson@example.com', 'British', 'Acting, French', 7);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Tom', 'Cruise',NULL , '2000-08-08', 'Masculino', '1834567', '1234567', 'tom.cruise@example.com',NULL, 'American', 'Acting, Stunts', 8);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Jennifer', 'Lawrence', 'Smith', '2000-09-09', 'Femenino', '1934567', '123478I', 'jennifer.lawrence@example.com', 'jennifer.smith@example.com', 'American', 'Acting, Archery', 9);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Chris', 'Hemsworth', 'Johnson', '2000-10-10', 'Masculino', '1104567', '123678J', 'chris.hemsworth@example.com',NULL , 'Australian', 'Acting, Fitness',10);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Brad', 'Pitt', 'Johnson', '2000-11-11', 'Masculino', '1114567', '123678K', 'brad.pitt@example.com', 'brad.johnson@example.com', 'American', 'Acting, Production', 11);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Angelina', 'Jolie', 'Smith', '2000-12-12', 'Femenino', '1124567', '123678L', 'angelina.jolie@example.com', 'angelina.smith@example.com', 'American', 'Acting, Humanitarian', 12);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Leonardo', 'DiCaprio', NULL , '2001-01-01', 'Masculino', '1134567', '123678M', 'leonardo.dicaprio@example.com',NULL , 'American', 'Acting, Environmental activism', 2);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Scarlett', 'Johansson', 'Johnson', '2001-02-02', 'Femenino', '1144567', '123678N', 'scarlett.johansson@example.com', 'scarlett.johnson@example.com', 'American', 'Acting, Singing', 1);
INSERT INTO alumnos (nombre, apellido, apellido2, fecha_nacimiento, genero, nia, dni, correo, correo2, nacionalidad, keywords, fk_ciclo) VALUES ('Hugh', 'Jackman', 'Smith', '2001-03-03', 'Masculino', '1154567', '115478O', 'hugh.jackman@example.com', null, 'Australian', 'Acting, Singing', 5);

@ -32,9 +32,6 @@ public class Usuario {
@Column(length = 60)
private String password;
private boolean logedIn;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, fetch = FetchType.EAGER)
@JoinColumn(name = "fk_rol", referencedColumnName = "id")
@OnDelete(action = OnDeleteAction.CASCADE)

@ -13,21 +13,10 @@ public interface UserRepository extends JpaRepository<Usuario, Long>{
@Query("SELECT u FROM Usuario u WHERE u.nombreLogIn = ?1")
Optional<Usuario> findByNombreUsuario(String nombreLogIn);
@Modifying
@Query("UPDATE Usuario u SET u.logedIn = true WHERE u.id = ?1")
void updateLogedIn(Long id);
@Modifying
@Query("UPDATE Usuario u SET u.logedIn = false WHERE u.id = ?1")
void resetLogedIn(Long id);
@Query("SELECT u FROM Usuario u WHERE u.nombreLogIn = ?1")
Optional<Usuario> findByNombreUsuarioLogIn(String logIn);
@Modifying
@Query("UPDATE Usuario u SET u.logedIn = false")
void resetAllLogedIn();
@Query("SELECT u FROM Usuario u WHERE u.email = ?1")
Optional<Object> findByEmail(String correo);
}

@ -1,9 +1,12 @@
package com.example.proyectofinal.servicios.empresa;
import com.example.proyectofinal.models.empresas.Alumno;
import com.example.proyectofinal.models.empresas.Ciclo;
import com.example.proyectofinal.models.empresas.Familia;
import com.example.proyectofinal.models.login.Usuario;
import com.example.proyectofinal.repositories.empresas.CicloRepository;
import com.example.proyectofinal.servicios.implemetations.empresas.ICiclos;
import com.example.proyectofinal.servicios.user.UsuarioService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;
@ -22,6 +25,8 @@ public class CicloService implements ICiclos {
@Autowired
private OfertaService ofertaService;
@Autowired
private UsuarioService usuarioService;
@Override
@ -48,6 +53,12 @@ public class CicloService implements ICiclos {
public void deleteById(Long id) {
Ciclo ciclo = cicloRepository.findById(id).orElse(null);
if(ciclo != null){
Alumno alumno = alumnoService.findById(id);
String logIn = "alu." + alumno.getNombre() + alumno.getNia().substring(0, 3);
Usuario usuario = usuarioService.findByLogInName(logIn);
if(usuario != null){
usuarioService.deleteById(usuario.getId());
}
alumnoService.deleteByCiclo(ciclo.getId());
ofertaService.deleteByCicloId(ciclo.getId());
cicloRepository.deleteById(id);

@ -8,7 +8,7 @@ import java.util.Optional;
public interface IUsuario {
Usuario createUsuario(String nombreUsuario, String nombreLogIn, String email, String password, boolean loged, Long rolId);
Usuario createUsuario(String nombreUsuario, String nombreLogIn, String email, String password, Long rolId);
Long findRolByName(String user);

@ -49,28 +49,20 @@ public class UsuarioService implements IUsuario {
Usuario usuario = userRepository.findByNombreUsuario(nombreLogIn)
.orElseThrow(() -> new UsernameNotFoundException("Usuario no encontrado"));
if (passwordEncoder.matches(password, usuario.getPassword())) {
userRepository.updateLogedIn( usuario.getId());
return usuario;
} else {
throw new BadCredentialsException("Invalid password");
}
}
@Transactional
public void logout(String nombreLogIn) {
Usuario usuario = userRepository.findByNombreUsuario(nombreLogIn)
.orElseThrow(() -> new UsernameNotFoundException("Usuario no encontrado"));
userRepository.resetLogedIn(usuario.getId());
}
@Override
public Usuario createUsuario(String nombreUsuario, String nombreLogIn, String email, String password, boolean loged, Long rolId) {
public Usuario createUsuario(String nombreUsuario, String nombreLogIn, String email, String password, Long rolId) {
// Insert into usuario table
//System.out.println("TEST: BEFORE"+ password);
String encodedPassword = passwordEncoder.encode(password);
//System.out.println("TEST AFTER: "+ encodedPassword);
String insertUsuarioSql = "INSERT INTO usuario (nombre_usuario, nombre_log_in, email, password, loged_in, fk_rol) VALUES (?, ?, ?, ?, ?, ?)";
jdbcTemplate.update(insertUsuarioSql, nombreUsuario, nombreLogIn, email, encodedPassword, loged, rolId);
String insertUsuarioSql = "INSERT INTO usuario (nombre_usuario, nombre_log_in, email, password, fk_rol) VALUES (?, ?, ?, ?, ?)";
jdbcTemplate.update(insertUsuarioSql, nombreUsuario, nombreLogIn, email, encodedPassword, rolId);
// Get the last inserted id
Long usuarioId = jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Long.class);
@ -89,9 +81,8 @@ public class UsuarioService implements IUsuario {
jdbcTemplate.update(insertRolAutoridadSql, rolId, autoridad.getId());
}
}
Usuario usuario = userRepository.findById(usuarioId).orElse(null);
return usuario;
return userRepository.findById(usuarioId).orElse(null);
}
@Override
@ -143,10 +134,6 @@ public class UsuarioService implements IUsuario {
userRepository.deleteById(id);
}
public void logoutAllUsers() {
userRepository.resetAllLogedIn();
}
public boolean isAdmin() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
for (GrantedAuthority authority : authentication.getAuthorities()) {

@ -16,6 +16,7 @@ server.port=8080
#Dialecto
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
#EMAIL DATA
spring.mail.host=mail.ies.edu.es

@ -1,122 +0,0 @@
-- Insert 'READ', 'WRITE', and 'DELETE' into the autoridad table if the table is empty
INSERT INTO autoridad (nombre)
SELECT 'READ' WHERE NOT EXISTS (SELECT 1 FROM autoridad);
INSERT INTO autoridad (nombre)
SELECT 'WRITE' WHERE NOT EXISTS (SELECT 1 FROM autoridad);
INSERT INTO autoridad (nombre)
SELECT 'DELETE' WHERE NOT EXISTS (SELECT 1 FROM autoridad);
INSERT INTO skills (nombre)
SELECT 'Java' WHERE NOT EXISTS (SELECT 1 FROM skills);
INSERT INTO skills (nombre)
SELECT 'Microsoft XL' WHERE NOT EXISTS (SELECT 1 FROM skills);
INSERT INTO skills (nombre)
SELECT 'Ingles' WHERE NOT EXISTS (SELECT 1 FROM skills);
INSERT INTO skills (nombre)
SELECT 'Aluman' WHERE NOT EXISTS (SELECT 1 FROM skills);
INSERT INTO skills (nombre)
SELECT 'Ruso' WHERE NOT EXISTS (SELECT 1 FROM skills);
INSERT INTO skills (nombre)
SELECT 'Python' WHERE NOT EXISTS (SELECT 1 FROM skills);
INSERT INTO skills (nombre)
SELECT 'C++' WHERE NOT EXISTS (SELECT 1 FROM skills);
INSERT INTO skills (nombre)
SELECT 'C#' WHERE NOT EXISTS (SELECT 1 FROM skills);
INSERT INTO skills (nombre)
SELECT 'HTML' WHERE NOT EXISTS (SELECT 1 FROM skills);
INSERT INTO skills (nombre)
SELECT 'CSS' WHERE NOT EXISTS (SELECT 1 FROM skills);
INSERT INTO skills (nombre)
SELECT 'JavaScript' WHERE NOT EXISTS (SELECT 1 FROM skills);
INSERT INTO skills (nombre)
SELECT 'PHP' WHERE NOT EXISTS (SELECT 1 FROM skills);
INSERT INTO skills (nombre)
SELECT 'SQL' WHERE NOT EXISTS (SELECT 1 FROM skills);
INSERT INTO skills (nombre)
SELECT 'Marketing' WHERE NOT EXISTS (SELECT 1 FROM skills);
INSERT INTO skills (nombre)
SELECT 'Carnet de conducir' WHERE NOT EXISTS (SELECT 1 FROM skills);
-- Insert for sectores
INSERT INTO sectores (nombre)
SELECT 'Agricultura' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Tecnologías de la información y la comunicación' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Ganadería' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Pesca' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Silvicultura' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Turismo' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Minería' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Industria manufacturera' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Construcción' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Industria energética' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Industria química' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Transporte y logística' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Turismo y hostelería' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Salud' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Finanzas' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Telecomunicaciones' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Entretenimiento y medios' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Servicios profesionales' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Investigación y desarrollo (I+D)' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Tecnologías de la información y la comunicación (TIC)' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Servicios de información' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Servicios gubernamentales' WHERE NOT EXISTS (SELECT 1 FROM sectores);
INSERT INTO sectores (nombre)
SELECT 'Servicios sin ánimo de lucro' WHERE NOT EXISTS (SELECT 1 FROM sectores);

@ -58,6 +58,10 @@ h1 {
white-space: normal; /* Allows text to wrap to next line */
max-height: 25px !important; /* Set a specific height */
}
.table .td.scrollable-cell .keyword-cell {
min-width: 300px !important;
}
.table tr td:first-child {
min-width: 150px !important;
}

@ -0,0 +1,136 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Editar Usuario</title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" th:href="@{/top.css}">
<style>
form {
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
width: 100%;
max-width: none;
margin: auto;
padding: 25px;
margin-top: 100px;
}
.btn {
margin-top: 25px;
margin-right: 5px;
width: 120px;
height: 40px;
font-family: Verdana, Geneva, Tahoma, sans-serif
}
form input[type="submit"], form input[type="button"] {
width: 100px;
}
form label{
font-size: 20px;
margin-bottom: 10px;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
body, h1 {
margin: 0;
padding: 0;
width: 100%;
box-sizing: border-box;
}
input[type="text"], input[type="password"], input[type="email"] {
width: 350px;
height: 25px;
font-size: 15px;
}
</style>
</head>
<body>
<h1>Editar Usuario</h1>
<form th:action="@{/admin/update_usuario}" th:object="${usuario}" method="post">
<input type="hidden" th:field="*{id}" id="userId">
<div class="form-group row">
<label class="col-sm-3 col-form-label" for="nombreUsuario">Username:</label>
<div class="col-sm-9">
<input type="text" th:field="*{nombreUsuario}" id="nombreUsuario" required maxlength="250" class="form-control">
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label" for="nombreLogIn">Login Name:</label>
<div class="col-sm-9">
<input type="text" th:field="*{nombreLogIn}" id="nombreLogIn" required maxlength=" 70" class="form-control">
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label" for="email">Email:</label>
<div class="col-sm-9">
<input type="email" th:field="*{email}" id="email" required maxlength="100" class="form-control">
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label" for="password">Password:</label>
<div class="col-sm-9">
<input type="password" th:field="*{password}" id="password" class="form-control" value="" placeholder="Complete esto solo si desea cambiar la contraseña.">
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label" for="confirmPassword">Confirm Password:</label>
<div class="col-sm-9">
<input type="password" id="confirmPassword" required maxlength="60" class="form-control" value="" placeholder=" Confirmar contraseña" disabled>
</div>
</div>
<input type="hidden" th:field="*{rol}" id="rol">
<div class="text-center">
<input type="submit" value="Guardar" class="btn"/>
<input type="button" value="Cancelar" id="btnCancelar" class="btn" onclick="goBack()"/>
</div>
</form>
<script>
function goBack() {
window.location.href = "/buscador";
}
// Log the selected user
//console.log('User selected: ' + userId);
$(document).ready(function() {
var $password = $('#password');
var $confirmPassword = $('#confirmPassword');
$password.on('input', function() {
var password = $password.val();
if (password) {
$confirmPassword.prop('disabled', false);
} else {
$confirmPassword.prop('disabled', true);
}
});
$('form').on('submit', function(e) {
var password = $password.val();
var confirmPassword = $confirmPassword.val();
if (password !== confirmPassword) {
alert("Las contraseñas no coinciden!");
e.preventDefault(); // Prevent form from submitting
}
});
});
$(document).ready(function() {
alert('ES NECESARIO EL CAMBIO DE LA CONTRASEÑA POR SEGURIDAD.');
});
</script>
</body>
</html>

@ -50,20 +50,21 @@
#user{
position: relative;
margin-left: 50px;
padding: 0px;
padding: 0;
z-index: 2;
color: white;
width: 50px; /* Adjust as needed */
height: 50px; /* Adjust as needed */
width: 50px;
height: 50px;
display: flex;
flex-direction: column; /* New property */
align-items: center; /* Vertically center the contents */
justify-content: center; /* Horizontally center the contents */
text-align: center; /* Center the text */
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
}
#user-icon {
width: 22px; /* Adjust as needed */
height: 22px; /* Adjust as needed */
width: 22px;
height: 22px;
}
#user p {
@ -169,6 +170,8 @@
if (userCreated === 'true') {
alert('Nuevo Usuario creado');
urlParams.set('userCreated', 'false');
window.history.replaceState({}, '', `${location.pathname}?${urlParams}`);
}
});
@ -192,16 +195,21 @@
if (userUpdated === 'true') {
alert('Usuario actualizado correctamente');
userUpdated === 'false';
urlParams.set('userUpdated', 'false');
window.history.replaceState({}, '', `${location.pathname}?${urlParams}`);
}
});
$(document).ready(function() {
const urlParams = new URLSearchParams(window.location.search);
const error = urlParams.get('error');
if (error === 'selfDelete') {
alert('No puedes eliminarte a ti mismo');
// Set 'error' parameter to 'false'
urlParams.set('error', 'false');
window.history.replaceState({}, '', `${location.pathname}?${urlParams}`);
}
});
@ -223,7 +231,8 @@
const userDeleted = urlParams.get('userDeleted');
if (userDeleted === 'true') {
alert('Usuario Borrado');
userDeleted === 'false';
urlParams.set('userDeleted', 'false');
window.history.replaceState({}, '', `${location.pathname}?${urlParams}`);
}
});
@ -321,7 +330,6 @@
this.action = "/buscador/" + searchOption.value + "/page/1";
return true;
}
</script>
</body>
</html>

@ -47,13 +47,11 @@
justify-content: space-between;
width: 100%;
}
#date{
margin-top: 15px;
}
#user{
position: relative;
margin-left: 50px;
padding: 0px;
padding: 0;
z-index: 2;
color: white;
width: 50px; /* Adjust as needed */
height: 50px; /* Adjust as needed */
@ -204,7 +202,8 @@
if (userUpdated === 'true') {
alert('Usuario actualizado correctamente');
userUpdated === 'false';
urlParams.set('userUpdated', 'false');
window.history.replaceState({}, '', `${location.pathname}?${urlParams}`);
}
});
document.getElementById('searchForm').addEventListener('submit', function() {

@ -10,13 +10,13 @@
<meta charset="UTF-8">
<title>Lista: Alumnos</title>
<style>
.nombre-cell{
width: 200px;
}
.table td.scrollable-cell .skill-cell {
width: 150px;
min-height: 50px;
}
.nombre-cell{
width: 200px;
}
</style>
</head>
<body>
@ -94,7 +94,7 @@
Keywords
</a>
</th>
<th class="table-header">
<th class="table-header ciclo-header">
<a th:href="@{'/buscador/alumnos/page/' + ${currentPage} + '?sortField=ciclo.nombre&sortDir=' + ${reverseSortDir}+ '&secondaryOption=' + ${secondaryOption}}">
Ciclo
</a>
@ -123,16 +123,12 @@
<td>[[${alumno.correo}]]</td>
<td>[[${alumno.correo2}]]</td>
<td>[[${alumno.nacionalidad}]]</td>
<td class="keywords-cell">
<div class="scrollable-content">
[[${alumno.keywords}]]
</div>
</td>
<td class="scrollable-cell">
<div class="scrollable-content skill-cell">
[[${alumno.ciclo.nombre}]]
[[${alumno.keywords}]]
</div>
</td>
<td>[[${alumno.ciclo.nombre}]]</td>
<td class="scrollable-cell">
<div class="scrollable-content skill-cell">
<span th:each="skill : ${alumno.skills}" th:text="${skill.nombre} + ' '"></span>
@ -310,14 +306,16 @@
<td>${alumno.correo}</td>
<td>${alumno.correo2}</td>
<td>${alumno.nacionalidad}</td>
<td class="keywords-cell">
<div class="scrollable-content">
<td class="scrollable-cell keyword">
<div class="scrollable-content skill-cell">
${alumno.keywords}
</div>
</td>
<td>${alumno.ciclo.nombre}</td>
<td class="keywords-cell">
<div class="scrollable-content">
<td >
${alumno.ciclo.nombre}
</td>
<td class="scrollable-cell">
<div class="scrollable-content skill-cell">
${alumno.skills.map(skill => skill.nombre).join(', ')}
</div>
</td>
@ -399,7 +397,6 @@
}
function generatePDF_All() {
var querySearchBar = document.querySelector('#myInput').value;
var query = /*[[${query}]]*/ 'defaultQuery';
var secondaryOption = /*[[${secondaryOption}]]*/ 'defaultSecondaryOption';

@ -10,7 +10,10 @@
<meta charset="UTF-8">
<title>Lista Empresas</title>
<style>
.table td.scrollable-cell .skill-cell {
width: 300px;
min-height: 50px;
}
</style>
</head>
<body>
@ -76,12 +79,16 @@
<td>[[${empresa.cif}]]</td>
<td>[[${empresa.correo}]]</td>
<td>[[${empresa.telefono}]]</td>
<td class="keywords-cell">
<div class="scrollable-content">
<td class="scrollable-cell">
<div class="scrollable-content skill-cell">
[[${empresa.keywords}]]
</div>
</td>
<td>[[${empresa.sector.nombre}]]</td>
<td class="scrollable-cell">
<div class="scrollable-content skill-cell">
[[${empresa.sector.nombre}]]
</div>
</td>
</tr>
</tbody>
</table>
@ -360,6 +367,7 @@
<th>Cif</th>
<th>Correo</th>
<th>Telefono</th>
<th>Keywords</th>
<th>Sector</th>
`;
tableHead.appendChild(headerRow);
@ -375,7 +383,16 @@
<td>${empresa.cif}</td>
<td>${empresa.correo}</td>
<td>${empresa.telefono}</td>
<td>${empresa.sector.nombre}</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);
});

@ -130,37 +130,43 @@
window.location = "/admin/familia/update/" + rowId;
}
var modal = document.getElementById("modalDelete");
function handleDelete(event) {
console.log("handleDelete function called");
console.log("Delete icon clicked");
const row = event.target.closest('tr');
const rowId = row.dataset.id;
var modal = document.getElementById("modalDelete");
var closeSpan = document.getElementsByClassName("close")[0];
var deleteSpan = document.getElementsByClassName("delete")[0];
modal.style.display = "block";
document.body.style.pointerEvents = 'none';
modal.style.pointerEvents = 'auto';
var closeSpan = document.getElementsByClassName("close")[0];
var deleteSpan = document.getElementsByClassName("delete")[0];
closeSpan.onclick = function() {
modal.style.display = "none";
document.body.style.pointerEvents = 'auto';
}
deleteSpan.onclick = function() {
$.ajax({
url: '/familia/delete/' + rowId,
type: 'GET',
success: function(response) {
if (response === "La familia ha sido eliminada") {
alert("Familia borrada con exito");
window.location.reload();
} else {
alert("Error al borrar familia");
setTimeout(function() {
deleteSpan.onclick = function() {
$.ajax({
url: '/familia/delete/' + rowId,
type: 'GET',
success: function(response) {
if (response === "La familia ha sido eliminada") {
alert("Familia borrada con exito");
modal.style.display = "none"; // Hide the modal
document.body.style.pointerEvents = 'auto'; // Enable pointer events
window.location.reload(); // Reload the page
} else {
alert("Error al borrar familia");
}
}
}
});
}
});
}
}, 500); // Delay of 500 milliseconds
}
$myInput.on('input', function() {

@ -11,8 +11,7 @@
<title>Lista Ofertas</title>
<style>
.table td.scrollable-cell .skill-cell {
width: 150px;
min-height: 50px;
max-height: 50px!important;
}
</style>
</head>
@ -76,7 +75,11 @@
<td>[[${oferta.fecha}]]</td>
<td>[[${oferta.descripcion}]]</td>
<td>[[${oferta.sucursal.nombre}]]</td>
<td>[[${oferta.ciclo.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>
@ -254,7 +257,11 @@
<td>${oferta.fecha}</td>
<td>${oferta.descripcion}</td>
<td>${oferta.sucursal.nombre}</td>
<td>${oferta.ciclo.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(', ')}

Loading…
Cancel
Save

Powered by INFORMATICA.FP.EDU.ES.