Skip to content

Commit d285485

Browse files
authored
Merge pull request #184 from shridarpatil/fix/centralize-account-decrypt
fix: centralize WhatsApp account fetch with decryption
2 parents 8e138ca + 70a7ee1 commit d285485

File tree

13 files changed

+232
-103
lines changed

13 files changed

+232
-103
lines changed

frontend/src/assets/index.css

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
--muted-foreground: 0 0% 45%;
5959
--accent: 0 0% 96%;
6060
--accent-foreground: 0 0% 9%;
61-
--destructive: 0 84% 60%;
61+
--destructive: 0 72% 51%;
6262
--destructive-foreground: 0 0% 100%;
6363
--border: 0 0% 90%;
6464
--input: 0 0% 90%;
@@ -319,6 +319,16 @@
319319
color: #e9edef;
320320
}
321321

322+
.chat-bubble-outgoing .text-destructive {
323+
color: #fd7878fc;
324+
font-size: 0.80rem;
325+
}
326+
327+
.light .chat-bubble-outgoing .text-destructive {
328+
color: #dc2626;
329+
font-size: 0.80rem;
330+
}
331+
322332
/* Time and status */
323333
.chat-bubble-time {
324334
@apply text-[10px] mt-1 flex items-center gap-1.5 float-right;

internal/handlers/accounts.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,10 @@ func (a *App) UpdateAccount(r *fastglue.Request) error {
185185
return nil
186186
}
187187

188-
account, err := findByIDAndOrg[models.WhatsAppAccount](a.DB, r, id, orgID, "Account")
188+
account, err := a.resolveWhatsAppAccountByID(r, id, orgID)
189189
if err != nil {
190190
return nil
191191
}
192-
a.decryptAccountSecrets(account)
193192

194193
var req AccountRequest
195194
if err := a.decodeRequest(r, &req); err != nil {
@@ -300,11 +299,10 @@ func (a *App) TestAccountConnection(r *fastglue.Request) error {
300299
return nil
301300
}
302301

303-
account, err := findByIDAndOrg[models.WhatsAppAccount](a.DB, r, id, orgID, "Account")
302+
account, err := a.resolveWhatsAppAccountByID(r, id, orgID)
304303
if err != nil {
305304
return nil
306305
}
307-
a.decryptAccountSecrets(account)
308306

309307
// Use the comprehensive validation function
310308
if err := a.validateAccountCredentials(account.PhoneID, account.BusinessID, account.AccessToken, account.APIVersion); err != nil {
@@ -425,11 +423,10 @@ func (a *App) SubscribeApp(r *fastglue.Request) error {
425423
return nil
426424
}
427425

428-
account, err := findByIDAndOrg[models.WhatsAppAccount](a.DB, r, id, orgID, "Account")
426+
account, err := a.resolveWhatsAppAccountByID(r, id, orgID)
429427
if err != nil {
430428
return nil
431429
}
432-
a.decryptAccountSecrets(account)
433430

434431
// Subscribe the app to webhooks
435432
ctx := context.Background()

internal/handlers/business_profile.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package handlers
22

33
import (
4-
"github.com/shridarpatil/whatomate/internal/models"
54
"github.com/shridarpatil/whatomate/pkg/whatsapp"
65
"github.com/valyala/fasthttp"
76
"github.com/zerodha/fastglue"
@@ -19,7 +18,7 @@ func (a *App) GetBusinessProfile(r *fastglue.Request) error {
1918
return nil
2019
}
2120

22-
account, err := findByIDAndOrg[models.WhatsAppAccount](a.DB, r, id, orgID, "Account")
21+
account, err := a.resolveWhatsAppAccountByID(r, id, orgID)
2322
if err != nil {
2423
return nil
2524
}
@@ -49,7 +48,7 @@ func (a *App) UpdateBusinessProfile(r *fastglue.Request) error {
4948
return nil
5049
}
5150

52-
account, err := findByIDAndOrg[models.WhatsAppAccount](a.DB, r, id, orgID, "Account")
51+
account, err := a.resolveWhatsAppAccountByID(r, id, orgID)
5352
if err != nil {
5453
return nil
5554
}
@@ -89,7 +88,7 @@ func (a *App) UpdateProfilePicture(r *fastglue.Request) error {
8988
return nil
9089
}
9190

92-
account, err := findByIDAndOrg[models.WhatsAppAccount](a.DB, r, id, orgID, "Account")
91+
account, err := a.resolveWhatsAppAccountByID(r, id, orgID)
9392
if err != nil {
9493
return nil
9594
}

internal/handlers/campaigns.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,7 @@ func (a *App) CreateCampaign(r *fastglue.Request) error {
164164
}
165165

166166
// Validate WhatsApp account exists
167-
var account models.WhatsAppAccount
168-
if err := a.DB.Where("name = ? AND organization_id = ?", req.WhatsAppAccount, orgID).First(&account).Error; err != nil {
167+
if _, err := a.resolveWhatsAppAccount(orgID, req.WhatsAppAccount); err != nil {
169168
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "WhatsApp account not found", nil, "")
170169
}
171170

@@ -786,8 +785,8 @@ func (a *App) UploadCampaignMedia(r *fastglue.Request) error {
786785
}
787786

788787
// Get WhatsApp account
789-
var account models.WhatsAppAccount
790-
if err := a.DB.Where("name = ? AND organization_id = ?", campaign.WhatsAppAccount, orgID).First(&account).Error; err != nil {
788+
account, err := a.resolveWhatsAppAccount(orgID, campaign.WhatsAppAccount)
789+
if err != nil {
791790
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "WhatsApp account not found", nil, "")
792791
}
793792

@@ -837,7 +836,7 @@ func (a *App) UploadCampaignMedia(r *fastglue.Request) error {
837836
}
838837

839838
// Upload to WhatsApp
840-
waAccount := a.toWhatsAppAccount(&account)
839+
waAccount := a.toWhatsAppAccount(account)
841840

842841
ctx := r.RequestCtx
843842
mediaID, err := a.WhatsApp.UploadMedia(ctx, waAccount, data, mimeType, fileHeader.Filename)

internal/handlers/catalog.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,14 @@ func (a *App) CreateCatalog(r *fastglue.Request) error {
111111
}
112112

113113
// Get WhatsApp account
114-
var account models.WhatsAppAccount
115-
if err := a.DB.Where("organization_id = ? AND name = ?", orgID, req.WhatsAppAccount).First(&account).Error; err != nil {
114+
account, err := a.resolveWhatsAppAccount(orgID, req.WhatsAppAccount)
115+
if err != nil {
116116
return r.SendErrorEnvelope(fasthttp.StatusNotFound, "WhatsApp account not found", nil, "")
117117
}
118118

119119
// Create catalog in Meta
120120
ctx := context.Background()
121-
waAccount := a.toWhatsAppAccount(&account)
121+
waAccount := a.toWhatsAppAccount(account)
122122

123123
metaCatalogID, err := a.WhatsApp.CreateCatalog(ctx, waAccount, req.Name)
124124
if err != nil {
@@ -188,14 +188,14 @@ func (a *App) DeleteCatalog(r *fastglue.Request) error {
188188
}
189189

190190
// Get WhatsApp account
191-
var account models.WhatsAppAccount
192-
if err := a.DB.Where("organization_id = ? AND name = ?", orgID, catalog.WhatsAppAccount).First(&account).Error; err != nil {
191+
account, err := a.resolveWhatsAppAccount(orgID, catalog.WhatsAppAccount)
192+
if err != nil {
193193
return r.SendErrorEnvelope(fasthttp.StatusNotFound, "WhatsApp account not found", nil, "")
194194
}
195195

196196
// Delete from Meta
197197
ctx := context.Background()
198-
waAccount := a.toWhatsAppAccount(&account)
198+
waAccount := a.toWhatsAppAccount(account)
199199

200200
if err := a.WhatsApp.DeleteCatalog(ctx, waAccount, catalog.MetaCatalogID); err != nil {
201201
a.Log.Error("Failed to delete catalog from Meta", "error", err)
@@ -231,14 +231,14 @@ func (a *App) SyncCatalogs(r *fastglue.Request) error {
231231
}
232232

233233
// Get WhatsApp account
234-
var account models.WhatsAppAccount
235-
if err := a.DB.Where("organization_id = ? AND name = ?", orgID, req.WhatsAppAccount).First(&account).Error; err != nil {
234+
account, err := a.resolveWhatsAppAccount(orgID, req.WhatsAppAccount)
235+
if err != nil {
236236
return r.SendErrorEnvelope(fasthttp.StatusNotFound, "WhatsApp account not found", nil, "")
237237
}
238238

239239
// Fetch catalogs from Meta
240240
ctx := context.Background()
241-
waAccount := a.toWhatsAppAccount(&account)
241+
waAccount := a.toWhatsAppAccount(account)
242242

243243
metaCatalogs, err := a.WhatsApp.ListCatalogs(ctx, waAccount)
244244
if err != nil {
@@ -343,8 +343,8 @@ func (a *App) CreateCatalogProduct(r *fastglue.Request) error {
343343
}
344344

345345
// Get WhatsApp account
346-
var account models.WhatsAppAccount
347-
if err := a.DB.Where("organization_id = ? AND name = ?", orgID, catalog.WhatsAppAccount).First(&account).Error; err != nil {
346+
account, err := a.resolveWhatsAppAccount(orgID, catalog.WhatsAppAccount)
347+
if err != nil {
348348
return r.SendErrorEnvelope(fasthttp.StatusNotFound, "WhatsApp account not found", nil, "")
349349
}
350350

@@ -355,7 +355,7 @@ func (a *App) CreateCatalogProduct(r *fastglue.Request) error {
355355

356356
// Create product in Meta
357357
ctx := context.Background()
358-
waAccount := a.toWhatsAppAccount(&account)
358+
waAccount := a.toWhatsAppAccount(account)
359359

360360
productInput := &whatsapp.ProductInput{
361361
Name: req.Name,
@@ -445,14 +445,14 @@ func (a *App) UpdateCatalogProduct(r *fastglue.Request) error {
445445
}
446446

447447
// Get WhatsApp account
448-
var account models.WhatsAppAccount
449-
if err := a.DB.Where("organization_id = ? AND name = ?", orgID, catalog.WhatsAppAccount).First(&account).Error; err != nil {
448+
account, err := a.resolveWhatsAppAccount(orgID, catalog.WhatsAppAccount)
449+
if err != nil {
450450
return r.SendErrorEnvelope(fasthttp.StatusNotFound, "WhatsApp account not found", nil, "")
451451
}
452452

453453
// Update product in Meta
454454
ctx := context.Background()
455-
waAccount := a.toWhatsAppAccount(&account)
455+
waAccount := a.toWhatsAppAccount(account)
456456

457457
productInput := &whatsapp.ProductInput{
458458
Name: req.Name,
@@ -523,14 +523,14 @@ func (a *App) DeleteCatalogProduct(r *fastglue.Request) error {
523523
}
524524

525525
// Get WhatsApp account
526-
var account models.WhatsAppAccount
527-
if err := a.DB.Where("organization_id = ? AND name = ?", orgID, catalog.WhatsAppAccount).First(&account).Error; err != nil {
526+
account, err := a.resolveWhatsAppAccount(orgID, catalog.WhatsAppAccount)
527+
if err != nil {
528528
return r.SendErrorEnvelope(fasthttp.StatusNotFound, "WhatsApp account not found", nil, "")
529529
}
530530

531531
// Delete from Meta
532532
ctx := context.Background()
533-
waAccount := a.toWhatsAppAccount(&account)
533+
waAccount := a.toWhatsAppAccount(account)
534534

535535
if err := a.WhatsApp.DeleteProduct(ctx, waAccount, product.MetaProductID); err != nil {
536536
a.Log.Error("Failed to delete product from Meta", "error", err)

internal/handlers/contacts.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -476,8 +476,7 @@ func (a *App) markMessagesAsRead(orgID uuid.UUID, contactID uuid.UUID, contact *
476476
a.DB.Model(contact).Update("is_read", true)
477477

478478
if len(unreadMessages) > 0 && contact.WhatsAppAccount != "" {
479-
var account models.WhatsAppAccount
480-
if err := a.DB.Where("organization_id = ? AND name = ?", orgID, contact.WhatsAppAccount).First(&account).Error; err == nil {
479+
if account, err := a.resolveWhatsAppAccount(orgID, contact.WhatsAppAccount); err == nil {
481480
if account.AutoReadReceipt {
482481
a.wg.Add(1)
483482
go func() {
@@ -486,7 +485,7 @@ func (a *App) markMessagesAsRead(orgID uuid.UUID, contactID uuid.UUID, contact *
486485
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
487486
defer cancel()
488487

489-
waAccount := a.toWhatsAppAccount(&account)
488+
waAccount := a.toWhatsAppAccount(account)
490489
for _, msg := range unreadMessages {
491490
// Check if context was cancelled
492491
if ctx.Err() != nil {
@@ -658,6 +657,7 @@ func (a *App) resolveWhatsAppAccount(orgID uuid.UUID, accountName string) (*mode
658657
if err := a.DB.Where("name = ? AND organization_id = ?", accountName, orgID).First(&account).Error; err != nil {
659658
return nil, fmt.Errorf("WhatsApp account not found")
660659
}
660+
a.decryptAccountSecrets(&account)
661661
return &account, nil
662662
}
663663

@@ -668,9 +668,20 @@ func (a *App) resolveWhatsAppAccount(orgID uuid.UUID, accountName string) (*mode
668668
return nil, fmt.Errorf("no WhatsApp account configured")
669669
}
670670
}
671+
a.decryptAccountSecrets(&account)
671672
return &account, nil
672673
}
673674

675+
// resolveWhatsAppAccountByID fetches a WhatsApp account by UUID and org, decrypts secrets.
676+
func (a *App) resolveWhatsAppAccountByID(r *fastglue.Request, id, orgID uuid.UUID) (*models.WhatsAppAccount, error) {
677+
account, err := findByIDAndOrg[models.WhatsAppAccount](a.DB, r, id, orgID, "Account")
678+
if err != nil {
679+
return nil, err
680+
}
681+
a.decryptAccountSecrets(account)
682+
return account, nil
683+
}
684+
674685
func truncateString(s string, maxLen int) string {
675686
if len(s) <= maxLen {
676687
return s

internal/handlers/flows.go

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,7 @@ func (a *App) CreateFlow(r *fastglue.Request) error {
111111
}
112112

113113
// Verify account exists and belongs to org
114-
var account models.WhatsAppAccount
115-
if err := a.DB.Where("organization_id = ? AND name = ?", orgID, req.WhatsAppAccount).First(&account).Error; err != nil {
114+
if _, err := a.resolveWhatsAppAccount(orgID, req.WhatsAppAccount); err != nil {
116115
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "WhatsApp account not found", nil, "")
117116
}
118117

@@ -279,14 +278,14 @@ func (a *App) SaveFlowToMeta(r *fastglue.Request) error {
279278
}
280279

281280
// Get the WhatsApp account
282-
var account models.WhatsAppAccount
283-
if err := a.DB.Where("organization_id = ? AND name = ?", orgID, flow.WhatsAppAccount).First(&account).Error; err != nil {
281+
account, err := a.resolveWhatsAppAccount(orgID, flow.WhatsAppAccount)
282+
if err != nil {
284283
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "WhatsApp account not found", nil, "")
285284
}
286285

287286
// Create WhatsApp API client
288287
waClient := whatsapp.New(a.Log)
289-
waAccount := a.toWhatsAppAccount(&account)
288+
waAccount := a.toWhatsAppAccount(account)
290289

291290
a.Log.Info("SaveFlowToMeta: Account details",
292291
"account_name", account.Name,
@@ -391,14 +390,14 @@ func (a *App) PublishFlow(r *fastglue.Request) error {
391390
}
392391

393392
// Get the WhatsApp account
394-
var account models.WhatsAppAccount
395-
if err := a.DB.Where("organization_id = ? AND name = ?", orgID, flow.WhatsAppAccount).First(&account).Error; err != nil {
393+
account, err := a.resolveWhatsAppAccount(orgID, flow.WhatsAppAccount)
394+
if err != nil {
396395
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "WhatsApp account not found", nil, "")
397396
}
398397

399398
// Create WhatsApp API client
400399
waClient := whatsapp.New(a.Log)
401-
waAccount := a.toWhatsAppAccount(&account)
400+
waAccount := a.toWhatsAppAccount(account)
402401

403402
ctx := context.Background()
404403

@@ -460,13 +459,13 @@ func (a *App) DeprecateFlow(r *fastglue.Request) error {
460459
// Call Meta API to deprecate the flow if we have a Meta flow ID
461460
if flow.MetaFlowID != "" {
462461
// Get the WhatsApp account
463-
var account models.WhatsAppAccount
464-
if err := a.DB.Where("organization_id = ? AND name = ?", orgID, flow.WhatsAppAccount).First(&account).Error; err != nil {
462+
account, err := a.resolveWhatsAppAccount(orgID, flow.WhatsAppAccount)
463+
if err != nil {
465464
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "WhatsApp account not found", nil, "")
466465
}
467466

468467
waClient := whatsapp.New(a.Log)
469-
waAccount := a.toWhatsAppAccount(&account)
468+
waAccount := a.toWhatsAppAccount(account)
470469

471470
ctx := context.Background()
472471
if err := waClient.DeprecateFlow(ctx, waAccount, flow.MetaFlowID); err != nil {
@@ -557,14 +556,14 @@ func (a *App) SyncFlows(r *fastglue.Request) error {
557556
}
558557

559558
// Get the WhatsApp account
560-
var account models.WhatsAppAccount
561-
if err := a.DB.Where("organization_id = ? AND name = ?", orgID, req.WhatsAppAccount).First(&account).Error; err != nil {
559+
account, err := a.resolveWhatsAppAccount(orgID, req.WhatsAppAccount)
560+
if err != nil {
562561
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "WhatsApp account not found", nil, "")
563562
}
564563

565564
// Create WhatsApp API client
566565
waClient := whatsapp.New(a.Log)
567-
waAccount := a.toWhatsAppAccount(&account)
566+
waAccount := a.toWhatsAppAccount(account)
568567

569568
ctx := context.Background()
570569

0 commit comments

Comments
 (0)