PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 2.0.1
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v2.0.1
2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 1.40 1.41 1.45 All 41 releases
fluent-boards / app / Services / NotificationService.php

NotificationService.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 2.0.1, at app/Services/NotificationService.php

370 lines 12.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBoards\App\Services;
4
5 use FluentBoards\App\Models\Meta;
6 use FluentBoards\App\Models\Notification;
7 use FluentBoards\App\Models\NotificationUser;
8 use FluentBoards\App\Models\Relation;
9 use FluentBoards\App\Models\Task;
10 use FluentBoards\App\Models\User;
11
12 class NotificationService
13 {
14 public function getAllNotifications($per_page, $page, $action = 'all')
15 {
16 $user = wp_get_current_user();
17
18 $query = Notification::where('object_type', Constant::OBJECT_TYPE_BOARD_NOTIFICATION)
19 ->whereHas('users', function($q) use ($user) {
20 $q->where('user_id', $user->ID);
21 });
22
23 // Add action filter if not 'all'
24 if ($action !== 'all') {
25 $query->where('action', $action);
26 }
27
28 $notifications = $query->with('activitist', 'task')
29 ->orderBy('created_at', 'desc')
30 ->paginate($per_page, ['*'], 'page', $page);
31
32 foreach ($notifications as $notification){
33 $notification->read = $notification->checkReadOrNot();
34 }
35
36 return $notifications;
37 }
38
39 /**
40 * @throws \Exception
41 */
42 public function getAllUnreadNotifications($per_page, $page)
43 {
44 $userId = get_current_user_id();
45 if (!$userId) {
46 throw new \Exception(esc_html__('You are not allowed to do that', 'fluent-boards'), 403);
47 }
48 $unreadNotifications = Notification::where('object_type', Constant::OBJECT_TYPE_BOARD_NOTIFICATION)
49 ->whereHas('users', function($q) use ($userId) {
50 $q->where('user_id', $userId)
51 ->whereNull('marked_read_at');
52 })->with('activitist', 'task')->orderBy('created_at', 'desc')->paginate($per_page, ['*'], 'page', $page);
53 return $unreadNotifications;
54 }
55
56 public function markAllRead()
57 {
58 $user = wp_get_current_user();
59
60 $userNotifications = NotificationUser::where('user_id', $user->ID)
61 ->with('notification')
62 ->get();
63
64 foreach ($userNotifications as $data)
65 {
66 $data->marked_read_at = current_time('mysql');
67 $data->save();
68 }
69 }
70
71 public function markNotificationRead($notificationId)
72 {
73 $user = wp_get_current_user();
74
75 $notification = NotificationUser::where('user_id', $user->ID)
76 ->where('notification_id', $notificationId)
77 ->first();
78 if (!$notification) {
79 throw new \Exception(esc_html__('Notification could not be found', 'fluent-boards'), 404);
80 }
81
82 $notification->marked_read_at = current_time('mysql');
83 $notification->save();
84 return $notification;
85 }
86
87 public function newNotificationNumber()
88 {
89 $user = wp_get_current_user();
90
91 $unread_notifications = Notification::query()->where('object_type', Constant::OBJECT_TYPE_BOARD_NOTIFICATION)
92 ->whereHas('users', function($q) use ($user) {
93 $q->where('user_id', $user->ID)
94 ->whereNull('marked_read_at');
95 });
96
97 return $unread_notifications->count();
98 }
99
100 public function isCurrentUserObservingTask($task)
101 {
102 $currentUserId = get_current_user_id();
103 $observers = $task->watchers()->get()->pluck('ID');
104
105 foreach ($observers as $id){
106 if($id == $currentUserId)
107 return true;
108 }
109
110 return false;
111 }
112
113 public function getBoardNotificationSettingsOfUser($id, $userId)
114 {
115 $boardSettings = Relation::where('object_type', Constant::OBJECT_TYPE_BOARD_USER)
116 ->where('object_id', $id)
117 ->where('foreign_id', $userId)
118 ->first();
119
120 return $boardSettings;
121 }
122
123 public function getGlobalNotificationSettingsOfUser($userId)
124 {
125 $settings = Meta::where('object_type', Constant::OBJECT_TYPE_USER)
126 ->where('object_id', $userId)
127 ->where('key', Constant::USER_GLOBAL_NOTIFICATIONS)
128 ->first();
129
130 return $settings;
131 }
132
133 /**
134 * Return board notification preferences with defaults and global watch fallbacks applied.
135 */
136 public function getBoardNotificationSettingsWithDefaults($boardId, $userId)
137 {
138 $settings = $this->getDefaultBoardNotificationSettings($userId);
139
140 $boardSettings = $this->getBoardNotificationSettingsOfUser($boardId, $userId);
141 if ($boardSettings && $boardSettings->preferences) {
142 $preferences = maybe_unserialize($boardSettings->preferences);
143 if (is_array($preferences)) {
144 $settings = array_merge($settings, array_intersect_key($preferences, $settings));
145 }
146 }
147
148 foreach ($settings as $key => $value) {
149 $settings[$key] = $this->normalizePreferenceValue($value);
150 }
151
152 return $settings;
153 }
154
155 /**
156 * Check if a board-scoped auto-watch preference is enabled for a user.
157 */
158 public function isBoardAutoWatchEnabled($boardId, $userId, $preferenceKey)
159 {
160 $settings = $this->getBoardNotificationSettingsWithDefaults($boardId, $userId);
161
162 return array_key_exists($preferenceKey, $settings) && $this->normalizePreferenceValue($settings[$preferenceKey]);
163 }
164
165 /**
166 * Get global watch preferences for fallback when a board has no saved watch keys.
167 */
168 private function getGlobalWatchNotificationSettings($userId)
169 {
170 $watchSettings = $this->getWatchNotificationDefaults();
171
172 $globalSettings = $this->getGlobalNotificationSettingsOfUser($userId);
173 if (!$globalSettings || !$globalSettings->value) {
174 return $watchSettings;
175 }
176
177 $preferences = maybe_unserialize($globalSettings->value);
178 if (!is_array($preferences)) {
179 return $watchSettings;
180 }
181
182 foreach (array_keys($watchSettings) as $key) {
183 if (array_key_exists($key, $preferences)) {
184 $watchSettings[$key] = $this->normalizePreferenceValue($preferences[$key]);
185 }
186 }
187
188 return $watchSettings;
189 }
190
191 private function getDefaultBoardNotificationSettings($userId)
192 {
193 return array_merge(
194 Constant::BOARD_NOTIFICATION_TYPES,
195 $this->getGlobalWatchNotificationSettings($userId)
196 );
197 }
198
199 private function getWatchNotificationDefaults()
200 {
201 return [
202 Constant::GLOBAL_EMAIL_NOTIFICATION_CREATING_TASK => true,
203 Constant::GLOBAL_EMAIL_NOTIFICATION_COMMENTING => true,
204 Constant::GLOBAL_EMAIL_NOTIFICATION_ASSIGNING => true,
205 ];
206 }
207
208 /**
209 * Convert stored preference values into strict booleans.
210 */
211 private function normalizePreferenceValue($value)
212 {
213 return true === $value || 1 === $value || '1' === $value || 'true' === $value;
214 }
215
216 public function updateBoardNotificationSettings($newSettings, $id)
217 {
218 $userId = get_current_user_id();
219 $boardSettings = $this->getBoardNotificationSettingsOfUser($id, $userId);
220 if(empty($boardSettings)){
221 return;
222 }
223
224 $allowedSettings = array_merge(
225 Constant::BOARD_NOTIFICATION_TYPES,
226 $this->getWatchNotificationDefaults()
227 );
228 $filteredSettings = [];
229 foreach ($newSettings as $index => $setting) {
230 if (!array_key_exists($index, $allowedSettings)) {
231 continue;
232 }
233
234 $filteredSettings[$index] = $this->normalizePreferenceValue($setting);
235 }
236
237 $boardSettings->preferences = $filteredSettings;
238 $boardSettings->save();
239
240 }
241
242 public function filterAssigneeToSendEmail($taskId, $emailPurpose){
243 $task = Task::findOrFail($taskId);
244 $watchers = $task->watchers;
245 $currentUserId = get_current_user_id();
246
247 $wathersToSendEmail = array();
248
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 }
257 }
258
259 return $wathersToSendEmail;
260 }
261
262 public function checkIfEmailEnable($userId, $emailPurpose, $boardId)
263 {
264 if(
265 $this->checkIfEmailEnabled($boardId, $userId, $emailPurpose)
266 ){
267 return true;
268 }else{
269 return false;
270 }
271 }
272
273 public function checkIfEmailEnabled($boardId, $userId, $purpose)
274 {
275 $boardSettings = $this->getBoardNotificationSettingsOfUser($boardId, $userId);
276
277 if($boardSettings){
278 $preferences = maybe_unserialize($boardSettings['preferences']);
279 if(!array_key_exists($purpose, $preferences)){
280 $preferences[$purpose] = true;
281 $boardSettings->preferences = $preferences;
282 $boardSettings->save();
283 return true;
284 }
285 return $preferences[$purpose];
286 }
287
288 return false;
289 }
290
291 public function mentionInComment($comment, $mentionedUserIds)
292 {
293 $uniqueIds = array_unique($mentionedUserIds);
294
295 $uniqueIds = array_filter($uniqueIds, function($value) {
296 return (int)$value !== get_current_user_id();
297 });
298
299 //sending emails to mentioned users
300 $mentionedUserEmails = User::whereIn('ID', $uniqueIds)->pluck('user_email');
301 $this->sendMailAfterMention($comment->id, $mentionedUserEmails);
302
303 //sending desktop notifications
304 do_action('fluent_boards/mention_comment_notification', $comment, $uniqueIds);
305 }
306
307 public function sendMailAfterMention($commentId, $usersToSendEmail)
308 {
309 $current_user_id = get_current_user_id();
310
311 /* this will run in background as soon as possible */
312 /* sending Model or Model Instance won't work here */
313 as_enqueue_async_action('fluent_boards/one_time_schedule_send_email_for_mention', [$commentId, $usersToSendEmail, $current_user_id], 'fluent-boards');
314 }
315
316 public function getUnreadNotificationsOfTasks($task)
317 {
318 $userId = get_current_user_id();
319 if (!$userId) {
320 throw new \Exception(esc_html__('You are not allowed to do that', 'fluent-boards'), 403);
321 }
322 $unreadNotifications = Notification::where('object_type', Constant::OBJECT_TYPE_BOARD_NOTIFICATION)
323 ->whereHas('users', function($q) use ($userId) {
324 $q->where('user_id', $userId)
325 ->whereNull('marked_read_at');
326 })->whereHas('task', function($q) use ($task) {
327 $q->where('id', $task->id);
328 })
329 ->with('activitist')->orderBy('created_at', 'desc')->count();
330 return $unreadNotifications;
331 }
332
333 public function getUnreadNotificationCountsByTaskIds($taskIds)
334 {
335 $userId = get_current_user_id();
336 if (!$userId) {
337 throw new \Exception(esc_html__('You are not allowed to do that', 'fluent-boards'), 403);
338 }
339
340 $taskIds = array_values(array_filter(array_map('intval', (array) $taskIds)));
341 if (!$taskIds) {
342 return [];
343 }
344
345 $rows = Notification::query()
346 // Board/list views can return many tasks at once, so unread counts are
347 // grouped in one query instead of issuing a count query per task.
348 ->selectRaw('task_id, COUNT(*) as unread_count')
349 ->join(
350 (new NotificationUser())->getTable(),
351 'fbs_notifications.id',
352 '=',
353 'fbs_notification_users.notification_id'
354 )
355 ->where('object_type', Constant::OBJECT_TYPE_BOARD_NOTIFICATION)
356 ->where('fbs_notification_users.user_id', $userId)
357 ->whereNull('fbs_notification_users.marked_read_at')
358 ->whereIn('task_id', $taskIds)
359 ->groupBy('task_id')
360 ->get();
361
362 $notificationCounts = [];
363 foreach ($rows as $row) {
364 $notificationCounts[(int) $row->task_id] = (int) $row->unread_count;
365 }
366
367 return $notificationCounts;
368 }
369 }
370