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