@ -33,8 +33,6 @@ import java.util.Map;
import java.util.Set ;
import java.util.stream.Collectors ;
import static org.atmosphere.annotation.AnnotationUtil.logger ;
@Route ( value = "" , layout = MainLayout . class )
@PermitAll
@PageTitle ( "Nuevo ticket" )
@ -50,15 +48,44 @@ public class CrearnuevoTicketView extends VerticalLayout {
this . api = api ;
this . userService = service ;
this . buffer = new MultiFileMemoryBuffer ( ) ;
this . uploadFile = new Upload ( buffer ) ;
this . uploadFile . setMaxFiles ( 5 ) ; / / Numero maximo de archivos permitido
this . uploadFile . setDropAllowed ( true ) ;
this . uploadFile . setAcceptedFileTypes ( "image/jpeg" , "image/png" , "application/pdf" , "image/gif" , "image/svg" , "text/plain" ,
"application/zip" , "application/msword" , "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ,
"application/vnd.ms-excel" , "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ) ; / / Tipos de archivos permitidos
this . uploadFile = createUploadComponent ( ) ;
RedmineUser user = userService . getRedmineUser ( ) ;
ComboBox < String > tipoTickets = createTicketTypeComboBox ( ) ;
TextField asunto = createTextField ( "Asunto" , "700px" ) ;
TextArea descripcion = createTextArea ( "Descripcion" , "1000px" , "250px" ) ;
/ / Marcar campos como obligatorios
tipoTickets . setRequiredIndicatorVisible ( true ) ;
asunto . setRequiredIndicatorVisible ( true ) ;
descripcion . setRequiredIndicatorVisible ( true ) ;
uploadFile . addSucceededListener ( event - > handleFileUpload ( event . getFileName ( ) ) ) ;
Button createButton = new Button ( "Enviar ticket" , event - > handleCreateButton ( user , tipoTickets , asunto , descripcion ) ) ;
createButton . addThemeVariants ( ButtonVariant . LUMO_PRIMARY ) ;
VerticalLayout fieldsLayout = new VerticalLayout ( descripcion , uploadFile ) ;
fieldsLayout . setAlignItems ( Alignment . CENTER ) ;
HorizontalLayout firstFields = new HorizontalLayout ( tipoTickets , asunto ) ;
VerticalLayout buttonLayout = new VerticalLayout ( createButton ) ;
buttonLayout . setAlignItems ( Alignment . END ) ;
buttonLayout . setMargin ( true ) ;
add ( new H2 ( "Crear nuevo ticket" ) , firstFields , fieldsLayout , buttonLayout ) ;
}
private Upload createUploadComponent ( ) {
MultiFileMemoryBuffer buffer = new MultiFileMemoryBuffer ( ) ;
Upload uploadFile = new Upload ( buffer ) ;
uploadFile . setMaxFiles ( 5 ) ;
uploadFile . setDropAllowed ( true ) ;
uploadFile . setAcceptedFileTypes ( "image/jpeg" , "image/png" , "application/pdf" , "image/gif" , "image/svg" , "text/plain" ,
"application/zip" , "application/msword" , "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ,
"application/vnd.ms-excel" , "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ) ;
UploadI18N i18N = new UploadI18N ( ) ;
UploadI18N . Uploading uploading = i18N . getUploading ( ) ;
if ( uploading = = null ) {
@ -72,128 +99,107 @@ public class CrearnuevoTicketView extends VerticalLayout {
uploading . setError ( error ) ;
}
error . setUnexpectedServerError ( "No se pudo cargar el archivo. Por favor, intentalo de nuevo" ) ;
error . setServerUnavailable ( "El archivo es demasiado grande. El tamaño máximo permitido es de 10 MB." ) ;
error . setForbidden ( "Archivo no permitido" ) ;
uploadFile . setI18n ( i18N ) ;
return uploadFile ;
}
/ / ComboBox para los tipos de tickets
private ComboBox < String > createTicketTypeComboBox ( ) {
ComboBox < String > tipoTickets = new ComboBox < > ( "Tipo de ticket" ) ;
tipoTickets . setPlaceholder ( "Seleccione un tipo de ticket" ) ;
Map < String , String > ticketTypesMap = api . getTicketTypes ( ) ;
Set < String > ticketTypesSet = Set . of ( "Acceso/Permiso/Bajas" , "Soporte de Software" , "Capacitacion de Software" , "Configuracion de Software" ,
"Digitalizacion GIS" , "Documento" , "Funcionalidad" , "Reporte" , "Soporte o Mantenimiento" ) ;
Set < String > ticketTypesSet = Set . of ( "Acceso/Permiso/Bajas" , "Soporte de Software" , "Capacitacion de Software" ,
"Configuracion de Software" , "Digitalizacion GIS" , "Documento" , "Funcionalidad" , "Reporte" ,
"Soporte o Mantenimiento" ) ;
List < String > filteredTicketTypes = ticketTypesMap . keySet ( ) . stream ( )
. filter ( ticketTypesSet : : contains )
. toList ( ) ;
. filter ( ticketTypesSet : : contains )
. collect ( Collectors . toList ( ) ) ;
tipoTickets . setItems ( filteredTicketTypes ) ;
tipoTickets . addValueChangeListener ( event - > selectedTrackerId = ticketTypesMap . get ( event . getValue ( ) ) ) ;
return tipoTickets ;
}
/ / Campo de texto para el asunto
TextField asunto = new TextField ( "Asunto" ) ;
asunto . setWidth ( "700px" ) ;
/ / Campo de texto para la descripcion
TextArea descripcion = new TextArea ( "Descripcion" ) ;
descripcion . setWidth ( "1000px" ) ;
descripcion . setHeight ( "250px" ) ;
/ / Listener para manejar el evento de subida exitosa de archivos
uploadFile . addSucceededListener ( event - > {
String fileName = event . getFileName ( ) ;
InputStream inputStream = buffer . getInputStream ( fileName ) ;
if ( fileName ! = null & & inputStream ! = null ) {
try ( ByteArrayOutputStream outputStream = new ByteArrayOutputStream ( ) ) {
byte [ ] bufferArray = new byte [ 1024 ] ;
int bytesRead ;
while ( ( bytesRead = inputStream . read ( bufferArray ) ) ! = - 1 ) {
outputStream . write ( bufferArray , 0 , bytesRead ) ;
}
byte [ ] fileContent = outputStream . toByteArray ( ) ;
} catch ( IOException e ) {
Notification . show ( "Error al leer el archivo: " + e . getMessage ( ) , 3000 , Notification . Position . MIDDLE ) ;
logger . error ( "Error al leer el archivo: " + e . getMessage ( ) ) ;
} finally {
try {
inputStream . close ( ) ;
} catch ( IOException e ) {
Notification . show ( "Error al cerrar el InputStream: " + e . getMessage ( ) )
. addThemeVariants ( NotificationVariant . LUMO_ERROR ) ;
}
}
} else {
Notification . show ( "Error: Nombre de archivo o contenido nulos" , 3000 , Notification . Position . MIDDLE ) ;
logger . error ( "Error: Nombre de archivo o contenido nulos" ) ;
}
} ) ;
private TextField createTextField ( String label , String width ) {
TextField textField = new TextField ( label ) ;
textField . setWidth ( width ) ;
return textField ;
}
private TextArea createTextArea ( String label , String width , String height ) {
TextArea textArea = new TextArea ( label ) ;
textArea . setWidth ( width ) ;
textArea . setHeight ( height ) ;
return textArea ;
}
/ / Boton para crear los tickets
Button createButton = new Button ( "Enviar ticket" , event - > {
if ( user . getKey ( ) = = null | | user . getKey ( ) . isEmpty ( ) ) {
Notification . show ( "No se encontró la API key en la sesión." , 5000 , Notification . Position . MIDDLE )
. addThemeVariants ( NotificationVariant . LUMO_ERROR ) ;
return ;
}
private void handleFileUpload ( String fileName ) {
try ( InputStream inputStream = buffer . getInputStream ( fileName ) ;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream ( ) ) {
/ / Obtener el tipo de ticket seleccionado
if ( selectedTrackerId = = null ) {
Notification . show ( "Por favor seleccione un tipo de ticket." , 3000 , Notification . Position . MIDDLE )
. addThemeVariants ( NotificationVariant . LUMO_WARNING ) ;
return ;
byte [ ] bufferArray = new byte [ 1024 ] ;
int bytesRead ;
while ( ( bytesRead = inputStream . read ( bufferArray ) ) ! = - 1 ) {
outputStream . write ( bufferArray , 0 , bytesRead ) ;
}
} catch ( IOException e ) {
Notification . show ( "Error al leer el archivo: " + e . getMessage ( ) , 3000 , Notification . Position . MIDDLE )
. addThemeVariants ( NotificationVariant . LUMO_ERROR ) ;
}
}
Map < String , String > issueDetails = new HashMap < > ( ) ;
issueDetails . put ( "project_id" , "soporte-tecnico-t-i" ) ;
issueDetails . put ( "subject" , asunto . getValue ( ) ) ;
issueDetails . put ( "description" , descripcion . getValue ( ) ) ;
issueDetails . put ( "tracker_id" , selectedTrackerId ) ; / / Añadir el tracker_id
/ / Process uploaded files
List < Map < String , String > > uploads = buffer . getFiles ( ) . stream ( )
. map ( fileName - > {
Map < String , String > fileDetails = new HashMap < > ( ) ;
try {
byte [ ] fileContent = buffer . getInputStream ( fileName ) . readAllBytes ( ) ;
String fileToken = api . uploadFile ( fileContent , fileName ) ;
fileDetails . put ( "token" , fileToken ) ;
fileDetails . put ( "filename" , fileName ) ;
fileDetails . put ( "content_type" , buffer . getFileData ( fileName ) . getMimeType ( ) ) ;
} catch ( IOException e ) {
logger . error ( "Error al cargar el archivo: " + e . getMessage ( ) ) ;
}
return fileDetails ;
} )
. collect ( Collectors . toList ( ) ) ;
JsonArray uploadsJsonArray = new JsonArray ( ) ;
for ( Map < String , String > upload : uploads ) {
JsonObject uploadJson = new JsonObject ( ) ;
uploadJson . addProperty ( "token" , upload . get ( "token" ) ) ;
uploadJson . addProperty ( "filename" , upload . get ( "filename" ) ) ;
uploadJson . addProperty ( "content_type" , upload . get ( "content_type" ) ) ;
uploadsJsonArray . add ( uploadJson ) ;
}
private void handleCreateButton ( RedmineUser user , ComboBox < String > tipoTickets , TextField asunto , TextArea descripcion ) {
if ( user . getKey ( ) = = null | | user . getKey ( ) . isEmpty ( ) ) {
Notification . show ( "No se encontró la API key en la sesión." , 5000 , Notification . Position . MIDDLE )
. addThemeVariants ( NotificationVariant . LUMO_ERROR ) ;
return ;
}
String response = api . createIssue ( issueDetails , uploadsJsonArray , user . getKey ( ) ) ;
if ( selectedTrackerId = = null ) {
Notification . show ( "Por favor seleccione un tipo de ticket." , 3000 , Notification . Position . MIDDLE )
. addThemeVariants ( NotificationVariant . LUMO_WARNING ) ;
return ;
}
handleResponse ( response , asunto , descripcion , tipoTickets ) ;
} ) ;
if ( asunto . isEmpty ( ) ) {
Notification . show ( "El asunto es obligatorio." , 3000 , Notification . Position . MIDDLE )
. addThemeVariants ( NotificationVariant . LUMO_WARNING ) ;
return ;
}
createButton . addThemeVariants ( ButtonVariant . LUMO_PRIMARY ) ;
if ( descripcion . isEmpty ( ) ) {
Notification . show ( "La descripción es obligatoria." , 3000 , Notification . Position . MIDDLE )
. addThemeVariants ( NotificationVariant . LUMO_WARNING ) ;
return ;
}
VerticalLayout fieldsLayout = new VerticalLayout ( descripcion , uploadFile ) ;
fieldsLayout . setAlignItems ( Alignment . CENTER ) ;
HorizontalLayout firstFields = new HorizontalLayout ( tipoTickets , asunto ) ;
VerticalLayout buttonLayout = new VerticalLayout ( createButton ) ;
buttonLayout . setAlignItems ( Alignment . END ) ;
buttonLayout . setMargin ( true ) ;
Map < String , String > issueDetails = new HashMap < > ( ) ;
issueDetails . put ( "project_id" , "soporte-tecnico-t-i" ) ;
issueDetails . put ( "subject" , asunto . getValue ( ) ) ;
issueDetails . put ( "description" , descripcion . getValue ( ) ) ;
issueDetails . put ( "tracker_id" , selectedTrackerId ) ;
JsonArray uploadsJsonArray = new JsonArray ( ) ;
buffer . getFiles ( ) . forEach ( fileName - > {
try ( InputStream inputStream = buffer . getInputStream ( fileName ) ) {
byte [ ] fileContent = inputStream . readAllBytes ( ) ;
String fileToken = api . uploadFile ( fileContent , fileName ) ;
JsonObject uploadJson = new JsonObject ( ) ;
uploadJson . addProperty ( "token" , fileToken ) ;
uploadJson . addProperty ( "filename" , fileName ) ;
uploadJson . addProperty ( "content_type" , buffer . getFileData ( fileName ) . getMimeType ( ) ) ;
uploadsJsonArray . add ( uploadJson ) ;
} catch ( IOException e ) {
Notification . show ( "Error al cargar el archivo: " + e . getMessage ( ) , 3000 , Notification . Position . MIDDLE )
. addThemeVariants ( NotificationVariant . LUMO_ERROR ) ;
}
} ) ;
add ( new H2 ( "Crear nuevo ticket" ) , firstFields , fieldsLayout , buttonLayout ) ;
String response = api . createIssue ( issueDetails , uploadsJsonArray , user . getKey ( ) ) ;
handleResponse ( response , asunto , descripcion , tipoTickets ) ;
}
private void handleResponse ( String response , TextField asunto , TextArea descripcion , ComboBox < String > tipoTickets ) {
@ -202,10 +208,9 @@ public class CrearnuevoTicketView extends VerticalLayout {
int issueNumber = jsonResponse . getAsJsonObject ( "issue" ) . get ( "id" ) . getAsInt ( ) ;
Notification . show ( "Su ticket se ha enviado correctamente! Numero de ticket: #" + issueNumber , 5000 , Notification . Position . MIDDLE )
. addThemeVariants ( NotificationVariant . LUMO_SUCCESS ) ;
resetForm ( asunto , descripcion , tipoTickets ) ;
} else {
Notification . show ( "Error al enviar el ticket. No tiene los permisos necesarios" , 5000 , Notification . Position . MIDDLE )
Notification . show ( "Error al crear el ticket: " + response , 5000 , Notification . Position . MIDDLE )
. addThemeVariants ( NotificationVariant . LUMO_ERROR ) ;
}
}
@ -214,6 +219,11 @@ public class CrearnuevoTicketView extends VerticalLayout {
asunto . clear ( ) ;
descripcion . clear ( ) ;
tipoTickets . clear ( ) ;
asunto . setInvalid ( false ) ;
descripcion . setInvalid ( false ) ;
tipoTickets . setInvalid ( false ) ;
buffer = new MultiFileMemoryBuffer ( ) ;
uploadFile . setReceiver ( buffer ) ;
uploadFile . clearFileList ( ) ;