From 93bf10b4ad74d8a992c6a181139f1ef9320309d1 Mon Sep 17 00:00:00 2001 From: Aldino Kemal Date: Tue, 10 Jun 2025 11:58:45 +0700 Subject: [PATCH] feat: add IsOnWhatsApp endpoint to check user availability - Add /user/check endpoint with phone query parameter - Implement CheckRequest and CheckResponse domain types - Add IsOnWhatsApp method to user usecase interface and implementation - Create AccountUserCheck Vue component for UI interaction - Update OpenAPI documentation with new endpoint schema - Bump version to 6.1.0 for new feature release --- docs/openapi.yaml | 51 ++++++++++++- src/domains/user/account.go | 8 ++ src/domains/user/user.go | 1 + src/ui/rest/user.go | 17 +++++ src/usecase/user.go | 10 +++ src/views/components/AccountUserCheck.js | 95 ++++++++++++++++++++++++ src/views/index.html | 4 +- 7 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 src/views/components/AccountUserCheck.js diff --git a/docs/openapi.yaml b/docs/openapi.yaml index f95c6a3..53d8317 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.0" info: title: WhatsApp API MultiDevice - version: 6.0.0 + version: 6.1.0 description: This API is used for sending whatsapp via API servers: - url: http://localhost:3000 @@ -348,6 +348,38 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorInternalServer' + /user/check: + get: + operationId: userCheck + tags: + - user + summary: Check if user is on WhatsApp + parameters: + - name: phone + in: query + schema: + type: string + example: '628912344551' + description: Phone number with country code + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/UserCheckResponse' + '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' /send/message: post: @@ -2137,4 +2169,19 @@ components: requested_at: type: string format: date-time - example: "2024-10-11T21:27:29+07:00" \ No newline at end of file + example: "2024-10-11T21:27:29+07:00" + UserCheckResponse: + type: object + properties: + code: + type: string + example: SUCCESS + message: + type: string + example: Success check user + results: + type: object + properties: + is_on_whatsapp: + type: boolean + example: true \ No newline at end of file diff --git a/src/domains/user/account.go b/src/domains/user/account.go index c0fb6b5..a60090e 100644 --- a/src/domains/user/account.go +++ b/src/domains/user/account.go @@ -73,3 +73,11 @@ type MyListContactsResponseData struct { type ChangePushNameRequest struct { PushName string `json:"push_name" form:"push_name"` } + +type CheckRequest struct { + Phone string `json:"phone" query:"phone"` +} + +type CheckResponse struct { + IsOnWhatsApp bool `json:"is_on_whatsapp"` +} diff --git a/src/domains/user/user.go b/src/domains/user/user.go index 902fb52..fc984eb 100644 --- a/src/domains/user/user.go +++ b/src/domains/user/user.go @@ -13,4 +13,5 @@ type IUserUsecase interface { MyListNewsletter(ctx context.Context) (response MyListNewsletterResponse, err error) MyPrivacySetting(ctx context.Context) (response MyPrivacySettingResponse, err error) MyListContacts(ctx context.Context) (response MyListContactsResponse, err error) + IsOnWhatsApp(ctx context.Context, request CheckRequest) (response CheckResponse, err error) } diff --git a/src/ui/rest/user.go b/src/ui/rest/user.go index 57ea47c..4281f17 100644 --- a/src/ui/rest/user.go +++ b/src/ui/rest/user.go @@ -21,6 +21,7 @@ func InitRestUser(app *fiber.App, service domainUser.IUserUsecase) User { app.Get("/user/my/groups", rest.UserMyListGroups) app.Get("/user/my/newsletters", rest.UserMyListNewsletter) app.Get("/user/my/contacts", rest.UserMyListContacts) + app.Get("/user/check", rest.UserCheck) return rest } @@ -141,3 +142,19 @@ func (controller *User) UserChangePushName(c *fiber.Ctx) error { Message: "Success change push name", }) } + +func (controller *User) UserCheck(c *fiber.Ctx) error { + var request domainUser.CheckRequest + err := c.QueryParser(&request) + utils.PanicIfNeeded(err) + + response, err := controller.Service.IsOnWhatsApp(c.UserContext(), request) + utils.PanicIfNeeded(err) + + return c.JSON(utils.ResponseData{ + Status: 200, + Code: "SUCCESS", + Message: "Success check user", + Results: response, + }) +} diff --git a/src/usecase/user.go b/src/usecase/user.go index 89fbb04..13e890b 100644 --- a/src/usecase/user.go +++ b/src/usecase/user.go @@ -242,3 +242,13 @@ func (service serviceUser) ChangePushName(ctx context.Context, request domainUse } return nil } + +func (service serviceUser) IsOnWhatsApp(ctx context.Context, request domainUser.CheckRequest) (response domainUser.CheckResponse, err error) { + whatsapp.MustLogin(service.WaCli) + + whatsapp.SanitizePhone(&request.Phone) + + response.IsOnWhatsApp = whatsapp.IsOnWhatsapp(service.WaCli, request.Phone) + + return response, nil +} diff --git a/src/views/components/AccountUserCheck.js b/src/views/components/AccountUserCheck.js new file mode 100644 index 0000000..c417c68 --- /dev/null +++ b/src/views/components/AccountUserCheck.js @@ -0,0 +1,95 @@ +import FormRecipient from "./generic/FormRecipient.js"; + +export default { + name: 'AccountUserCheck', + components: { + FormRecipient + }, + data() { + return { + type: window.TYPEUSER, + phone: '', + isOnWhatsApp: null, + loading: false, + } + }, + computed: { + phone_id() { + return this.phone + this.type; + } + }, + methods: { + async openModal() { + this.handleReset(); + $('#modalUserCheck').modal('show'); + }, + isValidForm() { + return this.phone.trim() !== ''; + }, + async handleSubmit() { + if (!this.isValidForm() || this.loading) { + return; + } + try { + await this.submitApi(); + showSuccessInfo("Check completed") + } catch (err) { + showErrorInfo(err) + } + }, + async submitApi() { + this.loading = true; + try { + let response = await window.http.get(`/user/check?phone=${this.phone_id}`) + this.isOnWhatsApp = response.data.results.is_on_whatsapp; + } catch (error) { + if (error.response) { + throw new Error(error.response.data.message); + } + throw new Error(error.message); + } finally { + this.loading = false; + } + }, + handleReset() { + this.phone = ''; + this.isOnWhatsApp = null; + this.type = window.TYPEUSER; + } + }, + template: ` +
+
+ Account +
User Check
+
+ Check if a user is on WhatsApp +
+
+
+ + + ` +} \ No newline at end of file diff --git a/src/views/index.html b/src/views/index.html index 7635eea..58e266f 100644 --- a/src/views/index.html +++ b/src/views/index.html @@ -161,6 +161,7 @@ + @@ -225,6 +226,7 @@ import AccountUserInfo from "./components/AccountUserInfo.js"; import AccountPrivacy from "./components/AccountPrivacy.js"; import AccountContact from "./components/AccountContact.js"; + import AccountUserCheck from "./components/AccountUserCheck.js"; const showErrorInfo = (message) => { $('body').toast({ @@ -263,7 +265,7 @@ MessageDelete, MessageUpdate, MessageReact, MessageRevoke, GroupList, GroupCreate, GroupJoinWithLink, GroupAddParticipants, NewsletterList, - AccountAvatar, AccountUserInfo, AccountPrivacy, AccountChangeAvatar, AccountContact, AccountChangePushName + AccountAvatar, AccountUserInfo, AccountPrivacy, AccountChangeAvatar, AccountContact, AccountChangePushName, AccountUserCheck }, delimiters: ['[[', ']]'], data() {