| @ -1,121 +0,0 @@ | |||
| package com.example.application.api; | |||
| import com.nimbusds.jose.shaded.gson.Gson; | |||
| import com.nimbusds.jose.shaded.gson.JsonObject; | |||
| import com.nimbusds.jose.shaded.gson.JsonParser; | |||
| import java.net.URI; | |||
| import java.net.http.HttpClient; | |||
| import java.net.http.HttpRequest; | |||
| import java.net.http.HttpResponse; | |||
| import java.util.ArrayList; | |||
| import java.util.HashMap; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| public class ApiRedmine { | |||
| public static final Gson GSON = new Gson(); | |||
| static String REDMINE_URL; | |||
| static String API_KEY; | |||
| public ApiRedmine(String redmineurl, String apikey) { | |||
| REDMINE_URL = redmineurl; | |||
| API_KEY = apikey; | |||
| } | |||
| public static String createIssue(Map<String, String> issueDetails) { | |||
| return createIssue(issueDetails, null); | |||
| } | |||
| public static String createIssue(Map<String, String> issueDetails, String fileUploadToken) { | |||
| Map<String, Object> payload = new HashMap<>(); | |||
| payload.put("issue", issueDetails); | |||
| if (fileUploadToken != null) { | |||
| List<Map<String, String>> uploads = new ArrayList<>(); | |||
| Map<String, String> fileTokenMap = new HashMap<>(); | |||
| fileTokenMap.put("token", fileUploadToken); | |||
| uploads.add(fileTokenMap); | |||
| payload.put("uploads", uploads); | |||
| } | |||
| String jsonPayload = GSON.toJson(payload); | |||
| try { | |||
| HttpRequest request = HttpRequest.newBuilder() | |||
| .uri(URI.create(REDMINE_URL + "/issues.json")) | |||
| .header("Content-Type", "application/json") | |||
| .header("X-Redmine-API-Key", API_KEY) | |||
| .POST(HttpRequest.BodyPublishers.ofString(jsonPayload)) | |||
| .build(); | |||
| HttpClient client = HttpClient.newHttpClient(); | |||
| HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | |||
| return response.body(); | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| return "Error: " + e.getMessage(); | |||
| } | |||
| } | |||
| public List<String> getTicketTypes() { | |||
| List<String> ticketTypes = new ArrayList<>(); | |||
| HttpClient client = HttpClient.newHttpClient(); | |||
| HttpRequest request = HttpRequest.newBuilder() | |||
| .uri(URI.create(REDMINE_URL + "/trackers.json")) | |||
| .header("Content-Type", "application/json") | |||
| .header("X-Redmine-API-Key", API_KEY) | |||
| .build(); | |||
| try { | |||
| HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | |||
| if (response.statusCode() == 200) { | |||
| String responseBody = response.body(); | |||
| ticketTypes = parseTicketTypes(responseBody); | |||
| } else { | |||
| System.err.println("Error en la respuesta: " + response.statusCode()); | |||
| } | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| return ticketTypes; | |||
| } | |||
| private List<String> parseTicketTypes(String json) { | |||
| List<String> names = new ArrayList<>(); | |||
| JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject(); | |||
| jsonObject.getAsJsonArray("trackers").forEach(trackerElement -> { | |||
| JsonObject tracker = trackerElement.getAsJsonObject(); | |||
| names.add(tracker.get("name").getAsString()); | |||
| }); | |||
| return names; | |||
| } | |||
| public static String uploadFile(byte[] fileContent, String fileName) { | |||
| HttpClient client = HttpClient.newHttpClient(); | |||
| HttpRequest request = HttpRequest.newBuilder() | |||
| .uri(URI.create(REDMINE_URL + "/uploads.json")) | |||
| .header("Content-Type", "application/octet-stream") | |||
| .header("X-Redmine-API-Key", API_KEY) | |||
| .header("Content-Disposition", "attachment; filename=\"" + fileName + "\"") | |||
| .POST(HttpRequest.BodyPublishers.ofByteArray(fileContent)) | |||
| .build(); | |||
| try { | |||
| HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | |||
| if (response.statusCode() == 201) { | |||
| JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject(); | |||
| return jsonResponse.get("upload").getAsJsonObject().get("token").getAsString(); | |||
| } else { | |||
| System.err.println("Error en la subida del archivo: " + response.statusCode()); | |||
| System.err.println("Response body: " + response.body()); | |||
| return null; | |||
| } | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| return null; | |||
| } | |||
| } | |||
| } | |||
| @ -1,127 +0,0 @@ | |||
| package com.example.application.api; | |||
| import com.example.application.models.Ticket; | |||
| import com.nimbusds.jose.shaded.gson.JsonArray; | |||
| import com.nimbusds.jose.shaded.gson.JsonElement; | |||
| import com.nimbusds.jose.shaded.gson.JsonObject; | |||
| import com.nimbusds.jose.shaded.gson.JsonParser; | |||
| 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.List; | |||
| import java.util.stream.Collectors; | |||
| public class RedmineClient { | |||
| private static final int PAGE_SIZE = 25; | |||
| static String REDMINE_URL; | |||
| static String API_KEY; | |||
| public RedmineClient(String redmineUrl, String apiKey) { | |||
| REDMINE_URL = redmineUrl; | |||
| API_KEY = apiKey; | |||
| } | |||
| public List<Ticket> getTickets() { | |||
| List<Ticket> tickets = new ArrayList<>(); | |||
| HttpClient client = HttpClient.newHttpClient(); | |||
| int offset = 0; | |||
| while (true) { | |||
| HttpRequest request = HttpRequest.newBuilder() | |||
| .uri(URI.create(REDMINE_URL + "/issues.json?key=" + API_KEY + "&offset=" + offset)) | |||
| .header("Content-Type", "application/json") | |||
| .build(); | |||
| try { | |||
| HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | |||
| if (response.statusCode() == 200) { | |||
| String responseBody = response.body(); | |||
| List<Ticket> 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; | |||
| } | |||
| private List<Ticket> parseTickets(String json) { | |||
| List<Ticket> 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(); | |||
| int id = issue.has("id") ? issue.get("id").getAsInt() : 0; | |||
| String subject = issue.has("subject") ? issue.get("subject").getAsString() : ""; | |||
| String description = issue.has("description") ? issue.get("description").getAsString() : ""; | |||
| String status = issue.has("status") ? issue.getAsJsonObject("status").get("name").getAsString() : "Unknown"; | |||
| String dateString = issue.has("created_on") ? 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(); | |||
| } | |||
| } | |||
| JsonObject authorJson = issue.has("author") ? issue.getAsJsonObject("author") : null; | |||
| Ticket.User author = null; | |||
| if (authorJson != null) { | |||
| String username = authorJson.has("name") ? authorJson.get("name").getAsString() : "Unknown"; | |||
| author = new Ticket.User(username); | |||
| } | |||
| tickets.add(new Ticket(id, subject, description, status, date != null ? date.toString() : "", author)); | |||
| } | |||
| } 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 List<Ticket> getTicketsCreatedBy(String username) { | |||
| List<Ticket> allTickets = getTickets(); | |||
| return allTickets.stream() | |||
| .filter(ticket -> ticket.getAuthor() != null && username.equals(ticket.getAuthor().getUsername())) | |||
| .collect(Collectors.toList()); | |||
| } | |||
| private static class TicketResponse { | |||
| private List<Ticket> issues; | |||
| public List<Ticket> getIssues() { | |||
| return issues; | |||
| } | |||
| public void setIssues(List<Ticket> issues) { | |||
| this.issues = issues; | |||
| } | |||
| } | |||
| } | |||
| @ -1,58 +0,0 @@ | |||
| package com.example.application.views.login; | |||
| import com.vaadin.flow.component.html.Image; | |||
| import com.vaadin.flow.component.login.LoginForm; | |||
| import com.vaadin.flow.component.login.LoginI18n; | |||
| import com.vaadin.flow.component.orderedlayout.VerticalLayout; | |||
| 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 com.vaadin.flow.server.auth.AnonymousAllowed; | |||
| @Route("login") | |||
| @PageTitle("Login") | |||
| @AnonymousAllowed | |||
| public class LoginView extends VerticalLayout implements BeforeEnterObserver { | |||
| private final LoginForm formularioLogin; | |||
| public LoginView() { | |||
| addClassName("vista-login"); | |||
| setSizeFull(); | |||
| setAlignItems(Alignment.CENTER); | |||
| setJustifyContentMode(JustifyContentMode.CENTER); | |||
| Image logo = new Image("images/NVO_JUMAPA.png", "Logo JUMAPA"); | |||
| logo.setWidth("300px"); | |||
| LoginI18n i18n = LoginI18n.createDefault(); | |||
| LoginI18n.Form i18nFormulario = i18n.getForm(); | |||
| i18nFormulario.setTitle("Sistema de Soporte Técnico Gcia. de T.I"); | |||
| i18nFormulario.setUsername("Usuario"); | |||
| i18nFormulario.setPassword("Contraseña"); | |||
| i18nFormulario.setSubmit("Iniciar sesión"); | |||
| i18n.setForm(i18nFormulario); | |||
| i18n.getErrorMessage().setTitle("Credenciales incorrectas"); | |||
| i18n.getErrorMessage().setMessage("El usuario o la contraseña son incorrectos, verifica tus credenciales."); | |||
| formularioLogin = new LoginForm(); | |||
| formularioLogin.setAction("login"); | |||
| formularioLogin.setForgotPasswordButtonVisible(false); | |||
| formularioLogin.setI18n(i18n); | |||
| add(logo, formularioLogin); | |||
| } | |||
| @Override | |||
| public void beforeEnter(BeforeEnterEvent beforeEnterEvent) { | |||
| if (beforeEnterEvent.getLocation() | |||
| .getQueryParameters() | |||
| .getParameters() | |||
| .containsKey("error")) { | |||
| formularioLogin.setError(true); | |||
| } | |||
| } | |||
| } | |||
| @ -0,0 +1 @@ | |||
| @ -0,0 +1,349 @@ | |||
| package mx.gob.jumapacelaya.api; | |||
| import com.nimbusds.jose.shaded.gson.*; | |||
| import com.vaadin.flow.server.VaadinService; | |||
| 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<Ticket> getTickets(RedmineUser user) { | |||
| List<Ticket> 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() + "&offset=" + offset)) | |||
| .header("Content-Type", "application/json") | |||
| .build(); | |||
| try { | |||
| HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | |||
| if (response.statusCode() == 200) { | |||
| String responseBody = response.body(); | |||
| List<Ticket> 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<Ticket> getTicketsAuthor(RedmineUser user) { | |||
| List<Ticket> 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<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | |||
| if (response.statusCode() == 200) { | |||
| String responseBody = response.body(); | |||
| List<Ticket> 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 se parsean todos los tickets que existen y se les da un formato con los campos a mostrarse | |||
| private List<Ticket> parseTickets(String json) { | |||
| List<Ticket> 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(); | |||
| int id = issue.has("id") ? issue.get("id").getAsInt() : 0; | |||
| String subject = issue.has("subject") ? issue.get("subject").getAsString() : ""; | |||
| String description = issue.has("description") ? issue.get("description").getAsString() : ""; | |||
| String status = issue.has("status") ? issue.getAsJsonObject("status").get("name").getAsString() : "Unknown"; | |||
| String dateString = issue.has("created_on") ? 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(); | |||
| } | |||
| } | |||
| JsonObject authorJson = issue.has("author") ? issue.getAsJsonObject("author") : null; | |||
| Ticket.User author = null; | |||
| if (authorJson != null) { | |||
| String username = authorJson.has("name") ? authorJson.get("name").getAsString() : "Unknown"; | |||
| author = new Ticket.User(username); | |||
| } | |||
| tickets.add(new Ticket(id, subject, description, status, date != null ? date.toString() : "", author)); | |||
| } | |||
| } 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; | |||
| } | |||
| private static class TicketResponse { | |||
| private List<Ticket> issues; | |||
| public List<Ticket> getIssues() { | |||
| return issues; | |||
| } | |||
| public void setIssues(List<Ticket> issues) { | |||
| this.issues = issues; | |||
| } | |||
| } | |||
| //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<String> 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; | |||
| } | |||
| 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<String> 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 String uploadFile(byte[] fileContent, String fileName) { | |||
| HttpClient client = HttpClient.newHttpClient(); | |||
| HttpRequest request = HttpRequest.newBuilder() | |||
| .uri(URI.create(REDMINE_URL + "/uploads.json")) | |||
| .header("Content-Type", "application/octet-stream") | |||
| .header("X-Redmine-API-Key", API_KEY) | |||
| .header("Content-Disposition", "attachment; filename=\"" + fileName + "\"") | |||
| .POST(HttpRequest.BodyPublishers.ofByteArray(fileContent)) | |||
| .build(); | |||
| try { | |||
| HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | |||
| if (response.statusCode() == 201) { | |||
| JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject(); | |||
| return jsonResponse.get("upload").getAsJsonObject().get("token").getAsString(); | |||
| } else { | |||
| System.err.println("Error en la subida del archivo: " + response.statusCode()); | |||
| System.err.println("Response body: " + response.body()); | |||
| return null; | |||
| } | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| return null; | |||
| } | |||
| } | |||
| public String createIssue(Map<String, String> issueDetails, String apiKey) { | |||
| return createIssue(issueDetails, null, apiKey); | |||
| } | |||
| public String createIssue(Map<String, String> issueDetails, String fileUploadToken, String apiKey) { | |||
| Map<String, Object> payload = new HashMap<>(); | |||
| payload.put("issue", issueDetails); | |||
| RedmineUser user = (RedmineUser) VaadinService.getCurrentRequest().getWrappedSession().getAttribute("myaccount"); | |||
| if (fileUploadToken != null) { | |||
| List<Map<String, String>> uploads = new ArrayList<>(); | |||
| Map<String, String> fileTokenMap = new HashMap<>(); | |||
| fileTokenMap.put("token", fileUploadToken); | |||
| uploads.add(fileTokenMap); | |||
| payload.put("uploads", uploads); | |||
| } | |||
| String jsonPayload = GSON.toJson(payload); | |||
| try { | |||
| HttpRequest request = HttpRequest.newBuilder() | |||
| .uri(URI.create(REDMINE_URL + "/issues.json")) | |||
| .header("Content-Type", "application/json") | |||
| .header("X-Redmine-API-Key", user.getKey()) | |||
| .POST(HttpRequest.BodyPublishers.ofString(jsonPayload)) | |||
| .build(); | |||
| HttpClient client = HttpClient.newHttpClient(); | |||
| HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | |||
| return response.body(); | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| return "Error: " + e.getMessage(); | |||
| } | |||
| } | |||
| public List<String> getTicketTypes() { | |||
| List<String> ticketTypes = new ArrayList<>(); | |||
| HttpClient client = HttpClient.newHttpClient(); | |||
| HttpRequest request = HttpRequest.newBuilder() | |||
| .uri(URI.create(REDMINE_URL + "/trackers.json")) | |||
| .header("Content-Type", "application/json") | |||
| .header("X-Redmine-API-Key", API_KEY) | |||
| .build(); | |||
| try { | |||
| HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | |||
| if (response.statusCode() == 200) { | |||
| String responseBody = response.body(); | |||
| ticketTypes = parseTicketTypes(responseBody); | |||
| } else { | |||
| System.err.println("Error en la respuesta: " + response.statusCode()); | |||
| } | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| return ticketTypes; | |||
| } | |||
| private List<String> parseTicketTypes(String json) { | |||
| List<String> names = new ArrayList<>(); | |||
| JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject(); | |||
| jsonObject.getAsJsonArray("trackers").forEach(trackerElement -> { | |||
| JsonObject tracker = trackerElement.getAsJsonObject(); | |||
| names.add(tracker.get("name").getAsString()); | |||
| }); | |||
| return names; | |||
| } | |||
| } | |||
| @ -0,0 +1,23 @@ | |||
| package mx.gob.jumapacelaya.controllers; | |||
| import mx.gob.jumapacelaya.models.RedmineUser; | |||
| import mx.gob.jumapacelaya.services.UserService; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.RestController; | |||
| @RestController | |||
| public class UserController { | |||
| private final UserService userService; | |||
| @Autowired | |||
| public UserController(UserService userService) { | |||
| this.userService = userService; | |||
| } | |||
| @GetMapping("/current-user") | |||
| public RedmineUser getCurrentUser() { | |||
| return userService.getAuthenticatedRedmineUser(); | |||
| } | |||
| } | |||
| @ -0,0 +1,73 @@ | |||
| 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 + '\'' + | |||
| '}'; | |||
| } | |||
| } | |||
| @ -0,0 +1,2 @@ | |||
| package mx.gob.jumapacelaya.models;public class RedmineUser_Model { | |||
| } | |||
| @ -0,0 +1,61 @@ | |||
| package mx.gob.jumapacelaya.services; | |||
| import com.vaadin.flow.server.VaadinService; | |||
| import mx.gob.jumapacelaya.api.RedmineClient; | |||
| import mx.gob.jumapacelaya.api.SecurityService; | |||
| 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); | |||
| public UserService(SecurityService securityService, RedmineClient redmineClient) { | |||
| this.securityService = securityService; | |||
| this.redmineClient = redmineClient; | |||
| } | |||
| /** | |||
| * Obtiene el usuario autenticado de Redmine. | |||
| * | |||
| * @return el usuario autenticado de Redmine, o null si no hay un usuario autenticado. | |||
| */ | |||
| public RedmineUser getAuthenticatedRedmineUser() { | |||
| try { | |||
| String usename = securityService.getAuthenticatedUser(); | |||
| logger.info("Usuario autenticado: " + usename); | |||
| if (usename != null) { | |||
| RedmineUser user = redmineClient.getUserByUsername(usename); | |||
| 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); | |||
| } | |||
| } | |||
| } | |||
| return userclient; | |||
| } | |||
| } | |||
| @ -0,0 +1,92 @@ | |||
| package mx.gob.jumapacelaya.views.login; | |||
| import com.vaadin.flow.component.html.Image; | |||
| import com.vaadin.flow.component.login.LoginForm; | |||
| import com.vaadin.flow.component.login.LoginI18n; | |||
| import com.vaadin.flow.component.orderedlayout.VerticalLayout; | |||
| 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 com.vaadin.flow.server.auth.AnonymousAllowed; | |||
| import mx.gob.jumapacelaya.api.RedmineClient; | |||
| import mx.gob.jumapacelaya.services.UserService; | |||
| @Route("login") | |||
| @PageTitle("Login") | |||
| @AnonymousAllowed | |||
| public class LoginView extends VerticalLayout implements BeforeEnterObserver { //}, ComponentEventListener<AbstractLogin.LoginEvent> { | |||
| private final LoginForm formularioLogin; | |||
| private static final String LOGIN_SUCCESS_URL = ""; // URL de redirección después del login exitoso | |||
| private final UserService userService; | |||
| private final RedmineClient redmineClient; | |||
| public LoginView(UserService userService, RedmineClient redmineClient) { | |||
| addClassName("vista-login"); | |||
| setSizeFull(); | |||
| setAlignItems(Alignment.CENTER); | |||
| setJustifyContentMode(JustifyContentMode.CENTER); | |||
| // Imagen del logo | |||
| Image logo = new Image("images/NVO_JUMAPA.png", "Logo JUMAPA"); | |||
| logo.setWidth("300px"); | |||
| // Configuración de i18n para el formulario de login | |||
| LoginI18n i18n = LoginI18n.createDefault(); | |||
| LoginI18n.Form i18nFormulario = i18n.getForm(); | |||
| i18nFormulario.setTitle("Sistema de Soporte Técnico Gcia. de T.I"); | |||
| i18nFormulario.setUsername("Usuario"); | |||
| i18nFormulario.setPassword("Contraseña"); | |||
| i18nFormulario.setSubmit("Iniciar sesión"); | |||
| i18n.setForm(i18nFormulario); | |||
| i18n.getErrorMessage().setTitle("Credenciales incorrectas"); | |||
| i18n.getErrorMessage().setMessage("El usuario o la contraseña son incorrectos, verifica tus credenciales."); | |||
| // Configuración del formulario de login | |||
| formularioLogin = new LoginForm(); | |||
| formularioLogin.setAction("login"); | |||
| formularioLogin.setForgotPasswordButtonVisible(false); | |||
| formularioLogin.setI18n(i18n); | |||
| // Añadir el listener del evento de login | |||
| //formularioLogin.addLoginListener(this); | |||
| // Añadir componentes a la vista | |||
| add(logo, formularioLogin); | |||
| this.userService = userService; | |||
| this.redmineClient = redmineClient; | |||
| } | |||
| @Override | |||
| public void beforeEnter(BeforeEnterEvent beforeEnterEvent) { | |||
| // Mostrar el mensaje de error si hay un parámetro de error en la URL | |||
| if (beforeEnterEvent.getLocation().getQueryParameters().getParameters().containsKey("error")) { | |||
| formularioLogin.setError(true); | |||
| } | |||
| } | |||
| // Manejar el evento de login | |||
| /*@Override | |||
| public void onComponentEvent(AbstractLogin.LoginEvent event) { | |||
| boolean authenticated = mx.gob.jumapacelaya.views.login.SecurityUtils.authenticate( | |||
| event.getUsername(), event.getPassword()); | |||
| if (authenticated) { | |||
| RedmineUser user = userService.getAuthenticatedRedmineUser(); | |||
| if (user != null) { | |||
| RedmineUser myAccount = redmineClient.getMyAccount(user.getLogin()); | |||
| if (myAccount != null && !myAccount.getKey().isEmpty()) { | |||
| VaadinService.getCurrentRequest().getWrappedSession().setAttribute("myaccount", myAccount); | |||
| //UI.getCurrent().getPage().setLocation(LOGIN_SUCCESS_URL); | |||
| } //else { | |||
| // formularioLogin.setError(true); | |||
| //} | |||
| //} else { | |||
| // formularioLogin.setError(true); | |||
| } | |||
| } //else { | |||
| //formularioLogin.setError(true); | |||
| // } | |||
| }*/ | |||
| } | |||
| @ -0,0 +1,39 @@ | |||
| package mx.gob.jumapacelaya.views.login; | |||
| import com.vaadin.flow.component.UI; | |||
| import com.vaadin.flow.server.VaadinServletRequest; | |||
| import com.vaadin.flow.server.VaadinSession; | |||
| import jakarta.servlet.ServletException; | |||
| public class SecurityUtils { | |||
| private static final String LOGOUT_SUCCESS_URL = "login"; | |||
| public static boolean isAuthenticated() { | |||
| VaadinServletRequest request = VaadinServletRequest.getCurrent(); | |||
| return request != null && request.getUserPrincipal() != null; | |||
| } | |||
| public static boolean authenticate(String username, String password) { | |||
| VaadinServletRequest request = VaadinServletRequest.getCurrent(); | |||
| if (request == null) { | |||
| // This is in a background thread and we can't access the request to | |||
| // log in the user | |||
| return false; | |||
| } | |||
| try { | |||
| request.login(username, password); | |||
| // change session ID to protect against session fixation | |||
| request.getHttpServletRequest().changeSessionId(); | |||
| return true; | |||
| } catch (ServletException e) { | |||
| // login exception handle code omitted | |||
| return false; | |||
| } | |||
| } | |||
| public static void logout() { | |||
| UI.getCurrent().getPage().setLocation(LOGOUT_SUCCESS_URL); | |||
| VaadinSession.getCurrent().getSession().invalidate(); | |||
| } | |||
| } | |||