Browse Source

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
pull/301/head
Aldino Kemal 9 months ago
parent
commit
93bf10b4ad
  1. 51
      docs/openapi.yaml
  2. 8
      src/domains/user/account.go
  3. 1
      src/domains/user/user.go
  4. 17
      src/ui/rest/user.go
  5. 10
      src/usecase/user.go
  6. 95
      src/views/components/AccountUserCheck.js
  7. 4
      src/views/index.html

51
docs/openapi.yaml

@ -1,7 +1,7 @@
openapi: "3.0.0" openapi: "3.0.0"
info: info:
title: WhatsApp API MultiDevice title: WhatsApp API MultiDevice
version: 6.0.0
version: 6.1.0
description: This API is used for sending whatsapp via API description: This API is used for sending whatsapp via API
servers: servers:
- url: http://localhost:3000 - url: http://localhost:3000
@ -348,6 +348,38 @@ paths:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/ErrorInternalServer' $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: /send/message:
post: post:
@ -2137,4 +2169,19 @@ components:
requested_at: requested_at:
type: string type: string
format: date-time format: date-time
example: "2024-10-11T21:27:29+07:00"
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

8
src/domains/user/account.go

@ -73,3 +73,11 @@ type MyListContactsResponseData struct {
type ChangePushNameRequest struct { type ChangePushNameRequest struct {
PushName string `json:"push_name" form:"push_name"` 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"`
}

1
src/domains/user/user.go

@ -13,4 +13,5 @@ type IUserUsecase interface {
MyListNewsletter(ctx context.Context) (response MyListNewsletterResponse, err error) MyListNewsletter(ctx context.Context) (response MyListNewsletterResponse, err error)
MyPrivacySetting(ctx context.Context) (response MyPrivacySettingResponse, err error) MyPrivacySetting(ctx context.Context) (response MyPrivacySettingResponse, err error)
MyListContacts(ctx context.Context) (response MyListContactsResponse, err error) MyListContacts(ctx context.Context) (response MyListContactsResponse, err error)
IsOnWhatsApp(ctx context.Context, request CheckRequest) (response CheckResponse, err error)
} }

17
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/groups", rest.UserMyListGroups)
app.Get("/user/my/newsletters", rest.UserMyListNewsletter) app.Get("/user/my/newsletters", rest.UserMyListNewsletter)
app.Get("/user/my/contacts", rest.UserMyListContacts) app.Get("/user/my/contacts", rest.UserMyListContacts)
app.Get("/user/check", rest.UserCheck)
return rest return rest
} }
@ -141,3 +142,19 @@ func (controller *User) UserChangePushName(c *fiber.Ctx) error {
Message: "Success change push name", 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,
})
}

10
src/usecase/user.go

@ -242,3 +242,13 @@ func (service serviceUser) ChangePushName(ctx context.Context, request domainUse
} }
return nil 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
}

95
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: `
<div class="olive card" @click="openModal" style="cursor: pointer;">
<div class="content">
<a class="ui olive right ribbon label">Account</a>
<div class="header">User Check</div>
<div class="description">
Check if a user is on WhatsApp
</div>
</div>
</div>
<div class="ui small modal" id="modalUserCheck">
<i class="close icon"></i>
<div class="header">
Check if User is on WhatsApp
</div>
<div class="content">
<form class="ui form">
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<button type="button" class="ui primary button" :class="{'loading': loading, 'disabled': !this.isValidForm() || this.loading}"
@click.prevent="handleSubmit">
Check
</button>
</form>
<div v-if="isOnWhatsApp !== null" class="ui message" :class="isOnWhatsApp ? 'positive' : 'negative'">
<div class="header">
<i :class="isOnWhatsApp ? 'check circle icon' : 'times circle icon'"></i>
{{ isOnWhatsApp ? 'User is on WhatsApp' : 'User is not on WhatsApp' }}
</div>
<p>Phone: {{ phone_id }}</p>
</div>
</div>
</div>
`
}

4
src/views/index.html

@ -161,6 +161,7 @@
<account-user-info></account-user-info> <account-user-info></account-user-info>
<account-privacy></account-privacy> <account-privacy></account-privacy>
<account-contact></account-contact> <account-contact></account-contact>
<account-user-check></account-user-check>
</div> </div>
</div> </div>
@ -225,6 +226,7 @@
import AccountUserInfo from "./components/AccountUserInfo.js"; import AccountUserInfo from "./components/AccountUserInfo.js";
import AccountPrivacy from "./components/AccountPrivacy.js"; import AccountPrivacy from "./components/AccountPrivacy.js";
import AccountContact from "./components/AccountContact.js"; import AccountContact from "./components/AccountContact.js";
import AccountUserCheck from "./components/AccountUserCheck.js";
const showErrorInfo = (message) => { const showErrorInfo = (message) => {
$('body').toast({ $('body').toast({
@ -263,7 +265,7 @@
MessageDelete, MessageUpdate, MessageReact, MessageRevoke, MessageDelete, MessageUpdate, MessageReact, MessageRevoke,
GroupList, GroupCreate, GroupJoinWithLink, GroupAddParticipants, GroupList, GroupCreate, GroupJoinWithLink, GroupAddParticipants,
NewsletterList, NewsletterList,
AccountAvatar, AccountUserInfo, AccountPrivacy, AccountChangeAvatar, AccountContact, AccountChangePushName
AccountAvatar, AccountUserInfo, AccountPrivacy, AccountChangeAvatar, AccountContact, AccountChangePushName, AccountUserCheck
}, },
delimiters: ['[[', ']]'], delimiters: ['[[', ']]'],
data() { data() {

Loading…
Cancel
Save