--- title: "Configurar la Integration Function" url: https://docs.catalyst.zoho.com/es/tutorials/githubbot/java/configure-integration-function/ description: "Crea una extensión en Zoho Cliq usando Integration Functions de Catalyst, que te permite acceder y trabajar con tus repositorios de GitHub usando un bot de Cliq" last_updated: 2026-03-30T08:10:30Z service: All Services type: tutorial related_links: - name: "Integration Functions" url: /es/serverless/help/functions/integration-functions --- # Configurar la Integration Function Ahora configuraremos la Integration Function y le agregaremos código. > **Nota:** Necesitaremos codificar y desplegar la función en la consola remota de Catalyst antes de configurar la extensión en Cliq, porque debemos asociar la extensión con una función existente en la consola de Catalyst. El [directorio de la Integration Function](https://docs.catalyst.zoho.com/es/serverless/help/functions/integration-functions) `functions/GithubExtension` contiene: * El archivo principal de la función `MainClass.java` * Los archivos de handlers en la carpeta `com/handlers` * El archivo de configuración `catalyst-config.json` * Los archivos de biblioteca Java en la carpeta lib * Los archivos de dependencias `.classpath` y `.project` Codificaremos `BotHandler.java`, `CommandHandler.java` y `FunctionHandler.java` en la carpeta `handlers`. También crearemos un nuevo archivo de clase `GithubConstants.java` en este directorio y le agregaremos código. > **Nota:** Revisa el código en esta sección para asegurarte de comprenderlo completamente. Analizaremos el código al final de esta sección. Copia el código a continuación y pégalo en los archivos correspondientes ubicados en el directorio `functions/GithubExtension/com/handlers` de tu proyecto usando un IDE y guarda los archivos. **BotHandler.java** ```java package com.handlers; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; import java.util.logging.Level; import org.json.JSONObject; import org.json.JSONArray; import org.json.JSONException; import com.fasterxml.jackson.databind.ObjectMapper; import com.zc.cliq.enums.ACTION_TYPE; import com.zc.cliq.enums.BANNER_STATUS; import com.zc.cliq.enums.BUTTON_TYPE; import com.zc.cliq.enums.CHANNEL_OPERATION; import com.zc.cliq.enums.SLIDE_TYPE; import com.zc.cliq.objects.Action; import com.zc.cliq.objects.ActionData; import com.zc.cliq.objects.BotDetails; import com.zc.cliq.objects.ButtonObject; import com.zc.cliq.objects.Confirm; import com.zc.cliq.objects.Message; import com.zc.cliq.objects.Slide; import com.zc.cliq.requests.BotCallHandlerRequest; import com.zc.cliq.requests.BotContextHandlerRequest; import com.zc.cliq.requests.BotMentionHandlerRequest; import com.zc.cliq.requests.BotMenuActionHandlerRequest; import com.zc.cliq.requests.BotMessageHandlerRequest; import com.zc.cliq.requests.BotParticipationHandlerRequest; import com.zc.cliq.requests.BotWebhookHandlerRequest; import com.zc.cliq.requests.BotWelcomeHandlerRequest; import com.zc.cliq.responses.BannerResponse; import com.zc.cliq.responses.CoreResponse; import com.zc.cliq.responses.WebhookHandlerResponse; // import com.zc.cliq.util.ZCCliqUtil; public class BotHandler implements com.zc.cliq.interfaces.BotHandler, CoreResponse { Logger LOGGER = Logger.getLogger(BotHandler.class.getName()); @Override public CoreResponse messageHandler(BotMessageHandlerRequest req) throws JSONException { LOGGER.log(Level.SEVERE, "class BotHandler method messageHandler"); String message = req.getMessage(); String text; if (message == null) { text = "Hello! How can I help you?"; } else if (message.equalsIgnoreCase("hello")) { text = "Hello! How can I help you?"; } else if (message.equalsIgnoreCase("webhooktoken")) { Message msg = Message.getInstance("Click on the token generation button below!"); ButtonObject btnObj = new ButtonObject(); btnObj.setType(BUTTON_TYPE.GREEN_OUTLINE); btnObj.setLabel("Create Webhook"); Action action = new Action(); action.setType(ACTION_TYPE.INVOKE_FUNCTION); ActionData actionData = new ActionData(); actionData.setName("authenticate"); // ** INGRESA EL NOMBRE DE TU BUTTON FUNCTION AQUÍ ** action.setData(actionData); Confirm confirm = new Confirm(); confirm.setTitle("Generate Webhooks for a GitLab Project"); confirm.setDescription("Connect to GitLab Projects from within Cliq"); confirm.setInput("user_webhook_token"); action.setConfirm(confirm); btnObj.setAction(action); msg.addButton(btnObj); return (CoreResponse) msg; } else { text = "Sorry, I'm not programmed yet to do this :sad:"; } Message resp = Message.getInstance(text); return (CoreResponse) resp; } @Override public CoreResponse menuActionHandler(BotMenuActionHandlerRequest req) throws Exception { LOGGER.log(Level.SEVERE, "class BotHandler method menuActionHandler"); Message msg = Message.getInstance(); BotDetails bot = BotDetails.getInstance(GithubConstants.BOT_NAME); msg.setBot(bot); if (req.getActionName().equals("Repos")) { JSONArray reposArray = CommandHandler.getRepos(); if (reposArray.length() == 0) { msg.setText("There aren't are repos created yet."); } else { Slide slide = Slide.getInstance(); msg.setText("Here's a list of the *repositories*"); slide.setType(SLIDE_TYPE.TABLE); slide.setTitle("Repo details"); List headers = new ArrayList<>(); headers.add("Name"); headers.add("Private"); headers.add("Open Issues"); headers.add("Link"); // Usar Map en lugar de JSONObject Map data = new HashMap<>(); data.put("headers", headers); // Usar List en lugar de JSONArray List> rows = new ArrayList<>(); for (int i = 0; i < reposArray.length(); i++) { JSONObject repo = reposArray.optJSONObject(i); Map row = new HashMap<>(); row.put("Name", repo.optString("name")); row.put("Private", repo.optBoolean("private") ? "Yes" : "No"); row.put("Open Issues", repo.optString("open_issues_count")); row.put("Link", "[Click here](" + repo.optString("html_url") + ")"); rows.add(row); } data.put("rows", rows); slide.setData(data); msg.addSlide(slide); } } else { msg.setText("Menu action triggered :fist:"); } return (CoreResponse) msg; } @Override public WebhookHandlerResponse webhookHandler(BotWebhookHandlerRequest req) throws Exception { LOGGER.log(Level.SEVERE, "class BotHandler method webhookHandler"); JSONObject reqBody = req.getBody(); LOGGER.info(reqBody.toString()); JSONObject commitJson = reqBody.optJSONArray("commits").optJSONObject(0); /// mensaje Message msg = Message.getInstance("A commit has been pushed !"); msg.setBot(BotDetails.getInstance(GithubConstants.BOT_NAME)); /// mensaje del commit Slide commitMsg = Slide.getInstance(); commitMsg.setType(SLIDE_TYPE.TEXT); commitMsg.setTitle("Commit message"); commitMsg.setData(commitJson.optString("message")); msg.addSlide(commitMsg); // diapositiva Slide details = Slide.getInstance(); details.setType(SLIDE_TYPE.LABEL); details.setTitle("Details"); JSONArray dataArray = new JSONArray(); JSONObject committer = new JSONObject(); committer.put("Committer", commitJson.optJSONObject("author").optString("username")); dataArray.put(committer); JSONObject repoName = new JSONObject(); repoName.put("Repo Name", reqBody.optJSONObject("repository").optString("name")); dataArray.put(repoName); JSONObject timestamp = new JSONObject(); timestamp.put("Timestamp", commitJson.optString("timestamp")); dataArray.put(timestamp); JSONObject compare = new JSONObject(); compare.put("Compare", "[Click here](" + reqBody.optString("compare") + ")"); dataArray.put(compare); details.setData(dataArray); LOGGER.log(Level.SEVERE, "printing array"); ObjectMapper mapper = new ObjectMapper(); LOGGER.log(Level.SEVERE, mapper.writeValueAsString(dataArray)); msg.addSlide(details); return (WebhookHandlerResponse) msg; } @Override public CoreResponse participationHandler(BotParticipationHandlerRequest req) throws Exception { LOGGER.log(Level.SEVERE, "class BotHandler method participationHandler"); String text; if (req.getOperation().equals(CHANNEL_OPERATION.ADDED)) { text = "Hi. Thanks for adding me to the channel :smile:"; } else if (req.getOperation().equals(CHANNEL_OPERATION.REMOVED)) { text = "Bye-Bye :bye-bye:"; } else { text = "I'm too a participant of this chat :wink:"; } Message msg = Message.getInstance(text); return (CoreResponse) msg; } @Override public Message welcomeHandler(BotWelcomeHandlerRequest req) { LOGGER.log(Level.SEVERE, "class BotHandler method welcomeHandler"); String uName = req.getUser() != null ? req.getUser().getFirstName() : "user"; String text = "Hello " + uName + ". Thank you for subscribing :smile:"; Message msg = Message.getInstance(text); return msg; } @Override public CoreResponse contextHandler(BotContextHandlerRequest req) { LOGGER.log(Level.SEVERE, "class BotHandler method contextHandler"); BannerResponse resp = new BannerResponse("", BANNER_STATUS.SUCCESS); if (req.getContextId().equals("personal_details")) { Map answers = req.getAnswers(); StringBuilder str = new StringBuilder(); str.append("Name: ").append(answers.get("name")).append("\n"); str.append("Department: ").append(answers.get("dept")).append("\n"); resp = new BannerResponse("Nice ! I have collected your info: \n" + str.toString(), BANNER_STATUS.SUCCESS); } return (CoreResponse) resp; } @Override public CoreResponse mentionHandler(BotMentionHandlerRequest req) { LOGGER.log(Level.SEVERE, "class BotHandler method mentionHandler"); String text = "Hey *" + req.getUser().getFirstName() + "*, thanks for mentioning me here. I'm from Catalyst city"; BannerResponse resp = new BannerResponse(text, BANNER_STATUS.SUCCESS); return (CoreResponse) resp; } @Override public void callHandler(BotCallHandlerRequest req) throws Exception { LOGGER.log(Level.SEVERE, "class BotHandler method callHandler"); return; } } ``` **CommandHandler.java** ```java package com.handlers; import java.util.logging.Logger; import java.util.logging.Level; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.json.JSONArray; import org.json.JSONObject; import com.zc.api.APIConstants.RequestMethod; import com.zc.api.APIRequest; import com.zc.cliq.enums.SLIDE_TYPE; import com.zc.cliq.objects.BotDetails; import com.zc.cliq.objects.CommandSuggestion; import com.zc.cliq.objects.Message; import com.zc.cliq.objects.Slide; import com.zc.cliq.requests.CommandHandlerRequest; import com.zc.cliq.responses.CoreResponse; import okhttp3.Response; public class CommandHandler implements com.zc.cliq.interfaces.CommandHandler { Logger LOGGER = Logger.getLogger(CommandHandler.class.getName()); @Override public CoreResponse executionHandler(CommandHandlerRequest req) throws Exception { LOGGER.log(Level.SEVERE, "class CommandHandler method executionHandler"); Message msg = Message.getInstance(); BotDetails bot = BotDetails.getInstance(GithubConstants.BOT_NAME); msg.setBot(bot); String commandName = req.getName(); if (commandName.equals("commits")) { List repoSuggestions = req.getSelections(); if (repoSuggestions == null || repoSuggestions.isEmpty()) { msg.setText("Please select a repo from the suggestions."); } else { String repoName = repoSuggestions.get(0).getTitle(); JSONArray commitsArray = getCommits(repoName); if (commitsArray.length() == 0) { msg.setText("There aren't are commits made yet."); } else { Slide slide = Slide.getInstance(); msg.setText("Here's a list of the latest " + GithubConstants.PER_PAGE + " commits made to the repository *" + repoName + "*."); slide.setType(SLIDE_TYPE.TABLE); slide.setTitle("Commit details"); List headers = new ArrayList<>(); headers.add("Date"); headers.add("Commit message"); headers.add("Committed by"); headers.add("Link"); // Usar Map en lugar de JSONObject Map data = new HashMap<>(); data.put("headers", headers); // Usar List en lugar de JSONArray List> rows = new ArrayList<>(); for (int i = 0; i < commitsArray.length(); i++) { JSONObject obj = commitsArray.optJSONObject(i); JSONObject commit = obj.optJSONObject("commit"); JSONObject author = commit.optJSONObject("author"); Map row = new HashMap<>(); row.put("Date", author.optString("date")); row.put("Commit message", commit.optString("message")); row.put("Committed by", author.optString("name")); row.put("Link", "[Click here](" + obj.optString("html_url") + ")"); rows.add(row); } data.put("rows", rows); slide.setData(data); msg.addSlide(slide); } } } else if (commandName.equals("issues")) { List repoSuggestions = req.getSelections(); if (repoSuggestions == null || repoSuggestions.isEmpty()) { msg.setText("Please select a repo from the suggestions."); } else { String repoName = repoSuggestions.get(0).getTitle(); JSONArray issuesArray = getIssues(repoName); if (issuesArray.length() == 0) { msg.setText("There aren't are issues raised yet."); } else { Slide slide = Slide.getInstance(); msg.setText("Here's a list of the latest " + GithubConstants.PER_PAGE + " issues raised to the repository *" + repoName + "*"); slide.setType(SLIDE_TYPE.TABLE); slide.setTitle("Issue details"); List headers = new ArrayList<>(); headers.add("Created At"); headers.add("Title"); headers.add("Created By"); headers.add("Link"); // Usar Map en lugar de JSONObject Map data = new HashMap<>(); data.put("headers", headers); // Usar List en lugar de JSONArray List> rows = new ArrayList<>(); for (int i = 0; i < issuesArray.length(); i++) { JSONObject issueObj = issuesArray.optJSONObject(i); Map row = new HashMap<>(); row.put("Created At", issueObj.optString("created_at")); row.put("Title", issueObj.optString("title")); row.put("Created By", issueObj.optJSONObject("user").optString("login")); row.put("Link", "[Click here](" + issueObj.optString("html_url") + ")"); rows.add(row); } data.put("rows", rows); slide.setData(data); msg.addSlide(slide); } } } else { msg.setText("Slash command executed"); } return (CoreResponse) msg; } @Override public List suggestionHandler(CommandHandlerRequest req) throws Exception { LOGGER.log(Level.SEVERE, "class CommandHandler method suggestionHandler"); List suggestionList = new ArrayList(); JSONArray reposArray = getRepos(); List repoNames = new ArrayList<>(); for (int i = 0; i < reposArray.length(); i++) { JSONObject repo = reposArray.optJSONObject(i); repoNames.add(repo.optString("name")); } if (req.getName().equals("commits") || req.getName().equals("issues")) { repoNames.forEach((name) -> { CommandSuggestion sugg = CommandSuggestion.getInstance(); sugg.setTitle(name); suggestionList.add(sugg); }); } return suggestionList; } public static JSONArray getRepos() throws Exception { APIRequest req = getRequestObj("https://api.github.com/user/repos"); req.executeRequest(); Response resp = req.getHttpResponse(); JSONArray reposArray = new JSONArray(resp.body().string()); return reposArray; } private String getUsername() throws Exception { LOGGER.log(Level.SEVERE, "class CommandHandler method getUsername"); APIRequest req = getRequestObj("https://api.github.com/user"); JSONObject respJson = new JSONObject(req.getResponse().getResponseJSON().get(0).toString()); return respJson.get("login").toString(); } private JSONArray getCommits(String repoName) throws Exception { LOGGER.log(Level.SEVERE, "class CommandHandler method getCommits"); APIRequest req = getRequestObj("https://api.github.com/repos/" + getUsername() + "/" + repoName + "/commits?per_page=" + GithubConstants.PER_PAGE); req.executeRequest(); Response resp = req.getHttpResponse(); JSONArray commitsArray = new JSONArray(resp.body().string()); return commitsArray; } private JSONArray getIssues(String repoName) throws Exception { LOGGER.log(Level.SEVERE, "class CommandHandler method getIssues"); APIRequest req = getRequestObj("https://api.github.com/repos/" + getUsername() + "/" + repoName + "/issues?per_page=" + GithubConstants.PER_PAGE); req.executeRequest(); Response resp = req.getHttpResponse(); JSONArray issuesArray = new JSONArray(resp.body().string()); return issuesArray; } private static APIRequest getRequestObj(String url) { APIRequest req = new APIRequest(); req.setUrl(url); req.setRequestMethod(RequestMethod.GET); req.setAuthNeeded(false); HashMap headers = new HashMap<>(); headers.put("Authorization", "Token " + GithubConstants.PERSONAL_ACCESS_TOKEN); req.setHeaders(headers); return req; } } ``` **FunctionHandler.java** ```java package com.handlers; import java.util.HashMap; import java.util.Map; import com.zc.cliq.objects.Form; import com.zc.cliq.objects.FormChangeResponse; import com.zc.cliq.objects.FormDynamicFieldResponse; import com.zc.cliq.objects.Message; import com.zc.cliq.objects.WidgetSection; import com.zc.cliq.requests.ButtonFunctionRequest; import com.zc.cliq.requests.FormFunctionRequest; import com.zc.cliq.requests.WidgetFunctionRequest; public class FunctionHandler implements com.zc.cliq.interfaces.FunctionHandler { @SuppressWarnings("unchecked") @Override public Message buttonFunctionHandler(ButtonFunctionRequest req) throws Exception { String text; if (req.getName().equals("authenticate")) { System.out.println("Arguments: " + req.getArguments()); text = req.getArguments().get("input").toString(); } else { text = "Button function executed"; } Message msg = Message.getInstance(text); return msg; } @Override public Message formSubmitHandler(FormFunctionRequest req) throws Exception { return Message.getInstance("Form submitted successfully"); } @Override public FormChangeResponse formChangeHandler(FormFunctionRequest req) throws Exception { FormChangeResponse resp = FormChangeResponse.getInstance(); return resp; } @Override public FormDynamicFieldResponse formDynamicFieldHandler(FormFunctionRequest req) throws Exception { FormDynamicFieldResponse resp = FormDynamicFieldResponse.getInstance(); return resp; } @Override public Form formViewHandler(FormFunctionRequest req) throws Exception { return Form.getInstance(); } @Override public WidgetSection widgetButtonHandler(WidgetFunctionRequest req) throws Exception { return getButtonsSection(); } private WidgetSection getButtonsSection() { WidgetSection buttonSection = WidgetSection.getInstance(); return buttonSection; } } ``` A continuación, crea un nuevo archivo de clase Java en el `directorio handlers/` y nómbralo `GithubConstants.java`. Agrega el código proporcionado a continuación en el archivo. **GithubConstants.java** ```java package com.handlers; public class GithubConstants { public static final String PERSONAL_ACCESS_TOKEN = "XXXXx"; public static final Integer PER_PAGE = 10; public static final String BOT_NAME = "github-bot"; } ``` > **Nota:** Después de copiar y pegar este código, **pega el token de acceso personal que obtuviste de GitHub** en el paso 2, en la línea 6 de este código. El directorio de funciones está ahora configurado. Repasemos rápidamente el código de las clases de handlers. Analizaremos los componentes especificados aquí en detalle al [configurar la extensión](https://docs.catalyst.zoho.com/es/tutorials/githubbot/java/create-extension-on-cliq). * La clase `BotHandler.java` contiene la lógica de negocio del componente del bot de GitHub que configuraremos en la extensión de Cliq. Después de habilitar el bot de chat, podrás generar un token de webhook para autenticar la conexión con GitHub, listar los detalles de tus repositorios de Git y obtener los detalles de los últimos commits e issues en un repositorio. Estas acciones se definen en esta clase. * La clase `CommandHandler.java` maneja las acciones que se deben realizar para los comandos de issues y commits. También define el handler de sugerencias que lista los repositorios de la cuenta de Git. El usuario debe seleccionar un repositorio de la sugerencia después de ingresar el comando, para ejecutar el comando en ese repositorio. `CommandHandler.java` también define las APIs para obtener otra información de la cuenta de Git. * La clase `FunctionHandler.java` contiene la lógica de negocio de la button function que autentica el token de webhook para GitHub. * El archivo de clase `GitHubConstants.java` almacena los valores constantes de la función, como el token de acceso personal y el nombre del bot.