Selaa lähdekoodia

Security changed to rols policy

Mario Martínez Hernández 13 tuntia sitten
vanhempi
commit
9883a17ac6

+ 15 - 19
src/main/java/es/uv/saic/service/AuthProvider.java

@@ -4,6 +4,7 @@ import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import javax.naming.Context;
 import javax.naming.NamingEnumeration;
@@ -46,7 +47,6 @@ public class AuthProvider implements AuthenticationProvider {
         String password = auth.getCredentials().toString(); 
         
         List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
-    	authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
         
         Usuari u = this.us.findByUsername(username);
         
@@ -59,15 +59,13 @@ public class AuthProvider implements AuthenticationProvider {
 	        if(!u.getLdap() && vigent) {
 	            if (u.getUsuari().equals(username) && u.getClau().equals(password)) {
 	            	logger.info("Autenticación LOCAL correcta: "+username);
-	            	if(u.isAdmin()) {
-	            		authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
-	            	}
-	            	if(u.isGranted()) {
-	            		authorities.add(new SimpleGrantedAuthority("ROLE_MANAGER"));
-	            	}
-	            	if(u.isDataTest()) {
-	            		authorities.add(new SimpleGrantedAuthority("ROLE_TESTER"));
-	            	}
+                    
+                    List<Integer> ids = u.getUsuarisRols().stream().map(ur -> ur.getRol().getIdRol()).collect(Collectors.toList());
+
+                    for (String permission : this.us.getPermisosRoles(ids)) {
+                        authorities.add(new SimpleGrantedAuthority("ROLE_" + permission.toUpperCase()));
+                    }
+
 	            	UsernamePasswordAuthenticationToken authUser = new UsernamePasswordAuthenticationToken(u, password, authorities);
 	            	authUser.setDetails(u);
 	                return authUser ;
@@ -127,15 +125,13 @@ public class AuthProvider implements AuthenticationProvider {
                     logger.info("Autenticación LDAP correcta: " + u.getUsuari());
                     u.setDataUltim(LocalDateTime.now());
                     this.us.save(u);
-	            	if(u.isAdmin()) {
-	            		authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
-	            	}
-	            	if(u.isGranted()) {
-	            		authorities.add(new SimpleGrantedAuthority("ROLE_MANAGER"));
-	            	}
-	            	if(u.isDataTest()) {
-	            		authorities.add(new SimpleGrantedAuthority("ROLE_TESTER"));
-	            	}
+
+                    List<Integer> ids = u.getUsuarisRols().stream().map(ur -> ur.getRol().getIdRol()).collect(Collectors.toList());
+
+                    for (String permission : this.us.getPermisosRoles(ids)) {
+                        authorities.add(new SimpleGrantedAuthority("ROLE_" + permission.toUpperCase()));
+                    }
+
 	            	UsernamePasswordAuthenticationToken authUser = new UsernamePasswordAuthenticationToken(u, password, authorities);
 	            	authUser.setDetails(u);
 	                return authUser ;

+ 5 - 1
src/main/java/es/uv/saic/service/UsuariService.java

@@ -26,7 +26,8 @@ public class UsuariService {
 	}
 	
 	public Usuari findByUsername(String usuari) {
-		return this.usuariRepository.findByUsername(usuari);
+		Usuari u = this.usuariRepository.findByUsername(usuari);
+		return u;
 	}
 	
 	public boolean hasActiveRol(Usuari usuari) {
@@ -101,4 +102,7 @@ public class UsuariService {
 		this.usuariRepository.flush();
 	}
 	
+	public List<String> getPermisosRoles(List<Integer> idRols) {
+		return this.usuariRepository.getPermisosRoles(idRols);
+	}
 }

+ 29 - 28
src/main/java/es/uv/saic/web/AdminController.java

@@ -11,6 +11,7 @@ import java.util.Map;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.annotation.Secured;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.core.Authentication;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -30,7 +31,6 @@ import es.uv.saic.shared.dto.OrganDTO;
 import es.uv.saic.shared.dto.ProcedureRequestDTO;
 import es.uv.saic.shared.dto.ProcesDTO;
 import es.uv.saic.shared.dto.RolDTO;
-import es.uv.saic.shared.dto.TemplateDataDTO;
 import es.uv.saic.shared.feign.AdminClient;
 import es.uv.saic.shared.feign.DataClient;
 import es.uv.saic.shared.feign.IndicadorClient;
@@ -64,7 +64,7 @@ public class AdminController {
 	
 	// GET para conseguir todas las instancias del sistema en ese momento.
 	@GetMapping("/admin/instances")
-	@Secured({"ROLE_ADMIN"})
+	@PreAuthorize("hasRole('ROLE_INSTS_W')")
 	public String getInstances(Model model, Authentication auth) {		
 		this.loadInstanceData(model);
 		return "adminInstances";
@@ -98,7 +98,7 @@ public class AdminController {
 	
 	// POST que recoge los campos introducidos en los inputs (Proceso, centro y titulación) y busca las instancias relacionadas
 	@PostMapping("/admin/instances")
-	@Secured({"ROLE_ADMIN"})
+	@PreAuthorize("hasRole('ROLE_INSTS_W')")
 	public String instantiate(Model model, Authentication auth, 
 			@RequestParam("procedure") Integer idProces,
 			@RequestParam("center") Integer idCentre,
@@ -116,14 +116,14 @@ public class AdminController {
 
 	// GET que recoge todos los procedimientos del sistema
 	@GetMapping("/admin/procedures")
-	@Secured({"ROLE_ADMIN"})
+	@PreAuthorize("hasRole('ROLE_PROCS_W')")
 	public String getProcedures(Model model, Authentication auth) {
 		this.loadProceduresData(model);
 		return "adminProcedures";
 	}
 	
 	// Función utilizada en el GET que recoge todos los procedimientos
-	public void loadProceduresData(Model model) {
+	private void loadProceduresData(Model model) {
 		List<DummyDataTransfer> procediments = new ArrayList<DummyDataTransfer>();
 		for(ProcesDTO p : pc.getAll()) {
 			DummyDataTransfer a = new DummyDataTransfer();
@@ -138,7 +138,7 @@ public class AdminController {
 	
 	// POST que elimina una instancia concreta
 	@PostMapping("/admin/instance/delete")
-	@Secured({"ROLE_ADMIN"})
+	@PreAuthorize("hasRole('ROLE_INSTS_W')")
 	public void deleteInstance(Model model, Authentication auth, HttpServletResponse response, @RequestParam BigInteger idInstancia) throws IOException {
 		ac.deleteInstance(idInstancia);
 		
@@ -147,7 +147,7 @@ public class AdminController {
 	
 	// POST que reinicia una instancia por completo
 	@PostMapping("/admin/instance/clear")
-	@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
+	@PreAuthorize("hasRole('ROLE_INSTS_W')")
 	public void clearInstance(Model model, Authentication auth, HttpServletResponse response, @RequestParam BigInteger idInstancia) throws IOException {
 		String instanciaid = ac.clearInstance(idInstancia);
 		
@@ -156,7 +156,7 @@ public class AdminController {
 	
 	// POST que establece que una instancia ha sido cerrada, cambiandole su estado
 	@PostMapping("/admin/instance/close")
-	@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
+	@PreAuthorize("hasRole('ROLE_INSTS_W')")
 	public void closeInstance(Model model, Authentication auth, HttpServletResponse response, @RequestParam BigInteger idInstancia) throws IOException {
 		String instanciaid = ac.closeInstance(idInstancia);
 		
@@ -165,7 +165,7 @@ public class AdminController {
 	
 	// POST que se encarga de eliminar una tarea concreta de una instancia
 	@PostMapping("/admin/instance/task/remove")
-	@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
+	@PreAuthorize("hasRole('ROLE_INSTS_W')")
 	public void removeTask(Model model, Authentication auth, HttpServletResponse response, @RequestParam BigInteger idInstanciaTasca) throws IOException {
 		String instanciaid = ac.removeTask(idInstanciaTasca);
 
@@ -174,7 +174,7 @@ public class AdminController {
 	
 	// POST que se encarga de reiniciar por completo una tarea de una instancia
 	@PostMapping("/admin/instance/task/clear")
-	@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
+	@PreAuthorize("hasRole('ROLE_W')")
 	public void clearTask(Model model, Authentication auth, HttpServletResponse response, @RequestParam BigInteger idInstanciaTasca) throws IOException {
 		String instanciaid = ac.clearTask(idInstanciaTasca);
 		
@@ -183,7 +183,7 @@ public class AdminController {
 	
 	// POST que reinicia una tarea del procedimiento, eliminando datos anteriores y creando una nueva vesión de esta
 	@PostMapping("/admin/instance/task/reload")
-	@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
+	@PreAuthorize("hasRole('ROLE_W')")
 	public void reloadTask(Model model, Authentication auth, HttpServletResponse response, @RequestParam BigInteger idInstanciaTasca) throws IOException {
 		String instanciaid = ac.reloadTask(idInstanciaTasca);
 		
@@ -192,7 +192,7 @@ public class AdminController {
 	
 	// POST que tiene como objetivo reactivar una tarea
 	@PostMapping("/admin/instance/task/reactivate")
-	@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
+	@PreAuthorize("hasRole('ROLE_W')")
 	public void activateTask(Model model, Authentication auth, HttpServletResponse response, @RequestParam BigInteger idInstanciaTasca) throws IOException {
 		String instanciaid = ac.activateTask(idInstanciaTasca);
 		
@@ -201,7 +201,7 @@ public class AdminController {
 	
 	// POST que edita la información de una tarea ya existente
 	@PostMapping("/admin/instance/task/edit")
-	@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
+	@PreAuthorize("hasRole('ROLE_INSTS_W')")
 	public void editTask(Model model, Authentication auth, HttpServletResponse response, @RequestParam BigInteger idInstanciaTasca) throws IOException {
 		String instanciaid = ac.editTask(idInstanciaTasca);
 		
@@ -209,7 +209,7 @@ public class AdminController {
 	}
 	
 	@GetMapping("/admin/mailing")
-	@Secured({"ROLE_ADMIN"})
+	@Secured({"ROLE_EMAILS"})
 	public String getMailing(Model model, Authentication auth, HttpServletResponse response) {
 		List<RolDTO> rols = uc.findAllRols();
 		List<OrganDTO> centres = oc.getActiveCentres();
@@ -220,7 +220,7 @@ public class AdminController {
 	}
 	
 	@PostMapping("/admin/mailing")
-	@Secured({"ROLE_ADMIN"})
+	@Secured({"ROLE_EMAILS"})
 	public String sendMails(Model model, Authentication auth, HttpServletResponse response, 
 			@RequestParam Integer idRol, @RequestParam("centres[]") List<Integer> centres,
 			@RequestParam String subject, @RequestParam String body) {
@@ -237,7 +237,7 @@ public class AdminController {
 	
 	// POST para la creación de un procedimiento nuevo
 	@PostMapping("/admin/procedures/new")
-	@Secured({"ROLE_ADMIN"})
+	@Secured({"ROLE_PROCS_W"})
 	public String newProcedure(Model model, @RequestBody ProcedureRequestDTO request) throws NumberFormatException, ParseException {
 	
 		ac.newProcedure(request);
@@ -248,7 +248,7 @@ public class AdminController {
 	}
 
 	@PostMapping("/admin/procedures/edit")
-	@Secured({"ROLE_ADMIN"})
+	@Secured({"ROLE_PROCS_W"})
 	public String editProcedure(Model model, @RequestBody ProcedureRequestDTO request) {
 		// Extraemos los datos del wrapper
 		ac.editProcedure(request);
@@ -260,7 +260,7 @@ public class AdminController {
 	
 	// POST que elimina un procedimiento
 	@PostMapping("/admin/procedures/remove")
-	@Secured({"ROLE_ADMIN"})
+	@Secured({"ROLE_PROCS_W"})
 	public String removeProcedure(Model model, Authentication auth, HttpServletResponse response, @RequestParam("idProces") Integer idProces){
 		ac.removeProcedure(idProces);
 		
@@ -271,7 +271,7 @@ public class AdminController {
 	
 	// POST que le eliminar un usuario concreto del sitema
 	@PostMapping("/admin/userrole/remove")
-	@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
+	@Secured({"ROLE_ADMINS"})
 	@ResponseBody
 	public boolean removeUserrole(Model model, Authentication auth, HttpServletResponse response, HttpSession session, @RequestParam("idRol") Integer idRol, 
 			@RequestParam("usuari") String usuari, @RequestParam("lugar") Integer lugar, @RequestParam("tlugar") String tlugar) throws IOException{
@@ -281,7 +281,7 @@ public class AdminController {
 	
 	// POST para añadir un nuevo usuario al sistema
 	@PostMapping("/admin/userrole/new")
-	@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
+	@Secured({"ROLE_ADMINS"})
 	@ResponseBody
 	public boolean newUserrole(Model model, Authentication auth, HttpServletResponse response, HttpSession session, @RequestParam("idRol") Integer idRol, 
 			@RequestParam(name="usuari", required=false) String usuari, @RequestParam("centre") Integer idCentre, 
@@ -292,7 +292,7 @@ public class AdminController {
 	
 	//¿POSIBLE ELIMINACIÓN?
 	@GetMapping("/admin/templates2")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_TEMPLATES_W')")
 	public String getTemplates(Model model, Authentication auth, HttpServletResponse response) {
 
 		this.loadInstanceData(model);
@@ -301,7 +301,7 @@ public class AdminController {
 	
 	// GET que recoge todas las plantillas actuales del sistema
 	@GetMapping("/admin/templates")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_TEMPLATES_W')")
 	public String getTemplates2(Model model, Authentication auth, HttpServletResponse response) {
 					
 		List<String> evs = ac.getTemplates2();
@@ -314,7 +314,7 @@ public class AdminController {
 	
 	// POST que redefine que indicadores están asociados a una evidencia dentro de un proceso
 	@PostMapping("/admin/templates/inds/update")
-	@Secured({"ROLE_ADMIN"})
+	@PreAuthorize("hasRole('ROLE_TEMPLATES_W')")
 	public String updateTemplateInds(Model model, Authentication auth, HttpServletResponse response,
 			@RequestParam(name="indicador[]", required=true) List<String> indicador,
 			@RequestParam(name="enquesta[]", required=true) List<String> enquesta,
@@ -330,7 +330,7 @@ public class AdminController {
 	
 	// GET para abrir el editor de plantillas
 	@GetMapping("/admin/editor")  
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_TEMPLATES_W')")
 	public String getTemplateEditor(Model model, Authentication auth, HttpServletResponse response) {
 
 		List<String> inds = this.ic.findTypes();
@@ -345,7 +345,7 @@ public class AdminController {
 	}
 	
 	@GetMapping("/admin/editor/test")  
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_TEMPLATES_W')")
 	public String testTemplateEditor(Model model, Authentication auth, HttpServletResponse response,
 			@RequestParam Integer idPlantilla, @RequestParam Integer idTitulacio, @RequestParam Integer idCentre, @RequestParam Integer curs) {
 		
@@ -358,7 +358,7 @@ public class AdminController {
 	
 	// GET para la carga del calendario
 	@GetMapping("/admin/calendar")  
-	@Secured({"ROLE_ADMIN"})
+	@PreAuthorize("hasRole('ROLE_INSTS_W')")
 	public String calendar(Model model, Authentication auth, HttpServletResponse response) {
 
 		this.loadInstanceData(model);
@@ -367,7 +367,7 @@ public class AdminController {
 	
 	@GetMapping("/admin/acredita/{curs}/{grup}/{tambit}")  
 	@ResponseBody
-	@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
+	@Secured({"ROLE_ADMINS"})
 	public List<AcreditacioTransfer> acreditacionsByCurs(Model model, Authentication auth, HttpServletResponse response,
 			@PathVariable Integer curs, @PathVariable Integer grup, @PathVariable String tambit) {
 		
@@ -376,7 +376,7 @@ public class AdminController {
 	
 	@PostMapping("/admin/acredita")  
 	@ResponseBody
-	@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
+	@Secured({"ROLE_ADMINS"})
 	public Acreditacio UpdateAcreditacio(Model model, Authentication auth, HttpServletResponse response, 
 									@RequestParam String tlugar, @RequestParam Integer lugar, 
 									@RequestParam Integer grupCurs, @RequestParam Integer grupNum, @RequestParam Integer cursImpla,
@@ -387,6 +387,7 @@ public class AdminController {
 	
 	@GetMapping("/admin/checkProcedureID")
 	@ResponseBody
+	@PreAuthorize("hasRole('ROLE_PROCS_W')")
 	public boolean checkProcedureID(@RequestParam String id) {
 		return pc.findProcesByID(Integer.parseInt(id)) != null;
 	}

+ 6 - 0
src/main/java/es/uv/saic/web/CalendarController.java

@@ -6,6 +6,7 @@ import java.util.List;
 import java.util.Optional;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.core.Authentication;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -28,6 +29,7 @@ public class CalendarController {
 
     @ResponseBody
 	@PostMapping("/calendar")
+	@PreAuthorize("hasRole('ROLE_INSTS')")
 	public Calendari calendarAddEvent(Model model, Authentication auth, @RequestParam("idProces") Integer idProces, 
 			@RequestParam("titulacions") List<String> titulacions, @RequestParam("centres") List<String> centres, 
 			@RequestParam("data") String data, @RequestParam("instancia") Optional<Integer> instancia) throws IOException, ParseException {	
@@ -38,6 +40,7 @@ public class CalendarController {
 	// POST que actualiza el evento ddel calendario
 	@ResponseBody
 	@PostMapping("/calendar/{id}")
+	@PreAuthorize("hasRole('ROLE_INSTS')")
 	public Calendari calendarAddEvent(Model model, Authentication auth, @PathVariable("id") Integer id, 
 			@RequestParam("idProces") Integer idProces, @RequestParam("titulacions") List<String> titulacions, 
 			@RequestParam("centres") List<String> centres, @RequestParam("data") String data) throws IOException, ParseException {	
@@ -47,6 +50,7 @@ public class CalendarController {
 	// GET que recoge todos los eventos del calendario
 	@ResponseBody
 	@GetMapping("/calendar")
+	@PreAuthorize("hasRole('ROLE_INSTS')")
 	public List<Calendari> calendarGetEvents(Model model, Authentication auth) throws IOException, ParseException {	
 		return cc.calendarGetEvents();
 	}
@@ -54,6 +58,7 @@ public class CalendarController {
 	// DELETE que elimina un evento del calendario
 	@ResponseBody
 	@DeleteMapping("/calendar")
+	@PreAuthorize("hasRole('ROLE_INSTS')")
 	public Integer calendarDeleteEvent(Model model, Authentication auth, @RequestParam("id") Integer id) throws IOException, ParseException {	
 		return cc.calendarDeleteEvent(id);
 	}
@@ -62,6 +67,7 @@ public class CalendarController {
 	// POST para instanciar un proceso desde el calendario
 	@ResponseBody
 	@PostMapping("/calendar/instantiate")
+	@PreAuthorize("hasRole('ROLE_INSTS')")
 	public List<String> instantiate(Model model, Authentication auth, @RequestParam("id") Integer id,
 			@RequestParam("idProces") Integer idProces, @RequestParam("centres") List<Integer> centres,
 			@RequestParam("titulacions") List<Integer> titulacions) throws IOException, ParseException {	

+ 19 - 4
src/main/java/es/uv/saic/web/DashboardController.java

@@ -9,6 +9,7 @@ import javax.xml.parsers.ParserConfigurationException;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.annotation.Secured;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.core.Authentication;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -46,19 +47,23 @@ public class DashboardController {
     private ObjectMapper objectMapper;
 
     @GetMapping("/dashboard")
+	@PreAuthorize("hasRole('ROLE_R')")
     public String getOrganList(Model model, Authentication auth) {
 
         HashMap<String, Object> response =
                 dbc.getOrganList(((Usuari) auth.getPrincipal()).getUsuari());
 
+		model.addAllAttributes(response);
+
         if (response != null) {
-            return response.get("organ").toString() == "0" ? "dashboard" : "redirect:/dashboard/" + response.get("organ").toString();
+            return response.get("organ").toString().equals("0") ? "dashboard" : "redirect:/dashboard/" + response.get("organ").toString();
         }
 
         return "401";
     }
 
     @GetMapping("/dashboard/{ruct}")
+	@PreAuthorize("hasRole('ROLE_R')")
     public String getDashboardOrgan(Model model, Authentication auth, @PathVariable Integer ruct) {
         HashMap<String, Object> response =
                 dbc.getDashboardOrgan(ruct, ((Usuari) auth.getPrincipal()).getUsuari());
@@ -122,24 +127,28 @@ public class DashboardController {
 	// GET para conseguir todos los procedimiento a partir del idTitulacio
 	@GetMapping("/dashboard/procedures/{idTitulacio}")
 	@ResponseBody
+	@PreAuthorize("hasRole('ROLE_R')")
 	public List<?> loadReports(Model model, Authentication auth, @PathVariable Integer idTitulacio) {
 		return dbc.loadReports(idTitulacio);
 	}
 
 	@GetMapping("/dashboard/graphs/inds/{ruct}/{tambit}")
 	@ResponseBody
+	@PreAuthorize("hasRole('ROLE_R')")
 	public List<Indicador> getGraphDataByRuctTambit(@PathVariable Integer ruct, @PathVariable String tambit) throws ParserConfigurationException {
 		return dbc.getGraphDataByRuctTambit(ruct, tambit);
 	}
 
     @GetMapping("/dashboard/graphs/inds/{ruct}")
 	@ResponseBody
+	@PreAuthorize("hasRole('ROLE_R')")
 	public List<Indicador> getGraphDataByRuct(@PathVariable Integer ruct) throws ParserConfigurationException {
 		return dbc.getGraphDataByRuct(ruct);
 	}
 	
 	// GET para conseguir la documentación ya a aportada a partir del id de la tituación
 	@GetMapping("/dashboard/documents/{idTitulacio}")
+	@PreAuthorize("hasRole('ROLE_R')")
 	@ResponseBody
 	public List<CategoriaDocumentDTO> loadDocuments(Model model, @PathVariable Integer idTitulacio){
 		List<CategoriaDocumentDTO> a = dbc.loadDocuments(idTitulacio);
@@ -150,18 +159,21 @@ public class DashboardController {
 	// GET para conseguir el diagrama de gantt a partir del ruct
 	@GetMapping("/dashboard/gantt/{ruct}")
 	@ResponseBody
+	@PreAuthorize("hasRole('ROLE_R')")
 	public List<InstanciaGanttDTOImp> loadGantt(Model model, @PathVariable Integer ruct){
 		return dbc.loadGantt(ruct);
 	}
 		
 	@GetMapping("/dashboard/documents/cats/{idCategoria}/{tambit}")
 	@ResponseBody
+	@PreAuthorize("hasRole('ROLE_R')")
 	public List<Categoria> getDocumentChildCats(@PathVariable Integer idCategoria, @PathVariable String tambit) {
 		return dbc.getDocumentChildCats(idCategoria, tambit);
 	}
 
 	@GetMapping("/dashboard/documents/catsu/{idCategoria}/{tambit}")
 	@ResponseBody
+	@PreAuthorize("hasRole('ROLE_R')")
 	public List<Categoria> getDocumentChildCatsU(@PathVariable Integer idCategoria, @PathVariable String tambit) {
 		return  dbc.getDocumentChildCatsU(idCategoria, tambit);
 	}
@@ -169,6 +181,7 @@ public class DashboardController {
 	// POST para guardar un documento en el sistema
 	@PostMapping("/dashboard/documents")
 	@ResponseBody
+	@PreAuthorize("hasRole('ROLE_R')")
 	public void uploadDocument(Model model, @RequestParam MultipartFile file, @RequestParam Integer idCategoria, 
 							   @RequestParam Integer lugar, @RequestParam String tlugar) throws IllegalStateException, IOException {
 		dbc.uploadDocument(file, idCategoria, lugar, tlugar);
@@ -177,6 +190,7 @@ public class DashboardController {
 	// POST para añadir un documento a un centro cocncreto
 	@PostMapping("/dashboard/documents/archive")
 	@ResponseBody
+	@PreAuthorize("hasRole('ROLE_W')")
 	public void archiveDocuments(Model model, @RequestParam Integer lugar, @RequestParam String tlugar) {
 		dbc.archiveDocuments(lugar, tlugar);
 	}
@@ -184,6 +198,7 @@ public class DashboardController {
 	// GET para conseguir todos los graficos a partir de un RUCT
 	@GetMapping("/dashboard/graphs/list/{ruct}")
 	@ResponseBody
+	@PreAuthorize("hasRole('ROLE_R')")
 	public List<Grafica> getGraphDataList(@PathVariable Integer ruct) throws ParserConfigurationException {
 		return dbc.getGraphDataList(ruct);
 	}
@@ -197,21 +212,21 @@ public class DashboardController {
 
 	@GetMapping("/dashboard/links/{ruct}")
 	@ResponseBody
-	@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
+	@PreAuthorize("hasRole('ROLE_R')")
 	public List<Link> getLinks(@PathVariable Integer ruct) {
 		return dbc.getLinks(ruct);
 	}
 
 	@PostMapping("/dashboard/links/{ruct}")
 	@ResponseBody
-	@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
+	@PreAuthorize("hasRole('ROLE_ADMINS')")
 	public Link createLink(@PathVariable Integer ruct, @RequestParam String dataExp) throws ParseException {
 		return dbc.createLink(ruct, dataExp);
 	}
 
 	@DeleteMapping("/dashboard/links/{id}")
 	@ResponseBody
-	@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
+	@PreAuthorize("hasRole('ROLE_ADMINS')")
 	public Integer deleteLink(@PathVariable Integer id) {
 		return dbc.deleteLink(id);
 	}

+ 16 - 15
src/main/java/es/uv/saic/web/DataController.java

@@ -10,6 +10,7 @@ import jakarta.mail.MessagingException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.i18n.LocaleContextHolder;
 import org.springframework.security.access.annotation.Secured;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.core.Authentication;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -43,7 +44,7 @@ public class DataController {
 	
 	// GET que carga la interfaz relacionada con toda la importación de datos
 	@GetMapping("/data/import")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_DATA_I')")
 	public String renderImport(Model model, Authentication auth) {
 		List<Datasource> sources = dc.renderImport();
 		for(Datasource d : sources){
@@ -55,7 +56,7 @@ public class DataController {
 	
 	// POST encargado de importar los datos que han sido adjuntados
 	@PostMapping("/data/import")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_DATA_I')")
 	@ResponseBody
 	public String uploadFile(Model model, Authentication auth, MultipartFile file, @RequestParam String enquesta, @RequestParam String ambit,
 							@RequestParam String estudi, @RequestParam String clau, @RequestParam String tipus, @RequestParam List<String> ignoredColumns,
@@ -78,7 +79,7 @@ public class DataController {
 
 	// POST encargado de eliminar unos datos concretos
 	@PostMapping("/data/delete")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_DATA_I')")
 	@ResponseBody
 	public String delete(Model model, Authentication auth, @RequestParam String enquesta,
 			@RequestParam Integer curs, @RequestParam String ambit, @RequestParam String estudi) throws IOException {  
@@ -96,7 +97,7 @@ public class DataController {
 	
 	// POST encargado de mostrar los datos por pantalla
 	@PostMapping("/data/show")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_DATA_I')")
 	@ResponseBody
 	public List<IndicadorEnquesta> show(Model model, Authentication auth, @RequestParam String enquesta,
 			@RequestParam Integer curs, @RequestParam String ambit, @RequestParam String estudi) throws IOException {    
@@ -108,7 +109,7 @@ public class DataController {
 	
 	// GET para mostrar el formulario de busqueda de datos
 	@GetMapping("/data/current")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_DATA_R')")
 	public String current(Model model, Authentication auth) throws IOException {
 		model.addAttribute("data", oc.getTitulacionsWithCentre());			
 		return "dataCurrent";
@@ -116,14 +117,14 @@ public class DataController {
 	
 	//GET para cargar el apartado de coonsolidate
 	@GetMapping("/data/consolidate")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_DATA_W')")
 	public String consolidate(Model model, Authentication auth) throws IOException {    
 		return "dataConsolidate";
 	}
 	
 	// POST para comprobar si existen problemas con los datos, si estan duplicados o su integridad
 	@PostMapping("/data/check/{type}")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_DATA_W')")
 	@ResponseBody
 	public List<IndicadorEnquestaTmpDup> check(Model model, Authentication auth, 
 			@RequestParam String enquesta, @PathVariable Integer type) throws IOException {   
@@ -132,7 +133,7 @@ public class DataController {
 
 	// POST que soluciona problemas de integridad que puedan tener los datos
 	@PostMapping("/data/fix/integrity/{deleteFrom}")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_DATA_W')")
 	@ResponseBody
 	public Integer fixIntegrityIssues(Model model, Authentication auth, 
 			@RequestParam String enquesta, @PathVariable String deleteFrom) throws IOException {   
@@ -149,7 +150,7 @@ public class DataController {
 
 	// POST que soluciona problemas de duplicados que puedan tener los datos
 	@PostMapping("/data/fix/duplication")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_DATA_W')")
 	@ResponseBody
 	public Integer fixDuplicatesIssues(Model model, Authentication auth, @RequestParam String enquesta) throws IOException {   
 		return ic.deleteDuplicates(enquesta);
@@ -157,7 +158,7 @@ public class DataController {
 	
 	// POST que consolida los datos pasadas por la encuesta
 	@PostMapping("/data/consolidate")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_DATA_W')")	
 	@ResponseBody
 	public Integer consolidate(Model model, Authentication auth, @RequestParam String enquesta) throws IOException {    
 		return dc.countByEnquesta(enquesta);
@@ -165,7 +166,7 @@ public class DataController {
 	
 	// POST que comprueba los datos a partir de la encuesta
 	@PostMapping("/data/count")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_DATA_W')")
 	@ResponseBody
 	public Integer countByEnquesta(Model model, Authentication auth, @RequestParam String enquesta) throws IOException {    
 		return dc.countByEnquesta(enquesta);
@@ -173,7 +174,7 @@ public class DataController {
 
 	// POST para mostrar los datos en columnas
 	@PostMapping("/data/view/columns")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_DATA_I')")
 	@ResponseBody
 	public List<String> listTableColumns(Model model, Authentication auth, @RequestParam Integer dbOrigen, @RequestParam String vista) {    
 		String locale = LocaleContextHolder.getLocale().getLanguage();
@@ -192,7 +193,7 @@ public class DataController {
 
 	// GET que muestra los datos de un curso que se ha elegido
 	@GetMapping("/data/current/show/{ruct}/{curs}")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_R')")
 	@ResponseBody
 	public List<IndicadorEnquesta> show(Model model, Authentication auth, @PathVariable Integer ruct, 
 			@PathVariable Integer curs) throws IOException { 
@@ -201,7 +202,7 @@ public class DataController {
 	
 	// POST que muestra los datos del curso actual
 	@PostMapping("/data/current/show")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_R')")
 	@ResponseBody
 	public List<IndicadorEnquesta> currentShow(Model model, Authentication auth, @RequestParam String enquesta,
 			@RequestParam Integer curs, @RequestParam String ambit, @RequestParam String estudi,
@@ -227,7 +228,7 @@ public class DataController {
 	}
 
 	@GetMapping("/data/sources")
-	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
+	@PreAuthorize("hasRole('ROLE_R')")
 	@ResponseBody
 	public List<Datasource> getDatasources(Model model, Authentication auth) throws IOException {  
     	return dc.getDatasources();

+ 6 - 0
src/main/java/es/uv/saic/web/DownloadController.java

@@ -12,6 +12,7 @@ import org.springframework.core.io.Resource;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -38,6 +39,7 @@ public class DownloadController {
 	 * @return A FileSystemResource representing the file to download
 	 */
 	@GetMapping(value="/download/{fileName}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
+	@PreAuthorize("hasRole('ROLE_R')")
 	@ResponseBody
 	public FileSystemResource download(Model model, @PathVariable("fileName") BigInteger idInstanciaTasca) throws IOException {	
 		// Convert byte[] to FileSystemResource
@@ -61,6 +63,7 @@ public class DownloadController {
 	 * @return A FileSystemResource representing the document to download
 	 */
 	@GetMapping(value="/download/document/{id}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
+	@PreAuthorize("hasRole('ROLE_R')")
 	@ResponseBody
 	public FileSystemResource downloadDocument(Model model, @PathVariable("id") Integer idDocument) {		
 		ResponseEntity<byte[]> response = dc.downloadDocument(idDocument);
@@ -90,6 +93,7 @@ public class DownloadController {
 	 * @return A byte array representing the populated template to download
 	 */
 	@GetMapping(value="/download/template/{id}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
+	@PreAuthorize("hasRole('ROLE_R')")
 	@ResponseBody 
 	public FileSystemResource downloadTemplate(Model model, @PathVariable("id") BigInteger idTascai) throws IOException, XDocReportException {
 		ResponseEntity<byte[]> response = dc.downloadTemplate(idTascai);
@@ -111,6 +115,7 @@ public class DownloadController {
 	 * @param response HttpServletResponse
 	 */
 	@PostMapping(value="/download/pdf/preview")
+	@PreAuthorize("hasRole('ROLE_R')")
 	@ResponseBody
 	public byte[] downloadTemplatePdf(Model model,
 			@RequestParam("content") String content, @RequestParam("idtascai") Optional<BigInteger> idtascai) throws IOException, InterruptedException {
@@ -119,6 +124,7 @@ public class DownloadController {
 	}
 
 	@GetMapping(value="/download/test/template2/{titulacio}/{centre}/{evidencia}/{curs}/{tipusTasca}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
+	@PreAuthorize("hasRole('ROLE_R')")
 	@ResponseBody
 	public ResponseEntity<Resource> testTemplate(Model model, @PathVariable("titulacio") Integer idTitulacio, @PathVariable("centre") Integer idCentre,
 			@PathVariable("evidencia") String evidencia, @PathVariable("curs") Integer curs, @PathVariable("tipusTasca") Integer tipusTasca) throws IOException, XDocReportException {

+ 5 - 0
src/main/java/es/uv/saic/web/ManagersController.java

@@ -7,6 +7,7 @@ import java.util.List;
 import jakarta.servlet.http.HttpSession;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.core.Authentication;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -23,6 +24,7 @@ public class ManagersController {
 	@Autowired
 	private ManagerClient mc;
 	
+	/* YA NO SE USA */
 	/*
 	 * Load the managers administration page data into the model
 	 * - List of centres and titulacions the logged user can manage
@@ -33,6 +35,7 @@ public class ManagersController {
 	 * - The view is managers.html
 	 */
 	@SuppressWarnings("unchecked")
+	@PreAuthorize("hasRole('ROLE_R')")
 	@GetMapping("/managers")
 	public String managersForm(Model model, Authentication auth, HttpSession session) {
 		
@@ -57,6 +60,7 @@ public class ManagersController {
 		return "managers";
 	}
 	
+	/* YA NO SE USA */
 	/*
 	 * Process the search form submission and load the results into the model
 	 * @Param centres List of centre ids to search managers in
@@ -64,6 +68,7 @@ public class ManagersController {
 	 * @Return The view component list_managers
 	 */
 	@PostMapping("/manager/search")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String managersSearch(Model model, Authentication auth, 
 			@RequestParam("center") List<Integer> centres,
 			@RequestParam(name="titulation[]", required=false) List<Integer> titulacions,

+ 11 - 0
src/main/java/es/uv/saic/web/OrganController.java

@@ -6,6 +6,7 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.core.Authentication;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -31,6 +32,7 @@ public class OrganController {
 	// POST que buscar titulaciones que se encuentren asociadas a uno o varios
 	// centros
 	@PostMapping("/search/titulations")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String getTitulationsByCenter(Model model, Authentication auth,
 			@RequestParam(name = "centers[]", required = false) List<Integer> centres) throws IOException {
 		HashMap<String, Object> response = oc.getTitulationsByCenter(centres,
@@ -45,6 +47,7 @@ public class OrganController {
 	}
 
 	@PostMapping("/search/managers/titulations")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String getCenterTitulations(Model model, Authentication auth,
 			@RequestParam("center") Integer centre,
 			HttpSession session) {
@@ -71,6 +74,7 @@ public class OrganController {
 	}
 
 	@PostMapping("/find/titulations2")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String getTitulationsByCenters(Model model, Authentication auth,
 			@RequestParam("centers[]") List<Integer> centres, @RequestParam("procedure") Integer idProces)
 			throws IOException {
@@ -85,6 +89,7 @@ public class OrganController {
 	}
 
 	@PostMapping("/find/titulations")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String getTitulationsByCenter(Model model, Authentication auth,
 			@RequestParam("center") Integer centre, @RequestParam("procedure") Integer idProces) throws IOException {
 		HashMap<String, Object> response = oc.getTitulationsByCenter(centre, idProces);
@@ -98,6 +103,7 @@ public class OrganController {
 	}
 
 	@PostMapping("/get/titulations")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String getAllTitulationsByCenter(Model model, Authentication auth, @RequestParam("center") Integer centre)
 			throws IOException {
 		HashMap<String, Object> response = oc.getAllTitulationsByCenter(centre);
@@ -111,6 +117,7 @@ public class OrganController {
 	}
 
 	@PostMapping("/find/centers")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String getAllCentresByAmbit(Model model, Authentication auth, @RequestParam("procedure") Integer idProces)
 			throws IOException {
 		HashMap<String, Object> response = oc.getAllCentresByAmbit(idProces);
@@ -124,6 +131,7 @@ public class OrganController {
 	}
 
 	@PutMapping("/organ/centre")
+	@PreAuthorize("hasRole('ROLE_ADMINS')")
 	@ResponseBody
 	public void createNewCentre(Model model, Authentication auth,
 			@RequestParam("codiCentro") Integer codigo,
@@ -134,6 +142,7 @@ public class OrganController {
 	}
 
 	@PutMapping("/organ/titulacion")	
+	@PreAuthorize("hasRole('ROLE_ADMINS')")
 	@ResponseBody
 	public void createNewTitulacion(Model model, Authentication auth,
 			@RequestParam("codiTit") Integer codigo,
@@ -146,6 +155,7 @@ public class OrganController {
 	}
 
 	@PostMapping("/organ/centre")
+	@PreAuthorize("hasRole('ROLE_ADMINS')")
 	@ResponseBody
 	public Integer updateCentre(Model model, Authentication auth, 
 			@RequestParam("lugar") Integer lugar,
@@ -159,6 +169,7 @@ public class OrganController {
 	}
 	
 	@PostMapping("/organ/titulacion")
+	@PreAuthorize("hasRole('ROLE_ADMINS')")
 	@ResponseBody
 	public Integer updateTitulacion(Model model, Authentication auth, 
 			@RequestParam("lugar") Integer lugar,

+ 23 - 1
src/main/java/es/uv/saic/web/ProceduresController.java

@@ -11,6 +11,7 @@ import java.util.Map;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.core.Authentication;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -25,7 +26,7 @@ import org.springframework.web.multipart.MultipartFile;
 import es.uv.saic.shared.domain.EvidenciaIndicadorEnquesta;
 import es.uv.saic.shared.domain.InstanciaTascaVer;
 import es.uv.saic.shared.domain.Plantilla;
-import es.uv.saic.shared.domain.Proces;	
+import es.uv.saic.shared.domain.Proces;
 import es.uv.saic.shared.domain.Tipus;
 import es.uv.saic.shared.domain.Usuari;
 import es.uv.saic.shared.dto.RolDTO;
@@ -53,6 +54,7 @@ public class ProceduresController {
 		
 	/* Redirect root to /procedures */
 	@GetMapping("/")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public void getRoot(Model model, Authentication auth, HttpSession session, HttpServletResponse response) throws IOException {
 		response.sendRedirect("/procedures");
 	}
@@ -67,6 +69,7 @@ public class ProceduresController {
 	 * @return The name of the view to render
 	 */
 	@GetMapping("/procedures")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String getActiveInstances(Model model, Authentication auth, HttpSession session, @RequestParam(required = false) String _new) {
 		
 		HashMap<String, Object> response =
@@ -91,6 +94,7 @@ public class ProceduresController {
 	 * @return The name of the view to render
 	 */
 	@GetMapping("/procedure/{id}")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String getInstance(Model model, Authentication auth, HttpSession session, @PathVariable BigInteger id) {
 		
 		HashMap<String, Object> response =
@@ -128,6 +132,7 @@ public class ProceduresController {
 	 * @throws InterruptedException
 	 */
 	@PostMapping("/procedure/files/{id}")
+	@PreAuthorize("hasRole('ROLE_W')")
 	@ResponseBody 
 	public String updateInstanciaTascaEvidencia(Model model, Authentication auth, HttpSession session, @PathVariable BigInteger id, @RequestParam Map<String,String> params, 
 		@RequestParam(required = true) List<MultipartFile> evidencias) throws IllegalStateException, IOException {
@@ -165,6 +170,7 @@ public class ProceduresController {
 	 * @return The name of the view to render
 	 */
 	@PostMapping("/procedure/{id}")
+	@PreAuthorize("hasRole('ROLE_W')")
 	public String updateInstanciaTasca(Model model, Authentication auth, HttpSession session, @PathVariable BigInteger id, @RequestParam Map<String,String> params, 
 			@RequestParam(required = false) List<MultipartFile> evidencias) throws IllegalStateException, IOException, InterruptedException {
 		model.addAttribute("location", "procedures");
@@ -193,6 +199,7 @@ public class ProceduresController {
 	 * @return The timestamp of the save operation formatted as a String
 	 */
 	@PostMapping("/procedure/save/{id}")
+	@PreAuthorize("hasRole('ROLE_W')")
 	@ResponseBody
 	public String saveDraft(Model model, Authentication auth, HttpSession session, @PathVariable BigInteger id, @RequestParam String text, 
 							@RequestParam boolean manual) {
@@ -219,6 +226,7 @@ public class ProceduresController {
 	 * @return The name of the view to render
 	 */
 	@GetMapping("/procedure/drafts/{id}")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String getDrafts(Model model, Authentication auth, HttpSession session, @PathVariable BigInteger id) {
 		HashMap<String, Object> response =
                 pc.getDrafts(id);
@@ -241,6 +249,7 @@ public class ProceduresController {
 	 * @return The InstanciaTascaVer object representing the draft
 	 */
 	@GetMapping("/procedure/draft/{id}")
+	@PreAuthorize("hasRole('ROLE_R')")
 	@ResponseBody
 	public InstanciaTascaVer getDraft(Model model, Authentication auth, HttpSession session, @PathVariable BigInteger id, @RequestParam Timestamp dataMod) {
 		return pc.getDraft(id, dataMod);
@@ -256,6 +265,7 @@ public class ProceduresController {
 	 * @return "1" if successful, "0" otherwise
 	 */
 	@PostMapping("/procedure/draft/{id}")
+	@PreAuthorize("hasRole('ROLE_W')")
 	@ResponseBody
 	public String restoreDraft(Model model, Authentication auth, HttpSession session, @PathVariable BigInteger id, @RequestParam Timestamp dataMod) {
 		return pc.restoreDraft(id, dataMod);
@@ -263,6 +273,7 @@ public class ProceduresController {
 
     // POST que se utiliza para conseguir los cursos a partir de la titulación
 	@PostMapping("/procedure/search/years")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String getYearsByCenterTitulation(Model model, Authentication auth, 
 			@RequestParam(name="centers[]", required=false) List<Integer> centres,
 			@RequestParam("titulations[]") List<Integer> titulacions) throws IOException {		
@@ -280,6 +291,7 @@ public class ProceduresController {
 
     // POST que se utiliza para conseguir los procedimiento que se han llevado a cabo por cursos y por titulación
 	@PostMapping("/procedure/search/procedures")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String getProceduresByCenterTitulationYear(Model model, Authentication auth,
 			@RequestParam(name="centers[]", required=false) List<Integer> centres,
 			@RequestParam("years[]") List<Integer> cursos,
@@ -296,6 +308,7 @@ public class ProceduresController {
 	}
 
     @PostMapping("/find/procedure")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String findProcedure(Model model, Authentication auth, @RequestParam("procedure") Integer idProces, 
 			@RequestParam("action") String action) throws IOException {	
 		
@@ -316,6 +329,7 @@ public class ProceduresController {
 
 	// POST para crear el form de creación de plantilla
 	@PostMapping("/template/form")
+	@PreAuthorize("hasRole('ROLE_W')")
 	public String formTemplate(Model model, Authentication auth, @RequestParam("id") Integer idPlantilla,
 			@RequestParam("action") String action) throws IOException {	
 		
@@ -332,6 +346,7 @@ public class ProceduresController {
 
 	// GET para renderizar el formulario de cración de nueva tarea
 	@GetMapping("/newTask/{i}")
+	@PreAuthorize("hasRole('ROLE_W')")
 	public String newTaskForm(Model model, Authentication auth, @PathVariable Integer i) throws IOException {	
 		List<RolDTO> roles = uc.findAssignables();
 		List<Tipus> tipus = pc.findAll();
@@ -345,6 +360,7 @@ public class ProceduresController {
 
 	@ResponseBody
 	@PostMapping("/find/template")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String findTemplate(Model model, Authentication auth, @RequestParam("id") Integer idPlantilla) throws IOException {	
 		Plantilla p = plc.findByID(idPlantilla);
 		return p.getText();
@@ -353,6 +369,7 @@ public class ProceduresController {
 	// GET para comprobar si una plantilla esta siendo usada
 	@ResponseBody
 	@GetMapping("/template/used/{idPlantilla}")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public int isTemplateUsed(Model model, Authentication auth, @PathVariable("idPlantilla") Integer idPlantilla) throws IOException {	
 		Boolean u = plc.isUsed(idPlantilla);
 		return u ? 1 : 0;
@@ -360,6 +377,7 @@ public class ProceduresController {
 
 	@ResponseBody
 	@PostMapping("/template/edit")
+	@PreAuthorize("hasRole('ROLE_W')")
 	public String templateEdit(Model model, Authentication auth, @RequestParam("id") Integer idPlantilla,@RequestParam("text") String text, @RequestParam("versio") Integer versio,
 			@RequestParam("nomCas") String nomCas, @RequestParam("nomVal") String nomVal, @RequestParam("ambit") String ambit) throws IOException {
 		Plantilla p = plc.findByID(idPlantilla);
@@ -373,6 +391,7 @@ public class ProceduresController {
 
 	@ResponseBody
 	@PostMapping("/template/save")
+	@PreAuthorize("hasRole('ROLE_W')")
 	public String templateSave(Model model, Authentication auth, @RequestParam("text") String text, @RequestParam("codi") String codi, @RequestParam("versio") Integer versio,
 			@RequestParam("nomCas") String nomCas, @RequestParam("nomVal") String nomVal, @RequestParam("ambit") String ambit) throws IOException {	
 		Plantilla p = new Plantilla();
@@ -392,6 +411,7 @@ public class ProceduresController {
 	
 	@ResponseBody
 	@PostMapping("/draft/save/{id}")
+	@PreAuthorize("hasRole('ROLE_W')")
 	public String saveTemplate(Model model, Authentication auth, @PathVariable("id") Integer idPlantilla, 
 			@RequestParam("text") String text) throws IOException {	
 		Plantilla p = plc.findByID(idPlantilla);
@@ -402,6 +422,7 @@ public class ProceduresController {
 
 	@DeleteMapping("/template/form")
 	@ResponseBody
+	@PreAuthorize("hasRole('ROLE_X')")
 	public String formTemplateRemove(Model model, Authentication auth, @RequestParam("id") Integer idPlantilla) throws IOException {	
 		if(plc.isUsed(idPlantilla)){
 			return "0";
@@ -415,6 +436,7 @@ public class ProceduresController {
 	}
 
 	@PostMapping("/find/template/inds")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String findTemplatesInds(Model model, Authentication auth, @RequestParam("procedure") Integer idProces, 
 			@RequestParam("center") String idCentre, @RequestParam("titulation") String idTitulacio,
 			@RequestParam("ev") String evidencia) throws IOException {	

+ 2 - 2
src/main/java/es/uv/saic/web/StatsController.java

@@ -55,7 +55,7 @@ public class StatsController {
 	 * @return The name of the view to render
 	 *
 	@GetMapping("/admin/stats")
-	@Secured({"ROLE_ADMIN"})
+	@Secured({"ROLE_ADMINS"})
 	public String getStats(Model model, Authentication auth) {
 		HashMap<String, Object> response =
                 sc.getStats();
@@ -69,7 +69,7 @@ public class StatsController {
 	}*/
 	
 	@GetMapping("/admin/stats")
-	@Secured({"ROLE_ADMIN"})
+	@Secured({"ROLE_ADMINS"})
 	public String getStats(Model model, Authentication auth) {
 		final List<Object> allPrincipals = sessionRegistry.getAllPrincipals();
 		List<ActiveSession> allLoggedUsers = new ArrayList<ActiveSession>();

+ 39 - 1
src/main/java/es/uv/saic/web/SupervisionController.java

@@ -1,11 +1,15 @@
 package es.uv.saic.web;
 
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Optional;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.core.Authentication;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -36,6 +40,7 @@ public class SupervisionController {
 	 * @return The name of the view to render
 	 */
 	@GetMapping("/supervision")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String supervisionForm(Model model, Authentication auth, HttpSession session) {
 
 		Object obj = session.getAttribute("searchParams");
@@ -79,6 +84,7 @@ public class SupervisionController {
 	 * @return The name of the view to render
 	 */
 	@PostMapping("/supervision/search")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String supervisionSearch(Model model, Authentication auth, 
 			@RequestParam(name="centers[]", required=false) List<Integer> centres,
 			@RequestParam("years[]") List<Integer> cursos,
@@ -89,12 +95,43 @@ public class SupervisionController {
 			HttpSession session) {
 
 		HashMap<String, Object> response =
-			sc.supervisionSearch(centres, cursos, titulacions, procediments, evidencies, searchType, searchType);
+			sc.supervisionSearch(centres, cursos, titulacions, procediments, evidencies, searchType, ((Usuari) auth.getPrincipal()).getUsuari());
 
 		if (response == null) {
         	return "401";
 		}
 
+
+		if (response != null && response.get("procedure_list") instanceof List<?> rawList) {
+			DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+			for (Object obj : rawList) {
+				if (obj instanceof HashMap<?, ?> item) {
+					// We use a cast here because we need to modify the map
+					@SuppressWarnings("unchecked")
+					HashMap<String, Object> map = (HashMap<String, Object>) item;
+
+					// Convert dataTascaActiva
+					if (map.get("dataTascaActiva") instanceof String dateStr && !dateStr.isBlank()) {
+						try {
+							map.put("dataTascaActiva", LocalDate.parse(dateStr, formatter));
+						} catch (DateTimeParseException e) {
+							System.err.println("Error parsing date for dataTascaActiva: " + e.getMessage());
+						}
+					}
+
+					// Convert dataLimTascaActiva
+					if (map.get("dataLimTascaActiva") instanceof String dateStr && !dateStr.isBlank()) {
+						try {
+							map.put("dataLimTascaActiva", LocalDate.parse(dateStr, formatter));
+						} catch (DateTimeParseException e) {
+							System.err.println("Error parsing date for dataLimTascaActiva: " + e.getMessage());
+						}
+					}
+				}
+			}
+		}
+
 		model.addAllAttributes(response);
 		session.setAttribute("searchParams", response.get("searchParams"));
 
@@ -110,6 +147,7 @@ public class SupervisionController {
 	 * @return The name of the view to render
 	 */
 	@GetMapping("/supervision/search")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String restoreSearch(Model model, Authentication auth, HttpSession session) {
 		Object obj = session.getAttribute("searchParams");
 

+ 3 - 0
src/main/java/es/uv/saic/web/TascaController.java

@@ -5,6 +5,7 @@ import java.util.HashMap;
 import java.util.List;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.core.Authentication;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -20,6 +21,7 @@ public class TascaController {
     private TascaClient tc;
 
     @PostMapping("/tasca/search/evidences")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String getEvidencesByCenterTitulationYear(Model model, Authentication auth,
 			@RequestParam(name="centers[]", required=false) List<Integer> centres,
 			@RequestParam("years[]") List<Integer> cursos,
@@ -37,6 +39,7 @@ public class TascaController {
 
     //NO se usa
 	@PostMapping("/tasca/find/templates")
+	@PreAuthorize("hasRole('ROLE_TEMPLATES_W')")
 	public String findTemplates(Model model, Authentication auth, @RequestParam("procedure") Integer idProces, 
 			@RequestParam("center") String idCentre, @RequestParam("titulation") String idTitulacio) throws IOException {	
 		model.addAttribute("evs", tc.getEvidencesByProcedure(idProces));

+ 2 - 0
src/main/java/es/uv/saic/web/UsuariController.java

@@ -4,6 +4,7 @@ import java.io.IOException;
 import java.util.List;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.core.Authentication;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -19,6 +20,7 @@ public class UsuariController {
     private UsuariClient us;
 
     @GetMapping("/user/form")
+	@PreAuthorize("hasRole('ROLE_ADMINS')")
 	public String newUserRoleForm(Model model, Authentication auth) throws IOException {	
 		List<UsuariDTO> users = us.findAllUsers();
 		List<RolDTO> roles = us.findAllRols();

+ 5 - 0
src/main/java/es/uv/saic/web/WikiController.java

@@ -1,6 +1,7 @@
 package es.uv.saic.web;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.core.Authentication;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -28,6 +29,7 @@ public class WikiController {
 	 * @return The name of the view to render
 	 */
 	@GetMapping("/wiki")
+	@PreAuthorize("hasRole('ROLE_R')")
 	public String renderWiki(Model model, Authentication auth) {
 		return "wiki";
 	}
@@ -40,6 +42,7 @@ public class WikiController {
 	 * @return The name of the view to render
 	 */
 	@GetMapping("/wiki/editor")
+	@PreAuthorize("hasRole('ROLE_W')")
 	public String renderWikiEditor(Model model, Authentication auth) {
 		return "wikiEditor";
 	}
@@ -53,6 +56,7 @@ public class WikiController {
 	 * @return The wiki text
 	 */
 	@GetMapping("/wiki/text/{categoria}")
+	@PreAuthorize("hasRole('ROLE_R')")
 	@ResponseBody
 	public Wiki renderWiki(Model model, Authentication auth, @PathVariable String categoria) {
 		return wc.renderWiki(categoria);
@@ -68,6 +72,7 @@ public class WikiController {
 	 * @return The updated wiki object
 	 */
 	@PostMapping("/wiki/editor")
+	@PreAuthorize("hasRole('ROLE_W')")
 	@ResponseBody
 	public Wiki updateWiki(Model model, Authentication auth, @RequestParam String cat, @RequestParam String text) {
 		return wc.updateWiki(cat, text);

+ 29 - 1
src/main/resources/static/css/saic.css

@@ -1502,7 +1502,35 @@ option {
     font-weight: bold;
     color: #1B3552;
     text-transform: uppercase;
-    margin-bottom: 4px;
+}
+
+.uv-buttons.btn-group {
+    background-color: #6c757d !important; 
+    border-radius: 4px;
+    overflow: hidden;
+    display: inline-flex;
+	margin-right: 30px;
+	margin-left: 20px;
+	margin-bottom: -30px;
+	margin-top: -15px;
+	height: 38px !important;
+
+}
+
+.custom-dt-btn {
+    background: transparent !important;
+    border: none !important;
+    color: white !important;
+    padding: 12px 12px !important;
+    font-size: 14px !important;
+    border-radius: 0 !important;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+.custom-dt-btn:hover {
+    background-color: rgba(255, 255, 255, 0.1) !important;
 }
 
 .uv-table-pam-modern.compact-mode td:nth-child(-n+3) { background-color: #f8fbff; } 

+ 0 - 0
src/main/resources/templates/blank.html


+ 4 - 4
src/main/resources/templates/dashboard.html

@@ -45,17 +45,17 @@
 						<tbody>
 							<tr th:each="item,inRowID : ${titulacions}">
 								<td>
-									<a th:href="${'/dashboard/'+item.ruct}"><span th:text="${item.ruct}"></span></a>
+									<span th:text="${item.ruct}"></span>
 								</td>
 								<td>
-									<span th:text="${#locale.language} == 'es' ? ${item.nomCas}:${item.nomVal}"></span>
+									<a th:href="${'/dashboard/'+item.ruct}"><span th:text="${#locale.language} == 'es' ? ${item.nomCas}:${item.nomVal}"></span></a>
 								</td>
 								<td>
 									<span th:text="${item.tambit == 'M' ? 'Máster' : item.tambit == 'G' ? 'Grado' : 'Doctorado'}"></span>
 								</td>
 								<td>
-									<a th:if="${showCentres}" th:href="${'/dashboard/'+item.organ.ruct}"><span th:text="${#locale.language} == 'es' ? ${item.organ.nomCas}:${item.organ.nomVal}"></span></a>
-									<span th:unless="${showCentres}" th:text="${#locale.language} == 'es' ? ${item.organ.nomCas}:${item.organ.nomVal}"></span>
+									<a th:if="${showCentres}" th:href="${'/dashboard/'+item.ruct2}"><span th:text="${#locale.language} == 'es' ? ${item.nomCas2}:${item.nomVal2}"></span></a>
+									<span th:unless="${showCentres}" th:text="${#locale.language} == 'es' ? ${item.nomCas2}:${item.nomVal2}"></span>
 								</td>
 							</tr>
 						</tbody>

+ 24 - 19
src/main/resources/templates/dashboardCentre.html

@@ -128,25 +128,30 @@
                             	</div>      
                             </div>
                             <div class="tab-pane" id="tab2">
-								<div th:if="${editable}" style="display: flex; justify-content: space-between; align-items: center; padding: 10px 0; width: 100%;">
-									<span class="btn btn-info pointer" 
-										style="font-size:75%; padding: 5px 8px 3px 8px; margin-left: 25px;" 
-										onclick="editOrgan(this)"
-										th:attr="data-lugar=${organ.lugar},
+								<div th:if="${#authorization.expression('hasRole(''ROLE_W'') and hasRole(''ROLE_ADMINS'')')}" style="display: flex; justify-content: space-between; align-items: center; padding: 10px 0; width: 100%; margin-bottom: 15px;" >
+									<div style="display: flex; justify-content: flex-start; margin-bottom: 15px;">
+										<div class="uv-buttons btn-group">
+											<button class="btn btn-secondary custom-dt-btn" type="button" onclick="editOrgan(this)"
+												th:attr="data-lugar=${organ.lugar},
 												data-tlugar=${organ.tlugar},
 												data-nomcas=${organ.nomCas},
 												data-nomval=${organ.nomVal},
-												data-ruct=${organ.ruct}">
-										<i class="fas fa-edit"></i>
-									</span>
-
-									<div style="display: flex; gap: 10px; margin-right: 25px;">
-										<span class="btn btn-warning pointer" style="font-size:75%; padding: 5px 8px 3px 8px;" onclick="$('#hideDocumentsModal').modal('toggle');">
-											<i class="fas fa-eye-slash"></i>
-										</span>
-										<span class="btn btn-primary pointer" style="font-size:75%; padding: 5px 8px 3px 8px;" onclick="$('#newDocumentModal').modal('toggle');">
-											<i class="fa fa-plus"></i>
-										</span>
+												data-ruct=${organ.ruct},
+												data-tambit=${organ.tambit},
+												data-idcentre=${organ.lugar2}">
+												<i class="fas fa-edit"></i>
+											</button>
+										</div>
+									</div>
+									<div style="display: flex; justify-content: flex-start; margin-bottom: 15px;">
+										<div class="uv-buttons btn-group">
+											<button class="btn custom-dt-btn" type="button" onclick="$('#hideDocumentsModal').modal('toggle');">
+												<i class="fas fa-eye-slash"></i>
+											</button>
+											<button class="btn custom-dt-btn" type="button" onclick="$('#newDocumentModal').modal('toggle');">
+												<i class="fa fa-plus"></i>
+											</button>
+										</div>
 									</div>
 								</div>
 								<div class="row" style="padding-left:25px;width:100%;">  	
@@ -263,7 +268,7 @@
 	                            </div>
                             </div>
                             <div class="tab-pane" id="tab4">
-								<span class="btn btn-primary pointer" id="btnAddManager" style="z-index:100;float:right;margin-right:25px;font-size:75%;padding: 5px 8px 3px 8px;" data-toggle="modal" data-target="#newRoleModal"><i class="fa fa-plus"></i></span>
+								<button th:if="${#authorization.expression('hasRole(''ROLE_W'')')}" class="btn pointer" id="btnAddManager" style="z-index:100;float:right;margin-right:25px;font-size:75%;padding: 5px 8px 3px 8px; background-color: #6c757d; color: white;" data-toggle="modal" data-target="#newRoleModal"><i class="fa fa-plus"></i></button>
 								<div class="uv-table-group" th:if="${results}" style="cursor: auto; width: 90%;">
 									<div class="col-sm-12 uv-table-section" th:each="item : ${resp_titulacions}" style="display: flex; align-items: flex-start; margin-bottom: 15px;">
     									<form id="deleteUserForm" enctype='multipart/form-data' onsubmit="deleteUserRole(event)" style="margin-right: 15px;">
@@ -272,7 +277,7 @@
 												<input type="hidden" name="usuari" th:value="${item.usuari.usuari}">
 												<input type="hidden" name="tlugar" th:value="${item.organ.tlugar}">
 												<input type="hidden" name="lugar" th:value="${item.organ.lugar}">
-												<button class="btn" style="width:40px; height:38px; color: red;" th:title="#{admin.action.delete}" >
+												<button th:if="${#authorization.expression('hasRole(''ROLE_W'')')}" class="btn" style="width:40px; height:38px; color: red;" th:title="#{admin.action.delete}" >
 													<i class="fas fa-times"></i>
 												</button>
 											</div>
@@ -292,7 +297,7 @@
 												<input type="hidden" name="usuari" th:value="${item.usuari.usuari}">
 												<input type="hidden" name="tlugar" th:value="${item.organ.tlugar}">
 												<input type="hidden" name="lugar" th:value="${item.organ.lugar}">
-												<button class="btn" style="width:40px; height:38px; color: red;" th:title="#{admin.action.delete}" >
+												<button th:if="${#authorization.expression('hasRole(''ROLE_W'')')}" class="btn" style="width:40px; height:38px; color: red;" th:title="#{admin.action.delete}" >
 													<i class="fas fa-times"></i>
 												</button>
 											</div>

+ 30 - 19
src/main/resources/templates/dashboardTitulacio.html

@@ -120,24 +120,36 @@
                             	</div>      
                             </div>
                             <div class="tab-pane" id="tab2">
-								<div th:if="${editable}" style="display: flex; justify-content: space-between; align-items: center; padding: 10px 0; width: 100%;">
-									<span class="btn btn-info pointer" 
-										style="font-size:75%; padding: 5px 8px 3px 8px; margin-left: 25px;" 
-										onclick="editOrgan(this)"
-										th:attr="data-lugar=${organ.lugar},
+								<div th:if="${#authorization.expression('hasRole(''ROLE_W'') and hasRole(''ROLE_ADMINS'')')}" style="display: flex; justify-content: space-between; align-items: center; padding: 10px 0; width: 100%;">
+									<div style="display: flex; justify-content: flex-start; margin-bottom: 15px;">
+										<div class="uv-buttons btn-group">
+											<button class="btn btn-secondary custom-dt-btn" type="button" onclick="editOrgan(this)"
+												th:attr="data-lugar=${organ.lugar},
 												data-tlugar=${organ.tlugar},
 												data-nomcas=${organ.nomCas},
 												data-nomval=${organ.nomVal},
 												data-ruct=${organ.ruct},
 												data-tambit=${organ.tambit},
 												data-idcentre=${organ.lugar2}">
-										<i class="fas fa-edit"></i>
-									</span>
-
-									<div style="display: flex; gap: 10px; margin-right: 25px;">
-										<span class="btn btn-secondary pointer" style="font-size:75%; padding: 5px 8px 3px 8px;" onclick="$('#updateAcreditaModal').modal('toggle');"><i class="fas fa-calendar-alt"></i></span>
-										<span class="btn btn-warning pointer" style="font-size:75%; padding: 5px 8px 3px 8px;" onclick="$('#hideDocumentsModal').modal('toggle');"><i class="fas fa-eye-slash"></i></span>
-										<span class="btn btn-primary pointer" style="font-size:75%; padding: 5px 8px 3px 8px;" onclick="$('#newDocumentModal').modal('toggle');"><i class="fa fa-plus"></i></span>
+												<i class="fas fa-edit"></i>
+											</button>
+										</div>
+									</div>
+									<div style="display: flex; justify-content: flex-start; margin-bottom: 15px;">
+										<div class="uv-buttons btn-group">
+											<button class="btn custom-dt-btn" type="button" onclick="$('#updateAcreditaModal').modal('toggle');">
+												<i class="fas fa-calendar-alt"></i>
+											</button>
+											<button class="btn custom-dt-btn" type="button" onclick="$('#hideDocumentsModal').modal('toggle');">
+												<i class="fas fa-eye-slash"></i>
+											</button>
+											<button class="btn custom-dt-btn" type="button" onclick="$('#newDocumentModal').modal('toggle');">
+												<i class="fa fa-plus"></i>
+											</button>
+											<button th:if="${#authorization.expression('hasRole(''ROLE_W'')')}" class="btn btn-secondary custom-dt-btn" type="button" onclick="$('#linksModal').modal('toggle');">
+												<i class="fa fa-link"></i>
+											</button>
+										</div>
 									</div>
 								</div>
                                	<div class="row" style="padding-left:25px;width:100%;">
@@ -205,7 +217,6 @@
                             		</div>
 	                            	<div class="col-lg-12"  style="margin-top:25px;">
                            				<strong th:text="#{dashboard.acred.docs.title}">Documentación:</strong>
-										<span th:if="${editable}" class="btn btn-primary pointer" style="z-index:100;float:right;margin-right:0;font-size:75%;padding: 5px 8px 3px 8px;" onclick="$('#linksModal').modal('toggle');"><i class="fa fa-link"></i></span>
                             		</div>
                             		<div class="col-lg-12" id="treeDocuments"></div>
                            		</div>     
@@ -287,8 +298,8 @@
 	                            </div>
                             </div>
                             <div class="tab-pane" id="tab4">
-								<span class="btn btn-primary pointer" th:if="${#authentication.principal.isAdmin() or #authentication.principal.isGranted()}" id="btnAddManager" style="z-index:100;float:right;margin-right:25px;font-size:75%;padding: 5px 8px 3px 8px;" data-toggle="modal" data-target="#newRoleModal"><i class="fa fa-plus"></i></span>
-                                <div class="uv-table-group" th:if="${results}" style="cursor: auto;  width: 90%">
+								<button th:if="${#authorization.expression('hasRole(''ROLE_W'')')}" class="btn pointer" id="btnAddManager" style="z-index:100;float:right;margin-right:25px;font-size:75%;padding: 5px 8px 3px 8px; background-color: #6c757d; color: white;" data-toggle="modal" data-target="#newRoleModal"><i class="fa fa-plus"></i></button>
+								<div class="uv-table-group" th:if="${results}" style="cursor: auto;  width: 90%">
 									<div class="col-sm-12 uv-table-section" th:each="item : ${resp_titulacions}" style="display: flex; align-items: flex-start; margin-bottom: 15px;">
     									<form id="deleteUserForm" enctype='multipart/form-data' onsubmit="deleteUserRole(event)" style="margin-right: 15px;">
 											<div class="form-group">
@@ -296,7 +307,7 @@
 												<input type="hidden" name="usuari" th:value="${item.usuari.usuari}">
 												<input type="hidden" name="tlugar" th:value="${item.organ.tlugar}">
 												<input type="hidden" name="lugar" th:value="${item.organ.lugar}">
-												<button class="btn" style="width:40px; height:38px; color: red;" th:title="#{admin.action.delete}" >
+												<button th:if="${#authorization.expression('hasRole(''ROLE_W'')')}" class="btn" style="width:40px; height:38px; color: red;" th:title="#{admin.action.delete}" >
 													<i class="fas fa-times"></i>
 												</button>
 											</div>
@@ -315,7 +326,7 @@
 												<input type="hidden" name="usuari" th:value="${item.usuari.usuari}">
 												<input type="hidden" name="tlugar" th:value="${item.organ.tlugar}">
 												<input type="hidden" name="lugar" th:value="${item.organ.lugar}">
-												<button class="btn" style="width:40px; height:38px; color: red;" th:title="#{admin.action.delete}" >
+												<button th:if="${#authorization.expression('hasRole(''ROLE_W'')')}" class="btn" style="width:40px; height:38px; color: red;" th:title="#{admin.action.delete}" >
 													<i class="fas fa-times"></i>
 												</button>
 											</div>
@@ -590,7 +601,7 @@
 		</div>
 	</div>
 
-	<div th:if="${#authentication.principal.isAdmin() or #authentication.principal.isGranted()}" class="modal fade" id="newRoleModal" tabindex="-1" role="dialog" aria-labelledby="newRoleModal" aria-hidden="true">
+	<div class="modal fade" id="newRoleModal" tabindex="-1" role="dialog" aria-labelledby="newRoleModal" aria-hidden="true">
 	  <div class="modal-dialog modal-lg">
 	    <div class="modal-content">
 		    <div class="modal-header">
@@ -643,7 +654,7 @@
 			</div>
 			<div class="modal-footer">
 		        <button type="button" class="btn btn-secondary" data-dismiss="modal" th:text="#{global.cancel}">Cancelar</button>
-		        <button class="btn btn-success" type="submit" form="newRoleForm" th:text="#{global.confirm}">Confirmar</button>
+		        <button th:if="${#authorization.expression('hasRole(''ROLE_W'')')}" class="btn btn-success" type="submit" form="newRoleForm" th:text="#{global.confirm}">Confirmar</button>
 	        </div>
 	    </div>
 	</div>

+ 15 - 8
src/main/resources/templates/dashboardUniversitat.html

@@ -125,8 +125,8 @@
                             	</div>      
                             </div>
 							<div class="tab-pane" id="tab2">
-								<span th:if="${editable}" class="btn btn-primary pointer" style="z-index:100;float:right;margin-right:25px;font-size:75%;padding: 5px 8px 3px 8px;" onclick="$('#newDocumentModal').modal('toggle');"><i class="fa fa-plus"></i></span>
-								<span th:if="${editable}" class="btn btn-warning pointer" style="z-index:100;float:right;margin-right:10px;font-size:75%;padding: 5px 8px 3px 8px;" onclick="$('#hideDocumentsModal').modal('toggle');"><i class="fas fa-eye-slash"></i></span>
+								<button th:if="!${#authorization.expression('hasRole(''ROLE_W'')')}" class="btn btn-primary pointer" style="z-index:100;float:right;margin-right:25px;font-size:75%; padding: 5px 8px 3px 8px;" onclick="$('#newDocumentModal').modal('toggle');"><i class="fa fa-plus"></i></button>
+								<button th:if="!${#authorization.expression('hasRole(''ROLE_W'')')}" class="btn btn-warning pointer" style="z-index:100;float:right;margin-right:10px;font-size:75%; padding: 5px 8px 3px 8px;" onclick="$('#hideDocumentsModal').modal('toggle');"><i class="fas fa-eye-slash"></i></button>
 								<div class="row" style="padding-left:25px;width:100%;">  	
                             		<div class="col-lg-12" style="margin-left:-5px;">
                            				<strong th:text="#{dashboard.acred.docs.title}">Documentación</strong>
@@ -197,7 +197,7 @@
 	                            </div>
                             </div>
                             <div class="tab-pane" id="tab4">
-								<span class="btn btn-primary pointer" id="btnAddManager" style="z-index:100;float:right;margin-right:25px;font-size:75%;padding: 5px 8px 3px 8px;" data-toggle="modal" data-target="#newRoleModal"><i class="fa fa-plus"></i></span>
+								<button th:if="${#authorization.expression('hasRole(''ROLE_W'')')}" class="btn pointer" id="btnAddManager" style="z-index:100;float:right;margin-right:25px;font-size:75%;padding: 5px 8px 3px 8px; background-color: #6c757d; color: white;" data-toggle="modal" data-target="#newRoleModal"><i class="fa fa-plus"></i></button>
 								<div class="uv-table-group" th:if="${results}" style="cursor: auto; width: 90%;">
 									<div class="col-sm-12 uv-table-section" th:each="item : ${resp_titulacions}" style="margin-top:20px;">
 										<div class="col-sm-12 uv-table-section" th:each="item : ${resp_titulacions}" style="margin-top:20px;">
@@ -214,7 +214,7 @@
 												<input type="hidden" name="usuari" th:value="${item.usuari.usuari}">
 												<input type="hidden" name="tlugar" th:value="${item.organ.tlugar}">
 												<input type="hidden" name="lugar" th:value="${item.organ.lugar}">
-												<button class="btn" style="width:40px; height:38px; color: red;" th:title="#{admin.action.delete}" >
+												<button th:if="${#authorization.expression('hasRole(''ROLE_W'')')}" class="btn" style="width:40px; height:38px; color: red;" th:title="#{admin.action.delete}" >
 													<i class="fas fa-times"></i>
 												</button>
 											</div>
@@ -386,7 +386,7 @@
 	  </div>
 	</div>
 
-	<div class="modal fade" id="newRoleModal" tabindex="-1" role="dialog" aria-labelledby="newRoleModal" aria-hidden="true" th:if="${#authentication.principal.isAdmin() or #authentication.principal.isGranted()}">
+	<div class="modal fade" id="newRoleModal" tabindex="-1" role="dialog" aria-labelledby="newRoleModal" aria-hidden="true" th:if="${#authorization.expression('hasRole(''ROLE_ADMINS'')')}">
 	  <div class="modal-dialog modal-lg">
 	    <div class="modal-content">
 		    <div class="modal-header">
@@ -446,6 +446,11 @@
 	  </div>
 	</div>
 
+	<div id="perms-config" 
+    	th:data-can-edit="${#authorization.expression('hasRole(''ROLE_ADMINS'')')}" 
+    	style="display: none;">
+	</div>
+
 	<!-- contactModal -->
 	<div th:replace="~{layouts/common.html :: contactModal}"></div>
 	
@@ -501,7 +506,7 @@
   		function editableSettings(){}
   		function hideAllDocuments(){}
   	</script>
-  
+
 	<script type="text/javascript">
 		var locale = '[[${#locale.language}]]';
 		var lugar = '[[${organ.lugar}]]';
@@ -581,7 +586,8 @@
 		});	
 		
 		function initTables(){
-			
+			const canEdit = $('#perms-config').data('can-edit');
+
 			$('#titsTable thead tr')
 		        .clone(true)
 		        .addClass('filters')
@@ -628,8 +634,9 @@
 						titleAttr: 'Mostrar/Ocultar columnas'
 					},
 					{
-						text: '<i class="fas fa-plus"></i>',
+						text: ' <i class="fas fa-plus"></i>',
 						titleAttr: 'Añadir nueva',
+						enabled: canEdit,
 						action: function ( ) {
 							$('#newOrganModal').modal('toggle');
 						}

+ 17 - 16
src/main/resources/templates/layouts/sidebar.html

@@ -24,37 +24,38 @@
 		</div>
 		<br>
 		<div class="list-group list-group-flush" style="margin-top:-10px;">	 
-			<a href="/dashboard" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.tits}"></a>	 
-			<a href="/procedures" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.procedures}"></a>
-			<a href="/supervision" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.supervision}"></a>
+			<a th:if="${#authorization.expression('hasRole(''ROLE_R'')')}" href="/dashboard" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.tits}"></a>	 
+			<a th:if="${#authorization.expression('hasRole(''ROLE_R'')')}"href="/procedures" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.procedures}"></a>
+			<a th:if="${#authorization.expression('hasRole(''ROLE_R'')')}"href="/supervision" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.supervision}"></a>
 			<!--<a href="/managers" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.managers}"></a>-->
 		</div>
 		<br>
-		<div class="list-group list-group-flush" th:if="${#authentication.principal.isAdmin() or #authentication.principal.isDataTest()}">
+		<div th:if="${#authorization.expression('hasAnyRole(''ROLE_DATA_I'', ''ROLE_DATA_R'', ''ROLE_DATA_W'', ''ROLE_TEMPLATES_W'')')}" class="list-group list-group-flush">			
 			<div class="btn-group dropright">
 				<strong type="button" class="uv-list-group-item list-group-item list-group-item-action bg-light dropdown-toggle" th:text="#{global.menu.data}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-offset="-200">
 					Datos y plantillas
 				</strong>
 				<div class="dropdown-menu">
-					<a href="/data/import" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.data.import}"></a>
-					<a href="/data/current" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.data.data}"></a>
-					<a href="/data/consolidate" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:if="${#authentication.principal.isAdmin()}" th:text="#{global.menu.data.parse}"></a>
-					<a href="/admin/templates" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.data.templates}"></a>
-					<a href="/admin/editor" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.data.editor}"></a>
-			  	</div>
+					<div th:text="${#authentication.authorities}"></div>
+					<a th:if="${#authorization.expression('hasRole(''ROLE_DATA_I'')')}" href="/data/import" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.data.import}"></a>
+					<a th:if="${#authorization.expression('hasRole(''ROLE_DATA_R'')')}" href="/data/current" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.data.data}"></a>
+					<a th:if="${#authorization.expression('hasRole(''ROLE_DATA_W'')')}" href="/data/consolidate" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.data.parse}"></a>
+					<a th:if="${#authorization.expression('hasRole(''ROLE_TEMPLATES_W'')')}" href="/admin/templates" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.data.templates}"></a>
+					<a th:if="${#authorization.expression('hasRole(''ROLE_TEMPLATES_W'')')}" href="/admin/editor" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.data.editor}"></a>
+				</div>
 			</div>
 		</div>
-		<div class="list-group list-group-flush" th:if="${#authentication.principal.isAdmin()}">
+		<div th:if="${#authorization.expression('hasAnyRole(''ROLE_INSTS_W'', ''ROLE_PROCS_W'', ''ROLE_EMAILS'', ''ROLE_ADMINS'')')}" class="list-group list-group-flush">			
 			<div class="btn-group dropright">
 				<strong type="button" class="uv-list-group-item list-group-item list-group-item-action bg-light dropdown-toggle" th:text="#{global.menu.admin}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-offset="-200">
 					Administración
 				</strong>
 				<div class="dropdown-menu">
-			  		<a href="/admin/instances" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.admin.instances}"></a>
-					<a href="/admin/calendar" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.admin.calendar}"></a>
-					<a href="/admin/procedures" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.admin.procedures}"></a>
-					<a href="/admin/mailing" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.admin.mailing}"></a>
-					<a href="/admin/stats" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.admin.stats}"></a>
+					<a th:if="${#authorization.expression('hasRole(''ROLE_INSTS_W'')')}" href="/admin/instances" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.admin.instances}"></a>
+					<a th:if="${#authorization.expression('hasRole(''ROLE_INSTS_W'')')}" href="/admin/calendar" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.admin.calendar}"></a>
+					<a th:if="${#authorization.expression('hasRole(''ROLE_PROCS_W'')')}" href="/admin/procedures" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.admin.procedures}"></a>
+					<a th:if="${#authorization.expression('hasRole(''ROLE_EMAILS'')')}" href="/admin/mailing" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.admin.mailing}"></a>
+					<a th:if="${#authorization.expression('hasRole(''ROLE_ADMINS'')')}" href="/admin/stats" class="uv-list-group-item list-group-item list-group-item-action bg-light" th:text="#{global.menu.admin.stats}"></a>
 			  	</div>
 			</div>
 		</div>

+ 5 - 5
src/main/resources/templates/procedure.html

@@ -67,7 +67,7 @@
 						<p th:text="${#locale.language} == 'es' ? ${instance.descripcioCas}:${instance.descripcioVal}"></p>
 					</div>
 					<hr class="uv-procedure-hr">
-					<div class="uv-table-group" th:if="${#authentication.principal.isAdmin() or #authentication.principal.isGranted()}" style="text-align: right;">
+					<div class="uv-table-group" th:if="${#authorization.expression('hasRole(''ROLE_ADMINS'')')}" style="text-align: right;">
 						<div class="btn-toolbar" role="toolbar" style="margin-bottom:-30px;">
 							<div class="btn-group mr-2 w-auto ml-auto" role="group" aria-label="First group">
 								<button form="formInstanceClear" class="btn btn-secondary pointer" style="width:38px; height:38px;" th:title="#{admin.action.reloadInstance}"><i class="fas fa-redo"></i></button>
@@ -118,9 +118,9 @@
 							<input type="hidden" id="activeOptions" th:if="${item.estat == 'A'}" th:value="${item.opcions}">
 							<div class="card-header pointer" 
 								th:classappend="${(item.estat == 'A' and item.isAssignedToUser?'card-header-active ':'') + (item.estat == 'A' and not item.isAssignedToUser?'card-header-active-other ':'') + (item.isExpired and item.estatInstancia == 'A' and item.estat == 'A'?'card-header-expired ':'') + (item.estat == null?'card-header-blocked ':'')}" 
-								th:attr="id='heading'+${i.index},data-target='#collapse'+${i.index},aria-controls='#collapse'+${i.index}, data-toggle=${item.estat != null or #authentication.principal.isAdmin() or #authentication.principal.isGranted() ? 'collapse' : ''}" 
+								th:attr="id='heading'+${i.index},data-target='#collapse'+${i.index},aria-controls='#collapse'+${i.index}, data-toggle=${item.estat != null or #authorization.expression('hasRole(''ROLE_W'')') ? 'collapse' : ''}" 
 								aria-expanded="true" onclick="showComments();">
-								<span style="float:left;font-size: 21px; margin-left:-10px;margin-top:-10px;" th:if="${item.estat != null or #authentication.principal.isAdmin() or #authentication.principal.isGranted()}"><i class="fas fa-caret-down"></i></span>
+								<span style="float:left;font-size: 21px; margin-left:-10px;margin-top:-10px;" th:if="${item.estat != null or #authorization.expression('hasRole(''ROLE_W'')')}"><i class="fas fa-caret-down"></i></span>
 								<h6 style="text-align:left; margin-left:15px;">
 									<strong th:text="${i.index+1}+'/'+${#lists.size(tasks)}"></strong><strong> - </strong>
 									<span th:text="${#locale.language} == 'es' ? ${item.titolCas}:${item.titolVal}"></span>
@@ -151,7 +151,7 @@
 							</div>
 							<div th:attr="id='collapse'+${i.index},aria-labelledby='heading'+${i.index}" class="collapse" data-parent="#accordion">
 								<div class="card-body uv-card-body">
-									<div id="taskAdminActions" th:if="${#authentication.principal.isAdmin() or #authentication.principal.isGranted()}" style="margin-bottom: 20px;">
+									<div id="taskAdminActions" th:if="${#authorization.expression('hasRole(''ROLE_W'')')}" style="margin-bottom: 20px;">
 										<div class="btn-toolbar" role="toolbar" style="margin-top:-15px; margin-bottom:-15px;">
 											<div class="btn-group mr-2 w-auto ml-auto" role="group" aria-label="First group">
 												<button type="submit" th:attr="form=${'formTaskReload'+item.idInstanciaTasca}" class="btn btn-secondary pointer" style="width:38px; height:38px;" th:title="#{admin.action.reloadTask}"><i class="fas fa-redo"></i></button>
@@ -181,7 +181,7 @@
 											var typeActive = "[[${item.tipus}]]";
 											var idInstanciaTasca = "[[${item.idInstanciaTasca}]]";
 										</script>
-										<div class="card-body-inner-action" th:if="${item.isAssignedToUser or #authentication.principal.isAdmin() or #authentication.principal.isGranted()}">
+										<div class="card-body-inner-action" th:if="${item.isAssignedToUser or #authorization.expression('hasRole(''ROLE_W'')')}">
 											<form enctype='multipart/form-data' method="POST" th:action="${'/procedure/'+instance.idInstancia}">
 												<input class="active-task" type="hidden" name="taskid" th:value="${item.idInstanciaTasca}">
 												<input class="active-task" type="hidden" name="procid" th:value="${instance.idInstancia}">

+ 4 - 4
src/main/resources/templates/supervisionProcedures.html

@@ -44,8 +44,8 @@
 							<input type="hidden" proc_val="center" th:value="${#locale.language} == 'es' ? ${item.centreCas}:${item.centreVal}">
 							<input type="hidden" proc_val="tit" th:value="${#locale.language} == 'es' ? ${item.titulacioCas}:${item.titulacioVal}">
 							<input type="hidden" proc_val="status" th:value="${item.estat}">
-							<input type="hidden" proc_val="datelim" th:value="${#temporals.format(item.dataLimTascaActiva, 'dd-MM-yyyy')}">
-							<input type="hidden" proc_val="date" th:value="${#temporals.format(item.dataTascaActiva, 'dd-MM-yyyy')}">
+							<input type="hidden" proc_val="datelim" th:value="${#temporals.format(item.dataLimTascaActiva, 'yyyy-MM-dd')}">
+							<input type="hidden" proc_val="date" th:value="${#temporals.format(item.dataTascaActiva, 'yyyy-MM-dd')}">
 							<input type="hidden" proc_val="t_active" th:value="${#locale.language} == 'es' ? ${item.nomTascaActivaCas}:${item.nomTascaActivaVal}">
 							<div class="row">
 								<div class="col-md-12">
@@ -69,9 +69,9 @@
 									<span>
 										<span th:text="#{procedures.activeTask}"></span>: <span th:text="${#locale.language} == 'es' ? ${item.nomTascaActivaCas}:${item.nomTascaActivaVal}"></span>
 										<br>
-										<span><span th:text="#{procedures.dateInstance}"></span>: <span th:text="${#temporals.format(item.dataTascaActiva, 'dd-MM-yyyy')}"></span></span>
+										<span><span th:text="#{procedures.dateInstance}"></span>: <span th:text="${#temporals.format(item.dataTascaActiva, 'yyyy-MM-dd')}"></span></span>
 										<br>
-										<span><span th:text="#{procedures.dateLimit}"></span>: <span th:text="${#temporals.format(item.dataLimTascaActiva, 'dd-MM-yyyy')}"></span></span>
+										<span><span th:text="#{procedures.dateLimit}"></span>: <span th:text="${#temporals.format(item.dataLimTascaActiva, 'yyyy-MM-dd')}"></span></span>
 									</span>
 								</div>
 								<div class="col-md-auto" th:if="${item.estat != 'A'}">