Skip to content

Commit

Permalink
Merge branch 'gabrielolivrp-refactor/architecture'
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrielolivrp committed Jan 23, 2024
2 parents f43f6da + 84fad59 commit 2742259
Show file tree
Hide file tree
Showing 70 changed files with 2,994 additions and 2,620 deletions.
6 changes: 3 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
ENV=development
ENVIRONMENT=development
PORT=:8900
REDIS_ADDR=localhost:6379
REDIS_PASSWORD=
DATABASE_PATH=data.db
STORAGE_PATH=storage
DATABASE_PATH=.zapmeow/zapmeow.db
STORAGE_PATH=.zapmeow/storage
WEBHOOK_URL=http://localhost:3000/api/whatsapp/message
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ storage
.env
.env.production
main
zapmeow
.zapmeow
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ RUN ls -la
RUN go mod download

ENV CGO_ENABLED=1
RUN go build -o main .
RUN go build -o server cmd/server/main.go

EXPOSE 8900

CMD ["./main"]
CMD ["./server"]
58 changes: 29 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,58 +4,58 @@ ZapMeow is a versatile API that allows developers to interact with WhatsApp usin

### Features

- **Multi-Instance Support**: Seamlessly manage and interact with multiple WhatsApp instances concurrently.
- **Message Sending**: Send text, image, and audio messages to WhatsApp contacts and groups.
- **Phone Number Verification**: Check if phone numbers are registered on WhatsApp.
- **Contact Information**: Obtain contact information.
- **Profile Information**: Obtain profile information.
- **QR Code Generation**: Generate QR codes to initiate WhatsApp login.
- **Instance Status**: Retrieve the connection status of a specific instance of WhatsApp.
- **Multi-Instance Support**: Seamlessly manage and interact with multiple WhatsApp instances concurrently.
- **Message Sending**: Send text, image, and audio messages to WhatsApp contacts and groups.
- **Phone Number Verification**: Check if phone numbers are registered on WhatsApp.
- **Contact Information**: Obtain contact information.
- **Profile Information**: Obtain profile information.
- **QR Code Generation**: Generate QR codes to initiate WhatsApp login.
- **Instance Status**: Retrieve the connection status of a specific instance of WhatsApp.

### Getting Started

To get started with the ZapMeow API, follow these simple steps:

1. **Clone the Repository**: Clone this repository to your local machine using the following command:

```sh
git clone [email protected]:capsulbrasil/zapmeow.git
```
```sh
git clone [email protected]:capsulbrasil/zapmeow.git
```

2. **Configuration**: Set up your project configuration by copying the provided `.env.example` file and updating the environment variables.

- Navigate to the project directory:
- Navigate to the project directory:

```sh
cd zapmeow
```
```sh
cd zapmeow
```

- Create a copy of the `.env.example` file as `.env`:
- Create a copy of the `.env.example` file as `.env`:

```sh
cp .env.example .env
```
```sh
cp .env.example .env
```

- Open the `.env` file using your preferred text editor and update the necessary environment variables.
- Open the `.env` file using your preferred text editor and update the necessary environment variables.

3. **Install Dependencies**: Install the project dependencies using the following command:

```sh
go mod tidy
```
```sh
go mod tidy
```

4. **Start the API**: Run the API server by executing the following command:

```sh
go run main.go
```
```sh
./zapmeow
```

5. **Access Swagger Documentation**: You can access the Swagger documentation by visiting the following URL in your web browser:

```
http://localhost:8900/api/swagger/index.html
```
```
http://localhost:8900/api/swagger/index.html
```

The Swagger documentation provides detailed information about the available API endpoints, request parameters, and response formats.
The Swagger documentation provides detailed information about the available API endpoints, request parameters, and response formats.

Now, your ZapMeow API is up and running, ready for you to start interacting with WhatsApp instances programmatically.
66 changes: 66 additions & 0 deletions api/handler/check_phones_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package handler

