Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mail-ru-im/bot-golang
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1.4.0
Choose a base ref
...
head repository: mail-ru-im/bot-golang
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
  • 12 commits
  • 14 files changed
  • 7 contributors

Commits on Apr 4, 2022

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    49e41cb View commit details

Commits on Apr 5, 2022

  1. Add response body logging when debug enabled

    s.kust committed Apr 5, 2022
    Copy the full SHA
    8d75085 View commit details
  2. Merge pull request #27 from BUSH1997/add-request-id

    Add request_id in request query params
    DmitryDorofeev authored Apr 5, 2022
    Copy the full SHA
    fea9ed7 View commit details

Commits on Apr 25, 2023

  1. added new method sendDeeplinkMessage

    Kirill Panasenkov committed Apr 25, 2023
    Copy the full SHA
    c7141a6 View commit details

Commits on Apr 26, 2023

  1. changed go version.

    Kirill Panasenkov committed Apr 26, 2023
    Copy the full SHA
    17f1e9e View commit details
  2. one more lint version update.

    Kirill Panasenkov committed Apr 26, 2023
    Copy the full SHA
    25342d0 View commit details
  3. Merge pull request #32 from KirillPanasenkov/send_text_with_deeplink

    added new method sendDeeplinkMessage
    ToxaSemenov authored Apr 26, 2023
    Copy the full SHA
    ca7c8ea View commit details

Commits on Apr 8, 2024

  1. Create go.yml

    AidarAzizov authored Apr 8, 2024
    Copy the full SHA
    4b0ef1c View commit details
  2. [refactoring] tests + contrib

    AidarAzizov committed Apr 8, 2024
    Copy the full SHA
    3fa4a04 View commit details

Commits on Apr 9, 2024

  1. Merge pull request #34 from AidarAzizov/repo_refactoring

    [add] contrib + tests
    AidarAzizov authored Apr 9, 2024
    Copy the full SHA
    e33706e View commit details
  2. Bump gopkg.in/yaml.v3 from 3.0.0-20210107192922-496545a6307b to 3.0.0

    Bumps gopkg.in/yaml.v3 from 3.0.0-20210107192922-496545a6307b to 3.0.0.
    
    ---
    updated-dependencies:
    - dependency-name: gopkg.in/yaml.v3
      dependency-type: indirect
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Apr 9, 2024
    Copy the full SHA
    644c729 View commit details
  3. Merge pull request #35 from mail-ru-im/dependabot/go_modules/gopkg.in…

    …/yaml.v3-3.0.0
    
    Bump gopkg.in/yaml.v3 from 3.0.0-20210107192922-496545a6307b to 3.0.0
    AidarAzizov authored Apr 9, 2024
    Copy the full SHA
    4d4de6b View commit details
Showing with 272 additions and 73 deletions.
  1. +0 −20 .circleci/config.yml
  2. +35 −0 .github/workflows/go.yml
  3. +23 −0 CONTRIBUTING.md
  4. +17 −25 README.md
  5. +40 −0 api_mock.go
  6. +23 −0 bot.go
  7. +60 −8 client.go
  8. +25 −1 client_test.go
  9. +13 −7 go.mod
  10. +13 −12 go.sum
  11. BIN logo_bot.png
  12. BIN logo_msg.png
  13. +9 −0 message.go
  14. +14 −0 message_easyjson.go
20 changes: 0 additions & 20 deletions .circleci/config.yml

This file was deleted.

35 changes: 35 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go

name: Go

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

jobs:


build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21'

- name: Lint
run: make lint

- name: Test
run: make test

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
files: cover.out
23 changes: 23 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Contribute
## Pull request
Если вы решили впервые стать контрибьютером и помочь развитию open-source проекта, этот пункт для вас.
1) Делается fork основного репозитория
2) git clone https://github.com/ваш-логин/bot-golang.git
3) Локальное изменение
4) Сделайте ребейз на remote master ветку
5) git push origin <ваш-логин>
6) В удаленном репозитории нажать _compare&pull request_

Также рекомендуем ознакомиться с подробной инструкцией для контрибьютеров - <a href="https://github.com/firstcontributions/first-contributions">README.md</a>

## Tests
1) Если добавляется новая функциональность, то покрывайте ее тестами
2) Следите за тем, чтобы тесты успешно выполнялись в PR перед мержем.

## Merge
Ветка будет смержена в мастер, когда:
1) Все пайплайны пройдут успешно
2) Новая функциональность будет покрыта тестами

После выполнения всех пунктов один из сотрудников проверит в ближайшее время PR и смержит его.

42 changes: 17 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
<img src="https://github.com/mail-ru-im/bot-python/blob/master/logo.png" width="100" height="100">
<img src="logo_bot.png" width="100" height="100">

