classify admin

This commit is contained in:
Husanjonazamov
2026-02-24 12:52:01 +05:00
commit e0f1989655
769 changed files with 1263008 additions and 0 deletions

View File

@@ -0,0 +1,267 @@
<?php
namespace App\Services;
use App\Models\Setting;
use App\Models\User;
use App\Models\UserFcmToken;
use Google\Client;
use Google\Exception;
use Illuminate\Http\Request as HttpRequest;
use RuntimeException;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Storage;
use Throwable;
class NotificationService {
/**
* @param array $registrationIDs
* @param string|null $title
* @param string|null $message
* @param string $type
* @param array $customBodyFields
* @return string|array|bool
*/
public static function sendFcmNotification(
array $registrationIDs,
string|null $title = '',
string|null $message = '',
string $type = "default",
array $customBodyFields = [],
bool $sendToAll = false
): string|array|bool {
try {
$project_id = Setting::select('value')->where('name', 'firebase_project_id')->first();
if (empty($project_id->value)) {
return ['error' => true, 'message' => 'FCM configurations are not configured.'];
}
$project_id = $project_id->value;
$url = 'https://fcm.googleapis.com/v1/projects/' . $project_id . '/messages:send';
$access_token = self::getAccessToken();
if ($access_token['error']) {
return $access_token;
}
$dataWithTitle = [
...$customBodyFields,
"title" => $title,
"body" => $message,
"type" => $type,
];
// ✅ Case 1: Send to all (topic-based)
if ($sendToAll) {
$data = [
"message" => [
"topic" => "allUsers", // universal topic (subscribe everyone here)
"data" => self::convertToStringRecursively($dataWithTitle),
"notification" => [
"title" => $title,
"body" => $message
]
]
];
$encodedData = json_encode($data);
$headers = [
'Authorization: Bearer ' . $access_token['data'],
'Content-Type: application/json',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $encodedData);
$result = curl_exec($ch);
if (!$result) {
return ['error' => true, 'message' => 'Curl failed: ' . curl_error($ch)];
}
curl_close($ch);
return ['error' => false, 'message' => "Bulk notification sent via topic", 'data' => $result];
}
// ✅ Case 2: Send individually (like existing code)
$deviceInfo = UserFcmToken::with('user')
->select(['platform_type', 'fcm_token'])
->whereIn('fcm_token', $registrationIDs)
->whereHas('user', fn($q) => $q->where('notification', 1))
->get();
// ✅ Log all targeted users and their FCM tokens before sending
try {
// Log::info('🔔 Device Info for Notification', $deviceInfo->toArray());
} catch (Throwable $e) {
Log::error('Failed to log device info: ' . $e->getMessage());
}
$result = [];
foreach ($registrationIDs as $registrationID) {
$platform = $deviceInfo->first(fn($q) => $q->fcm_token == $registrationID);
if (!$platform) continue;
$data = [
'message' => [
'token' => $registrationID,
// Notification block (title & body)
'notification' => [
'title' => $title,
'body' => $message,
],
// Custom data (ALL values must be strings)
'data' => self::convertToStringRecursively($dataWithTitle),
// Android config
'android' => [
'priority' => 'high',
'notification' => [
'image' => !empty($dataWithTitle['image']) ? $dataWithTitle['image'] : null,
],
],
// iOS (APNs) config
'apns' => [
'headers' => [
'apns-priority' => '10',
],
'payload' => [
'aps' => [
'alert' => [
'title' => $title,
'body' => $message,
],
'sound' => 'default',
'mutable-content' => 1, // REQUIRED for images
],
],
'fcm_options' => [
'image' => !empty($dataWithTitle['image']) ? $dataWithTitle['image'] : null,
],
],
],
];
$encodedData = json_encode($data);
$headers = [
'Authorization: Bearer ' . $access_token['data'],
'Content-Type: application/json',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $encodedData);
$result[] = curl_exec($ch);
curl_close($ch);
}
return ['error' => false, 'message' => "Individual notifications sent", 'data' => $result];
} catch (Throwable $th) {
throw new RuntimeException($th);
}
}
public static function getAccessToken() {
try {
$file_name = Setting::select('value')->where('name', 'service_file')->first();
if (empty($file_name)) {
return [
'error' => true,
'message' => 'FCM Configuration not found'
];
}
$disk = config('filesystems.default');
$file = $file_name->value;
if ($disk === 'local' || $disk === 'public') {
// LOCAL STORAGE
$file_path = Storage::disk($disk)->path($file);
} else {
// S3 (or any cloud disk)
// Download file to local temp
$fileContent = Storage::disk($disk)->get($file);
$file_path = storage_path('app/firebase_service.json');
file_put_contents($file_path, $fileContent);
}
if (!file_exists($file_path)) {
return [
'error' => true,
'message' => 'FCM Service File not found'
];
}
$client = new Client();
$client->setAuthConfig($file_path);
$client->setScopes(['https://www.googleapis.com/auth/firebase.messaging']);
return [
'error' => false,
'message' => 'Access Token generated successfully',
'data' => $client->fetchAccessTokenWithAssertion()['access_token']
];
} catch (Exception $e) {
throw new RuntimeException($e);
}
}
public static function convertToStringRecursively($data, &$flattenedArray = []) {
foreach ($data as $key => $value) {
if (is_array($value)) {
self::convertToStringRecursively($value, $flattenedArray);
} elseif (is_null($value)) {
$flattenedArray[$key] = '';
} else {
$flattenedArray[$key] = (string)$value;
}
}
return $flattenedArray;
}
public static function sendNewDeviceLoginEmail(User $user, HttpRequest $request)
{
try {
Log::info("sending New device login alert");
$deviceType = ucfirst($request->platform_type ?? 'Unknown');
$ip = request()->ip();
$loginTime = now()->format('d M Y - h:i A');
// Fetch company name
$companyName = Setting::where('name', 'company_name')->value('value') ?? 'Unknown';
// Email message
$message =
"A new device has just logged in to your {$companyName} account.\n\n" .
"⏰ Login Time: {$loginTime}\n\n";
Mail::raw($message, function ($msg) use ($user, $companyName) {
$msg->to($user->email)
->from('admin@yourdomain.com', $companyName)
->subject("New Device Login Detected - {$companyName}");
});
Log::info("New device login alert sent to: {$user->email}");
} catch (\Exception $e) {
Log::error("Failed to send new device login email: " . $e->getMessage());
}
}
}