import (
"net/http"
"zapmeow/api/response"
"zapmeow/api/service"
"zapmeow/pkg/whatsapp"

"github.com/gin-gonic/gin"
)

type getCheckPhonesBody struct {
Phones []string `json:"phones"`
}

type getCheckPhonesResponse struct {
Phones []whatsapp.IsOnWhatsAppResponse `json:"phones"`
}

type checkPhonesHandler struct {
whatsAppService service.WhatsAppService
}

func NewCheckPhonesHandler(
whatsAppService service.WhatsAppService,
) *checkPhonesHandler {
return &checkPhonesHandler{
whatsAppService: whatsAppService,
}
}

// Check Phones on WhatsApp
//
// @Summary Check Phones on WhatsApp
// @Description Verifies if the phone numbers in the provided list are registered WhatsApp users.
// @Tags WhatsApp Phone Verification
// @Param instanceId path string true "Instance ID"
// @Param data body getCheckPhonesBody true "Phone list"
// @Accept json
// @Produce json
// @Success 200 {object} getCheckPhonesResponse "List of verified numbers"
// @Router /{instanceId}/check/phones [post]
func (h *checkPhonesHandler) Handler(c *gin.Context) {
var body getCheckPhonesBody
if err := c.ShouldBindJSON(&body); err != nil {
response.ErrorResponse(c, http.StatusBadRequest, "Error trying to validate infos. ")
return
}

instanceID := c.Param("instanceId")
instance, err := h.whatsAppService.GetInstance(instanceID)
if err != nil {
response.ErrorResponse(c, http.StatusInternalServerError, err.Error())
return
}

phones, err := h.whatsAppService.IsOnWhatsApp(instance, body.Phones)
if err != nil {
response.ErrorResponse(c, http.StatusInternalServerError, err.Error())
return
}

response.Response(c, http.StatusOK, getCheckPhonesResponse{
Phones: phones,
})
}
69 changes: 69 additions & 0 deletions api/handler/get_contract_info_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package handler

import (
"net/http"
"zapmeow/api/helper"
"zapmeow/api/response"
"zapmeow/api/service"
"zapmeow/pkg/whatsapp"

"github.com/gin-gonic/gin"
)

type contactInfoResponse struct {
Info whatsapp.ContactInfo `json:"info"`
}

type getContactInfoHandler struct {
whatsAppService service.WhatsAppService
}

func NewGetContactInfoHandler(
whatsAppService service.WhatsAppService,
) *getContactInfoHandler {
return &getContactInfoHandler{
whatsAppService: whatsAppService,
}
}

// Get Contact Information
//
// @Summary Get Contact Information
// @Description Retrieves contact information.
// @Tags WhatsApp Contact
// @Param instanceId path string true "Instance ID"
// @Param phone query string true "Phone"
// @Accept json
// @Produce json
// @Success 200 {object} contactInfoResponse "Contact Information"
// @Router /{instanceId}/contact/info [get]
func (h *getContactInfoHandler) Handler(c *gin.Context) {
instanceID := c.Param("instanceId")
instance, err := h.whatsAppService.GetInstance(instanceID)
if err != nil {
response.ErrorResponse(c, http.StatusInternalServerError, err.Error())
return
}

if !h.whatsAppService.IsAuthenticated(instance) {
response.ErrorResponse(c, http.StatusUnauthorized, "unautenticated")
return
}

phone := c.Query("phone")
jid, ok := helper.MakeJID(phone)
if !ok {
response.ErrorResponse(c, http.StatusBadRequest, "Error trying to validate infos. ")
return
}

info, err := h.whatsAppService.GetContactInfo(instance, jid)
if err != nil || info == nil {
response.ErrorResponse(c, http.StatusInternalServerError, err.Error())
return
}

response.Response(c, http.StatusOK, contactInfoResponse{
Info: *info,
})
}
76 changes: 76 additions & 0 deletions api/handler/get_messages_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package handler

