| @@ -12,8 +12,10 @@ | ||
| 12 | 12 | class NotificationService |
| 13 | 13 | { |
| 14 | 14 | public function getAllNotifications($per_page, $page, $action = 'all') |
| 15 | 15 | { |
| 16 | + $per_page = Sanitize::perPage($per_page); | |
| 17 | + $page = max(1, (int) $page); | |
| 16 | 18 | $user = wp_get_current_user(); |
| 17 | 19 | |
| 18 | 20 | $query = Notification::where('object_type', Constant::OBJECT_TYPE_BOARD_NOTIFICATION) |
| 19 | 21 | ->whereHas('users', function($q) use ($user) { |
| @@ -40,8 +42,10 @@ | ||
| 40 | 42 | * @throws \Exception |
| 41 | 43 | */ |
| 42 | 44 | public function getAllUnreadNotifications($per_page, $page) |
| 43 | 45 | { |
| 46 | + $per_page = Sanitize::perPage($per_page); | |
| 47 | + $page = max(1, (int) $page); | |
| 44 | 48 | $userId = get_current_user_id(); |
| 45 | 49 | if (!$userId) { |
| 46 | 50 | throw new \Exception(esc_html__('You are not allowed to do that', 'fluent-boards'), 403); |
| 47 | 51 | } |
| @@ -243,21 +247,20 @@ | ||
| 243 | 247 | $task = Task::findOrFail($taskId); |
| 244 | 248 | $watchers = $task->watchers; |
| 245 | 249 | $currentUserId = get_current_user_id(); |
| 246 | 250 | |
| 247 | - $wathersToSendEmail = array(); | |
| 251 | + $watcherIds = array_diff($watchers->pluck('ID')->toArray(), [$currentUserId]); | |
| 252 | + $eligibleIds = $this->getEmailEnabledUserIds($task->board_id, $watcherIds, $emailPurpose); | |
| 253 | + $eligibleLookup = array_fill_keys($eligibleIds, true); | |
| 254 | + $watchersToSendEmail = []; | |
| 248 | 255 | |
| 249 | - foreach ($watchers as $watcher){ | |
| 250 | - if($watcher->ID != $currentUserId) | |
| 251 | - { | |
| 252 | - if($this->checkIfEmailEnable($watcher->ID, $emailPurpose, $task->board_id)) | |
| 253 | - { | |
| 254 | - $wathersToSendEmail[] = $watcher->user_email; | |
| 255 | - } | |
| 256 | + foreach ($watchers as $watcher) { | |
| 257 | + if (isset($eligibleLookup[$watcher->ID])) { | |
| 258 | + $watchersToSendEmail[] = $watcher->user_email; | |
| 256 | 259 | } |
| 257 | 260 | } |
| 258 | 261 | |
| 259 | - return $wathersToSendEmail; | |
| 262 | + return $watchersToSendEmail; | |
| 260 | 263 | } |
| 261 | 264 | |
| 262 | 265 | /** |
| 263 | 266 | * Get comment notification recipients as revocable user IDs for async delivery. |
| @@ -268,16 +271,17 @@ | ||
| 268 | 271 | public function getCommentRecipientUserIds($taskId) |
| 269 | 272 | { |
| 270 | 273 | $task = Task::findOrFail(absint($taskId)); |
| 271 | 274 | $currentUserId = get_current_user_id(); |
| 275 | + $watchers = $task->watchers; | |
| 276 | + $watcherIds = array_diff($watchers->pluck('ID')->toArray(), [$currentUserId]); | |
| 277 | + $eligibleIds = $this->getEmailEnabledUserIds($task->board_id, $watcherIds, Constant::BOARD_EMAIL_COMMENT); | |
| 278 | + $eligibleLookup = array_fill_keys($eligibleIds, true); | |
| 272 | 279 | $recipientUserIds = []; |
| 273 | 280 | |
| 274 | - foreach ($task->watchers as $watcher) { | |
| 281 | + foreach ($watchers as $watcher) { | |
| 275 | 282 | $watcherId = absint($watcher->ID); |
| 276 | - if ( | |
| 277 | - $watcherId !== $currentUserId && | |
| 278 | - $this->checkIfEmailEnable($watcherId, Constant::BOARD_EMAIL_COMMENT, $task->board_id) | |
| 279 | - ) { | |
| 283 | + if (isset($eligibleLookup[$watcherId])) { | |
| 280 | 284 | $recipientUserIds[] = $watcherId; |
| 281 | 285 | } |
| 282 | 286 | } |
| 283 | 287 | |
| @@ -294,8 +298,38 @@ | ||
| 294 | 298 | return false; |
| 295 | 299 | } |
| 296 | 300 | } |
| 297 | 301 | |
| 302 | + /** | |
| 303 | + * Resolve board email recipients in one query; missing preference keys default to enabled without writes. | |
| 304 | + */ | |
| 305 | + public function getEmailEnabledUserIds($boardId, $userIds, $purpose) | |
| 306 | + { | |
| 307 | + $boardId = absint($boardId); | |
| 308 | + $userIds = array_values(array_unique(array_filter(array_map('intval', (array) $userIds)))); | |
| 309 | + if (!$boardId || !$userIds) { | |
| 310 | + return []; | |
| 311 | + } | |
| 312 | + | |
| 313 | + // Match the first membership used by individual checks, including old duplicates. | |
| 314 | + $relations = Relation::where('object_type', Constant::OBJECT_TYPE_BOARD_USER) | |
| 315 | + ->where('object_id', $boardId) | |
| 316 | + ->whereIn('foreign_id', $userIds) | |
| 317 | + ->orderBy('id', 'ASC') | |
| 318 | + ->get(['foreign_id', 'preferences']) | |
| 319 | + ->unique('foreign_id'); | |
| 320 | + | |
| 321 | + $enabledUserIds = []; | |
| 322 | + foreach ($relations as $relation) { | |
| 323 | + $preferences = (array) maybe_unserialize($relation->preferences); | |
| 324 | + if (!array_key_exists($purpose, $preferences) || $preferences[$purpose]) { | |
| 325 | + $enabledUserIds[] = (int) $relation->foreign_id; | |
| 326 | + } | |
| 327 | + } | |
| 328 | + | |
| 329 | + return array_values(array_unique($enabledUserIds)); | |
| 330 | + } | |
| 331 | + | |
| 298 | 332 | public function checkIfEmailEnabled($boardId, $userId, $purpose) |
| 299 | 333 | { |
| 300 | 334 | $boardSettings = $this->getBoardNotificationSettingsOfUser($boardId, $userId); |
| 301 | 335 | |
| @@ -367,8 +401,12 @@ | ||
| 367 | 401 | } |
| 368 | 402 | |
| 369 | 403 | public function sendMailAfterMention($commentId, $recipientUserIds) |
| 370 | 404 | { |
| 405 | + if (empty($recipientUserIds)) { | |
| 406 | + return; | |
| 407 | + } | |
| 408 | + | |
| 371 | 409 | $current_user_id = get_current_user_id(); |
| 372 | 410 | |
| 373 | 411 | /* this will run in background as soon as possible */ |
| 374 | 412 | /* sending Model or Model Instance won't work here */ |