Giant Update

This commit is contained in:
Wian Drs
2026-07-31 13:57:11 +07:00
parent f68d967c8b
commit b0d08211ec
112 changed files with 6674 additions and 3 deletions
@@ -0,0 +1,50 @@
<?php
namespace App\Services\Notification\Adapters;
use App\Models\NotificationDelivery;
use App\Services\Notification\Contracts\NotificationChannelAdapter;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
class EmailAdapter implements NotificationChannelAdapter
{
public function send(NotificationDelivery $delivery): array
{
$config = $delivery->channelConfig;
$credentials = $config?->credentials ?? [];
$settings = $config?->settings ?? [];
if (! $delivery->destination || empty($settings['host'])) {
throw ValidationException::withMessages(['channel' => 'Alamat penerima atau konfigurasi SMTP belum lengkap.']);
}
$original = Config::get('mail.mailers.smtp');
$originalFrom = Config::get('mail.from');
try {
Config::set('mail.mailers.smtp', [
'transport' => 'smtp',
'host' => $settings['host'],
'port' => $settings['port'] ?? 587,
'encryption' => $settings['encryption'] ?? 'tls',
'username' => $credentials['username'] ?? null,
'password' => $credentials['password'] ?? null,
'timeout' => 30,
]);
Config::set('mail.from', [
'address' => $settings['from_address'],
'name' => $settings['from_name'] ?? null,
]);
Mail::purge('smtp');
Mail::raw($delivery->rendered_body, function ($mail) use ($delivery) {
$mail->to($delivery->destination)->subject($delivery->rendered_subject ?: 'Notifikasi');
});
} finally {
Config::set('mail.mailers.smtp', $original);
Config::set('mail.from', $originalFrom);
Mail::purge('smtp');
}
return ['provider_message_id' => (string) Str::uuid(), 'response' => ['accepted' => true]];
}
}
@@ -0,0 +1,45 @@
<?php
namespace App\Services\Notification\Adapters;
use App\Models\NotificationChannel;
use App\Models\NotificationDelivery;
use App\Models\User;
use App\Models\UserNotification;
use App\Services\Notification\Contracts\NotificationChannelAdapter;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
class SystemAdapter implements NotificationChannelAdapter
{
public function send(NotificationDelivery $delivery): array
{
$message = $delivery->message;
$user = $message->recipient instanceof User
? $message->recipient
: ($message->recipient?->user ?? null);
if (! $user) {
throw ValidationException::withMessages(['recipient' => 'Penerima tidak memiliki akun aplikasi.']);
}
$notification = UserNotification::create([
'uuid' => Str::uuid(),
'tenant_id' => $message->tenant_id,
'user_id' => $user->id,
'notification_message_id' => $message->id,
'title' => $delivery->rendered_subject ?: 'Notifikasi',
'body' => $delivery->rendered_body,
'action_url' => data_get($message->context, 'action_url'),
'icon' => data_get($message->context, 'icon', 'cil-bell'),
]);
$settings = NotificationChannel::where('tenant_id', $message->tenant_id)
->where('channel', 'system')->where('enabled', true)->where('is_default', true)
->first()?->settings ?? [];
$maximum = max(20, (int) ($settings['maximum_notifications_per_user'] ?? 500));
UserNotification::where('user_id', $user->id)
->whereNotIn('id', UserNotification::where('user_id', $user->id)->latest('id')->limit($maximum)->pluck('id'))
->delete();
return ['provider_message_id' => $notification->uuid, 'response' => ['stored' => true]];
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Services\Notification\Adapters;
use App\Models\NotificationDelivery;
use App\Services\Notification\Contracts\NotificationChannelAdapter;
use Illuminate\Support\Facades\Http;
use Illuminate\Validation\ValidationException;
class TelegramAdapter implements NotificationChannelAdapter
{
public function send(NotificationDelivery $delivery): array
{
$token = data_get($delivery->channelConfig?->credentials, 'bot_token');
if (! $token) {
throw ValidationException::withMessages(['channel' => 'Bot token Telegram belum diatur.']);
}
$response = Http::timeout(30)->post("https://api.telegram.org/bot{$token}/sendMessage", [
'chat_id' => $delivery->destination,
'text' => $delivery->rendered_body,
'parse_mode' => data_get($delivery->channelConfig?->settings, 'parse_mode'),
])->throw()->json();
return ['provider_message_id' => (string) data_get($response, 'result.message_id'), 'response' => $response];
}
}
@@ -0,0 +1,39 @@
<?php
namespace App\Services\Notification\Adapters;
use App\Models\NotificationDelivery;
use App\Services\Notification\Contracts\NotificationChannelAdapter;
use Illuminate\Support\Facades\Http;
use Illuminate\Validation\ValidationException;
class WhatsAppOfficialAdapter implements NotificationChannelAdapter
{
public function send(NotificationDelivery $delivery): array
{
$config = $delivery->channelConfig;
$credentials = $config?->credentials ?? [];
$settings = $config?->settings ?? [];
$phoneId = $credentials['phone_number_id'] ?? null;
$token = $credentials['access_token'] ?? null;
$templateName = data_get($delivery->provider_response, 'request_context.provider_template_name');
if (! $phoneId || ! $token || ! $templateName) {
throw ValidationException::withMessages(['channel' => 'Phone Number ID, access token, dan template WhatsApp Official wajib tersedia.']);
}
$baseUrl = rtrim($settings['base_url'] ?? 'https://graph.facebook.com/v22.0', '/');
$parameters = collect(data_get($delivery->provider_response, 'request_context.template_parameters', []))
->map(fn ($value) => ['type' => 'text', 'text' => (string) $value])->values()->all();
$response = Http::withToken($token)->timeout(30)->post("{$baseUrl}/{$phoneId}/messages", [
'messaging_product' => 'whatsapp',
'to' => $delivery->destination,
'type' => 'template',
'template' => [
'name' => $templateName,
'language' => ['code' => data_get($delivery->provider_response, 'request_context.language', 'id')],
'components' => $parameters ? [['type' => 'body', 'parameters' => $parameters]] : [],
],
])->throw()->json();
return ['provider_message_id' => data_get($response, 'messages.0.id'), 'response' => $response];
}
}
@@ -0,0 +1,34 @@
<?php
namespace App\Services\Notification\Adapters;
use App\Models\NotificationDelivery;
use App\Services\Notification\Contracts\NotificationChannelAdapter;
use Illuminate\Support\Facades\Http;
use Illuminate\Validation\ValidationException;
class WhatsAppUnofficialAdapter implements NotificationChannelAdapter
{
public function send(NotificationDelivery $delivery): array
{
$config = $delivery->channelConfig;
$credentials = $config?->credentials ?? [];
$settings = $config?->settings ?? [];
$url = $settings['send_url'] ?? null;
if (! $url) {
throw ValidationException::withMessages(['channel' => 'URL pengiriman gateway unofficial belum diatur.']);
}
$headers = [];
if ($apiKey = $credentials['api_key'] ?? null) {
$headers[$settings['api_key_header'] ?? 'X-API-Key'] = $apiKey;
}
$payload = [
$settings['destination_field'] ?? 'number' => $delivery->destination,
$settings['message_field'] ?? 'message' => $delivery->rendered_body,
'instance_id' => $credentials['instance_id'] ?? null,
];
$response = Http::withHeaders($headers)->timeout(30)->post($url, $payload)->throw()->json();
return ['provider_message_id' => data_get($response, $settings['message_id_path'] ?? 'id'), 'response' => $response];
}
}