From 1d063e83692ecbb2397588706b6cd21da063f6eb Mon Sep 17 00:00:00 2001 From: Abdul Rahman Date: Tue, 27 Aug 2024 19:12:36 +0500 Subject: [PATCH] update-ver --- .github/workflows/build-docker-image.yaml | 12 +- .github/workflows/release-linux.yml | 4 +- .github/workflows/release-mac.yml | 2 +- .github/workflows/release-windows.yml | 2 +- .gitignore | 3 +- docker/golang.Dockerfile | 6 +- docs/openapi.yaml | 169 +++++++++++++++--- readme.md | 75 ++++---- src/cmd/root.go | 12 +- src/config/settings.go | 20 +-- src/domains/app/app.go | 1 + src/domains/group/group.go | 12 +- src/go.mod | 36 ++-- src/go.sum | 90 ++++------ src/internal/rest/app.go | 15 ++ src/internal/rest/group.go | 68 ++++++- src/pkg/error/app_error.go | 2 +- src/pkg/utils/general.go | 13 ++ src/pkg/whatsapp/whatsapp.go | 28 +-- src/services/app.go | 23 +++ src/services/group.go | 6 +- src/services/send.go | 48 +++-- src/validations/app_validation.go | 21 +++ src/validations/app_validation_test.go | 61 +++++++ src/views/components/AppLogin.js | 7 +- src/views/components/AppLoginWithCode.js | 109 +++++++++++ src/views/components/AppReconnect.js | 3 +- ...icipants.js => GroupManageParticipants.js} | 69 ++++--- src/views/index.html | 8 +- 29 files changed, 704 insertions(+), 221 deletions(-) create mode 100644 src/validations/app_validation.go create mode 100644 src/validations/app_validation_test.go create mode 100644 src/views/components/AppLoginWithCode.js rename src/views/components/{GroupAddParticipants.js => GroupManageParticipants.js} (65%) diff --git a/.github/workflows/build-docker-image.yaml b/.github/workflows/build-docker-image.yaml index 38a4290..1d30ee2 100644 --- a/.github/workflows/build-docker-image.yaml +++ b/.github/workflows/build-docker-image.yaml @@ -63,13 +63,13 @@ jobs: password: ${{ secrets.REGISTRY_PASSWORD }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Create Latest Manifest - run: | - docker buildx imagetools create -t ${{ secrets.REGISTRY_USERNAME }}/go-whatsapp-web-multidevice:latest \ - ${{ secrets.REGISTRY_USERNAME }}/go-whatsapp-web-multidevice:latest-amd \ - ${{ secrets.REGISTRY_USERNAME }}/go-whatsapp-web-multidevice:latest-arm - name: Create Versioned Manifest (${{ github.ref_name }}) run: | docker buildx imagetools create -t ${{ secrets.REGISTRY_USERNAME }}/go-whatsapp-web-multidevice:${{ github.ref_name }} \ ${{ secrets.REGISTRY_USERNAME }}/go-whatsapp-web-multidevice:${{ github.ref_name }}-amd \ - ${{ secrets.REGISTRY_USERNAME }}/go-whatsapp-web-multidevice:${{ github.ref_name }}-arm \ No newline at end of file + ${{ secrets.REGISTRY_USERNAME }}/go-whatsapp-web-multidevice:${{ github.ref_name }}-arm + - name: Create Latest Manifest + run: | + docker buildx imagetools create -t ${{ secrets.REGISTRY_USERNAME }}/go-whatsapp-web-multidevice:latest \ + ${{ secrets.REGISTRY_USERNAME }}/go-whatsapp-web-multidevice:latest-amd \ + ${{ secrets.REGISTRY_USERNAME }}/go-whatsapp-web-multidevice:latest-arm \ No newline at end of file diff --git a/.github/workflows/release-linux.yml b/.github/workflows/release-linux.yml index 2cb61e4..4b6d0ae 100644 --- a/.github/workflows/release-linux.yml +++ b/.github/workflows/release-linux.yml @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Golang Installation - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: '1.21' - name: Golang build @@ -36,7 +36,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Golang Installation - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: '1.21' - name: Golang build diff --git a/.github/workflows/release-mac.yml b/.github/workflows/release-mac.yml index a30489f..9735f06 100644 --- a/.github/workflows/release-mac.yml +++ b/.github/workflows/release-mac.yml @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Golang Installation - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: '1.21' - name: Golang build diff --git a/.github/workflows/release-windows.yml b/.github/workflows/release-windows.yml index 12e738e..bf04e4f 100644 --- a/.github/workflows/release-windows.yml +++ b/.github/workflows/release-windows.yml @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Golang Installation - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: '1.21' - name: Golang build diff --git a/.gitignore b/.gitignore index 7677f1d..5c7040f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,4 @@ main main.exe *.jpe src/pkged.go -storages -.env \ No newline at end of file +storages \ No newline at end of file diff --git a/docker/golang.Dockerfile b/docker/golang.Dockerfile index 2b10469..ea9c7af 100644 --- a/docker/golang.Dockerfile +++ b/docker/golang.Dockerfile @@ -1,7 +1,7 @@ ############################ # STEP 1 build executable binary ############################ -FROM golang:1.21.5-alpine3.19 AS builder +FROM golang:1.22.5-alpine3.20 AS builder RUN apk update && apk add --no-cache gcc musl-dev gcompat WORKDIR /whatsapp COPY ./src . @@ -14,12 +14,10 @@ RUN go build -o /app/whatsapp ############################# ## STEP 2 build a smaller image ############################# -FROM alpine:3.19 +FROM alpine:3.20 RUN apk update && apk add --no-cache ffmpeg WORKDIR /app # Copy compiled from builder. COPY --from=builder /app/whatsapp /app/whatsapp -# Copy the .env file -COPY .env ./.env # Run the binary. ENTRYPOINT ["/app/whatsapp"] \ No newline at end of file diff --git a/docs/openapi.yaml b/docs/openapi.yaml index e958ac1..27ce576 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: WhatsApp API MultiDevice - version: 4.0.0 + version: 4.2.0 description: This API is used for sending whatsapp via API servers: - url: http://localhost:3000 @@ -36,6 +36,32 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorInternalServer' + /app/login-with-code: + get: + operationId: appLoginWithCode + tags: + - app + summary: Login with pairing code + parameters: + - name: phone + in: query + schema: + type: string + example: '628912344551' + description: Your phone number + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/LoginWithCodeResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInternalServer' /app/logout: get: operationId: appLogout @@ -838,30 +864,104 @@ paths: content: application/json: schema: - type: object - properties: - group_id: - type: string - example: '120363228882361111' - participants: - type: array - items: - type: string - example: - - '6819241294719274' - - '6829241294719274' - - '6839241294719274' - example: - - '6819241294719274' - - '6829241294719274' - - '6839241294719274' + $ref: '#/components/schemas/ManageParticipantRequest' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/ManageParticipantResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBadRequest' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInternalServer' + /group/participants/remove: + post: + operationId: removeParticipantFromGroup + tags: + - group + summary: Remove participants from group + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ManageParticipantRequest' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/ManageParticipantResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBadRequest' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInternalServer' + /group/participants/promote: + post: + operationId: promoteParticipantToAdmin + tags: + - group + summary: Promote participants to admin + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ManageParticipantRequest' responses: '200': description: OK content: application/json: schema: - $ref: '#/components/schemas/AddParticipantToGroupResponse' + $ref: '#/components/schemas/ManageParticipantResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBadRequest' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInternalServer' + /group/participants/demote: + post: + operationId: demoteParticipantToMember + tags: + - group + summary: Demote participants to member + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ManageParticipantRequest' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/ManageParticipantResponse' '400': description: Bad Request content: @@ -960,7 +1060,21 @@ components: group_id: type: string example: 1203632782168851111@g.us - AddParticipantToGroupResponse: + ManageParticipantRequest: + type: object + properties: + group_id: + type: string + example: 1203632782168851111@g.us + participants: + type: array + items: + type: string + example: + - '6819241294719274' + - '6829241294719274' + - '6839241294719274' + ManageParticipantResponse: type: object properties: code: @@ -1153,6 +1267,21 @@ components: device: type: string example: '628960561XXX.0:64@s.whatsapp.net' + LoginWithCodeResponse: + type: object + properties: + code: + type: string + example: SUCCESS + message: + type: string + example: Success + results: + type: object + properties: + pair_code: + type: string + example: ABCD-1234 LoginResponse: type: object properties: diff --git a/readme.md b/readme.md index 5ebebc2..e336fbc 100644 --- a/readme.md +++ b/readme.md @@ -33,7 +33,6 @@ Now that we support ARM64 for Linux: - Webhook for received message - `--webhook="http://yourwebhook.site/handler"`, or you can simplify - `-w="http://yourwebhook.site/handler"` - - *Note: Webhook can also be set via environment variable `WhatsappWebhook`* - For more command `./main --help` ### Required (without docker) @@ -99,21 +98,22 @@ You can fork or edit this source code ! to [SwaggerEditor](https://editor.swagger.io). - Furthermore you can generate HTTP Client from this API using [openapi-generator](https://openapi-generator.tech/#try) -| Feature | Menu | Method | URL | +| Feature | Menu | Method | URL | |---------|------------------------------|--------|-------------------------------| -| ✅ | Login | GET | /app/login | -| ✅ | Logout | GET | /app/logout | -| ✅ | Reconnect | GET | /app/reconnect | -| ✅ | Devices | GET | /app/devices | +| ✅ | Login with Scan QR | GET | /app/login | +| ✅ | Login With Pair Code | GET | /app/login-with-code | +| ✅ | Logout | GET | /app/logout | +| ✅ | Reconnect | GET | /app/reconnect | +| ✅ | Devices | GET | /app/devices | | ✅ | User Info | GET | /user/info | | ✅ | User Avatar | GET | /user/avatar | | ✅ | User My Group List | GET | /user/my/groups | | ✅ | User My Privacy Setting | GET | /user/my/privacy | | ✅ | Send Message | POST | /send/message | -| ✅ | Send Image | POST | /send/image | -| ✅ | Send Audio | POST | /send/audio | -| ✅ | Send File | POST | /send/file | -| ✅ | Send Video | POST | /send/video | +| ✅ | Send Image | POST | /send/image | +| ✅ | Send Audio | POST | /send/audio | +| ✅ | Send File | POST | /send/file | +| ✅ | Send Video | POST | /send/video | | ✅ | Send Contact | POST | /send/contact | | ✅ | Send Link | POST | /send/link | | ✅ | Send Location | POST | /send/location | @@ -122,41 +122,46 @@ You can fork or edit this source code ! | ✅ | React Message | POST | /message/:message_id/reaction | | ✅ | Delete Message | POST | /message/:message_id/delete | | ✅ | Edit Message | POST | /message/:message_id/update | +| ❌ | Star message | POST | /message/:message_id/star | | ✅ | Join Group With Link | POST | /group/join-with-link | | ✅ | Leave Group | POST | /group/leave | | ✅ | Create Group | POST | /group | | ✅ | Add Participants in Group | POST | /group/participants | -| ❌ | Remove Participant in Group | DELETE | /group/participants | -| ❌ | Promote Participant in Group | POST | /group/participants/promote | -| ❌ | Demote Participant in Group | POST | /group/participants/demote | +| ✅ | Remove Participant in Group | POST | /group/participants/remove | +| ✅ | Promote Participant in Group | POST | /group/participants/promote | +| ✅ | Demote Participant in Group | POST | /group/participants/demote | ``` ✅ = Available ❌ = Not Available Yet ``` -### App User Interface - -1. Homepage ![Homepage](https://i.ibb.co.com/681JTHK/image.png) -2. Login ![Login](https://i.ibb.co.com/jkcB15R/login.png?v=1) -3. Send Message ![Send Message](https://i.ibb.co.com/rc3NXMX/send-message.png?v1) -4. Send Image ![Send Image](https://i.ibb.co.com/BcFL3SD/send-image.png?v1) -5. Send File ![Send File](https://i.ibb.co.com/f4yxjpp/send-file.png) -6. Send Video ![Send Video](https://i.ibb.co.com/PrD3P51/send-video.png) -7. Send Contact ![Send Contact](https://i.ibb.co.com/4810H7N/send-contact.png) -8. Send Location ![Send Location](https://i.ibb.co.com/TWsy09G/send-location.png) -9. Send Audio ![Send Location](https://i.ibb.co.com/p1wL4wh/Send-Audio.png) -10. Send Poll ![Send Poll](https://i.ibb.co.com/mq2fGHz/send-poll.png) -11. Revoke Message ![Revoke Message](https://i.ibb.co.com/yswhvQY/revoke.png?v1) -12. Delete Message ![Delete Message](https://i.ibb.co.com/F70SZ84/image.png) -13. Reaction Message ![Revoke Message](https://i.ibb.co.com/BfHgSHG/react-message.png) -14. Edit Message ![Edit Message](https://i.ibb.co.com/kXfpqJw/update-message.png) -15. User Info ![User Info](https://i.ibb.co.com/3zjX6Cz/user-info.png?v=1) -16. User Avatar ![User Avatar](https://i.ibb.co.com/ZmJZ4ZW/search-avatar.png?v=1) -17. My Privacy ![My Privacy](https://i.ibb.co.com/Cw1sMQz/my-privacy.png) -18. My Group ![My Group](https://i.ibb.co.com/WB268Xy/list-group.png) -19. Auto Reply ![Auto Reply](https://i.ibb.co.com/D4rTytX/IMG-20220517-162500.jpg) -20. Basic Auth Prompt ![Basic Auth](https://i.ibb.co.com/PDjQ92W/Screenshot-2022-11-06-at-14-06-29.png) +### User Interface + +| Description | Image | +|--------------------|------------------------------------------------------------------------------------------| +| Homepage | ![Homepage](https://i.ibb.co.com/L0B1LVb/homepage-v4-16.png) | +| Login | ![Login](https://i.ibb.co.com/jkcB15R/login.png?v=1) | +| Login With Code | ![Login With Code](https://i.ibb.co.com/rdJGvGw/paircode.png) | +| Send Message | ![Send Message](https://i.ibb.co.com/rc3NXMX/send-message.png?v1) | +| Send Image | ![Send Image](https://i.ibb.co.com/BcFL3SD/send-image.png?v1) | +| Send File | ![Send File](https://i.ibb.co.com/f4yxjpp/send-file.png) | +| Send Video | ![Send Video](https://i.ibb.co.com/PrD3P51/send-video.png) | +| Send Contact | ![Send Contact](https://i.ibb.co.com/4810H7N/send-contact.png) | +| Send Location | ![Send Location](https://i.ibb.co.com/TWsy09G/send-location.png) | +| Send Audio | ![Send Audio](https://i.ibb.co.com/p1wL4wh/Send-Audio.png) | +| Send Poll | ![Send Poll](https://i.ibb.co.com/mq2fGHz/send-poll.png) | +| Revoke Message | ![Revoke Message](https://i.ibb.co.com/yswhvQY/revoke.png?v1) | +| Delete Message | ![Delete Message](https://i.ibb.co.com/F70SZ84/image.png) | +| Reaction Message | ![Reaction Message](https://i.ibb.co.com/BfHgSHG/react-message.png) | +| Edit Message | ![Edit Message](https://i.ibb.co.com/kXfpqJw/update-message.png) | +| User Info | ![User Info](https://i.ibb.co.com/3zjX6Cz/user-info.png?v=1) | +| User Avatar | ![User Avatar](https://i.ibb.co.com/ZmJZ4ZW/search-avatar.png?v=1) | +| My Privacy | ![My Privacy](https://i.ibb.co.com/Cw1sMQz/my-privacy.png) | +| My Group | ![My Group](https://i.ibb.co.com/WB268Xy/list-group.png) | +| Auto Reply | ![Auto Reply](https://i.ibb.co.com/D4rTytX/IMG-20220517-162500.jpg) | +| Basic Auth Prompt | ![Basic Auth Prompt](https://i.ibb.co.com/PDjQ92W/Screenshot-2022-11-06-at-14-06-29.png) | +| Manage Participant | ![Manage Participant](https://i.ibb.co.com/ynrN7cr/manage-participant.png) | ### Mac OS NOTE diff --git a/src/cmd/root.go b/src/cmd/root.go index 1fcc79b..575d16e 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -13,6 +13,8 @@ import ( "github.com/aldinokemal/go-whatsapp-web-multidevice/services" "github.com/dustin/go-humanize" "github.com/gofiber/fiber/v2" + // terminal: "go get github.com/joho/godotenv" + "github.com/joho/godotenv" "github.com/gofiber/fiber/v2/middleware/basicauth" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/filesystem" @@ -34,7 +36,7 @@ var ( // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Short: "Send free whatsapp API", - Long: `This application is from clone https://github.com/aldinokemal/go-whatsapp-web-multidevice, + Long: `This application is from clone https://github.com/aldinokemal/go-whatsapp-web-multidevice, you can send whatsapp over http api but your whatsapp account have to be multi device version`, Run: runRest, } @@ -47,6 +49,14 @@ func init() { rootCmd.PersistentFlags().StringVarP(&config.AppBasicAuthCredential, "basic-auth", "b", config.AppBasicAuthCredential, "basic auth credential | -b=yourUsername:yourPassword") rootCmd.PersistentFlags().StringVarP(&config.WhatsappAutoReplyMessage, "autoreply", "", config.WhatsappAutoReplyMessage, `auto reply when received message --autoreply | example: --autoreply="Don't reply this message"`) rootCmd.PersistentFlags().StringVarP(&config.WhatsappWebhook, "webhook", "w", config.WhatsappWebhook, `forward event to webhook --webhook | example: --webhook="https://yourcallback.com/callback"`) + + if config.WhatsappWebhook == "" { + err := godotenv.Load() + if err != nil { + log.Printf("Warning: .env file not loaded. %v", err) + } + config.WhatsappWebhook = os.Getenv("WhatsappWebhook") + } } func runRest(_ *cobra.Command, _ []string) { diff --git a/src/config/settings.go b/src/config/settings.go index 14b7494..136cbe4 100644 --- a/src/config/settings.go +++ b/src/config/settings.go @@ -1,18 +1,15 @@ package config import ( - "log" - "os" - "github.com/joho/godotenv" - waProto "go.mau.fi/whatsmeow/binary/proto" + "go.mau.fi/whatsmeow/proto/waCompanionReg" ) var ( - AppVersion = "v4.14.0" + AppVersion = "v4.16.0" AppPort = "3000" AppDebug = false AppOs = "AldinoKemal" - AppPlatform = waProto.DeviceProps_PlatformType(1) + AppPlatform = waCompanionReg.DeviceProps_PlatformType(1) AppBasicAuthCredential string PathQrCode = "statics/qrcode" @@ -30,14 +27,3 @@ var ( WhatsappTypeUser = "@s.whatsapp.net" WhatsappTypeGroup = "@g.us" ) - -func init() { - err := godotenv.Load() - if err != nil { - log.Printf("Warning: .env file not loaded. %v", err) - } - WhatsappWebhook = os.Getenv("WhatsappWebhook") - if WhatsappWebhook == "" { - log.Printf("Warning: WhatsappWebhook environment variable is not set") - } -} diff --git a/src/domains/app/app.go b/src/domains/app/app.go index 8c00e8f..dbe3bb3 100644 --- a/src/domains/app/app.go +++ b/src/domains/app/app.go @@ -7,6 +7,7 @@ import ( type IAppService interface { Login(ctx context.Context) (response LoginResponse, err error) + LoginWithCode(ctx context.Context, phoneNumber string) (loginCode string, err error) Logout(ctx context.Context) (err error) Reconnect(ctx context.Context) (err error) FirstDevice(ctx context.Context) (response DevicesResponse, err error) diff --git a/src/domains/group/group.go b/src/domains/group/group.go index c89e4ed..59d6764 100644 --- a/src/domains/group/group.go +++ b/src/domains/group/group.go @@ -1,12 +1,15 @@ package group -import "context" +import ( + "context" + "go.mau.fi/whatsmeow" +) type IGroupService interface { JoinGroupWithLink(ctx context.Context, request JoinGroupWithLinkRequest) (groupID string, err error) LeaveGroup(ctx context.Context, request LeaveGroupRequest) (err error) CreateGroup(ctx context.Context, request CreateGroupRequest) (groupID string, err error) - AddParticipant(ctx context.Context, request ParticipantRequest) (result []ParticipantStatus, err error) + ManageParticipant(ctx context.Context, request ParticipantRequest) (result []ParticipantStatus, err error) } type JoinGroupWithLinkRequest struct { @@ -23,8 +26,9 @@ type CreateGroupRequest struct { } type ParticipantRequest struct { - GroupID string `json:"group_id" form:"group_id"` - Participants []string `json:"participants" form:"participants"` + GroupID string `json:"group_id" form:"group_id"` + Participants []string `json:"participants" form:"participants"` + Action whatsmeow.ParticipantChange `json:"action" form:"action"` } type ParticipantStatus struct { diff --git a/src/go.mod b/src/go.mod index 332c466..137dd8d 100644 --- a/src/go.mod +++ b/src/go.mod @@ -1,25 +1,25 @@ module github.com/aldinokemal/go-whatsapp-web-multidevice -go 1.21 +go 1.22 require ( github.com/PuerkitoBio/goquery v1.9.2 github.com/disintegration/imaging v1.6.2 github.com/dustin/go-humanize v1.0.1 github.com/go-ozzo/ozzo-validation/v4 v4.3.0 - github.com/gofiber/fiber/v2 v2.52.4 - github.com/gofiber/template/html/v2 v2.1.1 + github.com/gofiber/fiber/v2 v2.52.5 + github.com/gofiber/template/html/v2 v2.1.2 github.com/gofiber/websocket/v2 v2.2.1 github.com/google/uuid v1.6.0 github.com/mattn/go-sqlite3 v1.14.22 github.com/sirupsen/logrus v1.9.3 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e - github.com/spf13/cobra v1.8.0 + github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.9.0 - github.com/valyala/fasthttp v1.54.0 - go.mau.fi/libsignal v0.1.0 - go.mau.fi/whatsmeow v0.0.0-20240523075404-7f13c31d2cb1 - google.golang.org/protobuf v1.34.1 + github.com/valyala/fasthttp v1.55.0 + go.mau.fi/libsignal v0.1.1 + go.mau.fi/whatsmeow v0.0.0-20240821142752-3d63c6fcc1a7 + google.golang.org/protobuf v1.34.2 ) require ( @@ -28,29 +28,29 @@ require ( github.com/andybalholm/cascadia v1.3.2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fasthttp/websocket v1.5.9 // indirect + github.com/fasthttp/websocket v1.5.10 // indirect github.com/gofiber/template v1.8.3 // indirect github.com/gofiber/utils v1.1.0 // indirect - github.com/gorilla/websocket v1.5.1 // indirect + github.com/gorilla/websocket v1.5.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/joho/godotenv v1.5.1 // indirect - github.com/klauspost/compress v1.17.8 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/kr/pretty v0.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rs/zerolog v1.33.0 // indirect - github.com/savsgio/gotils v0.0.0-20240303185622-093b76447511 // indirect + github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - go.mau.fi/util v0.4.2 // indirect - golang.org/x/crypto v0.23.0 // indirect - golang.org/x/image v0.16.0 // indirect - golang.org/x/net v0.25.0 // indirect - golang.org/x/sys v0.20.0 // indirect + go.mau.fi/util v0.7.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/image v0.19.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sys v0.24.0 // indirect golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/src/go.sum b/src/go.sum index 0010540..84ca06e 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,7 +1,5 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI= -github.com/PuerkitoBio/goquery v1.9.1/go.mod h1:cW1n6TmIMDoORQU5IU/P1T3tGFunOeXEpGP2WHRwkbY= github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE= github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= @@ -12,7 +10,7 @@ github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:o github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -20,19 +18,17 @@ github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1 github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/fasthttp/websocket v1.5.8 h1:k5DpirKkftIF/w1R8ZzjSgARJrs54Je9YJK37DL/Ah8= -github.com/fasthttp/websocket v1.5.8/go.mod h1:d08g8WaT6nnyvg9uMm8K9zMYyDjfKyj3170AtPRuVU0= -github.com/fasthttp/websocket v1.5.9 h1:9deGuzYcCRKjk940kNwSN6Hd14hk4zYwropm4UsUIUQ= -github.com/fasthttp/websocket v1.5.9/go.mod h1:NLzHBFur260OMuZHohOfYQwMTpR7sfSpUnuqKxMpgKA= +github.com/fasthttp/websocket v1.5.10 h1:bc7NIGyrg1L6sd5pRzCIbXpro54SZLEluZCu0rOpcN4= +github.com/fasthttp/websocket v1.5.10/go.mod h1:BwHeuXGWzCW1/BIKUKD3+qfCl+cTdsHu/f243NcAI/Q= github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es= github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofiber/fiber/v2 v2.52.4 h1:P+T+4iK7VaqUsq2PALYEfBBo6bJZ4q3FP8cZ84EggTM= -github.com/gofiber/fiber/v2 v2.52.4/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo= +github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= github.com/gofiber/template v1.8.3 h1:hzHdvMwMo/T2kouz2pPCA0zGiLCeMnoGsQZBTSYgZxc= github.com/gofiber/template v1.8.3/go.mod h1:bs/2n0pSNPOkRa5VJ8zTIvedcI/lEYxzV3+YPXdBvq8= -github.com/gofiber/template/html/v2 v2.1.1 h1:QEy3O3EBkvwDthy5bXVGUseOyO6ldJoiDxlF4+MJiV8= -github.com/gofiber/template/html/v2 v2.1.1/go.mod h1:2G0GHHOUx70C1LDncoBpe4T6maQbNa4x1CVNFW0wju0= +github.com/gofiber/template/html/v2 v2.1.2 h1:wkK/mYJ3nIhongTkG3t0QgV4ADdgOYJYVSAF2AHnh8Y= +github.com/gofiber/template/html/v2 v2.1.2/go.mod h1:E98Z/FzvpaSib06aWEgYk6GXNf3ctoyaJH8yW5ay5ak= github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM= github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0= github.com/gofiber/websocket/v2 v2.2.1 h1:C9cjxvloojayOp9AovmpQrk8VqvVnT8Oao3+IUygH7w= @@ -41,14 +37,14 @@ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -60,8 +56,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -71,19 +67,17 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/savsgio/gotils v0.0.0-20240303185622-093b76447511 h1:KanIMPX0QdEdB4R3CiimCAbxFrhB3j7h0/OvpYGVQa8= -github.com/savsgio/gotils v0.0.0-20240303185622-093b76447511/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg= +github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc= +github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= -github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -93,32 +87,24 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.52.0 h1:wqBQpxH71XW0e2g+Og4dzQM8pk34aFYlA1Ga8db7gU0= -github.com/valyala/fasthttp v1.52.0/go.mod h1:hf5C4QnVMkNXMspnsUlfM3WitlgYflyhHYoKol/szxQ= -github.com/valyala/fasthttp v1.54.0 h1:cCL+ZZR3z3HPLMVfEYVUMtJqVaui0+gu7Lx63unHwS0= -github.com/valyala/fasthttp v1.54.0/go.mod h1:6dt4/8olwq9QARP/TDuPmWyWcl4byhpvTJ4AAtcz+QM= +github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8= +github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mau.fi/libsignal v0.1.0 h1:vAKI/nJ5tMhdzke4cTK1fb0idJzz1JuEIpmjprueC+c= -go.mau.fi/libsignal v0.1.0/go.mod h1:R8ovrTezxtUNzCQE5PH30StOQWWeBskBsWE55vMfY9I= -go.mau.fi/util v0.4.2 h1:RR3TOcRHmCF9Bx/3YG4S65MYfa+nV6/rn8qBWW4Mi30= -go.mau.fi/util v0.4.2/go.mod h1:PlAVfUUcPyHPrwnvjkJM9UFcPE7qGPDJqk+Oufa1Gtw= -go.mau.fi/whatsmeow v0.0.0-20240327124018-350073db195c h1:a5O4nqmwUWvmC+27RUdefkuy5XzMOEUqR9ji+/BcHZA= -go.mau.fi/whatsmeow v0.0.0-20240327124018-350073db195c/go.mod h1:kNI5foyzqd77d5HaWc1Jico6/rxtZ/UE8nr80hIsbIk= -go.mau.fi/whatsmeow v0.0.0-20240523075404-7f13c31d2cb1 h1:mUEEmZs1xk5QHKXjDxiAP4bYgyj8r7PaZCafHN+KMQg= -go.mau.fi/whatsmeow v0.0.0-20240523075404-7f13c31d2cb1/go.mod h1:0+65CYaE6r4dWzr0dN8i+UZKy0gIfJ79VuSqIl0nKRM= +go.mau.fi/libsignal v0.1.1 h1:m/0PGBh4QKP/I1MQ44ti4C0fMbLMuHb95cmDw01FIpI= +go.mau.fi/libsignal v0.1.1/go.mod h1:QLs89F/OA3ThdSL2Wz2p+o+fi8uuQUz0e1BRa6ExdBw= +go.mau.fi/util v0.7.0 h1:l31z+ivrSQw+cv/9eFebEqtQW2zhxivGypn+JT0h/ws= +go.mau.fi/util v0.7.0/go.mod h1:bWYreIoTULL/UiRbZdfddPh7uWDFW5yX4YCv5FB0eE0= +go.mau.fi/whatsmeow v0.0.0-20240821142752-3d63c6fcc1a7 h1:Aa4uov0rM0SQQ7Fc/TZZpmQEGksie2SVTv/UuCJwViI= +go.mau.fi/whatsmeow v0.0.0-20240821142752-3d63c6fcc1a7/go.mod h1:BhHKalSq0qNtSCuGIUIvoJyU5KbT4a7k8DQ5yw1Ssk4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= -golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= -golang.org/x/image v0.16.0 h1:9kloLAKhUufZhA12l5fwnx2NZW39/we1UhBesW433jw= -golang.org/x/image v0.16.0/go.mod h1:ugSZItdV4nOxyqp56HmXwH0Ry0nBCpjnZdpDaIHdoPs= +golang.org/x/image v0.19.0 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ= +golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -126,10 +112,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -144,10 +128,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -164,10 +146,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/src/internal/rest/app.go b/src/internal/rest/app.go index 19775d4..c72cde0 100644 --- a/src/internal/rest/app.go +++ b/src/internal/rest/app.go @@ -14,6 +14,7 @@ type App struct { func InitRestApp(app *fiber.App, service domainApp.IAppService) App { rest := App{Service: service} app.Get("/app/login", rest.Login) + app.Get("/app/login-with-code", rest.LoginWithCode) app.Get("/app/logout", rest.Logout) app.Get("/app/reconnect", rest.Reconnect) app.Get("/app/devices", rest.Devices) @@ -36,6 +37,20 @@ func (handler *App) Login(c *fiber.Ctx) error { }) } +func (handler *App) LoginWithCode(c *fiber.Ctx) error { + pairCode, err := handler.Service.LoginWithCode(c.UserContext(), c.Query("phone")) + utils.PanicIfNeeded(err) + + return c.JSON(utils.ResponseData{ + Status: 200, + Code: "SUCCESS", + Message: "Login with code success", + Results: map[string]any{ + "pair_code": pairCode, + }, + }) +} + func (handler *App) Logout(c *fiber.Ctx) error { err := handler.Service.Logout(c.UserContext()) utils.PanicIfNeeded(err) diff --git a/src/internal/rest/group.go b/src/internal/rest/group.go index 95ccef6..53f98bd 100644 --- a/src/internal/rest/group.go +++ b/src/internal/rest/group.go @@ -6,6 +6,7 @@ import ( "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/utils" "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/whatsapp" "github.com/gofiber/fiber/v2" + "go.mau.fi/whatsmeow" ) type Group struct { @@ -18,6 +19,9 @@ func InitRestGroup(app *fiber.App, service domainGroup.IGroupService) Group { app.Post("/group/join-with-link", rest.JoinGroupWithLink) app.Post("/group/leave", rest.LeaveGroup) app.Post("/group/participants", rest.AddParticipants) + app.Post("/group/participants/remove", rest.DeleteParticipants) + app.Post("/group/participants/promote", rest.PromoteParticipants) + app.Post("/group/participants/demote", rest.DemoteParticipants) return rest } @@ -81,7 +85,9 @@ func (controller *Group) AddParticipants(c *fiber.Ctx) error { whatsapp.SanitizePhone(&request.GroupID) - result, err := controller.Service.AddParticipant(c.UserContext(), request) + request.Action = whatsmeow.ParticipantChangeAdd + + result, err := controller.Service.ManageParticipant(c.UserContext(), request) utils.PanicIfNeeded(err) return c.JSON(utils.ResponseData{ @@ -91,3 +97,63 @@ func (controller *Group) AddParticipants(c *fiber.Ctx) error { Results: result, }) } + +func (controller *Group) DeleteParticipants(c *fiber.Ctx) error { + var request domainGroup.ParticipantRequest + err := c.BodyParser(&request) + utils.PanicIfNeeded(err) + + whatsapp.SanitizePhone(&request.GroupID) + + request.Action = whatsmeow.ParticipantChangeRemove + + result, err := controller.Service.ManageParticipant(c.UserContext(), request) + utils.PanicIfNeeded(err) + + return c.JSON(utils.ResponseData{ + Status: 200, + Code: "SUCCESS", + Message: "Success delete participants", + Results: result, + }) +} + +func (controller *Group) PromoteParticipants(c *fiber.Ctx) error { + var request domainGroup.ParticipantRequest + err := c.BodyParser(&request) + utils.PanicIfNeeded(err) + + whatsapp.SanitizePhone(&request.GroupID) + + request.Action = whatsmeow.ParticipantChangePromote + + result, err := controller.Service.ManageParticipant(c.UserContext(), request) + utils.PanicIfNeeded(err) + + return c.JSON(utils.ResponseData{ + Status: 200, + Code: "SUCCESS", + Message: "Success promote participants", + Results: result, + }) +} + +func (controller *Group) DemoteParticipants(c *fiber.Ctx) error { + var request domainGroup.ParticipantRequest + err := c.BodyParser(&request) + utils.PanicIfNeeded(err) + + whatsapp.SanitizePhone(&request.GroupID) + + request.Action = whatsmeow.ParticipantChangeDemote + + result, err := controller.Service.ManageParticipant(c.UserContext(), request) + utils.PanicIfNeeded(err) + + return c.JSON(utils.ResponseData{ + Status: 200, + Code: "SUCCESS", + Message: "Success demote participants", + Results: result, + }) +} diff --git a/src/pkg/error/app_error.go b/src/pkg/error/app_error.go index 79b9f93..5d4c26d 100644 --- a/src/pkg/error/app_error.go +++ b/src/pkg/error/app_error.go @@ -101,7 +101,7 @@ func (err sessionSavedError) StatusCode() int { } var ( - ErrAlreadyLoggedIn = LoginError("you already logged in :)") + ErrAlreadyLoggedIn = LoginError("you are already logged in.") ErrNotConnected = throwAuthError("you are not connect to services server, please reconnect") ErrNotLoggedIn = throwAuthError("you are not logged in") ErrReconnect = throwReconnectError("reconnect error") diff --git a/src/pkg/utils/general.go b/src/pkg/utils/general.go index eddb504..f530c04 100644 --- a/src/pkg/utils/general.go +++ b/src/pkg/utils/general.go @@ -92,3 +92,16 @@ func GetMetaDataFromURL(url string) (meta Metadata) { fmt.Println("Meta data:", meta) return meta } + +// ContainsMention is checking if message contains mention, then return only mention without @ +func ContainsMention(message string) []string { + var mentions []string + words := strings.Fields(message) + for _, word := range words { + if strings.HasPrefix(word, "@") { + mentions = append(mentions, word[1:]) + } + } + + return mentions +} diff --git a/src/pkg/whatsapp/whatsapp.go b/src/pkg/whatsapp/whatsapp.go index 5c01437..5fc2fcd 100644 --- a/src/pkg/whatsapp/whatsapp.go +++ b/src/pkg/whatsapp/whatsapp.go @@ -12,7 +12,7 @@ import ( "github.com/sirupsen/logrus" "go.mau.fi/whatsmeow" "go.mau.fi/whatsmeow/appstate" - waProto "go.mau.fi/whatsmeow/binary/proto" + "go.mau.fi/whatsmeow/proto/waE2E" "go.mau.fi/whatsmeow/store" "go.mau.fi/whatsmeow/store/sqlstore" "go.mau.fi/whatsmeow/types" @@ -251,7 +251,7 @@ func handler(rawEvt interface{}) { if config.WhatsappAutoReplyMessage != "" && !isGroupJid(evt.Info.Chat.String()) && !strings.Contains(evt.Info.SourceString(), "broadcast") { - _, _ = cli.SendMessage(context.Background(), evt.Info.Sender, &waProto.Message{Conversation: proto.String(config.WhatsappAutoReplyMessage)}) + _, _ = cli.SendMessage(context.Background(), evt.Info.Sender, &waE2E.Message{Conversation: proto.String(config.WhatsappAutoReplyMessage)}) } if config.WhatsappWebhook != "" && @@ -314,7 +314,7 @@ func forwardToWebhook(evt *events.Message) error { message.ID = evt.Info.ID if extendedMessage := evt.Message.ExtendedTextMessage.GetText(); extendedMessage != "" { message.Text = extendedMessage - message.RepliedId = evt.Message.ExtendedTextMessage.ContextInfo.GetStanzaId() + message.RepliedId = evt.Message.ExtendedTextMessage.ContextInfo.GetStanzaID() } var quotedmessage any @@ -332,7 +332,7 @@ func forwardToWebhook(evt *events.Message) error { var waReaction evtReaction if reactionMessage := evt.Message.ReactionMessage; reactionMessage != nil { waReaction.Message = reactionMessage.GetText() - waReaction.ID = reactionMessage.GetKey().GetId() + waReaction.ID = reactionMessage.GetKey().GetID() } body := map[string]interface{}{ @@ -443,23 +443,29 @@ func ExtractMedia(storageLocation string, mediaFile whatsmeow.DownloadableMessag } switch media := mediaFile.(type) { - case *waProto.ImageMessage: + case *waE2E.ImageMessage: extractedMedia.MimeType = media.GetMimetype() extractedMedia.Caption = media.GetCaption() - case *waProto.AudioMessage: + case *waE2E.AudioMessage: extractedMedia.MimeType = media.GetMimetype() - case *waProto.VideoMessage: + case *waE2E.VideoMessage: extractedMedia.MimeType = media.GetMimetype() extractedMedia.Caption = media.GetCaption() - case *waProto.StickerMessage: + case *waE2E.StickerMessage: extractedMedia.MimeType = media.GetMimetype() - case *waProto.DocumentMessage: + case *waE2E.DocumentMessage: extractedMedia.MimeType = media.GetMimetype() extractedMedia.Caption = media.GetCaption() } - extensions, _ := mime.ExtensionsByType(extractedMedia.MimeType) - extractedMedia.MediaPath = fmt.Sprintf("%s/%d-%s%s", storageLocation, time.Now().Unix(), uuid.NewString(), extensions[0]) + var extension string + if ext, err := mime.ExtensionsByType(extractedMedia.MimeType); err != nil && len(ext) > 0 { + extension = ext[0] + } else if parts := strings.Split(extractedMedia.MimeType, "/"); len(parts) > 1 { + extension = "." + parts[len(parts)-1] + } + + extractedMedia.MediaPath = fmt.Sprintf("%s/%d-%s%s", storageLocation, time.Now().Unix(), uuid.NewString(), extension) err = os.WriteFile(extractedMedia.MediaPath, data, 0600) if err != nil { return extractedMedia, err diff --git a/src/services/app.go b/src/services/app.go index 9cf9d40..8aca9b9 100644 --- a/src/services/app.go +++ b/src/services/app.go @@ -7,6 +7,7 @@ import ( "github.com/aldinokemal/go-whatsapp-web-multidevice/config" domainApp "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/app" pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error" + "github.com/aldinokemal/go-whatsapp-web-multidevice/validations" fiberUtils "github.com/gofiber/fiber/v2/utils" "github.com/sirupsen/logrus" "github.com/skip2/go-qrcode" @@ -90,6 +91,28 @@ func (service serviceApp) Login(_ context.Context) (response domainApp.LoginResp return response, nil } +func (service serviceApp) LoginWithCode(ctx context.Context, phoneNumber string) (loginCode string, err error) { + if err = validations.ValidateLoginWithCode(ctx, phoneNumber); err != nil { + logrus.Errorf("Error when validate login with code: %s", err.Error()) + return loginCode, err + } + + // detect is already logged in + if service.WaCli.IsLoggedIn() { + logrus.Warn("User is already logged in") + return loginCode, pkgError.ErrAlreadyLoggedIn + } + + loginCode, err = service.WaCli.PairPhone(phoneNumber, true, whatsmeow.PairClientChrome, "Chrome (Linux)") + if err != nil { + logrus.Errorf("Error when pairing phone: %s", err.Error()) + return loginCode, err + } + + logrus.Infof("Successfully paired phone with code: %s", loginCode) + return loginCode, nil +} + func (service serviceApp) Logout(_ context.Context) (err error) { // delete history files, err := filepath.Glob(fmt.Sprintf("./%s/history-*", config.PathStorages)) diff --git a/src/services/group.go b/src/services/group.go index 3e096cb..afe2aa1 100644 --- a/src/services/group.go +++ b/src/services/group.go @@ -73,7 +73,7 @@ func (service groupService) CreateGroup(ctx context.Context, request domainGroup return groupInfo.JID.String(), nil } -func (service groupService) AddParticipant(ctx context.Context, request domainGroup.ParticipantRequest) (result []domainGroup.ParticipantStatus, err error) { +func (service groupService) ManageParticipant(ctx context.Context, request domainGroup.ParticipantRequest) (result []domainGroup.ParticipantStatus, err error) { if err = validations.ValidateParticipant(ctx, request); err != nil { return result, err } @@ -89,7 +89,7 @@ func (service groupService) AddParticipant(ctx context.Context, request domainGr return result, err } - participants, err := service.WaCli.UpdateGroupParticipants(groupJID, participantsJID, whatsmeow.ParticipantChangeAdd) + participants, err := service.WaCli.UpdateGroupParticipants(groupJID, participantsJID, request.Action) if err != nil { return result, err } @@ -105,7 +105,7 @@ func (service groupService) AddParticipant(ctx context.Context, request domainGr result = append(result, domainGroup.ParticipantStatus{ Participant: participant.JID.String(), Status: "success", - Message: "Participant added", + Message: "Action success", }) } } diff --git a/src/services/send.go b/src/services/send.go index 39e6c4b..08fb2f8 100644 --- a/src/services/send.go +++ b/src/services/send.go @@ -46,7 +46,18 @@ func (service serviceSend) SendText(ctx context.Context, request domainSend.Mess } // Send message - msg := &waE2E.Message{Conversation: proto.String(request.Message)} + msg := &waE2E.Message{ + ExtendedTextMessage: &waE2E.ExtendedTextMessage{ + Text: proto.String(request.Message), + }, + } + + parsedMentions := service.getMentionFromText(ctx, request.Message) + if len(parsedMentions) > 0 { + msg.ExtendedTextMessage.ContextInfo = &waE2E.ContextInfo{ + MentionedJID: parsedMentions, + } + } // Reply message if request.ReplyMessageID != nil && *request.ReplyMessageID != "" { @@ -59,18 +70,20 @@ func (service serviceSend) SendText(ctx context.Context, request domainSend.Mess participantJID = firstDevice.Device } - msg = &waE2E.Message{ - ExtendedTextMessage: &waE2E.ExtendedTextMessage{ - Text: proto.String(request.Message), - ContextInfo: &waE2E.ContextInfo{ - StanzaID: request.ReplyMessageID, - Participant: proto.String(participantJID), - QuotedMessage: &waE2E.Message{ - Conversation: proto.String(request.Message), - }, + msg.ExtendedTextMessage = &waE2E.ExtendedTextMessage{ + Text: proto.String(request.Message), + ContextInfo: &waE2E.ContextInfo{ + StanzaID: request.ReplyMessageID, + Participant: proto.String(participantJID), + QuotedMessage: &waE2E.Message{ + Conversation: proto.String(request.Message), }, }, } + + if len(parsedMentions) > 0 { + msg.ExtendedTextMessage.ContextInfo.MentionedJID = parsedMentions + } } ts, err := service.WaCli.SendMessage(ctx, dataWaRecipient, msg) @@ -196,9 +209,6 @@ func (service serviceSend) SendFile(ctx context.Context, request domainSend.File fileMimeType := http.DetectContentType(fileBytes) // Send to WA server - if err != nil { - return response, err - } uploadedFile, err := service.WaCli.Upload(context.Background(), fileBytes, whatsmeow.MediaDocument) if err != nil { fmt.Printf("Failed to upload file: %v", err) @@ -485,3 +495,15 @@ func (service serviceSend) SendPoll(ctx context.Context, request domainSend.Poll response.Status = fmt.Sprintf("Send poll success %s (server timestamp: %s)", request.Phone, ts.Timestamp.String()) return response, nil } + +func (service serviceSend) getMentionFromText(ctx context.Context, messages string) (result []string) { + mentions := utils.ContainsMention(messages) + for _, mention := range mentions { + // Get JID from phone number + if dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, mention); err == nil { + result = append(result, dataWaRecipient.String()) + } + } + return result + +} diff --git a/src/validations/app_validation.go b/src/validations/app_validation.go new file mode 100644 index 0000000..e9eb1f7 --- /dev/null +++ b/src/validations/app_validation.go @@ -0,0 +1,21 @@ +package validations + +import ( + "context" + "fmt" + pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error" + validation "github.com/go-ozzo/ozzo-validation/v4" + "regexp" +) + +func ValidateLoginWithCode(ctx context.Context, phoneNumber string) error { + // Combine validations using a single ValidateWithContext call + err := validation.ValidateWithContext(ctx, &phoneNumber, + validation.Required, + validation.Match(regexp.MustCompile(`^\+?[0-9]{1,15}$`)), + ) + if err != nil { + return pkgError.ValidationError(fmt.Sprintf("phone_number(%s): %s", phoneNumber, err.Error())) + } + return nil +} diff --git a/src/validations/app_validation_test.go b/src/validations/app_validation_test.go new file mode 100644 index 0000000..5757b32 --- /dev/null +++ b/src/validations/app_validation_test.go @@ -0,0 +1,61 @@ +package validations + +import ( + "context" + "testing" +) + +func TestValidateLoginWithCode(t *testing.T) { + type args struct { + phoneNumber string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "Phone with +", + args: args{phoneNumber: "+6281234567890"}, + wantErr: false, + }, + { + name: "Phone without +", + args: args{phoneNumber: "621234567890"}, + wantErr: false, + }, + { + name: "Phone with 0", + args: args{phoneNumber: "081234567890"}, + wantErr: false, + }, + { + name: "Phone contains alphabet", + args: args{phoneNumber: "+6281234567890a"}, + wantErr: true, + }, + { + name: "Empty phone number", + args: args{phoneNumber: ""}, + wantErr: true, + }, + { + name: "Phone with special characters", + args: args{phoneNumber: "+6281234567890!@#"}, + wantErr: true, + }, + { + name: "Extremely long phone number", + args: args{phoneNumber: "+62812345678901234567890"}, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := ValidateLoginWithCode(context.Background(), tt.args.phoneNumber); (err != nil) != tt.wantErr { + t.Errorf("ValidateLoginWithCode() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/src/views/components/AppLogin.js b/src/views/components/AppLogin.js index b276e7f..20cd062 100644 --- a/src/views/components/AppLogin.js +++ b/src/views/components/AppLogin.js @@ -1,5 +1,8 @@ export default { name: 'AppLogin', + props: { + connected: null, + }, data() { return { login_link: '', @@ -9,6 +12,8 @@ export default { methods: { async openModal() { try { + if (this.connected) throw Error('You are already logged in.'); + await this.submitApi(); $('#modalLogin').modal({ onApprove: function () { @@ -38,7 +43,7 @@ export default {
Login
- Scan your QRCode and you can use all this API feature + Scan your QR code to access all API capabilities.
diff --git a/src/views/components/AppLoginWithCode.js b/src/views/components/AppLoginWithCode.js new file mode 100644 index 0000000..8421e02 --- /dev/null +++ b/src/views/components/AppLoginWithCode.js @@ -0,0 +1,109 @@ +export default { + name: 'AppLoginWithCode', + props: { + connected: { + type: Boolean, + default: false, + } + }, + watch: { + connected: function(val) { + if (val) { + // reset form + this.phone = ''; + this.pair_code = null; + + $('#modalLoginWithCode').modal('hide'); + } + }, + }, + data: () => { + return { + phone: '', + submitting: false, + pair_code: null, + }; + }, + methods: { + async openModal() { + try { + if (this.connected) throw Error('You are already logged in.'); + + $('#modalLoginWithCode').modal({ + onApprove: function() { + return false; + }, + }).modal('show'); + } catch (err) { + showErrorInfo(err); + } + }, + async handleSubmit() { + if (this.submitting) return; + try { + this.submitting = true; + const { data } = await http.get(`/app/login-with-code`, { + params: { + phone: this.phone, + }, + }); + this.pair_code = data.results.pair_code; + } catch (err) { + if (err.response) { + showErrorInfo(err.response.data.message); + }else{ + showErrorInfo(err.message); + } + } finally { + this.submitting = false; + } + }, + }, + template: ` +
+
+
Login with Code
+
+ Enter your pairing code to log in and access your devices. +
+
+
+ + + + `, +}; \ No newline at end of file diff --git a/src/views/components/AppReconnect.js b/src/views/components/AppReconnect.js index dcc507b..1d41451 100644 --- a/src/views/components/AppReconnect.js +++ b/src/views/components/AppReconnect.js @@ -28,8 +28,7 @@ export default {
Reconnect
- Reconnect to whatsapp server, please do this if your api doesn't work or your application is down or - restart + Please reconnect to the WhatsApp service if your API doesn't work or if your app is down.
diff --git a/src/views/components/GroupAddParticipants.js b/src/views/components/GroupManageParticipants.js similarity index 65% rename from src/views/components/GroupAddParticipants.js rename to src/views/components/GroupManageParticipants.js index 4d272fc..914114b 100644 --- a/src/views/components/GroupAddParticipants.js +++ b/src/views/components/GroupManageParticipants.js @@ -1,48 +1,66 @@ export default { - name: 'AddParticipantsToGroup', + name: 'ManageGroupParticipants', data() { return { loading: false, group: '', + action: 'add', // add, remove, promote, demote participants: ['', ''], - } + }; }, computed: { group_id() { - return `${this.group}@${window.TYPEGROUP}` - } + return `${this.group}@${window.TYPEGROUP}`; + }, }, methods: { openModal() { $('#modalGroupAddParticipant').modal({ - onApprove: function () { + onApprove: function() { return false; - } + }, }).modal('show'); }, handleAddParticipant() { - this.participants.push('') + this.participants.push(''); }, handleDeleteParticipant(index) { - this.participants.splice(index, 1) + this.participants.splice(index, 1); }, async handleSubmit() { try { - let response = await this.submitApi() - showSuccessInfo(response) + let response = await this.submitApi(); + showSuccessInfo(response); $('#modalGroupAddParticipant').modal('hide'); } catch (err) { - showErrorInfo(err) + showErrorInfo(err); } }, async submitApi() { this.loading = true; try { - let response = await window.http.post(`/group/participants`, { + const payload = { group_id: this.group_id, // convert participant become list of string - participants: this.participants.filter(participant => participant !== '').map(participant => `${participant}`) - }) + participants: this.participants.filter(participant => participant !== '').map(participant => `${participant}`), + }; + + let response; + switch (this.action) { + case 'add': + response = await window.http.post(`/group/participants`, payload); + break; + case 'remove': + response = await window.http.post(`/group/participants/remove`, payload); + break; + case 'promote': + response = await window.http.post(`/group/participants/promote`, payload); + break; + case 'demote': + response = await window.http.post(`/group/participants/demote`, payload); + break; + } + this.handleReset(); return response.data.message; } catch (error) { @@ -56,6 +74,7 @@ export default { }, handleReset() { this.group = ''; + this.action = 'add'; this.participants = ['', '']; }, }, @@ -63,9 +82,9 @@ export default {
Group -
Add Participants
+
Manage Participants
- Add multiple participants + Add/Remove/Promote/Demote Participants
@@ -74,7 +93,7 @@ export default { + +
+ + +
- Create + Submit
- ` -} \ No newline at end of file + `, +}; \ No newline at end of file diff --git a/src/views/index.html b/src/views/index.html index 85140d7..8f3c029 100644 --- a/src/views/index.html +++ b/src/views/index.html @@ -41,9 +41,10 @@
- + +
@@ -127,6 +128,7 @@