| @ -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(); | |||||
| } | |||||
| } | |||||