Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Adding new route for check if user is in whatsapp #231

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ main
main.exe
*.jpe
src/pkged.go
storages
storages
.tool-versions

10 changes: 10 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ 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)

## CURL for the api

#### You need to encode to Base64 your user:pass [basic-auth] and pass in header

- curl -X 'GET' 'http://127.0.0.1:3000/user/check?phone=YOUR_PHONE' -H 'accept: application/json' \
-H 'Authorization: Basic qwertyASDFzxc='
- curl -X 'GET' 'http://127.0.0.1:3000/user/check?phone=YOUR_PHONE' -H 'accept: application/json'
RuanAyram marked this conversation as resolved.
Show resolved Hide resolved

| Feature | Menu | Method | URL |
|---------|------------------------------|--------|-------------------------------|
| ✅ | Login with Scan QR | GET | /app/login |
Expand All @@ -111,6 +119,7 @@ You can fork or edit this source code !
| ✅ | Reconnect | GET | /app/reconnect |
| ✅ | Devices | GET | /app/devices |
| ✅ | User Info | GET | /user/info |
| ✅ | Check User is on whatsapp | GET | /user/check |
| ✅ | User Avatar | GET | /user/avatar |
| ✅ | User My Groups | GET | /user/my/groups |
| ✅ | User My Newsletter | GET | /user/my/newsletters |
Expand Down Expand Up @@ -164,6 +173,7 @@ You can fork or edit this source code !
| 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) |
| Check User | ![Check User ](https://i.ibb.co/92gVZrx/Check-User.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) |
Expand Down
19 changes: 19 additions & 0 deletions src/domains/user/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ type InfoRequest struct {
Phone string `json:"phone" query:"phone"`
}

type CheckRequest struct {
Phone string `json:"phone" query:"phone"`
}
RuanAyram marked this conversation as resolved.
Show resolved Hide resolved

type InfoResponseDataDevice struct {
User string
Agent uint8
Expand All @@ -21,10 +25,25 @@ type InfoResponseData struct {
Devices []InfoResponseDataDevice `json:"devices"`
}

type CheckResponseData struct {
Query string `json:"query"`
IsInWhatsapp bool `json:"IsInWhatsapp"`
VerifiedName string `json:"verified_name"`
JID string `json:"jid"`
}
RuanAyram marked this conversation as resolved.
Show resolved Hide resolved

type InfoResponse struct {
Data []InfoResponseData `json:"data"`
}

type CheckResponse struct {
Data []CheckResponseData `json:"data"`
}

type UserCollection struct {
Users []CheckResponseData
}
RuanAyram marked this conversation as resolved.
Show resolved Hide resolved

type AvatarRequest struct {
Phone string `json:"phone" query:"phone"`
IsPreview bool `json:"is_preview" query:"is_preview"`
Expand Down
1 change: 1 addition & 0 deletions src/domains/user/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

type IUserService interface {
Info(ctx context.Context, request InfoRequest) (response InfoResponse, err error)
Check(ctx context.Context, request CheckRequest) (response CheckResponse, err error)
Avatar(ctx context.Context, request AvatarRequest) (response AvatarResponse, err error)
MyListGroups(ctx context.Context) (response MyListGroupsResponse, err error)
MyListNewsletter(ctx context.Context) (response MyListNewsletterResponse, err error)
Expand Down
20 changes: 20 additions & 0 deletions src/internal/rest/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type User struct {
func InitRestUser(app *fiber.App, service domainUser.IUserService) User {
rest := User{Service: service}
app.Get("/user/info", rest.UserInfo)
app.Get("/user/check", rest.UserCheck)
app.Get("/user/avatar", rest.UserAvatar)
app.Get("/user/my/privacy", rest.UserMyPrivacySetting)
app.Get("/user/my/groups", rest.UserMyListGroups)
Expand All @@ -40,6 +41,25 @@ func (controller *User) UserInfo(c *fiber.Ctx) error {
})
}

func (controller *User) UserCheck(c *fiber.Ctx) error {
var request domainUser.CheckRequest
err := c.QueryParser(&request)
utils.PanicIfNeeded(err)

whatsapp.SanitizePhone(&request.Phone)

response, err := controller.Service.Check(c.UserContext(), request)
utils.PanicIfNeeded(err)

return c.JSON(utils.ResponseData{
Status: 200,
Code: "SUCCESS",
Message: "Success get user info",
Results: response.Data[0],
})
}


func (controller *User) UserAvatar(c *fiber.Ctx) error {
var request domainUser.AvatarRequest
err := c.QueryParser(&request)
Expand Down
35 changes: 35 additions & 0 deletions src/services/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,41 @@ func (service userService) Info(ctx context.Context, request domainUser.InfoRequ
return response, nil
}

func (service userService) Check(ctx context.Context, request domainUser.CheckRequest) (response domainUser.CheckResponse, err error) {
err = validations.ValidateUserCheck(ctx, request)
if err != nil {
return response, err
}

resp, err := service.WaCli.IsOnWhatsApp([]string{request.Phone})
if err != nil {
return response, err
}

uc := new(domainUser.UserCollection)
if len(resp) == 0 {
return response, errors.New("no results found")
}
for _, item := range resp {
verifiedName := ""
if item.VerifiedName != nil {
verifiedName = item.VerifiedName.Details.GetVerifiedName()
}
msg := domainUser.CheckResponseData{
Query: item.Query,
IsInWhatsapp: item.IsIn,
JID: item.JID.String(),
VerifiedName: verifiedName,
}
uc.Users = append(uc.Users, msg)
}

if len(uc.Users) > 0 {
response.Data = append(response.Data, uc.Users[0])
}
return response, nil
}

func (service userService) Avatar(ctx context.Context, request domainUser.AvatarRequest) (response domainUser.AvatarResponse, err error) {

chanResp := make(chan domainUser.AvatarResponse)
Expand Down
11 changes: 11 additions & 0 deletions src/validations/user_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ func ValidateUserInfo(ctx context.Context, request domainUser.InfoRequest) error

return nil
}
func ValidateUserCheck(ctx context.Context, request domainUser.CheckRequest) error {
err := validation.ValidateStructWithContext(ctx, &request,
validation.Field(&request.Phone, validation.Required),
)

if err != nil {
return pkgError.ValidationError(err.Error())
}

return nil
}
func ValidateUserAvatar(ctx context.Context, request domainUser.AvatarRequest) error {
err := validation.ValidateStructWithContext(ctx, &request,
validation.Field(&request.Phone, validation.Required),
Expand Down
117 changes: 117 additions & 0 deletions src/views/components/AccountUserCheck.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import FormCheckUserRecipient from "./generic/FormCheckUserRecipient.js";

export default {
name: 'AccountUserCheck',
components: {
FormCheckUserRecipient
},
data() {
return {
type: window.TYPEUSER,
phone: '',
//
is_in_whatsapp: null,
jid: null,
verified_name: null,
query: null,
code: null,
//
loading: false,
}
},

computed: {
phone_id() {
return this.phone + this.type;
}
},
methods: {
async openModal() {
this.handleReset();
$('#modalUserCheck').modal('show');
},
async handleSubmit() {
try {
await this.submitApi();
showSuccessInfo("Info fetched")
} catch (err) {
showErrorInfo(err)
}
},
async submitApi() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you also add is validate method like existing else component?

this.loading = true;
try {
let response = await window.http.get(`/user/check?phone=${this.phone_id}`)
this.is_in_whatsapp = response.data.results.IsInWhatsapp;
this.jid = response.data.results.jid;
this.verified_name = response.data.results.verified_name;
this.query = response.data.results.query;
this.code = response.code;
} catch (error) {
if (error.response) {
this.verified_name = null;
this.jid = null;
throw new Error(error.response.data.message);
}
this.verified_name = null;
this.jid = null;
throw new Error(error.message);
} finally {
this.loading = false;
}
},
handleReset() {
this.phone = '';
this.is_in_whatsapp = null;
this.jid = null;
this.verified_name = null;
this.query = null;
this.code = null;
this.type = window.TYPEUSER;
}
},
template: `
<div class="green card" @click="openModal" style="cursor: pointer;">
<div class="content">
<div class="header">User Check</div>
<div class="description">
You can check if the user exists on whatapp
</div>
</div>
</div>


<!-- Modal UserInfo -->
<div class="ui small modal" id="modalUserCheck">
<i class="close icon"></i>
<div class="header">
Search User Information
</div>
<div class="content">
<form class="ui form">
<FormCheckUserRecipient v-model:type="type" v-model:phone="phone"/>

<button type="button" class="ui primary button" :class="{'loading': loading}"
@click="handleSubmit">
Search
</button>
</form>

<div v-if="is_in_whatsapp != null" class="center">
<ol>
<li>Name: {{ verified_name }}</li>
<li>JID: {{ jid }}</li>
</ol>
</div>
<div v-else class="center">
<div v-if="code == 'INVALID_JID'" class="center">
<ol>
<li>Name: {{ verified_name }}</li>
<li>JID: {{ jid }}</li>
</ol>
</div>
</div>
</div>
</div>
`
}
50 changes: 50 additions & 0 deletions src/views/components/generic/FormCheckUserRecipient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
export default {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this generic

name: 'FormCheckUserRecipient',
props: {
type: {
type: String,
required: true
},
phone: {
type: String,
required: true
},
},
data() {
return {
recipientTypes: []
};
},
computed: {
phone_id() {
return this.phone + this.type;
}
},
mounted() {
this.recipientTypes = [
{ value: window.TYPEUSER, text: 'Private Message' },
];
RuanAyram marked this conversation as resolved.
Show resolved Hide resolved
},
methods: {
updateType(event) {
this.$emit('update:type', event.target.value);
},
updatePhone(event) {
this.$emit('update:phone', event.target.value);
}
RuanAyram marked this conversation as resolved.
Show resolved Hide resolved
},
template: `
<div class="field">
<label>Type</label>
<select name="type" @change="updateType" class="ui dropdown">
<option v-for="type in recipientTypes" :value="type.value">{{ type.text }}</option>
</select>
</div>

<div class="field">
<label>Phone</label>
<input :value="phone" aria-label="wa identifier" @input="updatePhone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
RuanAyram marked this conversation as resolved.
Show resolved Hide resolved
`
}
4 changes: 3 additions & 1 deletion src/views/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ <h1 class="ui header center aligned">Whatsapp API Multi Device ({{ .AppVersion }
<div class="ui three column doubling grid cards">
<account-avatar></account-avatar>
<account-user-info></account-user-info>
<account-user-check></account-user-check>
<account-privacy></account-privacy>
</div>

Expand Down Expand Up @@ -158,6 +159,7 @@ <h1 class="ui header center aligned">Whatsapp API Multi Device ({{ .AppVersion }
import GroupAddParticipants from "./components/GroupManageParticipants.js";
import AccountAvatar from "./components/AccountAvatar.js";
import AccountUserInfo from "./components/AccountUserInfo.js";
import AccountUserCheck from "./components/AccountUserCheck.js";
import AccountPrivacy from "./components/AccountPrivacy.js";
import NewsletterList from "./components/NewsletterList.js";

Expand Down Expand Up @@ -198,7 +200,7 @@ <h1 class="ui header center aligned">Whatsapp API Multi Device ({{ .AppVersion }
MessageDelete, MessageUpdate, MessageReact, MessageRevoke,
GroupList, GroupCreate, GroupJoinWithLink, GroupAddParticipants,
NewsletterList,
AccountAvatar, AccountUserInfo, AccountPrivacy
AccountAvatar, AccountUserInfo, AccountUserCheck, AccountPrivacy
},
delimiters: ['[[', ']]'],
data() {
Expand Down