225 lines
7.5 KiB
PHP
225 lines
7.5 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\SystemSettings;
|
|
|
|
use App\Events\NotificationSent;
|
|
use App\Models\Notification;
|
|
use App\Repositories\NotificationRepository;
|
|
use App\Services\SystemConfig\SystemConfigService;
|
|
use App\Support\DataTable;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Routing\Controller;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Spatie\Permission\Models\Role;
|
|
|
|
class NotificationCenterController extends Controller
|
|
{
|
|
public function __construct(
|
|
protected SystemConfigService $systemConfig,
|
|
protected NotificationRepository $notificationRepo
|
|
) {
|
|
// Middleware handled in web.php
|
|
}
|
|
|
|
protected function ensureFeatureEnabled(): void
|
|
{
|
|
$featureEnabled = $this->systemConfig->get('feature_notification_center', true);
|
|
|
|
if (! $featureEnabled) {
|
|
// Instead of 404, we change the authorization requirement.
|
|
// If feature is disabled, only users who can 'manage global settings' can access.
|
|
abort_unless(
|
|
Auth::user()?->can('manage global settings'),
|
|
403,
|
|
__('The Notification Center feature is currently disabled by the system administrator.')
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* =====================================================
|
|
* INDEX
|
|
* =====================================================
|
|
*/
|
|
public function index(Request $request)
|
|
{
|
|
$this->ensureFeatureEnabled();
|
|
|
|
if (DataTable::isDataTableRequest($request)) {
|
|
return $this->dataTable($request);
|
|
}
|
|
|
|
$roles = Role::pluck('name')->toArray();
|
|
|
|
return view('pages.system_settings.notification-center', compact('roles'));
|
|
}
|
|
|
|
/**
|
|
* DATATABLE (Supports personal status)
|
|
*/
|
|
protected function dataTable(Request $request)
|
|
{
|
|
try {
|
|
$user = Auth::user();
|
|
$authorizedRecipients = $this->notificationRepo->getAuthorizedRecipients($user);
|
|
|
|
$start = DataTable::start($request);
|
|
$length = DataTable::length($request);
|
|
|
|
// Efficient query using LEFT JOIN (no N+1)
|
|
$baseQuery = Notification::whereIn('recipient', $authorizedRecipients)
|
|
->leftJoin('system_notification_user', function ($join) use ($user) {
|
|
$join->on('system_notifications.id', '=', 'system_notification_user.notification_id')
|
|
->where('system_notification_user.user_id', '=', $user->id);
|
|
})
|
|
->whereNull('system_notification_user.deleted_at')
|
|
->select('system_notifications.*', 'system_notification_user.read_at as personal_read_at');
|
|
|
|
$recordsTotal = $baseQuery->count();
|
|
$recordsFiltered = $recordsTotal;
|
|
|
|
$notifications = (clone $baseQuery)
|
|
->latest('system_notifications.created_at')
|
|
->skip($start)
|
|
->take($length)
|
|
->get();
|
|
|
|
$rows = $notifications->map(function ($n) {
|
|
return [
|
|
'id' => $n->id,
|
|
'is_unread' => is_null($n->personal_read_at),
|
|
'title' => e($n->title),
|
|
'message' => e(strip_tags($n->message)),
|
|
'type' => $n->type,
|
|
'recipient' => $n->recipient,
|
|
'time_ago' => $n->created_at ? $n->created_at->diffForHumans() : '',
|
|
'read_url' => route('notification-center.read', $n->id),
|
|
'delete_url' => route('notification-center.destroy', $n->id),
|
|
'created_at' => $n->created_at ? $n->created_at->format('Y-m-d H:i:s') : '',
|
|
];
|
|
})->values();
|
|
|
|
return DataTable::response($request, $recordsTotal, $recordsFiltered, $rows->toArray());
|
|
} catch (\Exception $e) {
|
|
\Log::error('NotificationCenter DataTable Error: '.$e->getMessage());
|
|
|
|
return response()->json(['error' => $e->getMessage(), 'data' => []], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* STORE (Send Broadcast)
|
|
*/
|
|
public function store(Request $request)
|
|
{
|
|
$this->ensureFeatureEnabled();
|
|
|
|
$roles = Role::pluck('name')->toArray();
|
|
$roles[] = 'all';
|
|
|
|
$validated = $request->validate([
|
|
'title' => 'required|string|max:255',
|
|
'message' => 'required|string',
|
|
'recipient' => 'required|in:'.implode(',', $roles),
|
|
'type' => 'required|in:info,warning,system',
|
|
]);
|
|
|
|
$notification = $this->notificationRepo->create([
|
|
...$validated,
|
|
'created_by' => Auth::id(),
|
|
'read_at' => null,
|
|
]);
|
|
|
|
event(new NotificationSent($notification));
|
|
|
|
return response()->json(['success' => true, 'message' => __('Notification broadcasted.')]);
|
|
}
|
|
|
|
/**
|
|
* MARK AS READ (Personal)
|
|
*/
|
|
public function markAsRead(Notification $notification)
|
|
{
|
|
$this->ensureFeatureEnabled();
|
|
$this->notificationRepo->markAsRead($notification->id, Auth::id());
|
|
|
|
return response()->json(['success' => true, 'message' => __('Marked as read.')]);
|
|
}
|
|
|
|
/**
|
|
* DELETE (Personal Hide)
|
|
*/
|
|
public function destroy(Notification $notification)
|
|
{
|
|
$this->ensureFeatureEnabled();
|
|
$this->notificationRepo->personalDelete($notification->id, Auth::id());
|
|
|
|
return response()->json(['success' => true, 'message' => __('Notification hidden.')]);
|
|
}
|
|
|
|
/**
|
|
* MARK ALL AS READ (Personal)
|
|
*/
|
|
public function markAllAsRead()
|
|
{
|
|
$this->ensureFeatureEnabled();
|
|
$this->notificationRepo->markAllAsReadForUser(Auth::user());
|
|
|
|
return response()->json(['success' => true, 'message' => __('All marked as read.')]);
|
|
}
|
|
|
|
/**
|
|
* CLEAR READ (Personal Hide all read)
|
|
*/
|
|
public function clearRead()
|
|
{
|
|
$this->ensureFeatureEnabled();
|
|
$user = Auth::user();
|
|
|
|
$readIds = \DB::table('system_notification_user')
|
|
->where('user_id', $user->id)
|
|
->whereNotNull('read_at')
|
|
->pluck('notification_id');
|
|
|
|
foreach ($readIds as $id) {
|
|
$this->notificationRepo->personalDelete($id, $user->id);
|
|
}
|
|
|
|
return response()->json(['success' => true, 'message' => __('Read notifications cleared from your view.')]);
|
|
}
|
|
|
|
/**
|
|
* RECENT NOTIFICATIONS API (Personal status)
|
|
*/
|
|
public function recentNotifications(Request $request)
|
|
{
|
|
$this->ensureFeatureEnabled();
|
|
$user = Auth::user();
|
|
$offset = $request->get('offset', 0);
|
|
$limit = $request->get('limit', 10);
|
|
|
|
$notifications = $this->notificationRepo->getActiveNotificationsForUser($user, $offset, $limit);
|
|
|
|
$mapped = $notifications->map(function ($n) {
|
|
return [
|
|
'id' => $n->id,
|
|
'title' => e($n->title),
|
|
'message' => e(strip_tags($n->message)),
|
|
'type' => $n->type,
|
|
'time_ago' => $n->created_at->diffForHumans(),
|
|
'read_url' => route('notification-center.read', $n->id),
|
|
'delete_url' => route('notification-center.destroy', $n->id),
|
|
'is_unread' => is_null($n->personal_read_at),
|
|
'recipient' => $n->recipient,
|
|
];
|
|
})->values()->all();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'unread_count' => $this->notificationRepo->getUnreadCount($user),
|
|
'notifications' => $mapped,
|
|
'has_more' => count($mapped) === (int) $limit,
|
|
]);
|
|
}
|
|
}
|