Skip to content

Commit 38ef3ec

Browse files
authored
feat: add send location (#43)
* feat: add send location * feat: update frontend * feat: update docs * feat: update docs * fix: logout remove file * fix: remove gitignore * fix: send video * feat: add context in validation
1 parent f4bd4a4 commit 38ef3ec

File tree

16 files changed

+424
-80
lines changed

16 files changed

+424
-80
lines changed

docs/openapi.yaml

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
openapi: 3.0.0
22
info:
33
title: WhatsApp API MultiDevice
4-
version: 3.0.0
4+
version: 3.1.0
55
description: This API is used for sending whatsapp via API
66
servers:
77
- url: http://localhost:3000
@@ -566,6 +566,49 @@ paths:
566566
application/json:
567567
schema:
568568
$ref: '#/components/schemas/ErrorInternalServer'
569+
/send/location:
570+
post:
571+
operationId: sendLocation
572+
tags:
573+
- message
574+
summary: Send Location
575+
requestBody:
576+
content:
577+
multipart/form-data:
578+
schema:
579+
type: object
580+
properties:
581+
phone:
582+
type: integer
583+
example: '6289685024051@s.whatsapp.net'
584+
description: Phone number with country code
585+
latitude:
586+
type: string
587+
example: "-7.797068"
588+
description: Latitude coordinate
589+
longitude:
590+
type: string
591+
example: '110.370529'
592+
description: Longitude coordinate
593+
responses:
594+
'200':
595+
description: OK
596+
content:
597+
application/json:
598+
schema:
599+
$ref: '#/components/schemas/SendResponse'
600+
'400':
601+
description: Bad Request
602+
content:
603+
application/json:
604+
schema:
605+
$ref: '#/components/schemas/ErrorBadRequest'
606+
'500':
607+
description: Internal Server Error
608+
content:
609+
application/json:
610+
schema:
611+
$ref: '#/components/schemas/ErrorInternalServer'
569612
/message/:message_id/revoke:
570613
post:
571614
operationId: revokeMessage

readme.md

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ API using [openapi-generator](https://openapi-generator.tech/#try)
107107
|| Send Video | POST | /send/video |
108108
|| Send Contact | POST | /send/contact |
109109
|| Send Link | POST | /send/link |
110-
|| Revoke Messave | POST | /message/:message_id/revoke |
110+
|| Send Location | POST | /send/location |
111+
|| Revoke Message | POST | /message/:message_id/revoke |
111112

112113
```
113114
✅ = Available
@@ -116,20 +117,21 @@ API using [openapi-generator](https://openapi-generator.tech/#try)
116117

117118
### App User Interface
118119

119-
1. Homepage ![Homepage](https://i.ibb.co/NNX2wWY/home.png)
120+
1. Homepage ![Homepage](https://i.ibb.co/GMNWqRq/homepage.png)
120121
2. Login ![Login](https://i.ibb.co/jkcB15R/login.png)
121-
3. Send Message ![Send Message](https://i.ibb.co/DrCVXS7/send-message.png)
122-
4. Send Image ![Send Image](https://i.ibb.co/WykfQc8/send-image.png)
123-
5. Send File ![Send File](https://i.ibb.co/wC4SfRp/send-file.png)
124-
6. Send Video ![Send Video](https://i.ibb.co/VDCRH3G/send-video.png)
122+
3. Send Message ![Send Message](https://i.ibb.co/rc3NXMX/send-message.png)
123+
4. Send Image ![Send Image](https://i.ibb.co/BcFL3SD/send-image.png)
124+
5. Send File ![Send File](https://i.ibb.co/f4yxjpp/send-file.png)
125+
6. Send Video ![Send Video](https://i.ibb.co/PrD3P51/send-video.png)
125126
7. Send Contact ![Send Contact](https://i.ibb.co/4810H7N/send-contact.png)
126-
8. Revoke Message ![Revoke Message](https://i.ibb.co/yswhvQY/revoke.png?)
127-
9. User Info ![User Info](https://i.ibb.co/3zjX6Cz/user-info.png)
128-
10. User Avatar ![User Avatar](https://i.ibb.co/cysjmjT/user-avatar.png?)
129-
11. My Privacy ![My Privacy](https://i.ibb.co/Cw1sMQz/my-privacy.png)
130-
12. My Group ![My Group](https://i.ibb.co/B6rW8Sh/list-group.png)
131-
13. Auto Reply ![Auto Reply](https://i.ibb.co/D4rTytX/IMG-20220517-162500.jpg)
132-
14. Basic Auth Prompt ![Basic Auth](https://i.ibb.co/PDjQ92W/Screenshot-2022-11-06-at-14-06-29.png)
127+
8. Send Location ![Send Location](https://i.ibb.co/TWsy09G/send-location.png)
128+
9. Revoke Message ![Revoke Message](https://i.ibb.co/yswhvQY/revoke.png?)
129+
10. User Info ![User Info](https://i.ibb.co/3zjX6Cz/user-info.png)
130+
11. User Avatar ![User Avatar](https://i.ibb.co/cysjmjT/user-avatar.png?)
131+
12. My Privacy ![My Privacy](https://i.ibb.co/Cw1sMQz/my-privacy.png)
132+
13. My Group ![My Group](https://i.ibb.co/B6rW8Sh/list-group.png)
133+
14. Auto Reply ![Auto Reply](https://i.ibb.co/D4rTytX/IMG-20220517-162500.jpg)
134+
15. Basic Auth Prompt ![Basic Auth](https://i.ibb.co/PDjQ92W/Screenshot-2022-11-06-at-14-06-29.png)
133135

134136
### Mac OS NOTE
135137

src/config/settings.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
)
77

88
var (
9-
AppVersion = "v4.2.0"
9+
AppVersion = "v4.3.0"
1010
AppPort = "3000"
1111
AppDebug = false
1212
AppOs = fmt.Sprintf("AldinoKemal")

src/domains/send/location.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package send
2+
3+
type LocationRequest struct {
4+
Phone string `json:"phone" form:"phone"`
5+
Latitude string `json:"latitude" form:"latitude"`
6+
Longitude string `json:"longitude" form:"longitude"`
7+
}
8+
9+
type LocationResponse struct {
10+
MessageID string `json:"message_id"`
11+
Status string `json:"status"`
12+
}

src/domains/send/send.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type ISendService interface {
1111
SendVideo(ctx context.Context, request VideoRequest) (response VideoResponse, err error)
1212
SendContact(ctx context.Context, request ContactRequest) (response ContactResponse, err error)
1313
SendLink(ctx context.Context, request LinkRequest) (response LinkResponse, err error)
14+
SendLocation(ctx context.Context, request LocationRequest) (response LocationResponse, err error)
1415
Revoke(ctx context.Context, request RevokeRequest) (response RevokeResponse, err error)
1516
UpdateMessage(ctx context.Context, request UpdateMessageRequest) (response UpdateMessageResponse, err error)
1617
}

src/internal/rest/send.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ func InitRestSend(app *fiber.App, service domainSend.ISendService) Send {
1919
app.Post("/send/video", rest.SendVideo)
2020
app.Post("/send/contact", rest.SendContact)
2121
app.Post("/send/link", rest.SendLink)
22+
app.Post("/send/location", rest.SendLocation)
2223
app.Post("/message/:message_id/revoke", rest.RevokeMessage)
2324
app.Post("/message/:message_id/update", rest.UpdateMessage)
2425
return rest
@@ -140,6 +141,23 @@ func (controller *Send) SendLink(c *fiber.Ctx) error {
140141
})
141142
}
142143

144+
func (controller *Send) SendLocation(c *fiber.Ctx) error {
145+
var request domainSend.LocationRequest
146+
err := c.BodyParser(&request)
147+
utils.PanicIfNeeded(err)
148+
149+
whatsapp.SanitizePhone(&request.Phone)
150+
151+
response, err := controller.Service.SendLocation(c.UserContext(), request)
152+
utils.PanicIfNeeded(err)
153+
154+
return c.JSON(utils.ResponseData{
155+
Status: 200,
156+
Message: response.Status,
157+
Results: response,
158+
})
159+
}
160+
143161
func (controller *Send) RevokeMessage(c *fiber.Ctx) error {
144162
var request domainSend.RevokeRequest
145163
err := c.BodyParser(&request)

src/pkg/utils/general.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"fmt"
55
"os"
66
"path/filepath"
7+
"strconv"
8+
"strings"
79
"time"
810
)
911

@@ -46,3 +48,11 @@ func PanicIfNeeded(err any, message ...string) {
4648
}
4749
}
4850
}
51+
52+
func StrToFloat64(text string) float64 {
53+
var result float64
54+
if text != "" {
55+
result, _ = strconv.ParseFloat(strings.TrimSpace(text), 64)
56+
}
57+
return result
58+
}

src/pkg/whatsapp/whatsapp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ func handler(rawEvt interface{}) {
240240
}
241241
case *events.HistorySync:
242242
id := atomic.AddInt32(&historySyncID, 1)
243-
fileName := fmt.Sprintf("%s/history-%d-%d.json", config.PathStorages, startupTime, id)
243+
fileName := fmt.Sprintf("%s/history-%d-%s-%d-%s.json", config.PathStorages, startupTime, cli.Store.ID.String(), id, evt.Data.SyncType.String())
244244
file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0600)
245245
if err != nil {
246246
log.Errorf("Failed to open file to write history sync: %v", err)

src/services/app.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"go.mau.fi/whatsmeow/store/sqlstore"
1313
"os"
1414
"path/filepath"
15+
"strings"
1516
"time"
1617
)
1718

@@ -86,7 +87,7 @@ func (service serviceApp) Login(_ context.Context) (response domainApp.LoginResp
8687

8788
func (service serviceApp) Logout(_ context.Context) (err error) {
8889
// delete history
89-
files, err := filepath.Glob("./history-*")
90+
files, err := filepath.Glob(fmt.Sprintf("./%s/history-*", config.PathStorages))
9091
if err != nil {
9192
return err
9293
}
@@ -98,7 +99,7 @@ func (service serviceApp) Logout(_ context.Context) (err error) {
9899
}
99100
}
100101
// delete qr images
101-
qrImages, err := filepath.Glob("./statics/images/qrcode/scan-*")
102+
qrImages, err := filepath.Glob(fmt.Sprintf("./%s/scan-*", config.PathQrCode))
102103
if err != nil {
103104
return err
104105
}
@@ -110,6 +111,21 @@ func (service serviceApp) Logout(_ context.Context) (err error) {
110111
}
111112
}
112113

114+
// delete senditems
115+
qrItems, err := filepath.Glob(fmt.Sprintf("./%s/*", config.PathSendItems))
116+
if err != nil {
117+
return err
118+
}
119+
120+
for _, f := range qrItems {
121+
if !strings.Contains(f, ".gitignore") {
122+
err = os.Remove(f)
123+
if err != nil {
124+
return err
125+
}
126+
}
127+
}
128+
113129
err = service.WaCli.Logout()
114130
return
115131
}

src/services/send.go

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func NewSendService(waCli *whatsmeow.Client) domainSend.ISendService {
3232
}
3333

3434
func (service serviceSend) SendText(ctx context.Context, request domainSend.MessageRequest) (response domainSend.MessageResponse, err error) {
35-
err = validations.ValidateSendMessage(request)
35+
err = validations.ValidateSendMessage(ctx, request)
3636
if err != nil {
3737
return response, err
3838
}
@@ -54,7 +54,7 @@ func (service serviceSend) SendText(ctx context.Context, request domainSend.Mess
5454
}
5555

5656
func (service serviceSend) SendImage(ctx context.Context, request domainSend.ImageRequest) (response domainSend.ImageResponse, err error) {
57-
err = validations.ValidateSendImage(request)
57+
err = validations.ValidateSendImage(ctx, request)
5858
if err != nil {
5959
return response, err
6060
}
@@ -152,7 +152,7 @@ func (service serviceSend) SendImage(ctx context.Context, request domainSend.Ima
152152
}
153153

154154
func (service serviceSend) SendFile(ctx context.Context, request domainSend.FileRequest) (response domainSend.FileResponse, err error) {
155-
err = validations.ValidateSendFile(request)
155+
err = validations.ValidateSendFile(ctx, request)
156156
if err != nil {
157157
return response, err
158158
}
@@ -207,7 +207,7 @@ func (service serviceSend) SendFile(ctx context.Context, request domainSend.File
207207
}
208208

209209
func (service serviceSend) SendVideo(ctx context.Context, request domainSend.VideoRequest) (response domainSend.VideoResponse, err error) {
210-
err = validations.ValidateSendVideo(request)
210+
err = validations.ValidateSendVideo(ctx, request)
211211
if err != nil {
212212
return response, err
213213
}
@@ -286,20 +286,23 @@ func (service serviceSend) SendVideo(ctx context.Context, request domainSend.Vid
286286

287287
msgId := whatsmeow.GenerateMessageID()
288288
msg := &waProto.Message{VideoMessage: &waProto.VideoMessage{
289-
Url: proto.String(uploaded.URL),
290-
Mimetype: proto.String(http.DetectContentType(dataWaVideo)),
291-
Caption: proto.String(request.Caption),
292-
FileLength: proto.Uint64(uploaded.FileLength),
293-
FileSha256: uploaded.FileSHA256,
294-
FileEncSha256: uploaded.FileEncSHA256,
295-
MediaKey: uploaded.MediaKey,
296-
DirectPath: proto.String(uploaded.DirectPath),
297-
ViewOnce: proto.Bool(request.ViewOnce),
298-
JpegThumbnail: dataWaThumbnail,
289+
Url: proto.String(uploaded.URL),
290+
Mimetype: proto.String(http.DetectContentType(dataWaVideo)),
291+
Caption: proto.String(request.Caption),
292+
FileLength: proto.Uint64(uploaded.FileLength),
293+
FileSha256: uploaded.FileSHA256,
294+
FileEncSha256: uploaded.FileEncSHA256,
295+
MediaKey: uploaded.MediaKey,
296+
DirectPath: proto.String(uploaded.DirectPath),
297+
ViewOnce: proto.Bool(request.ViewOnce),
298+
JpegThumbnail: dataWaThumbnail,
299+
ThumbnailEncSha256: dataWaThumbnail,
300+
ThumbnailSha256: dataWaThumbnail,
301+
ThumbnailDirectPath: proto.String(uploaded.DirectPath),
299302
}}
300303
ts, err := service.WaCli.SendMessage(ctx, dataWaRecipient, msgId, msg)
301304
go func() {
302-
errDelete := utils.RemoveFile(0, deletedItems...)
305+
errDelete := utils.RemoveFile(1, deletedItems...)
303306
if errDelete != nil {
304307
fmt.Println(errDelete)
305308
}
@@ -314,7 +317,7 @@ func (service serviceSend) SendVideo(ctx context.Context, request domainSend.Vid
314317
}
315318

316319
func (service serviceSend) SendContact(ctx context.Context, request domainSend.ContactRequest) (response domainSend.ContactResponse, err error) {
317-
err = validations.ValidateSendContact(request)
320+
err = validations.ValidateSendContact(ctx, request)
318321
if err != nil {
319322
return response, err
320323
}
@@ -341,7 +344,7 @@ func (service serviceSend) SendContact(ctx context.Context, request domainSend.C
341344
}
342345

343346
func (service serviceSend) SendLink(ctx context.Context, request domainSend.LinkRequest) (response domainSend.LinkResponse, err error) {
344-
err = validations.ValidateSendLink(request)
347+
err = validations.ValidateSendLink(ctx, request)
345348
if err != nil {
346349
return response, err
347350
}
@@ -372,8 +375,38 @@ func (service serviceSend) SendLink(ctx context.Context, request domainSend.Link
372375
return response, nil
373376
}
374377

375-
func (service serviceSend) Revoke(_ context.Context, request domainSend.RevokeRequest) (response domainSend.RevokeResponse, err error) {
376-
err = validations.ValidateRevokeMessage(request)
378+
func (service serviceSend) SendLocation(ctx context.Context, request domainSend.LocationRequest) (response domainSend.LocationResponse, err error) {
379+
err = validations.ValidateSendLocation(ctx, request)
380+
if err != nil {
381+
return response, err
382+
}
383+
dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone)
384+
if err != nil {
385+
return response, err
386+
}
387+
388+
// Compose WhatsApp Proto
389+
msgId := whatsmeow.GenerateMessageID()
390+
msg := &waProto.Message{
391+
LocationMessage: &waProto.LocationMessage{
392+
DegreesLatitude: proto.Float64(utils.StrToFloat64(request.Latitude)),
393+
DegreesLongitude: proto.Float64(utils.StrToFloat64(request.Longitude)),
394+
},
395+
}
396+
397+
// Send WhatsApp Message Proto
398+
ts, err := service.WaCli.SendMessage(ctx, dataWaRecipient, msgId, msg)
399+
if err != nil {
400+
return response, err
401+
}
402+
403+
response.MessageID = msgId
404+
response.Status = fmt.Sprintf("Send location success %s (server timestamp: %s)", request.Phone, ts)
405+
return response, nil
406+
}
407+
408+
func (service serviceSend) Revoke(ctx context.Context, request domainSend.RevokeRequest) (response domainSend.RevokeResponse, err error) {
409+
err = validations.ValidateRevokeMessage(ctx, request)
377410
if err != nil {
378411
return response, err
379412
}
@@ -394,7 +427,7 @@ func (service serviceSend) Revoke(_ context.Context, request domainSend.RevokeRe
394427
}
395428

396429
func (service serviceSend) UpdateMessage(ctx context.Context, request domainSend.UpdateMessageRequest) (response domainSend.UpdateMessageResponse, err error) {
397-
err = validations.ValidateUpdateMessage(request)
430+
err = validations.ValidateUpdateMessage(ctx, request)
398431
if err != nil {
399432
return response, err
400433
}

0 commit comments

Comments
 (0)