DEV Community

Edson Costa for Devs Norte

Posted on

Desenvolvendo um Bot do Telegram em Golang para Buscar Eventos da Comunidade Devs Norte no Sympla

Este รฉ um guia de como cria um bot para Telegram capaz de buscar e exibir eventos da Comunidade Devs Norte atravรฉs da plataforma Sympla. Vamos mergulhar no processo de desenvolvimento passo a passo.

Prรฉ-requisitos

Antes de comeรงarmos, assegure-se de ter o Go instalado em seu sistema. Alรฉm disso, serรก necessรกrio ter uma no Telegram.

Passo 1: Configuraรงรฃo do Ambiente

Crie um novo diretรณrio para o seu projeto

Cria e entrar na pasta

inicialize um mรณdulo Go usando o seguinte comando:

go mod init nome-do-seu-projeto
Enter fullscreen mode Exit fullscreen mode

Certifique-se de ter as dependรชncias necessรกrias instaladas:

go get github.com/joho/godotenv
Enter fullscreen mode Exit fullscreen mode
go get github.com/mymmrac/telego

Enter fullscreen mode Exit fullscreen mode

Passo 2: Configuraรงรฃo do Token

Agora, vocรช precisa obter um token de autenticaรงรฃo do bot do Telegram para interagir com a API do Telegram. Siga estas etapas para obter o token:

  1. Acesse o BotFather no Telegram.
  2. Siga as instruรงรตes para criar um novo bot. Envie o comando /newbot e siga as instruรงรตes para fornecer um nome e um username para o seu bot.
  3. Apรณs concluir o processo de criaรงรฃo do bot, o BotFather irรก fornecer um token de acesso para o seu bot.
  4. Agora, crie um arquivo chamado .env no mesmo diretรณrio do seu cรณdigo e adicione o token como uma variรกvel de ambiente.
TELEGRAM_BOT_TOKEN=seu_token_aqui
Enter fullscreen mode Exit fullscreen mode

Substitua seu_token_aqui pelo token fornecido pelo BotFather.

Passo 3: Escrevendo o Cรณdigo

  1. Crie um arquivo main.go e coloque nele:
  2. Importaรงรตes das bibliotecas necessรกrias.
  3. Definiรงรฃo das estruturas de dados necessรกrias para lidar com a resposta da API do Sympla.
  4. Implementaรงรฃo da funรงรฃo NewBot para criar uma nova instรขncia do bot do Telegram.
  5. Implementaรงรฃo do mรฉtodo Start para iniciar o bot.
  6. Implementaรงรฃo dos mรฉtodos para registrar os comandos do bot e lidar com eventos relacionados a eventos disponรญveis e encerrados.
  7. Implementaรงรฃo da funรงรฃo fetchSymplaEvents para fazer requisiรงรตes ร  API do Sympla e obter eventos futuros ou passados.
  8. Implementaรงรฃo da funรงรฃo intArrayToString para converter uma lista de inteiros em uma string.
  9. Implementaรงรฃo da funรงรฃo formatEventsMessage para formatar a 9ensagem a ser enviada ao usuรกrio com base nos eventos encontrados.
  10. Funรงรฃo main que carrega as variรกveis de ambiente, cria uma instรขncia do bot e inicia sua execuรงรฃo.

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "strings"

    "github.com/joho/godotenv"
    "github.com/mymmrac/telego"
    th "github.com/mymmrac/telego/telegohandler"
    tu "github.com/mymmrac/telego/telegoutil"
)
Enter fullscreen mode Exit fullscreen mode

package main: Define que este arquivo faz parte do pacote principal do programa.
Importaรงรตes: Importamos as bibliotecas necessรกrias para o funcionamento do bot, incluindo godotenv para lidar com variรกveis de ambiente, telego para interagir com a API do Telegram e telegohandler e telegoutil para lidar com os eventos e mensagens do Telegram.

type Bot struct {
    bot   *telego.Bot
    bh    *th.BotHandler
    token string
}
Enter fullscreen mode Exit fullscreen mode

Bot: Definimos uma estrutura Bot que contรฉm o bot do Telegram, o manipulador de bot e o token de autenticaรงรฃo.

type SymplaResponse struct {
    Data []Event `json:"data"`
}
Enter fullscreen mode Exit fullscreen mode

SymplaResponse: Define uma estrutura para armazenar a resposta da API do Sympla.

type Location struct {
    Country      string  `json:"country"`
    Address      string  `json:"address"`
    AddressAlt   string  `json:"address_alt"`
    City         string  `json:"city"`
    AddressNum   string  `json:"address_num"`
    Name         string  `json:"name"`
    Longitude    float64 `json:"lon"`
    State        string  `json:"state"`
    Neighborhood string  `json:"neighborhood"`
    ZipCode      string  `json:"zip_code"`
    Latitude     float64 `json:"lat"`
}
Enter fullscreen mode Exit fullscreen mode

Location: Define uma estrutura para armazenar informaรงรตes sobre a localizaรงรฃo de um evento.

type Images struct {
    Original string `json:"original"`
    XS       string `json:"xs"`
    LG       string `json:"lg"`
}
Enter fullscreen mode Exit fullscreen mode

