Practica 1

parent 37c2574b
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GitLabDefaultAccount">
<option name="defaultAccountId" value="3f871339-5570-4958-a075-631c6ecffa55" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_X" default="true" project-jdk-name="openjdk-23" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/DAELaura2526.iml" filepath="$PROJECT_DIR$/.idea/DAELaura2526.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
\ No newline at end of file
package com.ayto.incidencias;
import com.ayto.incidencias.web.AuthInterceptor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@SpringBootApplication
public class App implements WebMvcConfigurer {
private final AuthInterceptor auth;
public App(AuthInterceptor auth){ this.auth = auth; }
public static void main(String[] args){ SpringApplication.run(App.class, args); }
@Override public void addInterceptors(InterceptorRegistry reg){
reg.addInterceptor(auth).addPathPatterns("/api/**");
}
}
\ No newline at end of file
package com.ayto.incidencias.repo.memoria;
import com.ayto.incidencias.dominio.Incidencia;
import com.ayto.incidencias.repo.IncidenciaRepo;
import org.springframework.stereotype.Repository;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
@Repository
public class IncidenciaRepoMem implements IncidenciaRepo {
private final Map<Long,Incidencia> datos = new ConcurrentHashMap<>();
private final AtomicLong seq = new AtomicLong(0);
public Incidencia save(Incidencia i){
if(i.getId()==null) i.setId(seq.incrementAndGet());
datos.put(i.getId(), i);
return i;
}
public Optional<Incidencia> findById(Long id){ return Optional.ofNullable(datos.get(id)); }
public void delete(Long id){ datos.remove(id); }
public List<Incidencia> findByAutor(Long uid){
return datos.values().stream()
.filter(i -> i.getAutor()!=null && i.getAutor().getId().equals(uid))
.toList();
}
public List<Incidencia> findAll(){ return new ArrayList<>(datos.values()); }
}
\ No newline at end of file
package com.ayto.incidencias.repo.memoria;
import com.ayto.incidencias.dominio.TipoIncidencia;
import com.ayto.incidencias.repo.TipoIncidenciaRepo;
import org.springframework.stereotype.Repository;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
@Repository
public class TipoIncidenciaRepoMem implements TipoIncidenciaRepo {
private final Map<Long,TipoIncidencia> datos = new ConcurrentHashMap<>();
private final AtomicLong seq = new AtomicLong(0);
public TipoIncidencia save(TipoIncidencia t){
if(t.getId()==null) t.setId(seq.incrementAndGet());
datos.put(t.getId(), t);
return t;
}
public void delete(Long id){ datos.remove(id); }
public boolean existsByNombre(String n){
return datos.values().stream().anyMatch(t -> t.getNombre().equalsIgnoreCase(n));
}
public Optional<TipoIncidencia> findById(Long id){ return Optional.ofNullable(datos.get(id)); }
public List<TipoIncidencia> findAll(){ return new ArrayList<>(datos.values()); }
}
\ No newline at end of file
package com.ayto.incidencias.repo.memoria;
import com.ayto.incidencias.dominio.Usuario;
import com.ayto.incidencias.repo.UsuarioRepo;
import org.springframework.stereotype.Repository;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Repository
public class UsuarioRepoMem implements UsuarioRepo {
private final Map<String,Usuario> porLogin = new ConcurrentHashMap<>();
public Usuario save(Usuario u){ porLogin.put(u.getLogin(), u); return u; }
public Optional<Usuario> findByLogin(String login){ return Optional.ofNullable(porLogin.get(login)); }
}
\ No newline at end of file
package com.ayto.incidencias.servicio;
import com.ayto.incidencias.dominio.*;
import com.ayto.incidencias.repo.*;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class ServicioIncidencias {
private final IncidenciaRepo incidencias;
private final TipoIncidenciaRepo tipos;
public ServicioIncidencias(IncidenciaRepo incidencias, TipoIncidenciaRepo tipos){
this.incidencias = incidencias; this.tipos = tipos;
}
public Incidencia crearIncidencia(Usuario autor, Long tipoId, String desc,
Direccion dir, CoordenadaGPS gps){
TipoIncidencia tipo = tipos.findById(tipoId).orElseThrow();
Incidencia i = new Incidencia();
i.setAutor(autor); i.setTipo(tipo); i.setDescripcion(desc);
i.setDireccion(dir); i.setUbicacionGPS(gps);
i.setFecha(LocalDateTime.now()); i.setEstado(EstadoIncidencia.PENDIENTE);
return incidencias.save(i);
}
public List<Incidencia> listarMisIncidencias(Long autorId){ return incidencias.findByAutor(autorId); }
public List<Incidencia> buscar(Long tipoId, EstadoIncidencia estado){
return incidencias.findAll().stream()
.filter(i -> tipoId==null || (i.getTipo()!=null && i.getTipo().getId().equals(tipoId)))
.filter(i -> estado==null || i.getEstado()==estado)
.toList();
}
public void borrarSiPendiente(Long autorId, Long incId){
TipoIncidencia inc = incidencias.findById(incId).orElseThrow().getTipo();
if(!inc.getAutor().getId().equals(autorId)) throw new SecurityException("No puedes borrar de otros");
if(inc.getEstado()!=EstadoIncidencia.PENDIENTE) throw new IllegalStateException("Sólo PENDIENTE");
incidencias.delete(incId);
}
public Incidencia adminCambiarEstado(Long id, EstadoIncidencia nuevo){
TipoIncidencia inc = incidencias.findById(id).orElseThrow().getTipo();
inc.setEstado(nuevo);
return incidencias.save(inc);
}
public void adminBorrar(Long id){ incidencias.delete(id); }
}
\ No newline at end of file
package com.ayto.incidencias.servicio;
import com.ayto.incidencias.dominio.TipoIncidencia;
import com.ayto.incidencias.repo.*;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ServicioTiposIncidencia {
private final TipoIncidenciaRepo tipos;
private final IncidenciaRepo incidencias;
public ServicioTiposIncidencia(TipoIncidenciaRepo tipos, IncidenciaRepo incidencias){
this.tipos = tipos; this.incidencias = incidencias;
}
public TipoIncidencia crear(String nombre, String descripcion){
if(tipos.existsByNombre(nombre)) throw new IllegalArgumentException("Tipo duplicado");
var t = new TipoIncidencia(); t.setNombre(nombre); t.setDescripcion(descripcion);
return tipos.save(t);
}
public void eliminar(Long id){
boolean enUso = incidencias.findAll().stream()
.anyMatch(i -> i.getTipo()!=null && i.getTipo().getId().equals(id));
if(enUso) throw new IllegalStateException("No se puede borrar: tipo en uso");
tipos.delete(id);
}
public List<TipoIncidencia> listar(){ return tipos.findAll(); }
}
\ No newline at end of file
package com.ayto.incidencias.servicio;
import com.ayto.incidencias.dominio.*;
import com.ayto.incidencias.repo.UsuarioRepo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class ServicioUsuarios {
private final UsuarioRepo usuarios;
public ServicioUsuarios(UsuarioRepo usuarios,
@Value("${app.admin.login}") String adminLogin,
@Value("${app.admin.password}") String adminPass) {
this.usuarios = usuarios;
// Asegura admin fijo
usuarios.findByLogin(adminLogin).or(() -> {
Usuario a = new Usuario();
a.setLogin(adminLogin); a.setClaveHash(adminPass);
a.setNombre("Admin"); a.setApellidos("Sistema");
a.setRol(RolUsuario.ADMIN);
usuarios.save(a);
return java.util.Optional.of(a);
});
}
public Usuario autenticar(String login, String clave){
return usuarios.findByLogin(login)
.filter(u -> u.getClaveHash()!=null && u.getClaveHash().equals(clave))
.orElseThrow(() -> new RuntimeException("Credenciales inválidas"));
}
public Usuario registrar(Usuario u){ return usuarios.save(u); }
public Usuario actualizar(Usuario u){ return usuarios.save(u); }
}
\ No newline at end of file
package com.ayto.incidencias.web;
import com.ayto.incidencias.dominio.Usuario;
import com.ayto.incidencias.servicio.ServicioUsuarios;
import jakarta.servlet.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class AuthInterceptor implements HandlerInterceptor {
public static final String ATTR_USER = "AUTH_USER";
private final ServicioUsuarios usuarios;
public AuthInterceptor(ServicioUsuarios usuarios){ this.usuarios = usuarios; }
@Override public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler){
// Permite registrar sin credenciales
if(req.getMethod().equals("POST") && req.getRequestURI().equals("/api/usuarios/registro")) return true;
String login = req.getHeader("X-Login");
String pass = req.getHeader("X-Password");
try {
Usuario u = usuarios.autenticar(login, pass);
req.setAttribute(ATTR_USER, u);
return true;
} catch(Exception e){
res.setStatus(401);
return false;
}
}
}
\ No newline at end of file
package com.ayto.incidencias.web;
import com.ayto.incidencias.dominio.*;
import com.ayto.incidencias.servicio.ServicioIncidencias;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController @RequestMapping("/api/incidencias")
public class IncidenciaController {
private final ServicioIncidencias svc;
public IncidenciaController(ServicioIncidencias svc){ this.svc = svc; }
@PostMapping
public Incidencia crear(HttpServletRequest req,
@RequestParam Long tipoId,
@RequestParam String descripcion,
@RequestParam String calle, @RequestParam String numero,
@RequestParam String ciudad, @RequestParam String provincia, @RequestParam String cp,
@RequestParam(required=false) Double lat, @RequestParam(required=false) Double lon){
var u = (Usuario) req.getAttribute(AuthInterceptor.ATTR_USER);
var dir = new Direccion(); dir.setCalle(calle); dir.setNumero(numero);
dir.setCiudad(ciudad); dir.setProvincia(provincia); dir.setCp(cp);
CoordenadaGPS gps = (lat!=null && lon!=null) ? new CoordenadaGPS() : null;
if(gps!=null){ gps.setLatitud(lat); gps.setLongitud(lon); }
return svc.crearIncidencia(u, tipoId, descripcion, dir, gps);
}
@GetMapping("/mias")
public List<Incidencia> mias(HttpServletRequest req){
var u = (Usuario) req.getAttribute(AuthInterceptor.ATTR_USER);
return svc.listarMisIncidencias(u.getId());
}
@GetMapping
public List<Incidencia> buscar(@RequestParam(required=false) Long tipoId,
@RequestParam(required=false) EstadoIncidencia estado){
return svc.buscar(tipoId, estado);
}
@DeleteMapping("/{id}")
public void borrarPropia(HttpServletRequest req, @PathVariable Long id){
Usuario u = (Usuario) req.getAttribute(AuthInterceptor.ATTR_USER);
svc.borrarSiPendiente(u.getId(), id);
}
@PatchMapping("/{id}/estado")
public Incidencia cambiarEstado(HttpServletRequest req, @PathVariable Long id, @RequestParam EstadoIncidencia estado){
Usuario u = (Usuario) req.getAttribute(AuthInterceptor.ATTR_USER);
if(u.getRol()!=RolUsuario.ADMIN) throw new SecurityException("Sólo admin");
return svc.adminCambiarEstado(id, estado);
}
@DeleteMapping("/{id}/admin")
public void borrarAdmin(HttpServletRequest req, @PathVariable Long id){
Usuario u = (Usuario) req.getAttribute(AuthInterceptor.ATTR_USER);
if(u.getRol()!=RolUsuario.ADMIN) throw new SecurityException("Sólo admin");
svc.adminBorrar(id);
}
}
\ No newline at end of file
package com.ayto.incidencias.web;
import com.ayto.incidencias.dominio.*;
import com.ayto.incidencias.servicio.ServicioTiposIncidencia;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController @RequestMapping("/api/tipos")
public class TipoIncidenciaController {
private final ServicioTiposIncidencia tipos;
public TipoIncidenciaController(ServicioTiposIncidencia tipos){ this.tipos = tipos; }
@GetMapping public List<TipoIncidencia> listar(){ return tipos.listar(); }
@PostMapping
public TipoIncidencia crear(HttpServletRequest req, @RequestParam String nombre, @RequestParam String descripcion){
Usuario u = (Usuario) req.getAttribute(AuthInterceptor.ATTR_USER);
if(u.getRol()!=RolUsuario.ADMIN) throw new SecurityException("Sólo admin");
return tipos.crear(nombre, descripcion);
}
@DeleteMapping("/{id}")
public void eliminar(HttpServletRequest req, @PathVariable Long id){
Usuario u = (Usuario) req.getAttribute(AuthInterceptor.ATTR_USER);
if(u.getRol()!=RolUsuario.ADMIN) throw new SecurityException("Sólo admin");
tipos.eliminar(id);
}
}
\ No newline at end of file
package com.ayto.incidencias.web;
import com.ayto.incidencias.dominio.Usuario;
import com.ayto.incidencias.servicio.ServicioUsuarios;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.*;
@RestController @RequestMapping("/api/usuarios")
public class UsuarioController {
private final ServicioUsuarios svc;
public UsuarioController(ServicioUsuarios svc){ this.svc = svc; }
@PostMapping("/registro")
public Usuario registrar(@RequestBody Usuario u){ return svc.registrar(u); }
@PutMapping("/me")
public Usuario actualizar(HttpServletRequest req, @RequestBody Usuario u){
Usuario actual = (Usuario) req.getAttribute(AuthInterceptor.ATTR_USER);
u.setId(actual.getId()); u.setLogin(actual.getLogin()); u.setRol(actual.getRol());
return svc.actualizar(u);
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment