2 /*=====================================================================*\
3 || ###################################################################
4 || # Bugdar [#]version[#]
5 || # Copyright ©2002-[#]year[#] Blue Static
7 || # This program is free software; you can redistribute it and/or modify
8 || # it under the terms of the GNU General Public License as published by
9 || # the Free Software Foundation; version [#]gpl[#] of the License.
11 || # This program is distributed in the hope that it will be useful, but
12 || # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 || # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 || # You should have received a copy of the GNU General Public License along
17 || # with this program; if not, write to the Free Software Foundation, Inc.,
18 || # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 || ###################################################################
20 \*=====================================================================*/
25 * This class determines which emails need to be sent out based on user
26 * options and bug changes, and then it sends said emails.
29 * @copyright Copyright ©2002 - [#]year[#], Blue Static
34 class NotificationCenter
48 var $original = array();
55 var $modified = array();
58 * Global bugsys registry
65 * Role list: a list of user IDs with their relations to the bug
70 '-notapplicable-' => array(),
71 'reporter' => array(),
72 'assignee' => array(),
73 'favorite' => array(),
75 'commenter' => array()
86 * A list of notices per-user that are combined together in NotificationCenter::finalize()
90 var $notices = array();
92 // ###################################################################
94 * Constructor: set database objects
98 function __construct()
102 $this->registry
=& $bugsys;
105 // ###################################################################
107 * (PHP 4) Constructor
111 function NotificationCenter()
113 $this->__construct();
116 // ###################################################################
118 * Sets the bug data so that all methods in this class have access to
119 * it when sending emails.
123 * @param array Original bug data
124 * @param array Modified bug data
126 function set_bug_data($original, $modified = array())
128 if (sizeof($modified) > 0)
130 $this->bug
= $modified;
134 $this->bug
= $original;
137 $this->original
= $original;
138 $this->modified
= $modified;
140 $this->roles
['-notapplicable-'] = (sizeof($modified) > 0 ? array($original['assignedto'], $modified['assignedto']) : array($original['assignedto']));
141 $this->roles
['reporter'] = array($original['userid']);
142 $this->roles
['assignee'] = (sizeof($modified) > 0 ? array($modified['assignedto']) : array($original['assignedto']));
144 $this->fetch_user_cache();
147 // ###################################################################
149 * Fetches all the users who could be related to the bug and sticks
150 * their information into an array.
154 function fetch_user_cache()
156 $favorites = $this->registry
->db
->query("SELECT userid FROM " . TABLE_PREFIX
. "favorite WHERE bugid = " . $this->registry
->clean($this->bug
['bugid'], TYPE_UINT
));
157 while ($fav = $this->registry
->db
->fetch_array($favorites))
159 $this->roles
['favorite']["$fav[userid]"] = $fav['userid'];
162 $voters = $this->registry
->db
->query_first("SELECT userids FROM " . TABLE_PREFIX
. "vote WHERE bugid = " . $this->registry
->clean($this->bug
['bugid'], TYPE_UINT
));
163 $this->roles
['voter'] = preg_split('#,#', $voters['userids'], 0, PREG_SPLIT_NO_EMPTY
);
165 $commenters = $this->registry
->db
->query("SELECT userid FROM " . TABLE_PREFIX
. "comment WHERE bugid = " . $this->registry
->clean($this->bug
['bugid'], TYPE_UINT
));
166 while ($comment = $this->registry
->db
->fetch_array($commenters))
168 $this->roles
['commenter']["$comment[userid]"] = $comment['userid'];
171 $masterids = array_merge($this->roles
['-notapplicable-'], $this->roles
['reporter'], $this->roles
['assignee'], $this->roles
['favorite'], $this->roles
['voter'], $this->roles
['commenter']);
172 $masterids = $this->registry
->funct
->array_strip_empty(array_unique($masterids));
174 if (is_array($masterids) AND sizeof($masterids) > 0)
176 $userinfo = $this->registry
->db
->query("
177 SELECT user.*, useremail.*
178 FROM " . TABLE_PREFIX
. "useremail AS useremail
179 LEFT JOIN " . TABLE_PREFIX
. "user AS user
180 ON (user.userid = useremail.userid)
181 WHERE useremail.userid IN (" . implode(',', $masterids) . ")
183 while ($user = $this->registry
->db
->fetch_array($userinfo))
185 if (!is_array($this->users
["$user[userid]"]))
187 $this->users
["$user[userid]"] = $user;
188 unset($this->users
["$user[userid]"]['mask'], $this->users
["$user[userid]"]['relation']);
190 $this->users
["$user[userid]"]['options']["$user[relation]"] = $user['mask'];
195 // ###################################################################
197 * Sends the appropriate emails for changes to bugs. This function
198 * works a lot like the Logging class by taking BugAPI->objdata and
199 * BugAPI->values and then comparing the two arries and sending emails
200 * with the differences.
204 * @param array Original custom fields data
205 * @param array Modified custom fields data
207 function send_bug_changes_notice($original, $modified)
209 if (!isset($this->modified
['bugid']))
214 // fields with custom mask information
215 if ($this->original
['assignedto'] != $this->modified
['assignedto'])
217 if ($this->original
['assignedto'] != '')
219 $this->notice_no_longer_assigned($this->original
['assignedto']);
221 if ($this->modified
['assignedto'] != '')
223 $this->notice_now_assigned($this->modified
['assignedto']);
226 if ($this->original
['status'] != $this->modified
['status'])
228 $this->notice_status_change($this->original
['status'], $this->modified
['status']);
230 if ($this->original
['resolution'] != $this->modified
['resolution'])
232 $this->notice_resolution_change($this->original
['resolution'], $this->modified
['resolution']);
234 if ($this->original
['duplicates'] != $this->modified
['duplicates'])
236 $this->notice_duplicates_change($this->original
['duplicates'], $this->modified
['duplicates']);
239 // other standard fields that don't have custom masks
240 if ($this->original
['severity'] != $this->modified
['severity'])
242 $this->notice_severity_change($this->original
['severity'], $this->modified
['severity']);
244 if ($this->original
['priority'] != $this->modified
['priority'])
246 $this->notice_priority_change($this->original
['priority'], $this->modified
['priority']);
248 if (($this->original
['product'] != $this->modified
['product']) OR ($this->original
['component'] != $this->modified
['component']) OR ($this->original
['version'] != $this->modified
['version']))
250 $this->notice_pcv_change(array($this->original
['product'], $this->original
['component'], $this->original
['version']), array($this->modified
['product'], $this->modified
['component'], $this->modified
['version']));
258 foreach ($dofields AS $field => $lookup)
260 if ($this->original
["$field"] != $this->modified["$field"])
262 $this->notice_other_change($field, $this->original
["$field"], $this->modified["$field"]);
267 foreach ($modified AS $field => $value)
269 if ($field == 'bugid')
273 if ($original["$field"] != $modified["$field"])
275 $this->notice_other_change($field, $original["$field"], $modified["$field"]);
280 // ###################################################################
282 * Sends an email to the specified user ID that they are no longer the
283 * person assigned to the bug.
287 * @param integer User ID to send to
289 function notice_no_longer_assigned($userid)
291 if ($this->users
["$userid"]['options'][0] & $this->registry->emailoptions['notifications']['assignedto'] AND in_array($userid, $this->roles['-notapplicable-']))
293 $this->notices["$userid"][] = sprintf(
294 _('You are no longer assigned to this bug, per %1$s\'s changes.'),
296 construct_user_display($this->registry
->userinfo
, false)
301 // ###################################################################
303 * Informs the user that they have been made the assignee of the bug.
307 * @param integer User ID
309 function notice_now_assigned($userid)
311 if ($this->users
["$userid"]['options'][0] & $this->registry->emailoptions['notifications']['assignedto'] AND in_array($userid, $this->roles['-notapplicable-']))
313 $this->notices["$userid"][] = sprintf(
314 _('You have been assigned to this bug by %1$s.'),
316 construct_user_display($this->registry
->userinfo
, false)
321 // ###################################################################
323 * Sends a message to inform users that the status has changed.
327 * @param integer Old status
328 * @param integer New status
330 function notice_status_change($old, $new)
332 $userlist = $this->fetch_users_with_on_bit('statusresolve');
333 foreach ($userlist AS $userid => $user)
335 $this->notices
["$user[userid]"][] = sprintf(
336 _('The status of the bug is now "%2$s", from "%1$s".'),
338 $this->registry
->datastore
['status']["$old"]['status'],
339 $this->registry->datastore['status']["$new"]['status']
344 // ###################################################################
346 * Sends an email to inform users that the resolution has changed.
350 * @param integer Old resolution
351 * @param integer New resolution
353 function notice_resolution_change($old, $new)
355 $userlist = $this->fetch_users_with_on_bit('statusresolve');
356 foreach ($userlist AS $userid => $user)
358 $this->notices
["$user[userid]"][] = sprintf(
359 _('This bug has been resolved with resolution "%2$s", from "%1$s".'),
361 $this->registry
->datastore
['resolution']["$old"]['resolution'],
362 $this->registry->datastore['resolution']["$new"]['resolution']
367 // ###################################################################
369 * Informs users that the duplicates list has changed.
373 * @param string Old duplicates list
374 * @param string New duplicates list
376 function notice_duplicates_change($old, $new)
378 $userlist = $this->fetch_useres_with_on_bit('duplicates');
379 foreach ($userlist AS $userid => $user)
381 $this->notices
["$user[userid]"][] = sprintf(
382 _('The duplicates list has changed from "%1$s" to %2$s".'),
390 // ###################################################################
392 * Sends an email to inform users that the severity has changed.
396 * @param integer Old severity
397 * @param integer New severity
399 function notice_severity_change($old, $new)
401 $userlist = $this->fetch_users_with_on_bit('otherfield');
402 foreach ($userlist AS $userid => $user)
404 $this->notices
["$user[userid]"][] = sprintf(
405 _('The severity has been elevated from "%1$s" to "%2$s".'),
407 $this->registry
->datastore
['severity']["$old"]['severity'],
408 $this->registry->datastore['severity']["$new"]['severity']
413 // ###################################################################
415 * Informs users that the priority changed.
419 * @param integer Old priority
420 * @param integer New priority
422 function notice_priority_change($old, $new)
424 $userlist = $this->fetch_users_with_on_bit('otherfield');
425 foreach ($userlist AS $userid => $user)
427 $this->notices
["$user[userid]"][] = sprintf(
428 _('The priority has been elevatd from "%1$s" to "%2$s".'),
430 $this->registry
->datastore
['priority']["$old"]['priority'],
431 $this->registry->datastore['priority']["$new"]['priority']
436 // ###################################################################
438 * Sends an email telling users that the product, component, or version
439 * has changed. This is done all at once because you really need to see
440 * the whole thing in the notice.
444 * @param array Original PCV
445 * @param array Modified PCV
447 function notice_pcv_change($old, $new)
449 $userlist = $this->fetch_users_with_on_bit('otherfield');
450 foreach ($userlist AS $userid => $user)
452 $this->notices
["$user[userid]"][] = sprintf(
453 _('The product, component, and version combination has changed from "%1$s" to "%2$s".'),
455 $this->registry
->datastore
['product']["$old[0]"]['title'] . '/' . ($old[1] ? $this->registry
->datastore
['product']["$old[1]"]['title'] . '/' : '') . $this->registry
->datastore
['version']["$old[2]"]['version'],
456 $this->registry
->datastore
['product']["$new[0]"]['title'] . '/' . ($new[1] ? $this->registry
->datastore
['product']["$new[1]"]['title'] . '/' : '') . $this->registry
->datastore
['version']["$new[2]"]['version']
461 // ###################################################################
463 * Sends the appropriate users information about a new comment being
464 * posted to the bug report.
468 * @param array CommentAPI->values array
470 function send_new_comment_notice($comment)
472 $userlist = $this->fetch_users_with_on_bit('newcomment');
473 foreach ($userlist AS $userid => $user)
475 $this->notices
["$user[userid]"][] = sprintf(
476 _('The following comment was added by %1$s on %2$s:
477 ============================================
479 ============================================'),
481 construct_user_display($this->registry
->userinfo
, false),
482 $this->registry
->modules
['date']->format($this->registry
->options
['dateformat'], $comment['dateline']),
488 // ###################################################################
490 * A notice for an individual field changing.
494 * @param string Field name
495 * @param mixed Original value
496 * @param mixed Modified value
498 function notice_other_change($name, $old, $new)
500 $userlist = $this->fetch_users_with_on_bit('otherfield');
501 foreach ($userlist AS $userid => $user)
503 $this->notices
["$user[userid]"][] = sprintf(
504 _('The %1$s field changed from "%2$s" to "%3$s".'),
513 // ###################################################################
515 * Sends appropriate users a notice when a new attachment has been
520 * @param array AttachmentAPI->values array
521 * @param array List of all attachments made obsolete
522 * @param array Newly-inserted attachment ID
524 function send_new_attachment_notice($attachment, $obsolete, $id)
526 $userlist = $this->fetch_users_with_on_bit('newattachment');
527 foreach ($userlist AS $userid => $user)
529 $this->notices
["$userid"][] = sprintf(
530 _('%1$s has uploaded a new attachment:
531 ============================================
534 File size: %4$s Bytes
537 ============================================'),
539 construct_user_display($this->registry->userinfo, false),
540 $attachment['filename'],
541 $attachment['description'],
542 $attachment['filesize'],
543 implode(', ', (array)$obsolete),
544 $this->registry->options['trackerurl'] . '/viewattachment.php?attachmentid=' . $id
549 // ###################################################################
551 * Sends a new bug notification notice to all those who have the option
552 * turned no. This does not use fetch_users_with_on_bit() because a
553 * query is more effective.
557 * @param array Bug values array
558 * @param array Comment values array
560 function send_new_bug_notice($bug, $comment)
562 $userinfo = $this->registry->db->query("
563 SELECT user
.*, useremail
.*
564 FROM
" . TABLE_PREFIX . "useremail
AS useremail
565 LEFT JOIN
" . TABLE_PREFIX . "user
AS user
566 ON (user
.userid
= useremail
.userid
)
567 WHERE useremail
.relation
= 0
568 AND useremail
.mask
& " . $this->registry->emailoptions['notifications']['newbug'] . "
570 while ($user = $this->registry->db->fetch_array($userinfo))
572 if (!is_array($this->users["$user[userid
]"]))
574 $this->notices["$user[userid
]"][] = sprintf(
576 This bug has been added to the database:
577 ============================================
581 Product/Component/Version: %4$s
583 --------------------------------------------
585 --------------------------------------------
586 ============================================'),
589 construct_user_display($this->registry->userinfo, false),
590 $this->registry->datastore['product']["$bug[product
]"]['title'] . '/' . ($bug['component'] ? $this->registry->datastore['product']["$bug[component
]"]['title'] . '/' : '') . $this->registry->datastore['version']["$bug[version
]"]['version'],
593 $this->users["$user[userid
]"] = $user;
594 unset($this->users["$user[userid
]"]['mask'], $this->users["$user[userid
]"]['relation']);
596 $this->users["$user[userid
]"]['options']["$user[relation
]"] = $user['mask'];
600 // ###################################################################
602 * Generates an array of users who have a given email notification flag
603 * turned on in their bitfields.
607 * @param string Notification bitfield name
609 * @return array Array of users and their data
611 function fetch_users_with_on_bit($bitname)
615 foreach ($this->users AS $user)
617 foreach ($this->registry->emailoptions['relations'] AS $name => $bit)
619 if (in_array($user['userid'], $this->roles["$name"]) AND $user['options']["$bit"] & $this->registry->emailoptions['notifications']["$bitname"])
621 $idlist[] = $user['userid'];
626 $masters = array_unique($idlist);
629 foreach ($masters AS $userid)
631 $return["$userid"] =& $this->users["$userid"];
637 // ###################################################################
639 * Compiles and sends the actual emails to users.
645 // get the current bug for permissions checks
646 $bug = $this->registry
->db
->query_first("SELECT * FROM " . TABLE_PREFIX
. "bug WHERE bugid = " . $this->bug
['bugid']);
647 $this->registry
->mail
->setSubject(sprintf(_('%1$s Bug Notification - %2$s'), $this->registry->options['trackertitle
'], $this->bug['summary
']));
648 foreach ($this->notices AS $userid => $noticelist)
650 if ($userid == $this->registry->userinfo['userid
'])
655 // we wouldn't want people who favorite bugs getting hidden notices
656 if (!check_bug_permissions($bug, $this->users
["$userid"]))
658 $this->registry->debug("skipping user
$userid ({$this
->users
[$userid
]['email']}) because of permissions
");
662 $this->registry->mail->setBodyText(sprintf(_('Hi %1$s,
664 You are receiving this email because you have opted to get notifications for the %2$s bug tracker.
666 The bug is "%
5$s" (id
: %
6$s) located at %
4$s/showreport
.php
?bugid
=%
6$s
668 Here are the notices
:
669 ###################################################################
673 ###################################################################
674 If you no longer want to receive email from us
, please log into your account
and click the
"My Controls" tab at the top of the screen to change email preferences
.
677 $this->users
["$userid"]['displayname'],
678 $this->registry->options['trackertitle'],
679 implode("\n\n
", $noticelist),
680 $this->registry->options['trackerurl'],
681 $this->bug['summary'],
684 $this->registry->mail->send($this->users["$userid"]['email'], $this->users
["$userid"]['displayname']);
689 /*=====================================================================*\
690 || ###################################################################
693 || ###################################################################
694 \*=====================================================================*/