From d97728efeacfce1ed2b048e7a83fd422036f3ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Antonio=20Ram=C3=ADrez=20Galv=C3=A1n?= Date: Thu, 3 Oct 2024 16:18:36 -0600 Subject: [PATCH] Se agrego la vista de el listado de actividades que lo obtiene directamente desde ProyMan y tambien se agrego de que la fecha se establezca automaticamente cuando le dan clic al boton de realizar --- .../gob/jumapacelaya/api/RedmineClient.java | 288 ++++++++++++++++++ .../gob/jumapacelaya/api/SecurityService.java | 1 + .../jumapacelaya/api/ServerProperties.java | 13 + .../models/CustomUserDetails.java | 84 +++++ .../gob/jumapacelaya/models/RedmineUser.java | 72 +++++ .../mx/gob/jumapacelaya/models/Ticket.java | 98 ++++++ .../jumapacelaya/services/LdapService.java | 46 +++ .../jumapacelaya/services/UserService.java | 81 +++++ .../mx/gob/jumapacelaya/ui/ActDiariaView.java | 131 +++++--- .../jumapacelaya/ui/MantenimientoView.java | 35 ++- .../mx/gob/jumapacelaya/ui/PlanAnualView.java | 11 +- src/main/resources/application.properties | 4 +- 12 files changed, 803 insertions(+), 61 deletions(-) create mode 100644 src/main/java/mx/gob/jumapacelaya/api/RedmineClient.java create mode 100644 src/main/java/mx/gob/jumapacelaya/api/SecurityService.java create mode 100644 src/main/java/mx/gob/jumapacelaya/api/ServerProperties.java create mode 100644 src/main/java/mx/gob/jumapacelaya/models/CustomUserDetails.java create mode 100644 src/main/java/mx/gob/jumapacelaya/models/RedmineUser.java create mode 100644 src/main/java/mx/gob/jumapacelaya/models/Ticket.java create mode 100644 src/main/java/mx/gob/jumapacelaya/services/LdapService.java diff --git a/src/main/java/mx/gob/jumapacelaya/api/RedmineClient.java b/src/main/java/mx/gob/jumapacelaya/api/RedmineClient.java new file mode 100644 index 0000000..6dca37a --- /dev/null +++ b/src/main/java/mx/gob/jumapacelaya/api/RedmineClient.java @@ -0,0 +1,288 @@ +package mx.gob.jumapacelaya.api; + +import com.nimbusds.jose.shaded.gson.*; +import mx.gob.jumapacelaya.models.RedmineUser; +import mx.gob.jumapacelaya.models.Ticket; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +public class RedmineClient { + + private static final int PAGE_SIZE = 25; + static String REDMINE_URL; + static String API_KEY; + public static final Gson GSON = new Gson(); + + public RedmineClient(@Value("${redmine.url}") String redmineUrl, @Value("${redmine.api_key}") String apiKey) { + REDMINE_URL = redmineUrl; + API_KEY = apiKey; + + } + + //AQUI OBTENGO LOS TICKETS DESDE REDMINE + public List getTickets(RedmineUser user, boolean includeClosed) { + List tickets = new ArrayList<>(); + HttpClient client = HttpClient.newHttpClient(); + int offset = 0; + + // Si includeClose es true, incluira todos los tikets si no, incluira solo los que estan abiertos + String statusFilter = includeClosed ? "&status_id=*" : "&status_id=open"; + + + while (true) { + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(REDMINE_URL + "/issues.json?key=" + user.getKey() + statusFilter + "&offset=" + offset)) + .header("Content-Type", "application/json") + .build(); + + try { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + if (response.statusCode() == 200) { + String responseBody = response.body(); + List pageTickets = parseTickets(responseBody); + tickets.addAll(pageTickets); + if (pageTickets.size() < PAGE_SIZE) { + break; + } + offset += PAGE_SIZE; + } else { + System.err.println("Error en la respuesta: " + response.statusCode()); + break; + } + } catch (Exception e) { + e.printStackTrace(); + break; + } + } + System.out.println("Total tickets obtenidos: " + tickets.size()); + return tickets; + } + + + //AQUI OBTENGO LOS TICKETS DESDE REDMINE + public List getTicketsAuthor(RedmineUser user) { + List tickets = new ArrayList<>(); + HttpClient client = HttpClient.newHttpClient(); + int offset = 0; + + + while (true) { + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(REDMINE_URL + "/issues.json?key=" + user.getKey() + "&author_id=" + user.getId() + "&offset=" + offset)) + .header("Content-Type", "application/json") + .build(); + + try { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + if (response.statusCode() == 200) { + String responseBody = response.body(); + List pageTickets = parseTickets(responseBody); + tickets.addAll(pageTickets); + if (pageTickets.size() < PAGE_SIZE) { + break; + } + offset += PAGE_SIZE; + } else { + System.err.println("Error en la respuesta: " + response.statusCode()); + break; + } + } catch (Exception e) { + e.printStackTrace(); + break; + } + } + System.out.println("Total tickets obtenidos: " + tickets.size()); + return tickets; + } + + + // Aquí se parsean todos los tickets que existen y se les da un formato con los campos a mostrarse + private List parseTickets(String json) { + List tickets = new ArrayList<>(); + try { + JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject(); + JsonArray issues = jsonObject.getAsJsonArray("issues"); + if (issues != null) { + for (JsonElement issueElement : issues) { + JsonObject issue = issueElement.getAsJsonObject(); + + // Verifica y obtiene el ID + int id = issue.has("id") && !issue.get("id").isJsonNull() ? issue.get("id").getAsInt() : 0; + + // Verifica y obtiene el subject + String subject = issue.has("subject") && !issue.get("subject").isJsonNull() ? issue.get("subject").getAsString() : ""; + + // Verifica y obtiene la descripción + String description = issue.has("description") && !issue.get("description").isJsonNull() ? issue.get("description").getAsString() : ""; + + // Verifica y obtiene el status + String status = "Unknown"; + if (issue.has("status") && !issue.get("status").isJsonNull()) { + JsonObject statusObject = issue.getAsJsonObject("status"); + if (statusObject.has("name") && !statusObject.get("name").isJsonNull()) { + status = statusObject.get("name").getAsString(); + } + } + + // Verifica y obtiene la fecha de creación + String dateString = issue.has("created_on") && !issue.get("created_on").isJsonNull() ? issue.get("created_on").getAsString() : ""; + LocalDate date = null; + if (!dateString.isEmpty()) { + try { + DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME; + date = LocalDate.parse(dateString, formatter); + } catch (DateTimeParseException e) { + System.err.println("Error al parsear la fecha: " + dateString); + e.printStackTrace(); + } + } + + //Verifica y obtiene el ID del tipo de ticket + Integer trackerId = null; + if (issue.has("tracker") && !issue.get("tracker").isJsonNull()) { + JsonObject trackerObject = issue.getAsJsonObject("tracker"); + if (trackerObject.has("id") && !trackerObject.get("id").isJsonNull()) { + trackerId = trackerObject.get("id").getAsInt(); + } + } + + + // Agrega el ticket a la lista + tickets.add(new Ticket(id, subject, description, status, date != null ? date.toString() : "", trackerId)); + } + } else { + System.out.println("La respuesta JSON no contiene la clave 'issues'"); + } + } catch (Exception e) { + e.printStackTrace(); + System.out.println("Ocurrió un error al parsear los tickets: " + e.getMessage()); + } + return tickets; + } + + public RedmineUser getMyAccount(String username) { + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(REDMINE_URL + "/my/account.json")) + .header("Content-Type", "application/json") + .header("X-Redmine-Switch-User", username) + .header("X-Redmine-API-Key", API_KEY) + .GET() + .build(); + try { + HttpClient client = HttpClient.newHttpClient(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + + JsonObject jsonObject = JsonParser.parseString(response.body()).getAsJsonObject(); + JsonObject userJson = jsonObject.get("user").getAsJsonObject(); + + RedmineUser user = new RedmineUser(); + user.setId(userJson.get("id").getAsInt()); + user.setLogin(userJson.get("login").getAsString()); + user.setFirstname(userJson.get("firstname").getAsString()); + user.setLastname(userJson.get("lastname").getAsString()); + user.setMail(userJson.get("mail").getAsString()); + user.setKey(userJson.get("api_key").getAsString()); + return user; + + //return response.body(); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + return null; + } + } + + + public static RedmineUser createRedmineUser(String username, String firstname, String lastname, String mail) { + HttpClient client = HttpClient.newHttpClient(); + Map user = new HashMap<>(); + user.put("login", username); + user.put("firstname", firstname); + user.put("lastname", lastname); + user.put("mail", mail); + user.put("auth_source_id", "1"); + + Map payload = new HashMap<>(); + payload.put("user", user); + String jsonPayload = new Gson().toJson(payload); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(REDMINE_URL + "/users.json")) + .header("Content-Type", "application/json") + .header("X-Redmine-API-Key", API_KEY) + .POST(HttpRequest.BodyPublishers.ofString(jsonPayload)) + .build(); + + try { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + + JsonObject jsonObject = JsonParser.parseString(response.body()).getAsJsonObject(); + JsonObject userJson = jsonObject.get("user").getAsJsonObject(); + + RedmineUser newUser = new RedmineUser(); + newUser.setId(userJson.get("id").getAsInt()); + newUser.setLogin(userJson.get("login").getAsString()); + newUser.setFirstname(userJson.get("firstname").getAsString()); + newUser.setLastname(userJson.get("lastname").getAsString()); + newUser.setMail(userJson.get("mail").getAsString()); + + return newUser; + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + //AQUI OBTENGO A LOS USUARIOS + //Se devuelven en formato Json + public RedmineUser getUserByUsername(String username) { + HttpClient client = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(REDMINE_URL + "/users.json?name=" + username )) + .header("Content-Type", "application/json") + .header("X-Redmine-API-Key", API_KEY) + .build(); + + try { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + if (response.statusCode() == 200) { + String responseBody = response.body(); + System.out.println("Datos del usuario " + responseBody); + return parseUser(responseBody); + } else { + System.err.println("Error en la respuesta: " + response.statusCode()); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + //Aqui se parsean a los usuarios y se les da un formato con los campos a mostrarse + private RedmineUser parseUser(String json) { + JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject(); + JsonObject userJson = jsonObject.getAsJsonArray("users").get(0).getAsJsonObject(); + + RedmineUser user = new RedmineUser(); + user.setId(userJson.get("id").getAsInt()); + user.setLogin(userJson.get("login").getAsString()); + user.setFirstname(userJson.get("firstname").getAsString()); + user.setLastname(userJson.get("lastname").getAsString()); + user.setMail(userJson.get("mail").getAsString()); + //user.setKey(userJson.get("key").getAsString()); + return user; + } +} diff --git a/src/main/java/mx/gob/jumapacelaya/api/SecurityService.java b/src/main/java/mx/gob/jumapacelaya/api/SecurityService.java new file mode 100644 index 0000000..3d52e83 --- /dev/null +++ b/src/main/java/mx/gob/jumapacelaya/api/SecurityService.java @@ -0,0 +1 @@ +package mx.gob.jumapacelaya.api; diff --git a/src/main/java/mx/gob/jumapacelaya/api/ServerProperties.java b/src/main/java/mx/gob/jumapacelaya/api/ServerProperties.java new file mode 100644 index 0000000..441630f --- /dev/null +++ b/src/main/java/mx/gob/jumapacelaya/api/ServerProperties.java @@ -0,0 +1,13 @@ +package mx.gob.jumapacelaya.api; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ServerProperties { + @Value("${redmine.url}") + public String REDMINE_URL; + + @Value("${redmine.api_key}") + public String API_KEY; +} diff --git a/src/main/java/mx/gob/jumapacelaya/models/CustomUserDetails.java b/src/main/java/mx/gob/jumapacelaya/models/CustomUserDetails.java new file mode 100644 index 0000000..f627f2f --- /dev/null +++ b/src/main/java/mx/gob/jumapacelaya/models/CustomUserDetails.java @@ -0,0 +1,84 @@ +package mx.gob.jumapacelaya.models; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Collection; + +public class CustomUserDetails implements UserDetails { + private String username; + private String firstName; + private String lastName; + private String email; + private Collection authorities; + private String password; + + public CustomUserDetails(String username, String firstName, String lastName, String email, Collection authorities, String password) { + this.username = username; + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + this.authorities = authorities; + this.password = password; + } + + // Getters and setters + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + @Override + public Collection getAuthorities() { + return authorities; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } +} diff --git a/src/main/java/mx/gob/jumapacelaya/models/RedmineUser.java b/src/main/java/mx/gob/jumapacelaya/models/RedmineUser.java new file mode 100644 index 0000000..c5e5fb1 --- /dev/null +++ b/src/main/java/mx/gob/jumapacelaya/models/RedmineUser.java @@ -0,0 +1,72 @@ +package mx.gob.jumapacelaya.models; + +public class RedmineUser { + private int id; + private String login; + private String firstname; + private String lastname; + private String mail; + private String key; + + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public String getMail() { + return mail; + } + + public void setMail(String mail) { + this.mail = mail; + } + + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + @Override + public String toString() { + return "RedmineUser{" + + "id=" + id + + ", login='" + login + '\'' + + ", firstname='" + firstname + '\'' + + ", lastname='" + lastname + '\'' + + ", mail='" + mail + '\'' + + ", key='" + key + '\'' + + '}'; + } +} diff --git a/src/main/java/mx/gob/jumapacelaya/models/Ticket.java b/src/main/java/mx/gob/jumapacelaya/models/Ticket.java new file mode 100644 index 0000000..0a9941a --- /dev/null +++ b/src/main/java/mx/gob/jumapacelaya/models/Ticket.java @@ -0,0 +1,98 @@ +package mx.gob.jumapacelaya.models; + +import java.sql.Date; +import java.time.LocalDate; + +public class Ticket { + private int id; + private String subject; + private String description; + private String status; + private LocalDate dateCreate; + private User author; + private Integer trackerId; + + + public Ticket(int id, String subject, String description, String status, String dateCreate, Integer trackerId) { + this.id = id; + this.subject = subject; + this.description = description; + this.status = status; + this.dateCreate = LocalDate.parse(dateCreate); + this.author = author; + this.trackerId = trackerId; + } + + public int getId() { + return id; + } + + public String getSubject() { + return subject; + } + + public String getDescription() { + return description; + } + + public String getStatus() { + return status; + } + + public User getAuthor() { + return author; + } + + public void setAuthor(User author) { + this.author = author; + } + + public Date getDateCreate() { + return java.sql.Date.valueOf(this.dateCreate); + } + + public Integer getTrackerId() { + return trackerId; + } + + public void setTrackerId(Integer tipoId) { + this.trackerId = trackerId; + } + + public static class User { + private String username; + + public User(String username) { + this.username = username; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + } + + + public String tiempoEst(Integer trackerId) { + if (trackerId == null) { + return "Desconocido"; + } + + switch (trackerId) { + case 5,16,17: + return "2 horas max."; + + case 4,13,14: + return "2 a 6 horas"; + + case 6,7,9,10,11,15: + return "1 a 2 Dias"; + + default: + return "N/A"; + } + } +} diff --git a/src/main/java/mx/gob/jumapacelaya/services/LdapService.java b/src/main/java/mx/gob/jumapacelaya/services/LdapService.java new file mode 100644 index 0000000..53b5a71 --- /dev/null +++ b/src/main/java/mx/gob/jumapacelaya/services/LdapService.java @@ -0,0 +1,46 @@ +package mx.gob.jumapacelaya.services; + +import mx.gob.jumapacelaya.models.CustomUserDetails; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.filter.EqualsFilter; +import org.springframework.stereotype.Service; + +import javax.naming.NamingException; +import javax.naming.directory.Attributes; +import javax.naming.directory.SearchControls; +import java.util.List; + +@Service +public class LdapService { + + private final LdapTemplate ldapTemplate; + + + public LdapService(LdapTemplate ldapTemplate) { + this.ldapTemplate = ldapTemplate; + } + + public CustomUserDetails getUserDetails(String username) { + EqualsFilter filter = new EqualsFilter("sAMAccountName", username); + SearchControls searchControls = new SearchControls(); + searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); + searchControls.setReturningAttributes(new String[]{"givenName", "sn", "mail"}); + searchControls.setReturningObjFlag(true); + + List result = ldapTemplate.search("", filter.encode(), searchControls, (Attributes attrs) -> { + String firstName = getAttribute(attrs, "givenName"); + String lastName = getAttribute(attrs, "sn"); + String email = getAttribute(attrs, "mail"); + return new CustomUserDetails(username, firstName, lastName, email, null, null); // Ajustar los últimos dos parámetros si es necesario + }); + return result.isEmpty() ? null : result.get(0); + } + + private String getAttribute(Attributes attributes, String attributeName) { + try { + return attributes.get(attributeName) != null ? attributes.get(attributeName).get().toString(): null; + } catch (NamingException e) { + return null; + } + } +} diff --git a/src/main/java/mx/gob/jumapacelaya/services/UserService.java b/src/main/java/mx/gob/jumapacelaya/services/UserService.java index 40531a4..043c23d 100644 --- a/src/main/java/mx/gob/jumapacelaya/services/UserService.java +++ b/src/main/java/mx/gob/jumapacelaya/services/UserService.java @@ -1,8 +1,89 @@ package mx.gob.jumapacelaya.services; +import com.vaadin.flow.server.VaadinService; +import mx.gob.jumapacelaya.api.RedmineClient; +import mx.gob.jumapacelaya.services.SecurityService; +import mx.gob.jumapacelaya.models.CustomUserDetails; +import mx.gob.jumapacelaya.models.RedmineUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; + @Service public class UserService { + private final SecurityService securityService; + private final RedmineClient redmineClient; + private static final Logger logger = LoggerFactory.getLogger(UserService.class); + private final LdapService ldpaService; + + public UserService(SecurityService securityService, RedmineClient redmineClient, LdapService ldpaService) { + this.securityService = securityService; + this.redmineClient = redmineClient; + this.ldpaService = ldpaService; + } + + + public RedmineUser getAuthenticatedRedmineUser() { + try { + String username = securityService.getAuthenticatedUser(); + logger.info("Usuario autenticado: " + username); + if (username != null) { + RedmineUser user = redmineClient.getUserByUsername(username); + if (user == null) { + CustomUserDetails userDetails = ldpaService.getUserDetails(username); + if (userDetails != null) { + if (userDetails.getEmail() == null || userDetails.getEmail().isEmpty()) { + logger.error("El usuario: " + username + " no tiene correo electronico."); + return null; + } + RedmineUser newUser = RedmineClient.createRedmineUser( + username, + userDetails.getFirstName(), + userDetails.getLastName(), + userDetails.getEmail() + ); + if (newUser != null) { + logger.info("Usuario creado en Redmine: " + newUser); + return newUser; + } else { + logger.error("Error al crear el usuario en Redmine"); + } + } else { + logger.error("No se encontraron detalles del usuario en LDAP"); + } + } else { + logger.info("Usuario autenticado en Redmine: " + user); + } + return user; + } + } catch (Exception e) { + logger.error("Error al obtener al usuario autenticado en Redmine", e); + } + return null; + } + + public RedmineUser getRedmineUser() { + + RedmineUser userclient = (RedmineUser) VaadinService.getCurrentRequest().getWrappedSession().getAttribute("myaccount"); + if (userclient == null) { + RedmineUser user = getAuthenticatedRedmineUser(); + if (user != null) { + RedmineUser myAccount = redmineClient.getMyAccount(user.getLogin()); + if (myAccount != null && !myAccount.getKey().isEmpty()) { + userclient = myAccount; + VaadinService.getCurrentRequest().getWrappedSession().setAttribute("myaccount", myAccount); + } else { + // Crear un nuevo usuario si no existe + myAccount = RedmineClient.createRedmineUser(user.getLogin(), user.getFirstname(), user.getLastname(), user.getMail()); + if (myAccount != null && !myAccount.getKey().isEmpty()) { + userclient = myAccount; + VaadinService.getCurrentRequest().getWrappedSession().setAttribute("myaccount", myAccount); + } + } + } + } + return userclient; + } } diff --git a/src/main/java/mx/gob/jumapacelaya/ui/ActDiariaView.java b/src/main/java/mx/gob/jumapacelaya/ui/ActDiariaView.java index 2931e3a..6c4377d 100644 --- a/src/main/java/mx/gob/jumapacelaya/ui/ActDiariaView.java +++ b/src/main/java/mx/gob/jumapacelaya/ui/ActDiariaView.java @@ -3,13 +3,21 @@ package mx.gob.jumapacelaya.ui; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.dependency.CssImport; import com.vaadin.flow.component.grid.Grid; +import com.vaadin.flow.component.grid.GridVariant; import com.vaadin.flow.component.html.H3; +import com.vaadin.flow.component.html.Span; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.data.renderer.ComponentRenderer; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import jakarta.annotation.security.PermitAll; +import mx.gob.jumapacelaya.api.RedmineClient; +import mx.gob.jumapacelaya.api.ServerProperties; import mx.gob.jumapacelaya.models.ActividadDiaria; +import mx.gob.jumapacelaya.models.Ticket; +import mx.gob.jumapacelaya.services.LdapService; +import mx.gob.jumapacelaya.services.UserService; import java.text.SimpleDateFormat; @@ -22,52 +30,85 @@ import java.util.*; @CssImport("./themes/sistema-mantenimiento/styles.css") public class ActDiariaView extends VerticalLayout { - //Variables globales - SimpleDateFormat formato = new SimpleDateFormat("dd/MM/yyyy"); - HorizontalLayout header = new HorizontalLayout(); - H3 titulo = new H3(); - Button btnCorrectivo = new Button("Correctivo"); - Grid grdColumnas = new Grid<>(ActividadDiaria.class,false); - List people = Arrays.asList( - new ActividadDiaria(11, "Soprote", "Confi", "Sol", "Urgente",new Date(), new Date()), - new ActividadDiaria(12, "Soprote", "Confi", "Sol", "Urgente",new Date(), new Date()), - new ActividadDiaria(13, "Soprote", "Confi", "Sol", "Urgente",new Date(), new Date())); - //new ActividadDiaria("Johannes Kepler", 1571)); - - public ActDiariaView() { - VerticalLayout headerLayout = new VerticalLayout(); - headerLayout.addClassName("act-diaria-header"); - headerLayout.add(titulo); - titulo.setText("Listado de Actividades por Atender - Área de Soporte Mantenimiento Técnico"); - titulo.addClassName("act-diaria-titulo"); - header.setAlignSelf(Alignment.CENTER, titulo); - - - VerticalLayout gridLayout = new VerticalLayout(); - gridLayout.addClassName("act-diaria-grid"); - gridLayout.add(grdColumnas); - //Tabla echa con un grid - grdColumnas.addColumn(ActividadDiaria::getNumero).setHeader("Numero"); - grdColumnas.addColumn(ActividadDiaria::getProyecto).setHeader("Proyecto"); - grdColumnas.addColumn(ActividadDiaria::getTipo).setHeader("Tipo"); - grdColumnas.addColumn(ActividadDiaria::getEstado).setHeader("Estado"); - grdColumnas.addColumn(ActividadDiaria::getAsunto).setHeader("Asunto"); - grdColumnas.addColumn(date->{ - return formato.format(date.getFechaInicial()); - }).setHeader("Fecha de Inicio"); - grdColumnas.addColumn(date->{ - return formato.format(date.getFechaCierre()); - }).setHeader("Fecha de cierre"); - - grdColumnas.setItems(people); - - - // add(titulo, header, grdColumnas); - this.setPadding(false); - this.setMargin(false); - this.setSpacing(false); - add(headerLayout, gridLayout); + private final RedmineClient redmineClient; + private final UserService userService; + private final Grid grid; + + + public ActDiariaView(ServerProperties properties, RedmineClient redmineClient, UserService userService) { + this.userService = userService; + this.redmineClient = redmineClient; + this.grid = new Grid<>(Ticket.class, false); + + // Configuración de columnas del grid + grid.addColumn(Ticket::getId).setHeader("No.") + .setAutoWidth(true).setFlexGrow(0).setSortable(true); + + grid.addColumn(Ticket::getSubject).setHeader("Asunto") + .setAutoWidth(true); + + grid.addColumn(createStatusRender()).setHeader("Estado"); + + grid.addColumn(ticket -> { + Date date = ticket.getDateCreate(); + if (date != null) { + SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy"); + return formatter.format(date); + } else { + return ""; + } + }).setHeader("Fecha creacion"); + + grid.addColumn(ticket -> ticket.tiempoEst(ticket.getTrackerId())).setHeader("Tiempo estimado de atencion").setAutoWidth(false); + + grid.addColumn(Ticket::getDescription).setHeader("Descripción").setWidth("25em"); + + grid.addThemeVariants(GridVariant.LUMO_WRAP_CELL_CONTENT); + grid.getStyle().set("opacity", "0.8"); + grid.setAllRowsVisible(true); + + // Ajustar tamaño del Grid y Layout + //grid.setSizeFull(); + //setSizeFull(); + + + add(grid); + expand(grid); + setMargin(false); + + loadTickets(); } + private void loadTickets() { + try { + List tickets = redmineClient.getTicketsAuthor(userService.getRedmineUser()); + grid.setItems(tickets); + } catch (Exception e) { + e.printStackTrace(); + // Manejo de error al cargar los tickets + } + } + + private ComponentRenderer createStatusRender() { + return new ComponentRenderer<>(ticket -> { + // Creamos un Span para mostrar el estado + Span span = new Span(ticket.getStatus()); + // Estilos basados en el estado del ticket + switch (ticket.getStatus().toLowerCase()) { + case "análisis": + span.getElement().getStyle().set("color", "purple"); + break; + case "desarrollo": + span.getElement().getStyle().set("color", "green"); + break; + default: + span.getElement().getStyle().set("color", "blue"); + break; + } + + return span; + }); } + +} diff --git a/src/main/java/mx/gob/jumapacelaya/ui/MantenimientoView.java b/src/main/java/mx/gob/jumapacelaya/ui/MantenimientoView.java index 905be48..ebb97fc 100644 --- a/src/main/java/mx/gob/jumapacelaya/ui/MantenimientoView.java +++ b/src/main/java/mx/gob/jumapacelaya/ui/MantenimientoView.java @@ -5,9 +5,6 @@ import com.vaadin.flow.component.checkbox.CheckboxGroup; import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.datepicker.DatePicker; import com.vaadin.flow.component.dependency.CssImport; -import com.vaadin.flow.component.html.H1; -import com.vaadin.flow.component.html.H2; -import com.vaadin.flow.component.html.H3; import com.vaadin.flow.component.html.Span; import com.vaadin.flow.component.icon.Icon; import com.vaadin.flow.component.icon.VaadinIcon; @@ -18,12 +15,13 @@ import com.vaadin.flow.component.radiobutton.RadioButtonGroup; import com.vaadin.flow.component.textfield.TextArea; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.router.BeforeEnterEvent; +import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import jakarta.annotation.security.PermitAll; import mx.gob.jumapacelaya.services.DatabaseService; -import java.awt.*; import java.time.LocalDate; import java.util.List; @@ -32,12 +30,13 @@ import java.util.List; @PageTitle("Mantenimiento") @Route(value = "mantenimiento", layout = MainLayout.class) @CssImport("./themes/sistema-mantenimiento/styles.css") -public class MantenimientoView extends VerticalLayout { +public class MantenimientoView extends VerticalLayout implements BeforeEnterObserver { private final VerticalLayout controlsLayout; private final DatabaseService databaseService; private final VerticalLayout actualizacionesLayout; private final VerticalLayout etiquetaLayout; + private DatePicker fecha; public MantenimientoView() { this.databaseService = new DatabaseService(); @@ -56,8 +55,9 @@ public class MantenimientoView extends VerticalLayout { otras.addClassName("mantenimiento-text-field"); //Selector de fecha - DatePicker fecha = new DatePicker("Fecha"); - // fecha.setPlaceholder("Fecha"); + this.fecha = new DatePicker("Fecha"); + //fecha.setPlaceholder("Fecha"); + //ComboBox Tipo de Mantenimiento @@ -74,18 +74,18 @@ public class MantenimientoView extends VerticalLayout { //Si el tipo es preventivo se establecera la fecha automaticamente a la fecha del sistema if ("PREVENTIVO".equals(tipoSeleccionado)) { - fecha.setValue(LocalDate.now()); + this.fecha.setValue(LocalDate.now()); etiquetaLayout.setVisible(false); } else { - fecha.clear(); + this.fecha.clear(); etiquetaLayout.setVisible(true); } } else { nomenclatura.clear(); - fecha.clear(); + this.fecha.clear(); } }); - fechaLayout.add(fecha); + fechaLayout.add(this.fecha); fechaLayout.addAndExpand(new HorizontalLayout()); fechaLayout.add(tipoMantt, nomenclatura); fechaLayout.setWidthFull(); @@ -294,4 +294,17 @@ public class MantenimientoView extends VerticalLayout { etiquetaLayout.add(Titulo, model, hard); } + + @Override + public void beforeEnter(BeforeEnterEvent beforeEnterEvent) { + String fechaParam = beforeEnterEvent.getLocation().getQueryParameters().getParameters().get("fecha") != null ? beforeEnterEvent.getLocation().getQueryParameters().getParameters().get("fecha").stream().findFirst().orElse(null) : null; + if (fechaParam != null) { + try { + LocalDate fechaActual = LocalDate.parse(fechaParam); + this.fecha.setValue(fechaActual); // Establece la fecha en el DatePicker + } catch (Exception e) { + Notification.show("Error al establecer la fecha: " + e.getMessage(), 3000, Notification.Position.MIDDLE); + } + } + } } diff --git a/src/main/java/mx/gob/jumapacelaya/ui/PlanAnualView.java b/src/main/java/mx/gob/jumapacelaya/ui/PlanAnualView.java index 885a8d6..016f753 100644 --- a/src/main/java/mx/gob/jumapacelaya/ui/PlanAnualView.java +++ b/src/main/java/mx/gob/jumapacelaya/ui/PlanAnualView.java @@ -17,6 +17,7 @@ import jakarta.annotation.security.PermitAll; import mx.gob.jumapacelaya.models.PlanAnual; import java.lang.reflect.Array; +import java.time.LocalDate; import java.util.Arrays; import java.util.List; @@ -63,15 +64,17 @@ public class PlanAnualView extends VerticalLayout { planAnualGrid.addComponentColumn(plan -> getIcon(plan.getMiniPrint())).setHeader("MiniPrint").setAutoWidth(true); planAnualGrid.addComponentColumn(plan -> getIcon(plan.getLaptop())).setHeader("Laptop").setAutoWidth(true); planAnualGrid.addComponentColumn(plan -> getIcon(plan.getEscaner())).setHeader("Escáner").setAutoWidth(true); - planAnualGrid.addColumn(PlanAnual::getFecha).setHeader("Realizar").setAutoWidth(true); + planAnualGrid.addColumn(PlanAnual::getFecha).setHeader("Fecha Programada").setAutoWidth(true); planAnualGrid.addColumn(PlanAnual::getSmt).setHeader("Smt").setAutoWidth(true); planAnualGrid.addColumn(PlanAnual::getEstado).setHeader("Estado").setAutoWidth(true); - planAnualGrid.addColumn(PlanAnual::getFechaRealizado).setHeader("Mes Realizacion").setAutoWidth(true); + planAnualGrid.addColumn(PlanAnual::getFechaRealizado).setHeader("Fecha Realizado").setAutoWidth(true); planAnualGrid.addComponentColumn(plan -> { Button btnRealizar = new Button("Realizar"); btnRealizar.addClickListener(event -> { - btnRealizar.getUI().ifPresent(ui -> ui.navigate(MantenimientoView.class)); + LocalDate fechaSistem = LocalDate.now(); + String fechaStr = fechaSistem.toString(); + btnRealizar.getUI().ifPresent(ui -> ui.navigate("mantenimiento?fecha=" + fechaStr)); }); return btnRealizar; }).setHeader("Realizar").setAutoWidth(true); @@ -84,7 +87,7 @@ public class PlanAnualView extends VerticalLayout { new PlanAnual(1, "INFORM15","T.I", "No", "Logitech", "Logitech", "APC", "si", "HP", "No", "Dell", "Canon", "01-01-2024", "Hector", "Pendiente", "02-01-2024"), new PlanAnual(2, "ATENCI01", "Atencion", "si", "Dell", "no", "APC", "AMD", "Brother", "Sí", "HP", "no", "15-01-2024", "JuanPI", "Realizado", "16-01-2024"), new PlanAnual(3, "MEDCAT08", "T.I", "si", "Dell", "no", "APC", "AMD", "Brother", "Sí", "HP", "no", "15-01-2024", "JuanPI", "Cancelado", "16-01-2024"), - new PlanAnual(4, "CALAGUA03", "T.I", "si", "Dell", "no", "APC", "AMD", "Brother", "Sí", "HP", "no", "15-01-2024", "JuanPI", "Pendiente", "16-01-2024") + new PlanAnual(4, "CALAGUA03", "T.I", "si", "Dell", "no", "APC", "AMD", "Brother", "Sí", "HP", "no", "15-01-2024", "Hector", "Realizado", "16-01-2024") ); planAnualGrid.setItems(planes); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 395cd04..5119dfd 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -15,7 +15,9 @@ spring.ldap.base=DC=JUMAPACELAYA,DC=GOB,DC=MX spring.ldap.username=administrator spring.ldap.password=Dr3na%134$4guA - +########PRODUCTIVO################################# +redmine.url=https://proyman.jumapacelaya.gob.mx/ +redmine.api_key=ce4dc8b6b531c818017e6831a5732ccc15b8faf6 #Conexion a la base de datos Mantenimientos #MySQL Configuration