Initial commit: MOPC platform with Docker deployment setup
Full Next.js 15 platform with tRPC, Prisma, PostgreSQL, NextAuth. Includes production Dockerfile (multi-stage, port 7600), docker-compose with registry-based image pull, Gitea Actions CI workflow, nginx config for portal.monaco-opc.com, deployment scripts, and DEPLOYMENT.md guide. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
151
src/lib/whatsapp/index.ts
Normal file
151
src/lib/whatsapp/index.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* WhatsApp Provider Abstraction Layer
|
||||
*
|
||||
* Supports multiple WhatsApp providers with a common interface:
|
||||
* - Meta WhatsApp Business Cloud API
|
||||
* - Twilio WhatsApp
|
||||
*/
|
||||
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import { MetaWhatsAppProvider } from './meta-provider'
|
||||
import { TwilioWhatsAppProvider } from './twilio-provider'
|
||||
|
||||
export interface WhatsAppResult {
|
||||
success: boolean
|
||||
messageId?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
export interface WhatsAppProvider {
|
||||
sendText(to: string, body: string): Promise<WhatsAppResult>
|
||||
sendTemplate(
|
||||
to: string,
|
||||
template: string,
|
||||
params: Record<string, string>
|
||||
): Promise<WhatsAppResult>
|
||||
testConnection(): Promise<{ success: boolean; error?: string }>
|
||||
}
|
||||
|
||||
export type WhatsAppProviderType = 'META' | 'TWILIO'
|
||||
|
||||
/**
|
||||
* Get the configured WhatsApp provider
|
||||
* Returns null if WhatsApp is not enabled or not configured
|
||||
*/
|
||||
export async function getWhatsAppProvider(): Promise<WhatsAppProvider | null> {
|
||||
try {
|
||||
// Check if WhatsApp is enabled
|
||||
const enabledSetting = await prisma.systemSettings.findUnique({
|
||||
where: { key: 'whatsapp_enabled' },
|
||||
})
|
||||
|
||||
if (enabledSetting?.value !== 'true') {
|
||||
return null
|
||||
}
|
||||
|
||||
// Get provider type
|
||||
const providerSetting = await prisma.systemSettings.findUnique({
|
||||
where: { key: 'whatsapp_provider' },
|
||||
})
|
||||
|
||||
const providerType = (providerSetting?.value || 'META') as WhatsAppProviderType
|
||||
|
||||
if (providerType === 'META') {
|
||||
return await createMetaProvider()
|
||||
} else if (providerType === 'TWILIO') {
|
||||
return await createTwilioProvider()
|
||||
}
|
||||
|
||||
return null
|
||||
} catch (error) {
|
||||
console.error('Failed to get WhatsApp provider:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Meta WhatsApp provider from settings
|
||||
*/
|
||||
async function createMetaProvider(): Promise<WhatsAppProvider | null> {
|
||||
const [phoneNumberIdSetting, accessTokenSetting] = await Promise.all([
|
||||
prisma.systemSettings.findUnique({
|
||||
where: { key: 'whatsapp_meta_phone_number_id' },
|
||||
}),
|
||||
prisma.systemSettings.findUnique({
|
||||
where: { key: 'whatsapp_meta_access_token' },
|
||||
}),
|
||||
])
|
||||
|
||||
if (!phoneNumberIdSetting?.value || !accessTokenSetting?.value) {
|
||||
console.warn('Meta WhatsApp not fully configured')
|
||||
return null
|
||||
}
|
||||
|
||||
return new MetaWhatsAppProvider(
|
||||
phoneNumberIdSetting.value,
|
||||
accessTokenSetting.value
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Twilio WhatsApp provider from settings
|
||||
*/
|
||||
async function createTwilioProvider(): Promise<WhatsAppProvider | null> {
|
||||
const [accountSidSetting, authTokenSetting, phoneNumberSetting] = await Promise.all([
|
||||
prisma.systemSettings.findUnique({
|
||||
where: { key: 'whatsapp_twilio_account_sid' },
|
||||
}),
|
||||
prisma.systemSettings.findUnique({
|
||||
where: { key: 'whatsapp_twilio_auth_token' },
|
||||
}),
|
||||
prisma.systemSettings.findUnique({
|
||||
where: { key: 'whatsapp_twilio_phone_number' },
|
||||
}),
|
||||
])
|
||||
|
||||
if (
|
||||
!accountSidSetting?.value ||
|
||||
!authTokenSetting?.value ||
|
||||
!phoneNumberSetting?.value
|
||||
) {
|
||||
console.warn('Twilio WhatsApp not fully configured')
|
||||
return null
|
||||
}
|
||||
|
||||
return new TwilioWhatsAppProvider(
|
||||
accountSidSetting.value,
|
||||
authTokenSetting.value,
|
||||
phoneNumberSetting.value
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if WhatsApp is configured and available
|
||||
*/
|
||||
export async function isWhatsAppEnabled(): Promise<boolean> {
|
||||
const provider = await getWhatsAppProvider()
|
||||
return provider !== null
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current provider type
|
||||
*/
|
||||
export async function getWhatsAppProviderType(): Promise<WhatsAppProviderType | null> {
|
||||
try {
|
||||
const enabledSetting = await prisma.systemSettings.findUnique({
|
||||
where: { key: 'whatsapp_enabled' },
|
||||
})
|
||||
|
||||
if (enabledSetting?.value !== 'true') {
|
||||
return null
|
||||
}
|
||||
|
||||
const providerSetting = await prisma.systemSettings.findUnique({
|
||||
where: { key: 'whatsapp_provider' },
|
||||
})
|
||||
|
||||
return (providerSetting?.value || 'META') as WhatsAppProviderType
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user