Browse Source

Security changed to rols policy

Mario Martínez Hernández 13 giờ trước cách đây
mục cha
commit
9883a17ac6
24 tập tin đã thay đổi với 314 bổ sung147 xóa
  1. 15 19
      src/main/java/es/uv/saic/service/AuthProvider.java
  2. 5 1
      src/main/java/es/uv/saic/service/UsuariService.java
  3. 29 28
      src/main/java/es/uv/saic/web/AdminController.java
  4. 6 0
      src/main/java/es/uv/saic/web/CalendarController.java
  5. 19 4
      src/main/java/es/uv/saic/web/DashboardController.java
  6. 16 15
      src/main/java/es/uv/saic/web/DataController.java
  7. 6 0
      src/main/java/es/uv/saic/web/DownloadController.java
  8. 5 0
      src/main/java/es/uv/saic/web/ManagersController.java
  9. 11 0
      src/main/java/es/uv/saic/web/OrganController.java
  10. 23 1
      src/main/java/es/uv/saic/web/ProceduresController.java
  11. 2 2
      src/main/java/es/uv/saic/web/StatsController.java
  12. 39 1
      src/main/java/es/uv/saic/web/SupervisionController.java
  13. 3 0
      src/main/java/es/uv/saic/web/TascaController.java
  14. 2 0
      src/main/java/es/uv/saic/web/UsuariController.java
  15. 5 0
      src/main/java/es/uv/saic/web/WikiController.java
  16. 29 1
      src/main/resources/static/css/saic.css
  17. 0 0
      src/main/resources/templates/blank.html
  18. 4 4
      src/main/resources/templates/dashboard.html
  19. 24 19
      src/main/resources/templates/dashboardCentre.html
  20. 30 19
      src/main/resources/templates/dashboardTitulacio.html
  21. 15 8
      src/main/resources/templates/dashboardUniversitat.html
  22. 17 16
      src/main/resources/templates/layouts/sidebar.html
  23. 5 5
      src/main/resources/templates/procedure.html
  24. 4 4
      src/main/resources/templates/supervisionProcedures.html

+ 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'}">