Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion docs/wiki/guias-api/api-groups.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Documentação completa dos endpoints para gerenciar grupos WhatsApp.

- [Listar Grupos](#listar-grupos)
- [Informações do Grupo](#informações-do-grupo)
- [Informações via Link de Convite](#informações-via-link-de-convite)
- [Link de Convite](#link-de-convite)
- [Criar Grupo](#criar-grupo)
- [Gerenciar Participantes](#gerenciar-participantes)
Expand Down Expand Up @@ -141,11 +142,57 @@ curl -X POST http://localhost:4000/group/info \
"groupJid": "120363XXXXXXXXXX@g.us"
}'
```
---

## Informações via Link de Convite

Obtém informações de um grupo através de um link de convite sem precisar entrar nele.

**Endpoint**: `POST /group/invite-info`

**Body**:
```json
{
"code": "https://chat.whatsapp.com/ABCDEFGHIJKLMNOP"
}
```

**Parâmetros**:

| Campo | Tipo | Obrigatório | Descrição |
|-------|------|-------------|-----------|
| `code` | string | ✅ Sim | Código do link ou URL completa |

**Resposta de Sucesso (200)**:
```json
{
"message": "success",
"data": {
"JID": "120363XXXXXXXXXX@g.us",
"OwnerJID": "5511999999999@s.whatsapp.net",
"GroupName": {
"Name": "Nome do Grupo",
"NameSetAt": "2025-01-15T10:30:00Z",
"NameSetBy": "5511999999999@s.whatsapp.net"
},
"GroupCreated": "2025-01-15T10:00:00Z"
}
}
```

**Exemplo cURL**:
```bash
curl -X POST http://localhost:4000/group/invite-info \
-H "Content-Type: application/json" \
-H "apikey: SUA-CHAVE-API" \
-d '{
"code": "https://chat.whatsapp.com/ABCDEFGHIJKLMNOP"
}'
```

---

## Link de Convite

Obtém ou regenera o link de convite do grupo.

**Endpoint**: `POST /group/invitelink`
Expand Down
42 changes: 42 additions & 0 deletions pkg/group/handler/group_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type GroupHandler interface {
ListGroups(ctx *gin.Context)
GetGroupInfo(ctx *gin.Context)
GetGroupInviteLink(ctx *gin.Context)
GetGroupInfoFromInviteLink(ctx *gin.Context)
SetGroupPhoto(ctx *gin.Context)
SetGroupName(ctx *gin.Context)
SetGroupDescription(ctx *gin.Context)
Expand Down Expand Up @@ -135,6 +136,47 @@ func (g *groupHandler) GetGroupInviteLink(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{"message": "success", "data": resp})
}

// Get group info from invite link
// @Summary Get group info from invite link
// @Description Get group info from invite link
// @Tags Group
// @Accept json
// @Produce json
// @Param message body group_service.GetGroupInfoFromInviteLinkStruct true "Group Invite Data"
// @Success 200 {object} gin.H "success"
// @Failure 400 {object} gin.H "Error on validation"
// @Failure 500 {object} gin.H "Internal server error"
// @Router /group/invite-info [post]
func (g *groupHandler) GetGroupInfoFromInviteLink(ctx *gin.Context) {
getInstance := ctx.MustGet("instance")

instance, ok := getInstance.(*instance_model.Instance)
if !ok {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "instance not found"})
return
}

var data group_service.GetGroupInfoFromInviteLinkStruct
err := ctx.ShouldBindBodyWithJSON(&data)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

if data.Code == "" {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "code is required"})
return
}

resp, err := g.groupService.GetGroupInfoFromInviteLink(&data, instance)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}

ctx.JSON(http.StatusOK, gin.H{"message": "success", "data": resp})
}

// Set group photo
// @Summary Set group photo
// @Description Set group photo
Expand Down
40 changes: 39 additions & 1 deletion pkg/group/service/group_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"

Expand All @@ -23,6 +24,7 @@ type GroupService interface {
ListGroups(instance *instance_model.Instance) ([]*types.GroupInfo, error)
GetGroupInfo(data *GetGroupInfoStruct, instance *instance_model.Instance) (*types.GroupInfo, error)
GetGroupInviteLink(data *GetGroupInviteLinkStruct, instance *instance_model.Instance) (string, error)
GetGroupInfoFromInviteLink(data *GetGroupInfoFromInviteLinkStruct, instance *instance_model.Instance) (*types.GroupInfo, error)
SetGroupPhoto(data *SetGroupPhotoStruct, instance *instance_model.Instance) (string, error)
SetGroupName(data *SetGroupNameStruct, instance *instance_model.Instance) error
SetGroupDescription(data *SetGroupDescriptionStruct, instance *instance_model.Instance) error
Expand Down Expand Up @@ -60,6 +62,10 @@ type GetGroupInviteLinkStruct struct {
Reset bool `json:"reset"`
}

type GetGroupInfoFromInviteLinkStruct struct {
Code string `json:"code"`
}

type SetGroupPhotoStruct struct {
GroupJID string `json:"groupJid"`
Image string `json:"image"`
Expand Down Expand Up @@ -222,6 +228,37 @@ func (g *groupService) GetGroupInviteLink(data *GetGroupInviteLinkStruct, instan
return resp, nil
}

func extractInviteCode(code string) string {
code = strings.TrimSpace(code)
if strings.Contains(code, "chat.whatsapp.com/") {
u, err := url.Parse(code)
if err == nil {
pathParts := strings.Split(strings.Trim(u.Path, "/"), "/")
if len(pathParts) > 0 {
return pathParts[len(pathParts)-1]
}
}
}
return code
}

func (g *groupService) GetGroupInfoFromInviteLink(data *GetGroupInfoFromInviteLinkStruct, instance *instance_model.Instance) (*types.GroupInfo, error) {
client, err := g.ensureClientConnected(instance.Id)
if err != nil {
return nil, err
}

code := extractInviteCode(data.Code)

resp, err := client.GetGroupInfoFromLink(context.Background(), code)
if err != nil {
g.loggerWrapper.GetLogger(instance.Id).LogError("[%s] error getting group info from link: %v", instance.Id, err)
return nil, err
}

return resp, nil
}

func (g *groupService) SetGroupPhoto(data *SetGroupPhotoStruct, instance *instance_model.Instance) (string, error) {
client, err := g.ensureClientConnected(instance.Id)
if err != nil {
Expand Down Expand Up @@ -443,7 +480,8 @@ func (g *groupService) JoinGroupLink(data *JoinGroupStruct, instance *instance_m
return err
}

_, err = client.JoinGroupWithLink(context.Background(), data.Code)
code := extractInviteCode(data.Code)
_, err = client.JoinGroupWithLink(context.Background(), code)
if err != nil {
g.loggerWrapper.GetLogger(instance.Id).LogError("[%s] error create group: %v", instance.Id, err)
return err
Expand Down
1 change: 1 addition & 0 deletions pkg/routes/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ func (r *Routes) AssignRoutes(eng *gin.Engine) {
routes.GET("/list", r.groupHandler.ListGroups)
routes.POST("/info", r.jidValidationMiddleware.ValidateNumberField(), r.groupHandler.GetGroupInfo)
routes.POST("/invitelink", r.jidValidationMiddleware.ValidateNumberField(), r.groupHandler.GetGroupInviteLink)
routes.POST("/invite-info", r.groupHandler.GetGroupInfoFromInviteLink)
routes.POST("/photo", r.jidValidationMiddleware.ValidateNumberField(), r.groupHandler.SetGroupPhoto)
routes.POST("/name", r.jidValidationMiddleware.ValidateNumberField(), r.groupHandler.SetGroupName)
routes.POST("/description", r.jidValidationMiddleware.ValidateNumberField(), r.groupHandler.SetGroupDescription)
Expand Down