Implementar controladores Estudiante, Materia y Empresarial
- Materia: entidad, repositorio, servicio y GET /materias (listado con filtro opcional por tipo) y GET /materias/{id} - Estudiante: entidad, repositorio, servicio y endpoints /estudiantes (listar, /me, crear y actualizar perfil del usuario autenticado, obtener por id) - Empresarial: entidades EmpresaVinculada y ResenaEmpresarial, repositorios, servicio y endpoints GET /empresarial (con filtros busqueda/calificacionMinima, contrato { empresas: [...] } esperado por el frontend), GET /empresarial/{id}/resenas y POST /empresarial/resenas Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
dantereach committed
Sep 2, 2026 at 13:26 UTC
f4703edd835cb42a24dc28e42a20fcea833ded65
21 files changed
+796
-6
src/main/java/com/tecmilenio/mapsconect/controller/EmpresarialController.java
+42
-2
@@ -1,9 +1,49 @@
1
package com.tecmilenio.mapsconect.controller;
2
3
-import org.springframework.web.bind.annotation.RequestMapping;
4
-import org.springframework.web.bind.annotation.RestController;
3
+import com.tecmilenio.mapsconect.dto.ApiResponse;
4
+import com.tecmilenio.mapsconect.dto.EmpresaDTO;
5
+import com.tecmilenio.mapsconect.dto.ResenaDTO;
6
+import com.tecmilenio.mapsconect.dto.ResenaRequestDTO;
7
+import com.tecmilenio.mapsconect.service.EmpresarialService;
8
+import jakarta.validation.Valid;
9
+import org.springframework.beans.factory.annotation.Autowired;
10
+import org.springframework.http.HttpStatus;
11
+import org.springframework.http.ResponseEntity;
12
+import org.springframework.security.core.Authentication;
13
+import org.springframework.web.bind.annotation.*;
14
+
15
+import java.util.List;
16
+import java.util.Map;
17
18
@RestController
19
@RequestMapping("/empresarial")
20
public class EmpresarialController {
21
+
22
+ @Autowired
23
+ private EmpresarialService empresarialService;
24
+
25
+ // Contrato consumido por frontend/js/pages/empresarial.js: { empresas: [...] }
26
+ @GetMapping
27
+ public ResponseEntity<Map<String, Object>> listar(
28
+ @RequestParam(required = false) String busqueda,
29
+ @RequestParam(required = false) Double calificacionMinima) {
30
+ List<EmpresaDTO> empresas = empresarialService.listarEmpresas(busqueda, calificacionMinima);
31
+ return ResponseEntity.ok(Map.of("empresas", empresas));
32
+ }
33
+
34
+ @GetMapping("/{id}/resenas")
35
+ public ResponseEntity<ApiResponse<List<ResenaDTO>>> listarResenas(@PathVariable Integer id) {
36
+ return ResponseEntity.ok(ApiResponse.success(empresarialService.listarResenasPorEmpresa(id)));
37
+ }
38
+
39
+ @PostMapping("/resenas")
40
+ public ResponseEntity<ApiResponse<ResenaDTO>> crearResena(
41
+ Authentication authentication,
42
+ @Valid @RequestBody ResenaRequestDTO dto) {
43
+ ResenaDTO resena = empresarialService.crearResena(authentication.getName(), dto);
44
+ return ResponseEntity.status(HttpStatus.CREATED)
45
+ .body(ApiResponse.success(resena, "Reseña publicada correctamente"));
46
+ }
47
+
48
}
49
+
src/main/java/com/tecmilenio/mapsconect/controller/EstudianteController.java
+50
-2
@@ -1,9 +1,57 @@
1
package com.tecmilenio.mapsconect.controller;
2
3
-import org.springframework.web.bind.annotation.RequestMapping;
4
-import org.springframework.web.bind.annotation.RestController;
3
+import com.tecmilenio.mapsconect.dto.ApiResponse;
4
+import com.tecmilenio.mapsconect.dto.EstudianteDTO;
5
+import com.tecmilenio.mapsconect.dto.EstudianteRequestDTO;
6
+import com.tecmilenio.mapsconect.service.EstudianteService;
7
+import jakarta.validation.Valid;
8
+import org.springframework.beans.factory.annotation.Autowired;
9
+import org.springframework.http.HttpStatus;
10
+import org.springframework.http.ResponseEntity;
11
+import org.springframework.security.core.Authentication;
12
+import org.springframework.web.bind.annotation.*;
13
+
14
+import java.util.List;
15
16
@RestController
17
@RequestMapping("/estudiantes")
18
public class EstudianteController {
19
+
20
+ @Autowired
21
+ private EstudianteService estudianteService;
22
+
23
+ @GetMapping
24
+ public ResponseEntity<ApiResponse<List<EstudianteDTO>>> listar() {
25
+ return ResponseEntity.ok(ApiResponse.success(estudianteService.listar()));
26
+ }
27
+
28
+ @GetMapping("/me")
29
+ public ResponseEntity<ApiResponse<EstudianteDTO>> obtenerMiPerfil(Authentication authentication) {
30
+ EstudianteDTO estudiante = estudianteService.obtenerPerfilActual(authentication.getName());
31
+ return ResponseEntity.ok(ApiResponse.success(estudiante));
32
+ }
33
+
34
+ @GetMapping("/{id}")
35
+ public ResponseEntity<ApiResponse<EstudianteDTO>> obtenerPorId(@PathVariable Integer id) {
36
+ return ResponseEntity.ok(ApiResponse.success(estudianteService.obtenerPorId(id)));
37
+ }
38
+
39
+ @PostMapping
40
+ public ResponseEntity<ApiResponse<EstudianteDTO>> crear(
41
+ Authentication authentication,
42
+ @Valid @RequestBody EstudianteRequestDTO dto) {
43
+ EstudianteDTO estudiante = estudianteService.crearPerfil(authentication.getName(), dto);
44
+ return ResponseEntity.status(HttpStatus.CREATED)
45
+ .body(ApiResponse.success(estudiante, "Perfil de estudiante creado correctamente"));
46
+ }
47
+
48
+ @PutMapping("/me")
49
+ public ResponseEntity<ApiResponse<EstudianteDTO>> actualizar(
50
+ Authentication authentication,
51
+ @Valid @RequestBody EstudianteRequestDTO dto) {
52
+ EstudianteDTO estudiante = estudianteService.actualizarPerfil(authentication.getName(), dto);
53
+ return ResponseEntity.ok(ApiResponse.success(estudiante, "Perfil actualizado correctamente"));
54
+ }
55
+
56
}
57
+
src/main/java/com/tecmilenio/mapsconect/controller/MateriaController.java
+26
-2
@@ -1,9 +1,33 @@
1
package com.tecmilenio.mapsconect.controller;
2
3
-import org.springframework.web.bind.annotation.RequestMapping;
4
-import org.springframework.web.bind.annotation.RestController;
3
+import com.tecmilenio.mapsconect.dto.ApiResponse;
4
+import com.tecmilenio.mapsconect.dto.MateriaDTO;
5
+import com.tecmilenio.mapsconect.service.MateriaService;
6
+import org.springframework.beans.factory.annotation.Autowired;
7
+import org.springframework.http.ResponseEntity;
8
+import org.springframework.web.bind.annotation.*;
9
+
10
+import java.util.List;
11
12
@RestController
13
@RequestMapping("/materias")
14
public class MateriaController {
15
+
16
+ @Autowired
17
+ private MateriaService materiaService;
18
+
19
+ @GetMapping
20
+ public ResponseEntity<ApiResponse<List<MateriaDTO>>> listar(
21
+ @RequestParam(required = false) String tipo) {
22
+ List<MateriaDTO> materias = materiaService.listar(tipo);
23
+ return ResponseEntity.ok(ApiResponse.success(materias));
24
+ }
25
+
26
+ @GetMapping("/{id}")
27
+ public ResponseEntity<ApiResponse<MateriaDTO>> obtenerPorId(@PathVariable Integer id) {
28
+ MateriaDTO materia = materiaService.obtenerPorId(id);
29
+ return ResponseEntity.ok(ApiResponse.success(materia));
30
+ }
31
+
32
}
33
+
src/main/java/com/tecmilenio/mapsconect/dto/EmpresaDTO.java
new
+23
@@ -0,0 +1,23 @@
1
+package com.tecmilenio.mapsconect.dto;
2
+
3
+import lombok.AllArgsConstructor;
4
+import lombok.Builder;
5
+import lombok.Data;
6
+import lombok.NoArgsConstructor;
7
+
8
+@Data
9
+@NoArgsConstructor
10
+@AllArgsConstructor
11
+@Builder
12
+public class EmpresaDTO {
13
+
14
+ private Integer id;
15
+ private String nombre;
16
+ private String sector;
17
+ private String descripcion;
18
+ private Boolean activa;
19
+ private Double calificacion;
20
+ private Long totalResenas;
21
+ private ExperienciaDTO experienciaDestacada;
22
+
23
+}
src/main/java/com/tecmilenio/mapsconect/dto/EstudianteDTO.java
new
+24
@@ -0,0 +1,24 @@
1
+package com.tecmilenio.mapsconect.dto;
2
+
3
+import lombok.AllArgsConstructor;
4
+import lombok.Builder;
5
+import lombok.Data;
6
+import lombok.NoArgsConstructor;
7
+
8
+@Data
9
+@NoArgsConstructor
10
+@AllArgsConstructor
11
+@Builder
12
+public class EstudianteDTO {
13
+
14
+ private Integer id;
15
+ private Integer idUsuario;
16
+ private String nombreCompleto;
17
+ private String email;
18
+ private Integer idCarrera;
19
+ private String matricula;
20
+ private Integer semestreActual;
21
+ private String propositoVida;
22
+ private Integer puntosReputacion;
23
+
24
+}
src/main/java/com/tecmilenio/mapsconect/dto/EstudianteRequestDTO.java
new
+31
@@ -0,0 +1,31 @@
1
+package com.tecmilenio.mapsconect.dto;
2
+
3
+import jakarta.validation.constraints.Max;
4
+import jakarta.validation.constraints.Min;
5
+import jakarta.validation.constraints.NotBlank;
6
+import jakarta.validation.constraints.NotNull;
7
+import lombok.AllArgsConstructor;
8
+import lombok.Builder;
9
+import lombok.Data;
10
+import lombok.NoArgsConstructor;
11
+
12
+@Data
13
+@NoArgsConstructor
14
+@AllArgsConstructor
15
+@Builder
16
+public class EstudianteRequestDTO {
17
+
18
+ private Integer idCarrera;
19
+
20
+ @NotBlank(message = "La matrícula es obligatoria")
21
+ @jakarta.validation.constraints.Size(max = 20, message = "La matrícula no puede exceder 20 caracteres")
22
+ private String matricula;
23
+
24
+ @NotNull(message = "El semestre actual es obligatorio")
25
+ @Min(value = 1, message = "El semestre debe estar entre 1 y 12")
26
+ @Max(value = 12, message = "El semestre debe estar entre 1 y 12")
27
+ private Integer semestreActual;
28
+
29
+ private String propositoVida;
30
+
31
+}
src/main/java/com/tecmilenio/mapsconect/dto/ExperienciaDTO.java
new
+18
@@ -0,0 +1,18 @@
1
+package com.tecmilenio.mapsconect.dto;
2
+
3
+import lombok.AllArgsConstructor;
4
+import lombok.Builder;
5
+import lombok.Data;
6
+import lombok.NoArgsConstructor;
7
+
8
+@Data
9
+@NoArgsConstructor
10
+@AllArgsConstructor
11
+@Builder
12
+public class ExperienciaDTO {
13
+
14
+ private String autor;
15
+ private Integer semestre;
16
+ private String texto;
17
+
18
+}
src/main/java/com/tecmilenio/mapsconect/dto/MateriaDTO.java
new
+20
@@ -0,0 +1,20 @@
1
+package com.tecmilenio.mapsconect.dto;
2
+
3
+import lombok.AllArgsConstructor;
4
+import lombok.Builder;
5
+import lombok.Data;
6
+import lombok.NoArgsConstructor;
7
+
8
+@Data
9
+@NoArgsConstructor
10
+@AllArgsConstructor
11
+@Builder
12
+public class MateriaDTO {
13
+
14
+ private Integer id;
15
+ private String clave;
16
+ private String nombre;
17
+ private Integer creditos;
18
+ private String tipo;
19
+
20
+}
src/main/java/com/tecmilenio/mapsconect/dto/ResenaDTO.java
new
+25
@@ -0,0 +1,25 @@
1
+package com.tecmilenio.mapsconect.dto;
2
+
3
+import lombok.AllArgsConstructor;
4
+import lombok.Builder;
5
+import lombok.Data;
6
+import lombok.NoArgsConstructor;
7
+
8
+import java.time.LocalDateTime;
9
+
10
+@Data
11
+@NoArgsConstructor
12
+@AllArgsConstructor
13
+@Builder
14
+public class ResenaDTO {
15
+
16
+ private Integer id;
17
+ private Integer idEmpresa;
18
+ private Integer idEstudiante;
19
+ private String nombreEstudiante;
20
+ private Integer calificacion;
21
+ private String proyectoRealizado;
22
+ private String recomendaciones;
23
+ private LocalDateTime fechaResena;
24
+
25
+}
src/main/java/com/tecmilenio/mapsconect/dto/ResenaRequestDTO.java
new
+29
@@ -0,0 +1,29 @@
1
+package com.tecmilenio.mapsconect.dto;
2
+
3
+import jakarta.validation.constraints.Max;
4
+import jakarta.validation.constraints.Min;
5
+import jakarta.validation.constraints.NotNull;
6
+import lombok.AllArgsConstructor;
7
+import lombok.Builder;
8
+import lombok.Data;
9
+import lombok.NoArgsConstructor;
10
+
11
+@Data
12
+@NoArgsConstructor
13
+@AllArgsConstructor
14
+@Builder
15
+public class ResenaRequestDTO {
16
+
17
+ @NotNull(message = "La empresa es obligatoria")
18
+ private Integer idEmpresa;
19
+
20
+ @NotNull(message = "La calificación es obligatoria")
21
+ @Min(value = 1, message = "La calificación debe estar entre 1 y 5")
22
+ @Max(value = 5, message = "La calificación debe estar entre 1 y 5")
23
+ private Integer calificacion;
24
+
25
+ private String proyectoRealizado;
26
+
27
+ private String recomendaciones;
28
+
29
+}
src/main/java/com/tecmilenio/mapsconect/entity/EmpresaVinculada.java
new
+41
@@ -0,0 +1,41 @@
1
+package com.tecmilenio.mapsconect.entity;
2
+
3
+import jakarta.persistence.*;
4
+import lombok.AllArgsConstructor;
5
+import lombok.Builder;
6
+import lombok.Data;
7
+import lombok.NoArgsConstructor;
8
+
9
+import java.time.LocalDateTime;
10
+
11
+@Entity
12
+@Table(name = "empresas_vinculadas")
13
+@Data
14
+@NoArgsConstructor
15
+@AllArgsConstructor
16
+@Builder
17
+public class EmpresaVinculada {
18
+
19
+ @Id
20
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
21
+ @Column(name = "id_empresa")
22
+ private Integer id;
23
+
24
+ @Column(nullable = false, length = 200)
25
+ private String nombre;
26
+
27
+ @Column(length = 100)
28
+ private String sector;
29
+
30
+ @Column(columnDefinition = "TEXT")
31
+ private String descripcion;
32
+
33
+ @Builder.Default
34
+ @Column(nullable = false)
35
+ private Boolean activa = true;
36
+
37
+ @Builder.Default
38
+ @Column(name = "fecha_creacion", nullable = false)
39
+ private LocalDateTime fechaCreacion = LocalDateTime.now();
40
+
41
+}
src/main/java/com/tecmilenio/mapsconect/entity/Estudiante.java
new
+42
@@ -0,0 +1,42 @@
1
+package com.tecmilenio.mapsconect.entity;
2
+
3
+import jakarta.persistence.*;
4
+import lombok.AllArgsConstructor;
5
+import lombok.Builder;
6
+import lombok.Data;
7
+import lombok.NoArgsConstructor;
8
+
9
+@Entity
10
+@Table(name = "estudiantes")
11
+@Data
12
+@NoArgsConstructor
13
+@AllArgsConstructor
14
+@Builder
15
+public class Estudiante {
16
+
17
+ @Id
18
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
19
+ @Column(name = "id_estudiante")
20
+ private Integer id;
21
+
22
+ @OneToOne
23
+ @JoinColumn(name = "id_usuario", nullable = false, unique = true)
24
+ private Usuario usuario;
25
+
26
+ @Column(name = "id_carrera")
27
+ private Integer idCarrera;
28
+
29
+ @Column(nullable = false, length = 20)
30
+ private String matricula;
31
+
32
+ @Column(name = "semestre_actual", nullable = false)
33
+ private Integer semestreActual;
34
+
35
+ @Column(name = "proposito_vida", columnDefinition = "TEXT")
36
+ private String propositoVida;
37
+
38
+ @Builder.Default
39
+ @Column(name = "puntos_reputacion", nullable = false)
40
+ private Integer puntosReputacion = 0;
41
+
42
+}
src/main/java/com/tecmilenio/mapsconect/entity/Materia.java
new
+46
@@ -0,0 +1,46 @@
1
+package com.tecmilenio.mapsconect.entity;
2
+
3
+import jakarta.persistence.*;
4
+import lombok.AllArgsConstructor;
5
+import lombok.Builder;
6
+import lombok.Data;
7
+import lombok.NoArgsConstructor;
8
+
9
+import java.time.LocalDateTime;
10
+
11
+@Entity
12
+@Table(name = "materias")
13
+@Data
14
+@NoArgsConstructor
15
+@AllArgsConstructor
16
+@Builder
17
+public class Materia {
18
+
19
+ @Id
20
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
21
+ @Column(name = "id_materia")
22
+ private Integer id;
23
+
24
+ @Column(nullable = false, length = 20)
25
+ private String clave;
26
+
27
+ @Column(nullable = false, length = 150)
28
+ private String nombre;
29
+
30
+ @Builder.Default
31
+ @Column(nullable = false)
32
+ private Integer creditos = 0;
33
+
34
+ @Enumerated(EnumType.STRING)
35
+ @Column(nullable = false)
36
+ private Tipo tipo;
37
+
38
+ @Builder.Default
39
+ @Column(name = "fecha_creacion", nullable = false)
40
+ private LocalDateTime fechaCreacion = LocalDateTime.now();
41
+
42
+ public enum Tipo {
43
+ TRONCO_COMUN, DISCIPLINAR, CERTIFICADO, BIENESTAR
44
+ }
45
+
46
+}
src/main/java/com/tecmilenio/mapsconect/entity/ResenaEmpresarial.java
new
+45
@@ -0,0 +1,45 @@
1
+package com.tecmilenio.mapsconect.entity;
2
+
3
+import jakarta.persistence.*;
4
+import lombok.AllArgsConstructor;
5
+import lombok.Builder;
6
+import lombok.Data;
7
+import lombok.NoArgsConstructor;
8
+
9
+import java.time.LocalDateTime;
10
+
11
+@Entity
12
+@Table(name = "resenas_empresarial")
13
+@Data
14
+@NoArgsConstructor
15
+@AllArgsConstructor
16
+@Builder
17
+public class ResenaEmpresarial {
18
+
19
+ @Id
20
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
21
+ @Column(name = "id_resena")
22
+ private Integer id;
23
+
24
+ @ManyToOne
25
+ @JoinColumn(name = "id_estudiante", nullable = false)
26
+ private Estudiante estudiante;
27
+
28
+ @ManyToOne
29
+ @JoinColumn(name = "id_empresa", nullable = false)
30
+ private EmpresaVinculada empresa;
31
+
32
+ @Column(nullable = false)
33
+ private Integer calificacion;
34
+
35
+ @Column(name = "proyecto_realizado", columnDefinition = "TEXT")
36
+ private String proyectoRealizado;
37
+
38
+ @Column(columnDefinition = "TEXT")
39
+ private String recomendaciones;
40
+
41
+ @Builder.Default
42
+ @Column(name = "fecha_resena", nullable = false)
43
+ private LocalDateTime fechaResena = LocalDateTime.now();
44
+
45
+}
src/main/java/com/tecmilenio/mapsconect/repository/EmpresaVinculadaRepository.java
new
+16
@@ -0,0 +1,16 @@
1
+package com.tecmilenio.mapsconect.repository;
2
+
3
+import com.tecmilenio.mapsconect.entity.EmpresaVinculada;
4
+import org.springframework.data.jpa.repository.JpaRepository;
5
+import org.springframework.stereotype.Repository;
6
+
7
+import java.util.List;
8
+
9
+@Repository
10
+public interface EmpresaVinculadaRepository extends JpaRepository<EmpresaVinculada, Integer> {
11
+
12
+ List<EmpresaVinculada> findByActivaTrueAndNombreContainingIgnoreCase(String nombre);
13
+
14
+ List<EmpresaVinculada> findByActivaTrue();
15
+
16
+}
src/main/java/com/tecmilenio/mapsconect/repository/EstudianteRepository.java
new
+16
@@ -0,0 +1,16 @@
1
+package com.tecmilenio.mapsconect.repository;
2
+
3
+import com.tecmilenio.mapsconect.entity.Estudiante;
4
+import org.springframework.data.jpa.repository.JpaRepository;
5
+import org.springframework.stereotype.Repository;
6
+
7
+import java.util.Optional;
8
+
9
+@Repository
10
+public interface EstudianteRepository extends JpaRepository<Estudiante, Integer> {
11
+
12
+ Optional<Estudiante> findByUsuario_Id(Integer idUsuario);
13
+
14
+ boolean existsByMatricula(String matricula);
15
+
16
+}
src/main/java/com/tecmilenio/mapsconect/repository/MateriaRepository.java
new
+17
@@ -0,0 +1,17 @@
1
+package com.tecmilenio.mapsconect.repository;
2
+
3
+import com.tecmilenio.mapsconect.entity.Materia;
4
+import org.springframework.data.jpa.repository.JpaRepository;
5
+import org.springframework.stereotype.Repository;
6
+
7
+import java.util.List;
8
+import java.util.Optional;
9
+
10
+@Repository
11
+public interface MateriaRepository extends JpaRepository<Materia, Integer> {
12
+
13
+ List<Materia> findByTipo(Materia.Tipo tipo);
14
+
15
+ Optional<Materia> findByClave(String clave);
16
+
17
+}
src/main/java/com/tecmilenio/mapsconect/repository/ResenaEmpresarialRepository.java
new
+14
@@ -0,0 +1,14 @@
1
+package com.tecmilenio.mapsconect.repository;
2
+
3
+import com.tecmilenio.mapsconect.entity.ResenaEmpresarial;
4
+import org.springframework.data.jpa.repository.JpaRepository;
5
+import org.springframework.stereotype.Repository;
6
+
7
+import java.util.List;
8
+
9
+@Repository
10
+public interface ResenaEmpresarialRepository extends JpaRepository<ResenaEmpresarial, Integer> {
11
+
12
+ List<ResenaEmpresarial> findByEmpresa_Id(Integer idEmpresa);
13
+
14
+}
src/main/java/com/tecmilenio/mapsconect/service/EmpresarialService.java
new
+126
@@ -0,0 +1,126 @@
1
+package com.tecmilenio.mapsconect.service;
2
+
3
+import com.tecmilenio.mapsconect.dto.EmpresaDTO;
4
+import com.tecmilenio.mapsconect.dto.ExperienciaDTO;
5
+import com.tecmilenio.mapsconect.dto.ResenaDTO;
6
+import com.tecmilenio.mapsconect.dto.ResenaRequestDTO;
7
+import com.tecmilenio.mapsconect.entity.EmpresaVinculada;
8
+import com.tecmilenio.mapsconect.entity.Estudiante;
9
+import com.tecmilenio.mapsconect.entity.ResenaEmpresarial;
10
+import com.tecmilenio.mapsconect.entity.Usuario;
11
+import com.tecmilenio.mapsconect.exception.ResourceNotFoundException;
12
+import com.tecmilenio.mapsconect.repository.EmpresaVinculadaRepository;
13
+import com.tecmilenio.mapsconect.repository.EstudianteRepository;
14
+import com.tecmilenio.mapsconect.repository.ResenaEmpresarialRepository;
15
+import com.tecmilenio.mapsconect.repository.UsuarioRepository;
16
+import org.springframework.beans.factory.annotation.Autowired;
17
+import org.springframework.stereotype.Service;
18
+
19
+import java.util.Comparator;
20
+import java.util.List;
21
+
22
+@Service
23
+public class EmpresarialService {
24
+
25
+ @Autowired
26
+ private EmpresaVinculadaRepository empresaRepository;
27
+
28
+ @Autowired
29
+ private ResenaEmpresarialRepository resenaRepository;
30
+
31
+ @Autowired
32
+ private EstudianteRepository estudianteRepository;
33
+
34
+ @Autowired
35
+ private UsuarioRepository usuarioRepository;
36
+
37
+ public List<EmpresaDTO> listarEmpresas(String busqueda, Double calificacionMinima) {
38
+ List<EmpresaVinculada> empresas = (busqueda != null && !busqueda.isBlank())
39
+ ? empresaRepository.findByActivaTrueAndNombreContainingIgnoreCase(busqueda)
40
+ : empresaRepository.findByActivaTrue();
41
+
42
+ return empresas.stream()
43
+ .map(this::mapearAEmpresaDTO)
44
+ .filter(dto -> calificacionMinima == null
45
+ || dto.getCalificacion() == null
46
+ || dto.getCalificacion() >= calificacionMinima)
47
+ .toList();
48
+ }
49
+
50
+ public List<ResenaDTO> listarResenasPorEmpresa(Integer idEmpresa) {
51
+ if (!empresaRepository.existsById(idEmpresa)) {
52
+ throw new ResourceNotFoundException("Empresa no encontrada");
53
+ }
54
+ return resenaRepository.findByEmpresa_Id(idEmpresa).stream().map(this::mapearAResenaDTO).toList();
55
+ }
56
+
57
+ public ResenaDTO crearResena(String email, ResenaRequestDTO dto) {
58
+ Usuario usuario = usuarioRepository.findByEmail(email)
59
+ .orElseThrow(() -> new ResourceNotFoundException("Usuario no encontrado"));
60
+
61
+ Estudiante estudiante = estudianteRepository.findByUsuario_Id(usuario.getId())
62
+ .orElseThrow(() -> new RuntimeException("Debes completar tu perfil de estudiante antes de dejar una reseña"));
63
+
64
+ EmpresaVinculada empresa = empresaRepository.findById(dto.getIdEmpresa())
65
+ .orElseThrow(() -> new ResourceNotFoundException("Empresa no encontrada"));
66
+
67
+ ResenaEmpresarial resena = ResenaEmpresarial.builder()
68
+ .estudiante(estudiante)
69
+ .empresa(empresa)
70
+ .calificacion(dto.getCalificacion())
71
+ .proyectoRealizado(dto.getProyectoRealizado())
72
+ .recomendaciones(dto.getRecomendaciones())
73
+ .build();
74
+
75
+ return mapearAResenaDTO(resenaRepository.save(resena));
76
+ }
77
+
78
+ private EmpresaDTO mapearAEmpresaDTO(EmpresaVinculada empresa) {
79
+ List<ResenaEmpresarial> resenas = resenaRepository.findByEmpresa_Id(empresa.getId());
80
+
81
+ Double promedio = resenas.isEmpty() ? null
82
+ : resenas.stream().mapToInt(ResenaEmpresarial::getCalificacion).average().orElse(0);
83
+
84
+ ResenaEmpresarial mejorResena = resenas.stream()
85
+ .max(Comparator.comparingInt(ResenaEmpresarial::getCalificacion))
86
+ .orElse(null);
87
+
88
+ ExperienciaDTO experiencia = null;
89
+ if (mejorResena != null) {
90
+ Usuario autorUsuario = mejorResena.getEstudiante().getUsuario();
91
+ experiencia = ExperienciaDTO.builder()
92
+ .autor(autorUsuario != null ? autorUsuario.getNombre() : "Estudiante")
93
+ .semestre(mejorResena.getEstudiante().getSemestreActual())
94
+ .texto(mejorResena.getRecomendaciones() != null
95
+ ? mejorResena.getRecomendaciones()
96
+ : mejorResena.getProyectoRealizado())
97
+ .build();
98
+ }
99
+
100
+ return EmpresaDTO.builder()
101
+ .id(empresa.getId())
102
+ .nombre(empresa.getNombre())
103
+ .sector(empresa.getSector())
104
+ .descripcion(empresa.getDescripcion())
105
+ .activa(empresa.getActiva())
106
+ .calificacion(promedio)
107
+ .totalResenas((long) resenas.size())
108
+ .experienciaDestacada(experiencia)
109
+ .build();
110
+ }
111
+
112
+ private ResenaDTO mapearAResenaDTO(ResenaEmpresarial resena) {
113
+ Usuario usuario = resena.getEstudiante().getUsuario();
114
+ return ResenaDTO.builder()
115
+ .id(resena.getId())
116
+ .idEmpresa(resena.getEmpresa().getId())
117
+ .idEstudiante(resena.getEstudiante().getId())
118
+ .nombreEstudiante(usuario != null ? (usuario.getNombre() + " " + usuario.getApellido()) : null)
119
+ .calificacion(resena.getCalificacion())
120
+ .proyectoRealizado(resena.getProyectoRealizado())
121
+ .recomendaciones(resena.getRecomendaciones())
122
+ .fechaResena(resena.getFechaResena())
123
+ .build();
124
+ }
125
+
126
+}
src/main/java/com/tecmilenio/mapsconect/service/EstudianteService.java
new
+95
@@ -0,0 +1,95 @@
1
+package com.tecmilenio.mapsconect.service;
2
+
3
+import com.tecmilenio.mapsconect.dto.EstudianteDTO;
4
+import com.tecmilenio.mapsconect.dto.EstudianteRequestDTO;
5
+import com.tecmilenio.mapsconect.entity.Estudiante;
6
+import com.tecmilenio.mapsconect.entity.Usuario;
7
+import com.tecmilenio.mapsconect.exception.ResourceNotFoundException;
8
+import com.tecmilenio.mapsconect.repository.EstudianteRepository;
9
+import com.tecmilenio.mapsconect.repository.UsuarioRepository;
10
+import org.springframework.beans.factory.annotation.Autowired;
11
+import org.springframework.stereotype.Service;
12
+
13
+import java.util.List;
14
+
15
+@Service
16
+public class EstudianteService {
17
+
18
+ @Autowired
19
+ private EstudianteRepository estudianteRepository;
20
+
21
+ @Autowired
22
+ private UsuarioRepository usuarioRepository;
23
+
24
+ public List<EstudianteDTO> listar() {
25
+ return estudianteRepository.findAll().stream().map(this::mapearADTO).toList();
26
+ }
27
+
28
+ public EstudianteDTO obtenerPorId(Integer id) {
29
+ Estudiante estudiante = estudianteRepository.findById(id)
30
+ .orElseThrow(() -> new ResourceNotFoundException("Estudiante no encontrado"));
31
+ return mapearADTO(estudiante);
32
+ }
33
+
34
+ public EstudianteDTO obtenerPerfilActual(String email) {
35
+ Usuario usuario = obtenerUsuario(email);
36
+ Estudiante estudiante = estudianteRepository.findByUsuario_Id(usuario.getId())
37
+ .orElseThrow(() -> new ResourceNotFoundException("Aún no has completado tu perfil de estudiante"));
38
+ return mapearADTO(estudiante);
39
+ }
40
+
41
+ public EstudianteDTO crearPerfil(String email, EstudianteRequestDTO dto) {
42
+ Usuario usuario = obtenerUsuario(email);
43
+
44
+ if (estudianteRepository.findByUsuario_Id(usuario.getId()).isPresent()) {
45
+ throw new RuntimeException("Ya existe un perfil de estudiante para este usuario");
46
+ }
47
+ if (estudianteRepository.existsByMatricula(dto.getMatricula())) {
48
+ throw new RuntimeException("La matrícula ya está registrada");
49
+ }
50
+
51
+ Estudiante estudiante = Estudiante.builder()
52
+ .usuario(usuario)
53
+ .idCarrera(dto.getIdCarrera())
54
+ .matricula(dto.getMatricula())
55
+ .semestreActual(dto.getSemestreActual())
56
+ .propositoVida(dto.getPropositoVida())
57
+ .puntosReputacion(0)
58
+ .build();
59
+
60
+ return mapearADTO(estudianteRepository.save(estudiante));
61
+ }
62
+
63
+ public EstudianteDTO actualizarPerfil(String email, EstudianteRequestDTO dto) {
64
+ Usuario usuario = obtenerUsuario(email);
65
+ Estudiante estudiante = estudianteRepository.findByUsuario_Id(usuario.getId())
66
+ .orElseThrow(() -> new ResourceNotFoundException("Aún no has completado tu perfil de estudiante"));
67
+
68
+ estudiante.setIdCarrera(dto.getIdCarrera());
69
+ estudiante.setSemestreActual(dto.getSemestreActual());
70
+ estudiante.setPropositoVida(dto.getPropositoVida());
71
+
72
+ return mapearADTO(estudianteRepository.save(estudiante));
73
+ }
74
+
75
+ private Usuario obtenerUsuario(String email) {
76
+ return usuarioRepository.findByEmail(email)
77
+ .orElseThrow(() -> new ResourceNotFoundException("Usuario no encontrado"));
78
+ }
79
+
80
+ private EstudianteDTO mapearADTO(Estudiante estudiante) {
81
+ Usuario usuario = estudiante.getUsuario();
82
+ return EstudianteDTO.builder()
83
+ .id(estudiante.getId())
84
+ .idUsuario(usuario != null ? usuario.getId() : null)
85
+ .nombreCompleto(usuario != null ? (usuario.getNombre() + " " + usuario.getApellido()) : null)
86
+ .email(usuario != null ? usuario.getEmail() : null)
87
+ .idCarrera(estudiante.getIdCarrera())
88
+ .matricula(estudiante.getMatricula())
89
+ .semestreActual(estudiante.getSemestreActual())
90
+ .propositoVida(estudiante.getPropositoVida())
91
+ .puntosReputacion(estudiante.getPuntosReputacion())
92
+ .build();
93
+ }
94
+
95
+}
src/main/java/com/tecmilenio/mapsconect/service/MateriaService.java
new
+50
@@ -0,0 +1,50 @@
1
+package com.tecmilenio.mapsconect.service;
2
+
3
+import com.tecmilenio.mapsconect.dto.MateriaDTO;
4
+import com.tecmilenio.mapsconect.entity.Materia;
5
+import com.tecmilenio.mapsconect.exception.ResourceNotFoundException;
6
+import com.tecmilenio.mapsconect.repository.MateriaRepository;
7
+import org.springframework.beans.factory.annotation.Autowired;
8
+import org.springframework.stereotype.Service;
9
+
10
+import java.util.List;
11
+
12
+@Service
13
+public class MateriaService {
14
+
15
+ @Autowired
16
+ private MateriaRepository materiaRepository;
17
+
18
+ public List<MateriaDTO> listar(String tipo) {
19
+ List<Materia> materias;
20
+ if (tipo != null && !tipo.isBlank()) {
21
+ Materia.Tipo tipoEnum;
22
+ try {
23
+ tipoEnum = Materia.Tipo.valueOf(tipo.toUpperCase());
24
+ } catch (IllegalArgumentException ex) {
25
+ throw new IllegalArgumentException("Tipo de materia inválido: " + tipo);
26
+ }
27
+ materias = materiaRepository.findByTipo(tipoEnum);
28
+ } else {
29
+ materias = materiaRepository.findAll();
30
+ }
31
+ return materias.stream().map(this::mapearADTO).toList();
32
+ }
33
+
34
+ public MateriaDTO obtenerPorId(Integer id) {
35
+ Materia materia = materiaRepository.findById(id)
36
+ .orElseThrow(() -> new ResourceNotFoundException("Materia no encontrada"));
37
+ return mapearADTO(materia);
38
+ }
39
+
40
+ private MateriaDTO mapearADTO(Materia materia) {
41
+ return MateriaDTO.builder()
42
+ .id(materia.getId())
43
+ .clave(materia.getClave())
44
+ .nombre(materia.getNombre())
45
+ .creditos(materia.getCreditos())
46
+ .tipo(materia.getTipo() != null ? materia.getTipo().name() : null)
47
+ .build();
48
+ }
49
+
50
+}