import (
"net/http"
"zapmeow/api/response"
"zapmeow/api/service"

"github.com/gin-gonic/gin"
)

type getMessagesBody struct {
Phone string `json:"phone"`
}

type getMessagesResponse struct {
Messages []response.Message `json:"messages"`
}

type getMessagesHandler struct {
whatsAppService service.WhatsAppService
messageService service.MessageService
}

func NewGetMessagesHandler(
whatsAppService service.WhatsAppService,
messageService service.MessageService,
) *getMessagesHandler {
return &getMessagesHandler{
whatsAppService: whatsAppService,
messageService: messageService,
}
}

// Get WhatsApp Chat Messages
//
// @Summary Get WhatsApp Chat Messages
// @Description Returns chat messages from the specified WhatsApp instance.
// @Tags WhatsApp Chat
// @Param instanceId path string true "Instance ID"
// @Param data body getMessagesBody true "Phone"
// @Accept json
// @Produce json
// @Success 200 {object} getMessagesResponse "List of chat messages"
// @Router /{instanceId}/chat/messages [post]
func (h *getMessagesHandler) Handler(c *gin.Context) {
instanceID := c.Param("instanceId")
instance, err := h.whatsAppService.GetInstance(instanceID)
if err != nil {
response.ErrorResponse(c, http.StatusInternalServerError, err.Error())
return
}

if !h.whatsAppService.IsAuthenticated(instance) {
response.ErrorResponse(c, http.StatusUnauthorized, "unautenticated")
return
}

var body getMessagesBody
if err := c.ShouldBindJSON(&body); err != nil {
response.ErrorResponse(c, http.StatusBadRequest, "Error trying to validate infos. ")
return
}

messages, err := h.messageService.GetChatMessages(
instanceID,
body.Phone,
)
if err != nil {
response.ErrorResponse(c, http.StatusInternalServerError, err.Error())
return
}

response.Response(c, http.StatusOK, getMessagesResponse{
Messages: response.NewMessagesResponse(messages),
})
}
67 changes: 67 additions & 0 deletions api/handler/get_profile_info_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package handler

import (
"net/http"
"zapmeow/api/helper"
"zapmeow/api/response"
"zapmeow/api/service"
"zapmeow/pkg/whatsapp"

"github.com/gin-gonic/gin"
)

type getProfileInfoResponse struct {
Info whatsapp.ContactInfo `json:"info"`
}

type getProfileInfoHandler struct {
whatsAppService service.WhatsAppService
}

func NewGetProfileInfoHandler(
whatsAppService service.WhatsAppService,
) *getProfileInfoHandler {
return &getProfileInfoHandler{
whatsAppService: whatsAppService,
}
}

// Get Profile Information
//
// @Summary Get Profile Information
// @Description Retrieves profile information.
// @Tags WhatsApp Profile
// @Param instanceId path string true "Instance ID"
// @Accept json
// @Produce json
// @Success 200 {object} getProfileInfoResponse "Profile Information"
// @Router /{instanceId}/profile [get]
func (h *getProfileInfoHandler) Handler(c *gin.Context) {
instanceID := c.Param("instanceId")
instance, err := h.whatsAppService.GetInstance(instanceID)
if err != nil {
response.ErrorResponse(c, http.StatusInternalServerError, err.Error())
return
}

if !h.whatsAppService.IsAuthenticated(instance) {
response.ErrorResponse(c, http.StatusUnauthorized, "unautenticated")
return
}

jid, ok := helper.MakeJID(instance.Client.Store.ID.User)
if !ok {
response.ErrorResponse(c, http.StatusBadRequest, "Error trying to validate infos. ")
return
}

info, err := h.whatsAppService.GetContactInfo(instance, jid)
if err != nil || info == nil {
response.ErrorResponse(c, http.StatusInternalServerError, err.Error())
return
}

response.Response(c, http.StatusOK, getProfileInfoResponse{
Info: *info,
})
}
Loading

0 comments on commit 2742259

Please sign in to comment.