Files
gochat/internal/model/channel/whatsapp.go
T
2026-06-04 15:44:48 +08:00

122 lines
5.3 KiB
Go

package channel
import (
"github.com/gochat/gochat/internal/model"
)
// ChannelWhatsApp represents a WhatsApp Business channel configuration.
// Reference: Chatwoot app/models/channel/whatsapp.rb
//
// Chatwoot's ChannelWhatsApp (Channel::Whatsapp) model attributes:
// - account_id: FK to Account
// - phone_number: WhatsApp phone number in international format
// - phone_number_id: WhatsApp Business Phone Number ID (from Meta Business Manager)
// - business_account_id: WhatsApp Business Account ID (WABA ID)
// - provider: WhatsApp provider backend (whatsapp_cloud or 360dialog)
// - message_templates: Cached WhatsApp message templates JSON
// - template_namespace: WhatsApp template namespace (deprecated, retained for migration)
// - provider_config: Provider-specific configuration JSON
// - reauthorization_required: Flag when token/API connection fails
//
// Chatwoot lifecycle hooks:
// - before_create :validate_provider_config (checks provider-specific setup)
// - after_create :setup_webhook (registers webhook with provider)
// - after_destroy :delete_webhook (removes webhook registration)
//
// gochat enhancements beyond Chatwoot:
// - webhook_verify_token: Token for WhatsApp webhook verification (Cloud API hub.mode=subscribe)
// - auto_create_contact: Whether to auto-create contacts from incoming messages
// - provider_config stored as typed JSON rather than serialized hash
//
// WhatsApp supports two provider backends:
// - whatsapp_cloud: Meta WhatsApp Business Cloud API (https://developers.facebook.com/docs/whatsapp/cloud-api)
// - 360dialog: 360dialog WhatsApp Business API (https://docs.360dialog.com/docs/whatsapp-api)
type ChannelWhatsApp struct {
model.Base // ID, CreatedAt, UpdatedAt, DeletedAt (soft delete via GORM)
// Account foreign key
AccountID uint `gorm:"index;not null" json:"account_id"`
// Inbox foreign key — links to the Inbox that wraps this channel
InboxID uint `gorm:"not null;uniqueIndex" json:"inbox_id"`
// WhatsApp phone number in international format (e.g., "+1234567890")
PhoneNumber string `gorm:"size:50;not null;index" json:"phone_number"`
// WhatsApp Business Phone Number ID — from Meta Business Manager or 360dialog dashboard
// Used as the sender identifier in Cloud API calls
PhoneNumberID string `gorm:"size:255" json:"phone_number_id"`
// WhatsApp Business Account ID (WABA ID) — identifies the WhatsApp Business Account
BusinessAccountID string `gorm:"size:255" json:"business_account_id"`
// Display name of the WhatsApp Business account
WhatsAppAccountName string `gorm:"size:255" json:"whatsapp_account_name"`
// Access token for WhatsApp Business API (Cloud API or 360dialog API)
// For Cloud API: permanent access token from Meta App dashboard
// For 360dialog: API key from 360dialog hub
AccessToken string `gorm:"size:512;not null" json:"access_token"`
// WhatsApp provider backend — determines which API to use
// Reference: model.WhatsAppProvider enum (whatsapp_cloud / 360dialog)
Provider string `gorm:"size:50" json:"provider"`
// Cached WhatsApp message templates (JSON blob)
// Reference: Chatwoot caches templates locally for quick lookup
MessageTemplates string `gorm:"type:text" json:"message_templates"`
// Template namespace (deprecated by WhatsApp, retained for backward compatibility)
TemplateNamespace string `gorm:"size:255" json:"template_namespace"`
// Provider-specific configuration (JSON blob)
// For 360dialog: { "api_key": "...", "namespace": "..." }
// For Cloud API: { "app_id": "...", "webhook_verify_token": "..." }
ProviderConfig string `gorm:"type:text" json:"provider_config"`
// Webhook verify token — used during WhatsApp webhook subscription verification
// Reference: Cloud API GET webhook with hub.mode=subscribe, hub.verify_token
WebhookVerifyToken string `gorm:"size:255" json:"webhook_verify_token"`
// Whether to auto-create contacts from incoming WhatsApp messages
AutoCreateContact bool `gorm:"default:false" json:"auto_create_contact"`
// Flag indicating the channel needs re-authorization (token expired or API failure)
ReauthorizationRequired bool `gorm:"default:false" json:"reauthorization_required"`
// Inbox relationship
Inbox model.Inbox `gorm:"foreignKey:InboxID" json:"inbox,omitempty"`
}
// TableName returns the GORM table name for ChannelWhatsApp.
func (ChannelWhatsApp) TableName() string { return "channel_whatsapps" }
// GetChannelBase returns a ChannelBase populated from ChannelWhatsApp fields.
// Required by the Channelable interface.
func (c *ChannelWhatsApp) GetChannelBase() ChannelBase {
return ChannelBase{
ID: c.ID,
AccountID: c.AccountID,
InboxID: c.InboxID,
ChannelType: c.GetChannelType(),
CreatedAt: c.CreatedAt,
UpdatedAt: c.UpdatedAt,
DeletedAt: c.DeletedAt,
}
}
// GetChannelType returns the channel type identifier.
func (c *ChannelWhatsApp) GetChannelType() string { return "whatsapp" }
// GetInboxID returns the inbox ID for this channel.
func (c *ChannelWhatsApp) GetInboxID() uint { return c.InboxID }
// IsCloudAPI returns true if this channel uses the WhatsApp Cloud API provider.
func (c *ChannelWhatsApp) IsCloudAPI() bool {
return c.Provider == "whatsapp_cloud"
}
// Is360Dialog returns true if this channel uses the 360dialog provider.
func (c *ChannelWhatsApp) Is360Dialog() bool {
return c.Provider == "360dialog"
}