DEV Community

Cover image for Criando um bot para WhatsApp que se comunica com o Jira
Emerson Vieira
Emerson Vieira

Posted on

Criando um bot para WhatsApp que se comunica com o Jira

Este projeto faz uso dos seguintes módulos node:

1 - whatsapp-web.js
2 - axios, axios-cookiejar-support e tough-cookie
3 - node-cron
4 - qrcode-terminal

OBS: Crie um projeto node e adicione os módulos acima

Estrutura do Projeto

project
├── services
│   └── api.js
├── utils
│   └── jiraUtils.js
├── index.js
├── jiraClient.js
└── package.json
Enter fullscreen mode Exit fullscreen mode

Código do Projeto

// api.js

const axios = require("axios");
const { wrapper } = require("axios-cookiejar-support");
const { CookieJar } = require("tough-cookie");

const cookieJar = new CookieJar();

axios.defaults.withCredentials = true;
axios.defaults.jar = cookieJar;

const instance = wrapper(
  axios.create({
    baseURL: process.env.JIRA_REST_API_URL,
  })
);

module.exports = instance;
Enter fullscreen mode Exit fullscreen mode

Os módulos axios-cookiejar-support e tough-cookie ajudam a tratar e manipualr cookies.

// jiraClient.js

const instance = require("./services/api");

const loginJira = async () => {
  try {
    const result = await instance.post("/rest/auth/1/session", {
      username: process.env.JIRA_USERNAME;,
      password: process.env.JIRA_PASSWORD,
    });
    if (result.status === 200) {
      console.log("Login realizado com sucesso");
      return true;
    }
  } catch (error) {
    console.log("Erro ao realizar o login:", error.message);
  }
  return false;
};

const getIssue = async (id) => {
  const result = await instance.get(`/rest/api/2/issue/${id}`);
  return result;
};

const jiraClient = async (id) => {
  try {
    const result = await instance.get("/rest/auth/1/session");
    if (result) {
      console.log("Sessão ativa");
      const issue = await getIssue(id);
      return issue;
    }
  } catch (error) {
    if (error.response.status === 401) {
      console.log("Não autorizado");
      const loginResult = await loginJira();
      if (loginResult) {
        return jiraClient(id);
      } else {
        throw error;
      }
    } else {
      console.log("Erro ao obter a sessão:", error);
      throw error;
    }
  }
};

module.exports = jiraClient;
Enter fullscreen mode Exit fullscreen mode
// jiraUtils.js

const jiraClient = require(".././jiraClient");

const JIRA_REMINDER_MESSAGE = "Não esquecer de logar as horas no Jira!";

const makeResponseJira = async (id) => {
  try {
    const jiraIssue = await jiraClient(id);
    return `Issue: ${jiraIssue?.data?.key}\nLabel: ${jiraIssue?.data?.fields?.labels[0]}\nAssignee: ${jiraIssue?.data?.fields?.assignee?.name}\nDescription: ${jiraIssue?.data?.fields?.description}`;
  } catch (error) {
    if (error.response.status === 404) {
      return `Issue ${id} não encontrada!`;
    }
    if (error.response.status === 401) {
      return `Verifique suas credenciais!`;
    }
  }
};

const processMsgReceived = async (msg) => {
  let response;
  if (msg.body.startsWith("DEV-")) {
    response = await makeResponseJira(msg.body);
  } else if (msg.body.startsWith("!lembrete")) {
    response = JIRA_REMINDER_MESSAGE;
  } else {
    return null;
  }
  return response;
};

module.exports = processMsgReceived;
Enter fullscreen mode Exit fullscreen mode

OBS: DEV refere-se ao padrão de nomenclatura das issues do Jira durante os testes
Exemplo de issue: DEV-100

// index.js 

const qrcode = require("qrcode-terminal");
const { Client, MessageMedia, LocalAuth } = require("whatsapp-web.js");
const cron = require("node-cron");
const processMsgReceived = require("./utils/jiraUtils");

const GROUP_ID = process.env.WPP_GROUP_ID;
const JIRA_LOGO_URL =
  "https://visuresolutions.com/wp-content/uploads/2022/07/Logo-Jira.png";
const JIRA_REMINDER_MESSAGE = "Não esquecer de logar as horas no Jira!";

const newBotClient = async () => {
  const client = new Client({ authStrategy: new LocalAuth() });
  return client;
};

const botJira = async (client) => {
  client.initialize();

  client.on("qr", (qr) => {
    qrcode.generate(qr, { small: true });
  });

  client.on("authenticated", () => {
    console.log("AUTHENTICATED");
  });

  client.on("ready", async () => {
    console.log("Client is ready!");
    cron.schedule(
      "0 17 * * *",
      async () => {
        // running a task every day 17 hrs
        const media = await MessageMedia.fromUrl(JIRA_LOGO_URL);
        let message = JIRA_REMINDER_MESSAGE;
        client.sendMessage(GROUP_ID, media, {
          caption: message,
        });
      },
      {
        scheduled: true,
        timezone: process.env.TIMEZONE || "America/Sao_Paulo",
      }
    );
    client.on("message", async (message) => {
      const processedMsg = await processMsgReceived(message);
      console.log("processedMsg MSG: ", processedMsg);
      if (processedMsg !== null) {
        const media = await MessageMedia.fromUrl(JIRA_LOGO_URL);
        const response = client.sendMessage(message.from, media, {
          caption: processedMsg,
        });

        return response;
      }
    });
  });
};

const startBot = async () => {
  try {
    const client = await newBotClient();
    botJira(client);
    console.log("Bot started!");
  } catch (error) {
    console.log("ERROR INIT BOT: ", error);
  }
};

startBot();
Enter fullscreen mode Exit fullscreen mode

Alguns pontos a serem explicados:

1 - Ao Startar o projeto, será exibido um QR Code no terminal. Você deverá ler o mesmo utilizando a conta do WhatsApp que será o bot.
2 - GROUP_ID refere-se ao grupo do WhatsApp em que o bot será adicionado para responder.
3 - cron.schedule é utilizado para disparar um lembrete todo dia às 17hrs

Link do projeto: https://github.com/mensonones/bot-jira-tutorial

Por hora é isso! Espero que seja útil e qualquer dúvida basta comentar ou entrar em contato comigo. Até a próxima :)

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay