File: /home/xedaptot/hi.naniguide.com/app/Models/UniboxAccount.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class UniboxAccount extends Model
{
protected $fillable = [
'customer_id', 'name', 'email', 'type',
'imap_host', 'imap_port', 'imap_encryption', 'imap_username', 'imap_password',
'smtp_host', 'smtp_port', 'smtp_encryption', 'smtp_username', 'smtp_password',
'oauth_token', 'oauth_refresh_token', 'oauth_expires_at',
'status', 'last_error', 'last_synced_at', 'last_uid',
];
protected $hidden = ['imap_password', 'smtp_password', 'oauth_token', 'oauth_refresh_token'];
protected $casts = [
'oauth_expires_at' => 'datetime',
'last_synced_at' => 'datetime',
];
public function customer(): BelongsTo
{
return $this->belongsTo(Customer::class);
}
public function conversations(): HasMany
{
return $this->hasMany(UniboxConversation::class, 'account_id');
}
public static function syncFromDeliveryServersForCustomer(int $customerId): void
{
// Remove any previously-synced Gmail SMTP accounts (basic auth / app password).
// Gmail OAuth/API accounts are preserved (they have oauth_refresh_token set).
static::where('customer_id', $customerId)
->where('type', 'gmail')
->whereNull('oauth_refresh_token')
->delete();
$deliveryServers = DeliveryServer::query()
->where('customer_id', $customerId)
->whereIn('type', ['smtp', 'gmail', 'outlook', 'gmail-api'])
->get();
foreach ($deliveryServers as $server) {
// Skip Gmail SMTP delivery servers — only Gmail OAuth/API connects to the inbox.
if ($server->type === 'gmail') {
continue;
}
if ($server->type === 'smtp' && $server->hostname === 'smtp.gmail.com') {
continue;
}
if ($server->type === 'gmail-api') {
$account = static::upsertFromGmailApi($customerId, $server);
} else {
$account = static::upsertFromSmtpServer($customerId, $server);
}
if ($account && $account->status === 'active') {
\App\Jobs\SyncUniboxAccountJob::dispatch($account);
}
}
static::syncFromReplyServersForCustomer($customerId);
}
public static function syncFromReplyServersForCustomer(int $customerId): void
{
$replyServers = \App\Models\ReplyServer::query()
->where('customer_id', $customerId)
->where('active', true)
->get();
foreach ($replyServers as $server) {
if (!$server->username || !$server->password) {
continue;
}
$email = strtolower(trim((string) ($server->username ?? '')));
if ($email === '') {
continue;
}
// UniBox only supports IMAP sync; skip POP3 reply servers.
if (strtolower((string) ($server->protocol ?? 'imap')) === 'pop3') {
continue;
}
$existing = static::where('customer_id', $customerId)->where('email', $email)->first();
$account = static::updateOrCreate(
[
'customer_id' => $customerId,
'email' => $email,
],
[
'name' => $existing ? $existing->name : ($server->name ?: $email),
'type' => 'imap',
'imap_host' => (string) ($server->hostname ?? ''),
'imap_port' => (int) ($server->port ?? 993),
'imap_encryption' => (string) ($server->encryption ?? 'ssl'),
'imap_username' => $server->username,
'imap_password' => static::normalizeEncryptedValue($server->password),
'smtp_host' => (string) ($server->hostname ?? ''),
'smtp_port' => (int) ($server->port ?? 587),
'smtp_encryption' => (string) ($server->encryption ?? 'tls'),
'smtp_username' => $server->username,
'smtp_password' => static::normalizeEncryptedValue($server->password),
'status' => 'active',
]
);
if ($account->status === 'active') {
\App\Jobs\SyncUniboxAccountJob::dispatch($account);
}
}
}
protected static function upsertFromSmtpServer(int $customerId, DeliveryServer $server): ?self
{
if (!$server->username || !$server->password) {
return null;
}
$imap = static::inferImapConfiguration($server);
if (!$imap) {
return null;
}
$email = $server->from_email ?: $server->username;
if (!is_string($email) || trim($email) === '') {
return null;
}
$email = strtolower(trim($email));
$defaultName = is_string($server->name) && trim($server->name) !== '' ? $server->name : $email;
$smtpEncryption = $server->encryption ?: 'tls';
$existing = static::where('customer_id', $customerId)->where('email', $email)->first();
return static::updateOrCreate(
[
'customer_id' => $customerId,
'email' => $email,
],
[
// Preserve user-customized name once set; only seed on first create.
'name' => $existing ? $existing->name : $defaultName,
'type' => in_array($server->type, ['gmail', 'outlook'], true) ? $server->type : 'imap',
'imap_host' => $imap['host'],
'imap_port' => $imap['port'],
'imap_encryption' => $imap['encryption'],
'imap_username' => $server->username,
'imap_password' => static::normalizeEncryptedValue($server->password),
'smtp_host' => $server->hostname,
'smtp_port' => $server->port ?: 587,
'smtp_encryption' => $smtpEncryption,
'smtp_username' => $server->username,
'smtp_password' => static::normalizeEncryptedValue($server->password),
'oauth_token' => null,
'oauth_refresh_token' => null,
'status' => $server->status === 'inactive' ? 'paused' : 'active',
'last_error' => null,
]
);
}
protected static function upsertFromGmailApi(int $customerId, DeliveryServer $server): ?self
{
$settings = is_array($server->settings) ? $server->settings : [];
$refreshToken = $settings['refresh_token'] ?? null;
$email = $server->from_email;
if (!$refreshToken || !$email) {
return null;
}
$email = strtolower(trim($email));
$defaultName = is_string($server->name) && trim($server->name) !== '' ? $server->name : $email;
$existing = static::where('customer_id', $customerId)->where('email', $email)->first();
return static::updateOrCreate(
[
'customer_id' => $customerId,
'email' => $email,
],
[
// Preserve user-customized name once set; only seed on first create.
'name' => $existing ? $existing->name : $defaultName,
'type' => 'gmail',
'imap_host' => 'imap.gmail.com',
'imap_port' => 993,
'imap_encryption' => 'ssl',
'imap_username' => $email,
'imap_password' => null,
'smtp_host' => 'smtp.gmail.com',
'smtp_port' => 587,
'smtp_encryption' => 'tls',
'smtp_username' => $email,
'smtp_password' => null,
'oauth_token' => null,
'oauth_refresh_token' => static::normalizeEncryptedValue($refreshToken),
'oauth_expires_at' => null,
'status' => $server->status === 'inactive' ? 'paused' : 'active',
'last_error' => null,
]
);
}
protected static function inferImapConfiguration(DeliveryServer $server): ?array
{
if ($server->type === 'gmail' || $server->hostname === 'smtp.gmail.com') {
return ['host' => 'imap.gmail.com', 'port' => 993, 'encryption' => 'ssl'];
}
if (
$server->type === 'outlook'
|| in_array($server->hostname, ['smtp.office365.com', 'outlook.office365.com'], true)
) {
return ['host' => 'outlook.office365.com', 'port' => 993, 'encryption' => 'tls'];
}
if ($server->type !== 'smtp' || !is_string($server->hostname) || trim($server->hostname) === '') {
return null;
}
$host = trim($server->hostname);
if (str_starts_with($host, 'smtp.')) {
$host = 'imap.' . substr($host, 5);
}
return ['host' => $host, 'port' => 993, 'encryption' => 'ssl'];
}
protected static function normalizeEncryptedValue(?string $value): ?string
{
if (!is_string($value) || trim($value) === '') {
return null;
}
try {
decrypt($value);
return $value;
} catch (\Throwable $e) {
return encrypt($value);
}
}
}