Images: Define uma estrutura para armazenar URLs de imagens relacionadas a um evento.

type StartDateFormats struct {
    Pt string `json:"pt"`
    En string `json:"en"`
    Es string `json:"es"`
}
type EndDateFormats struct {
    Pt string `json:"pt"`
    En string `json:"en"`
    Es string `json:"es"`
}
Enter fullscreen mode Exit fullscreen mode

StartDateFormats e EndDateFormats: Definem estruturas para armazenar formatos de data de inรญcio e fim de um evento.

type Event struct {
    Name             string           `json:"name"`
    Images           Images           `json:"images"`
    Location         Location         `json:"location"`
    StartDateFormats StartDateFormats `json:"start_date_formats"`
    EndDateFormats   EndDateFormats   `json:"end_date_formats"`
    URL              string           `json:"url"`
}
Enter fullscreen mode Exit fullscreen mode

Event: Define uma estrutura para representar um evento, incluindo seu nome, imagens, localizaรงรฃo, datas e URL.

func NewBot(token string) (*Bot, error) {
    bot, err := telego.NewBot(token, telego.WithDefaultDebugLogger())
    if err != nil {
        return nil, err
    }

    updates, err := bot.UpdatesViaLongPolling(nil)
    if err != nil {
        return nil, err
    }

    bh, err := th.NewBotHandler(bot, updates)
    if err != nil {
        return nil, err
    }

    return &Bot{
        bot:   bot,
        bh:    bh,
        token: token,
    }, nil
}
Enter fullscreen mode Exit fullscreen mode

NewBot: Esta funรงรฃo cria uma nova instรขncia do bot do Telegram, configura os manipuladores de atualizaรงรฃo e retorna uma estrutura Bot inicializada.

func (b *Bot) Start() {
    defer b.bh.Stop()
    defer b.bot.StopLongPolling()

    b.registerCommands()

    b.bh.Start()
}
Enter fullscreen mode Exit fullscreen mode

Start: Mรฉtodo que inicia o bot. Ele registra os comandos e inicia o manipulador de bot para receber atualizaรงรตes do Telegram.

func (b *Bot) registerCommands() {
    b.registerBotCommand()
    b.registerEventCommands()
}
Enter fullscreen mode Exit fullscreen mode

registerCommands: Mรฉtodo que registra todos os comandos disponรญveis do bot.

func (b *Bot) registerBotCommand() {
    b.bh.Handle(func(bot *telego.Bot, update telego.Update) {
        infoMessage := `
๐Ÿ‘‹ Bem-vindo ao Bot da Comunidade Devs Norte! ๐Ÿš€

Este bot estรก aqui para ajudรก-lo a encontrar os eventos mais recentes e emocionantes hospedados no Sympla pela nossa comunidade.

Para consultar os eventos disponรญveis, basta digitar /disponiveis. E se estiver interessado nos eventos que jรก passaram, digite /encerrados.

Fique ร  vontade para explorar e participar dos eventos que mais lhe interessarem!๐Ÿ˜Š
`

        _, _ = bot.SendMessage(tu.Message(
            tu.ID(update.Message.Chat.ID),
            infoMessage,
        ))
    }, th.CommandEqual("start"))
}
Enter fullscreen mode Exit fullscreen mode

registerBotCommand: Mรฉtodo que registra o comando /start, que envia uma mensagem de boas-vindas ao usuรกrio quando o bot รฉ iniciado.

func (b *Bot) registerEventCommands() {
    b.registerAvailableEventsCommand()
    b.registerClosedEventsCommand()
}
Enter fullscreen mode Exit fullscreen mode

registerEventCommands: Mรฉtodo que registra os comandos relacionados aos eventos disponรญveis e encerrados.

func (b *Bot) registerAvailableEventsCommand() {
    b.bh.Handle(func(bot *telego.Bot, update telego.Update) {
        events, err := fetchSymplaEvents("future")
        if err != nil {
            fmt.Println("Erro ao buscar eventos:", err)
            return
        }
        message := formatEventsMessage(events)
        _, _ = bot.SendMessage(tu.Message(
            tu.ID(update.Message.Chat.ID),
            message,
        ))
    }, th.CommandEqual("disponรญveis"))
}
Enter fullscreen mode Exit fullscreen mode

registerAvailableEventsCommand: Mรฉtodo que registra o comando /disponiveis, que busca e exibe eventos futuros.

func (b *Bot) registerClosedEventsCommand() {
    b.bh.Handle(func(bot *telego.Bot, update telego.Update) {
        events, err := fetchSymplaEvents("past")
        if err != nil {
            fmt.Println("Erro ao buscar eventos:", err)
            return
        }
        message := formatEventsMessage(events)
        _, _ = bot.SendMessage(tu.Message(
            tu.ID(update.Message.Chat.ID),
            message,
        ))
    }, th.CommandEqual("encerrados"))
}
Enter fullscreen mode Exit fullscreen mode

registerClosedEventsCommand: Mรฉtodo que registra o comando /encerrados, que busca e exibe eventos passados.

