Criando um bot para WhatsApp que se comunica com o Jira
Tags: bot, jira, node, whatsapp
Published: 2023-02-26 18:48:08


### Este projeto faz uso dos seguintes módulos node:
1 - [whatsapp-web.js](https://wwebjs.dev/)
2 - [axios](https://www.npmjs.com/package/axios), [axios-cookiejar-support](https://www.npmjs.com/package/axios-cookiejar-support?activeTab=readme) e [tough-cookie](https://www.npmjs.com/package/tough-cookie)
3 - [node-cron](https://www.npmjs.com/package/node-cron)
4 - [qrcode-terminal](https://www.npmjs.com/package/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
```
## Código do Projeto
```js
// 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;
```
Os módulos **axios-cookiejar-support** e **tough-cookie** ajudam a tratar e manipualr cookies.

```js
// 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;
```
```js
// 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;
```
**OBS**: **DEV** refere-se ao padrão de nomenclatura das **issues** do **Jira** durante os testes
Exemplo de issue: **DEV-100**
```js
// 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();
```
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 :)