# Golang interface for Mail.ru Instant Messengers bot API
![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)
[![CircleCI](https://circleci.com/gh/mail-ru-im/bot-golang.svg?style=svg)](https://circleci.com/gh/mail-ru-im/bot-golang)
# VK Teams Bot API for Golang
[![Go](https://github.com/mail-ru-im/bot-golang/actions/workflows/go.yml/badge.svg)](https://github.com/mail-ru-im/bot-golang/actions/workflows/go.yml)
[![codecov](https://codecov.io/github/mail-ru-im/bot-golang/graph/badge.svg?token=0HX8DY24SR)](https://codecov.io/github/mail-ru-im/bot-golang)
[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/mail-ru-im/bot-golang)
![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)

- *Brand new Bot API!*

- *Zero-configuration library*

- *Simple and clear interface*
### [<img src="logo_msg.png" width="16"> VK Teams API Specification](https://teams.vk.com/botapi/)

## API specification:
### [<img src="https://icq.com/cached/img/landing/icon_and_192.png" width="15"> ICQ New ](https://icq.com/botapi/)
### [<img src="https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/e8/4f/1b/e84f1b57-206f-7750-ac5a-27f93ff4a0d8/icons-bundle.png/460x0w.png" width="16"> Myteam ](https://myteam.mail.ru/botapi/)
## Getting started

### [<img src="https://agent.mail.ru/img/agent2014/common/2x/button_logo.png" width="16"> Agent Mail.ru](https://agent.mail.ru/botapi/)
* Create your own bot by sending the _/newbot_ command to _Metabot_ and follow the instructions.
>Note: a bot can only reply after the user has added it to his contact list, or if the user was the first to start a dialogue.
* You can configure the domain that hosts your VK Teams server. When instantiating the Bot class, add the address of your domain.
* An example of how to use the framework can be seen in _example/main.go_

## Install
```bash
@@ -24,8 +22,7 @@ go get github.com/mail-ru-im/bot-golang

## Usage

Create your own bot by sending the /newbot command to Metabot and follow the instructions.

Create your own bot by sending the /newbot command to _Metabot_ and follow the instructions.
Note a bot can only reply after the user has added it to his contacts list, or if the user was the first to start a dialogue.

### Create your bot
@@ -41,7 +38,7 @@ func main() {
log.Println("wrong token")
}

message := bot.NewTextMessage("awesomechat@agent.chat", "text")
message := bot.NewTextMessage("some@mail.com", "text")
message.Send()
}
```
@@ -51,18 +48,13 @@ func main() {
You can create, edit and reply to messages like a piece of cake.

```go
message := bot.NewTextMessage("awesomechat@agent.chat", "text")
message := bot.NewTextMessage("some@mail.com", "text")
message.Send()

fmt.Println(message.MsgID)

message.Text = "new text"

message.Edit()
// AWESOME!

message.Reply("hey, what did you write before???")
// SO HOT!
message.Reply("I changed my text")
```

### Subscribe events
@@ -73,7 +65,7 @@ Get all updates from the channel. Use context for cancellation.
ctx, finish := context.WithCancel(context.Background())
updates := bot.GetUpdatesChannel(ctx)
for update := range updates {
// your awesome logic here
// your logic here
}
```

@@ -83,7 +75,7 @@ You don't need this.
But if you do, you can override bot's API URL:

```go
bot := botgolang.NewBot(BOT_TOKEN, botgolang.BotApiURL("https://agent.mail.ru/bot/v1"))
bot := botgolang.NewBot(BOT_TOKEN, botgolang.BotApiURL("https://vkteams.com/bot/v1"))
```
And debug all api requests and responses:

40 changes: 40 additions & 0 deletions api_mock.go
Original file line number Diff line number Diff line change
@@ -258,6 +258,43 @@ func (h *MockHandler) GetEvents(w http.ResponseWriter) {
}
}

func (h *MockHandler) SelfGet(w http.ResponseWriter, r *http.Request) {

encoder := json.NewEncoder(w)

if r.FormValue("chatId") == "" {
err := encoder.Encode(&Response{
OK: false,
Description: "Missing required parameter 'chatId'",
})

if err != nil {
h.logger.WithFields(logrus.Fields{
"err": err,
}).Error("cannot encode json")
}
}

chats_getInfo := `{
"about": "about user",
"firstName": "User",
"language": "en",
"lastName": "Userov",
"photo": [
{
"url": "https://rapi.myteaminternal/avatar/get?targetSn=test@test&size=1024"
}
],
"type": "private",
"ok": true
}`

_, err := w.Write([]byte(chats_getInfo))
if err != nil {
h.logger.Fatal("failed to write events")
}
}

func (h *MockHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch {
case r.FormValue("token") == "":
@@ -269,6 +306,9 @@ func (h *MockHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
case r.URL.Path == "/events/get":
h.GetEvents(w)
return
case r.URL.Path == "/self/get":
h.SelfGet(w, r)
return
default:
encoder := json.NewEncoder(w)
err := encoder.Encode(&Response{
23 changes: 23 additions & 0 deletions bot.go
Original file line number Diff line number Diff line change
@@ -124,6 +124,17 @@ func (b *Bot) NewTextMessage(chatID, text string) *Message {
}
}

// NewTextMessageWithRequestID returns new text message with client requestID
func (b *Bot) NewTextMessageWithRequestID(chatID, text, requestID string) *Message {
return &Message{
client: b.client,
Chat: Chat{ID: chatID},
Text: text,
ContentType: Text,
RequestID: requestID,
}
}

// NewInlineKeyboardMessage returns new text message with inline keyboard
func (b *Bot) NewInlineKeyboardMessage(chatID, text string, keyboard Keyboard) *Message {
return &Message{
@@ -135,6 +146,18 @@ func (b *Bot) NewInlineKeyboardMessage(chatID, text string, keyboard Keyboard) *
}
}

// NewDeeplinkMessage returns new text message with inline keyboard and deeplink
func (b *Bot) NewDeeplinkMessage(chatID, text string, keyboard Keyboard, deeplink string) *Message {
return &Message{
client: b.client,
Chat: Chat{ID: chatID},
Text: text,
ContentType: Deeplink,
InlineKeyboard: &keyboard,
Deeplink: deeplink,
}
}

// NewFileMessage returns new file message
func (b *Bot) NewFileMessage(chatID string, file *os.File) *Message {
return &Message{
68 changes: 60 additions & 8 deletions client.go
Original file line number Diff line number Diff line change
@@ -6,7 +6,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
@@ -60,7 +59,7 @@ func (c *Client) DoWithContext(ctx context.Context, path string, params url.Valu
}

req.Header.Set("Content-Type", multipartWriter.FormDataContentType())
req.Body = ioutil.NopCloser(buffer)
req.Body = io.NopCloser(buffer)
req.Method = http.MethodPost
}

@@ -84,17 +83,23 @@ func (c *Client) DoWithContext(ctx context.Context, path string, params url.Valu
}
}()

responseBody, err := ioutil.ReadAll(resp.Body)
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
c.logger.WithFields(logrus.Fields{
"err": err,
}).Error("cannot read body")
return []byte{}, fmt.Errorf("cannot read body: %s", err)
}

c.logger.WithFields(logrus.Fields{
"response": string(responseBody),
}).Debug("got response from API")
if c.logger.IsLevelEnabled(logrus.DebugLevel) {
c.logger.WithFields(logrus.Fields{
"response": responseBody,
}).Debug("got response from API")
}

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("error status from API: %s", resp.Status)
}

response := &Response{}

@@ -347,8 +352,9 @@ func (c *Client) GetVoiceInfo(fileID string) (*File, error) {

func (c *Client) SendTextMessage(message *Message) error {
params := url.Values{
"chatId": {message.Chat.ID},
"text": {message.Text},
"chatId": {message.Chat.ID},
"text": {message.Text},
"request-id": {message.RequestID},
}

if message.ReplyMsgID != "" {
@@ -385,6 +391,52 @@ func (c *Client) SendTextMessage(message *Message) error {
return nil
}

func (c *Client) SendTextWithDeeplinkMessage(message *Message) error {
params := url.Values{
"chatId": {message.Chat.ID},
"text": {message.Text},
"request-id": {message.RequestID},
}

if message.ReplyMsgID != "" {
params.Set("replyMsgId", message.ReplyMsgID)
}

if message.ForwardMsgID != "" {
params.Set("forwardMsgId", message.ForwardMsgID)
params.Set("forwardChatId", message.ForwardChatID)
}

if message.InlineKeyboard != nil {
data, err := json.Marshal(message.InlineKeyboard.GetKeyboard())
if err != nil {
return fmt.Errorf("cannot marshal inline keyboard markup: %s", err)
}

params.Set("inlineKeyboardMarkup", string(data))
}

if len(message.Deeplink) == 0 {
return fmt.Errorf("deeplink can't be empty for SendTextWithDeeplink")
}
params.Set("deeplink", message.Deeplink)

if message.ParseMode != "" {
params.Set("parseMode", string(message.ParseMode))
}

response, err := c.Do("/messages/sendTextWithDeeplink", params, nil)
if err != nil {
return fmt.Errorf("error while sending text: %s", err)
}

if err := json.Unmarshal(response, message); err != nil {
return fmt.Errorf("cannot unmarshal response from API: %s", err)
}

return nil
}

func (c *Client) EditMessage(message *Message) error {
params := url.Values{
"msgId": {message.ID},
Loading