func fetchSymplaEvents(eventType string) ([]Event, error) {
    // Define os IDs dos organizadores
    organizerIDs := []int{3125215, 5478152}

    // Define o serviรงo a ser chamado na API do Sympla com base no tipo de evento
    service := "/v4/search"
    if eventType == "past" {
        service = "/v4/events/past"
    }

    // Monta o corpo da requisiรงรฃo
    requestBody := fmt.Sprintf(`{
        "service": "%s",
        "params": {
            "only": "name,images,location,start_date_formats,end_date_formats,url",
            "organizer_id": %s,
            "sort": "date",
            "order_by": "desc",
            "limit": "6",
            "page": 1
        },
        "ignoreLocation": true
    }`, service, intArrayToString(organizerIDs))

    // Faz a requisiรงรฃo HTTP para a API do Sympla
    resp, err := http.Post("https://www.sympla.com.br/api/v1/search", "application/json", strings.NewReader(requestBody))
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    // Lรช a resposta da requisiรงรฃo
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    // Decodifica a resposta JSON em uma estrutura SymplaResponse
    var symplaResp SymplaResponse
    if err := json.NewDecoder(bytes.NewReader(body)).Decode(&symplaResp); err != nil {
        return nil, err
    }

    // Retorna os eventos encontrados na resposta
    return symplaResp.Data, nil
}
Enter fullscreen mode Exit fullscreen mode

fetchSymplaEvents: Esta funรงรฃo faz uma requisiรงรฃo para a API do Sympla para buscar eventos, com base no tipo de evento (futuro ou passado), e retorna uma lista de eventos encontrados.

func intArrayToString(arr []int) string {
    strArr := make([]string, len(arr))
    for i, num := range arr {
        strArr[i] = fmt.Sprint(num)
    }
    return "[" + strings. Join(strArr, ",") + "]"
}
Enter fullscreen mode Exit fullscreen mode

intArrayToString: Esta funรงรฃo converte uma lista de inteiros em uma string formatada para ser usada na construรงรฃo do corpo da requisiรงรฃo para a API do Sympla.

func formatEventsMessage(events []Event) string {
    message := "#BOT Devs Norte ๐Ÿค–\n\n\n"
    if events == nil || len(events) == 0 {
        message += "Ops... Nem um evento disponivel no momento, mas nรฃo fique triste logo estaremos fazendo mais eventos! ๐Ÿฅบ\n\n\n"
    } else {
        message += "๐ŸŽ‰ Eventos: ๐ŸŽ‰\n\n\n"
        for _, event := range events {
            message += fmt.Sprintf("- %s\n  Local: %s\n  Data: %s\n  URL: %s\n \n\n\n", event. Name, event.Location.City, event.StartDateFormats.Pt, event.URL)
            message += "----------------------------------------\n\n\n"
        }
    }
    return message
}
}
Enter fullscreen mode Exit fullscreen mode

formatEventsMessage: Esta funรงรฃo formata uma mensagem a ser enviada ao usuรกrio com base nos eventos encontrados.

func main() {
    // Carrega as variรกveis de ambiente do arquivo .env
    if err := godotenv.Load(); err != nil {
        fmt.Println("Erro ao carregar o arquivo .env:", err)
        os.Exit(1)
    }

    // Obtรฉm o token do bot do Telegram das variรกveis de ambiente
    token := os.Getenv("TELEGRAM_BOT_TOKEN")
    if token == "" {
        fmt.Println("Token do bot do Telegram nรฃo fornecido")
        os.Exit(1)
    }

    // Cria uma nova instรขncia do bot e inicia sua execuรงรฃo
    bot, err := NewBot(token)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    bot.Start()
}
Enter fullscreen mode Exit fullscreen mode

main: A funรงรฃo main รฉ o ponto de entrada do programa. Ela carrega as variรกveis de ambiente do arquivo .env, obtรฉm o token do bot do Telegram, cria uma instรขncia do bot e inicia sua execuรงรฃo.

Passo 5: Executar o Cรณdigo

No diretรณrio do projeto.
execute o cรณdigo Go:

go run main. Go
Enter fullscreen mode Exit fullscreen mode

Isso iniciarรก o bot do Telegram. Agora vocรช pode acessar o bot no Telegram e interagir com ele usando os comandos /start, /disponiveis e /encerrados.

Bot no Telegram

Vocรช pode encontrar o cรณdigo completo do projeto no repositรณrio GitHub aqui.

Espero que essa explicaรงรฃo detalhada ajude a entender como o cรณdigo funciona e como cada parte contribui para o funcionamento do bot do Telegram. Se tiver mais alguma dรบvida ou precisar de mais alguma explicaรงรฃo, estou ร  disposiรงรฃo!

Top comments (3)

Collapse
 
suamirochadev profile image
Suami Rocha Devs Norte

Adoreii! Ficou incrivel, parabรฉns Edson!! ๐Ÿ™๐Ÿ‘๐Ÿ‘๐Ÿ‘

Collapse
 
ecsistem profile image
Edson Costa Devs Norte

Muito obrigado!

Collapse
 
julinux profile image
Julio Saraiva

The best!