39 changed files with 940 additions and 280 deletions
-
4.gitignore
-
347docs/openapi.yaml
-
8readme.md
-
2src/cmd/root.go
-
2src/config/settings.go
-
6src/domains/message/message.go
-
11src/domains/newsletter/newsletter.go
-
4src/domains/user/account.go
-
1src/domains/user/user.go
-
22src/go.mod
-
25src/go.sum
-
20src/internal/rest/message.go
-
32src/internal/rest/newsletter.go
-
13src/internal/rest/user.go
-
32src/pkg/whatsapp/whatsapp.go
-
27src/services/message.go
-
32src/services/newsletter.go
-
20src/services/send.go
-
14src/services/user.go
-
14src/validations/message_validation.go
-
20src/validations/newsletter_validation.go
-
26src/views/components/AccountAvatar.js
-
24src/views/components/AccountUserInfo.js
-
2src/views/components/GroupManageParticipants.js
-
27src/views/components/MessageDelete.js
-
27src/views/components/MessageReact.js
-
27src/views/components/MessageRevoke.js
-
27src/views/components/MessageUpdate.js
-
117src/views/components/NewsletterList.js
-
26src/views/components/SendAudio.js
-
27src/views/components/SendContact.js
-
27src/views/components/SendFile.js
-
27src/views/components/SendImage.js
-
27src/views/components/SendLocation.js
-
26src/views/components/SendMessage.js
-
29src/views/components/SendPoll.js
-
27src/views/components/SendVideo.js
-
52src/views/components/generic/FormRecipient.js
-
19src/views/index.html
@ -0,0 +1,11 @@ |
|||
package newsletter |
|||
|
|||
import "context" |
|||
|
|||
type INewsletterService interface { |
|||
Unfollow(ctx context.Context, request UnfollowRequest) (err error) |
|||
} |
|||
|
|||
type UnfollowRequest struct { |
|||
NewsletterID string `json:"newsletter_id" form:"newsletter_id"` |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
package rest |
|||
|
|||
import ( |
|||
domainNewsletter "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/newsletter" |
|||
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/utils" |
|||
"github.com/gofiber/fiber/v2" |
|||
) |
|||
|
|||
type Newsletter struct { |
|||
Service domainNewsletter.INewsletterService |
|||
} |
|||
|
|||
func InitRestNewsletter(app *fiber.App, service domainNewsletter.INewsletterService) Newsletter { |
|||
rest := Newsletter{Service: service} |
|||
app.Post("/newsletter/unfollow", rest.Unfollow) |
|||
return rest |
|||
} |
|||
|
|||
func (controller *Newsletter) Unfollow(c *fiber.Ctx) error { |
|||
var request domainNewsletter.UnfollowRequest |
|||
err := c.BodyParser(&request) |
|||
utils.PanicIfNeeded(err) |
|||
|
|||
err = controller.Service.Unfollow(c.UserContext(), request) |
|||
utils.PanicIfNeeded(err) |
|||
|
|||
return c.JSON(utils.ResponseData{ |
|||
Status: 200, |
|||
Code: "SUCCESS", |
|||
Message: "Success unfollow newsletter", |
|||
}) |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
package services |
|||
|
|||
import ( |
|||
"context" |
|||
domainNewsletter "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/newsletter" |
|||
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/whatsapp" |
|||
"github.com/aldinokemal/go-whatsapp-web-multidevice/validations" |
|||
"go.mau.fi/whatsmeow" |
|||
) |
|||
|
|||
type newsletterService struct { |
|||
WaCli *whatsmeow.Client |
|||
} |
|||
|
|||
func NewNewsletterService(waCli *whatsmeow.Client) domainNewsletter.INewsletterService { |
|||
return &newsletterService{ |
|||
WaCli: waCli, |
|||
} |
|||
} |
|||
|
|||
func (service newsletterService) Unfollow(ctx context.Context, request domainNewsletter.UnfollowRequest) (err error) { |
|||
if err = validations.ValidateUnfollowNewsletter(ctx, request); err != nil { |
|||
return err |
|||
} |
|||
|
|||
JID, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.NewsletterID) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
return service.WaCli.UnfollowNewsletter(JID) |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
package validations |
|||
|
|||
import ( |
|||
"context" |
|||
domainNewsletter "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/newsletter" |
|||
pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error" |
|||
validation "github.com/go-ozzo/ozzo-validation/v4" |
|||
) |
|||
|
|||
func ValidateUnfollowNewsletter(ctx context.Context, request domainNewsletter.UnfollowRequest) error { |
|||
err := validation.ValidateStructWithContext(ctx, &request, |
|||
validation.Field(&request.NewsletterID, validation.Required), |
|||
) |
|||
|
|||
if err != nil { |
|||
return pkgError.ValidationError(err.Error()) |
|||
} |
|||
|
|||
return nil |
|||
} |
|||
@ -0,0 +1,117 @@ |
|||
export default { |
|||
name: 'ListNewsletter', |
|||
data() { |
|||
return { |
|||
newsletters: [] |
|||
} |
|||
}, |
|||
methods: { |
|||
async openModal() { |
|||
try { |
|||
this.dtClear() |
|||
await this.submitApi(); |
|||
$('#modalNewsletterList').modal('show'); |
|||
this.dtRebuild() |
|||
showSuccessInfo("Newsletters fetched") |
|||
} catch (err) { |
|||
showErrorInfo(err) |
|||
} |
|||
}, |
|||
dtClear() { |
|||
$('#account_newsletters_table').DataTable().destroy(); |
|||
}, |
|||
dtRebuild() { |
|||
$('#account_newsletters_table').DataTable({ |
|||
"pageLength": 100, |
|||
"reloadData": true, |
|||
}).draw(); |
|||
}, |
|||
async handleUnfollowNewsletter(newsletter_id) { |
|||
try { |
|||
const ok = confirm("Are you sure to leave this newsletter?"); |
|||
if (!ok) return; |
|||
|
|||
await this.unfollowNewsletterApi(newsletter_id); |
|||
this.dtClear() |
|||
await this.submitApi(); |
|||
this.dtRebuild() |
|||
showSuccessInfo("Success unfollow newsletter") |
|||
} catch (err) { |
|||
showErrorInfo(err) |
|||
} |
|||
}, |
|||
async unfollowNewsletterApi(newsletter_id) { |
|||
try { |
|||
let payload = { |
|||
newsletter_id: newsletter_id |
|||
}; |
|||
await window.http.post(`/newsletter/unfollow`, payload) |
|||
} catch (error) { |
|||
if (error.response) { |
|||
throw new Error(error.response.data.message); |
|||
} |
|||
throw new Error(error.message); |
|||
|
|||
} |
|||
}, |
|||
async submitApi() { |
|||
try { |
|||
let response = await window.http.get(`/user/my/newsletters`) |
|||
this.newsletters = response.data.results.data; |
|||
} catch (error) { |
|||
if (error.response) { |
|||
throw new Error(error.response.data.message); |
|||
} |
|||
throw new Error(error.message); |
|||
} |
|||
}, |
|||
formatDate: function (value) { |
|||
if (!value) return '' |
|||
if (isNaN(value)) return 'Invalid date'; |
|||
return moment.unix(value).format('LLL'); |
|||
} |
|||
}, |
|||
template: `
|
|||
<div class="green card" @click="openModal" style="cursor: pointer"> |
|||
<div class="content"> |
|||
<a class="ui green right ribbon label">Newsletter</a> |
|||
<div class="header">List Newsletters</div> |
|||
<div class="description"> |
|||
Display all your newsletters |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Modal AccountNewsletter --> |
|||
<div class="ui small modal" id="modalNewsletterList"> |
|||
<i class="close icon"></i> |
|||
<div class="header"> |
|||
My Newsletter List |
|||
</div> |
|||
<div class="content"> |
|||
<table class="ui celled table" id="account_newsletters_table"> |
|||
<thead> |
|||
<tr> |
|||
<th>Newsletter ID</th> |
|||
<th>Name</th> |
|||
<th>Role</th> |
|||
<th>Created At</th> |
|||
<th>Action</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody v-if="newsletters != null"> |
|||
<tr v-for="n in newsletters"> |
|||
<td>{{ n.id.split('@')[0] }}</td> |
|||
<td>{{ n.thread_metadata?.name?.text || 'N/A' }}</td> |
|||
<td>{{ n.viewer_metadata?.role || 'N/A' }}</td> |
|||
<td>{{ formatDate(n.thread_metadata?.creation_time) }}</td> |
|||
<td> |
|||
<button class="ui red tiny button" @click="handleUnfollowNewsletter(n.id)">Unfollow</button> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
`
|
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
export default { |
|||
name: 'FormRecipient', |
|||
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' }, |
|||
{ value: window.TYPEGROUP, text: 'Group Message' }, |
|||
{ value: window.TYPENEWSLETTER, text: 'Newsletter' } |
|||
]; |
|||
}, |
|||
methods: { |
|||
updateType(event) { |
|||
this.$emit('update:type', event.target.value); |
|||
}, |
|||
updatePhone(event) { |
|||
this.$emit('update:phone', event.target.value); |
|||
} |
|||
}, |
|||
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 / Group ID</label> |
|||
<input :value="phone" aria-label="wa identifier" @input="updatePhone"> |
|||
<input :value="phone_id" disabled aria-label="whatsapp_id"> |
|||
</div> |
|||
`
|
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue