]>
src.bluestatic.org Git - bugdar.git/blob - includes/class_notification.php
2 /*=====================================================================*\
3 || ###################################################################
5 || # Copyright (c)2002-2007 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 2 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 (c)2002 - 2007, 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 ? $modified [ 'assignedto' ] : $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 $newbuggers = $this- > registry
-> db
-> query ( "SELECT userid FROM " . TABLE_PREFIX
. "useremail WHERE relation = " . $this- > registry
-> emailoptions
[ 'relations' ][ '-notapplicable-' ] . " AND mask & " . $this- > registry
-> emailoptions
[ 'notifications' ][ 'newbug' ]);
157 while ( $newbug = $this- > registry
-> db
-> fetch_array ( $newbuggers ))
159 $this- > roles
[ '-notapplicable-' ][ " $newbug [userid]" ] = $newbug [ 'userid' ];
162 $favorites = $this- > registry
-> db
-> query ( "SELECT userid FROM " . TABLE_PREFIX
. "favorite WHERE bugid = " . $this- > registry
-> clean ( $this- > bug
[ 'bugid' ], TYPE_UINT
));
163 while ( $fav = $this- > registry
-> db
-> fetch_array ( $favorites ))
165 $this- > roles
[ 'favorite' ][ " $fav [userid]" ] = $fav [ 'userid' ];
168 $voters = $this- > registry
-> db
-> query_first ( "SELECT userids FROM " . TABLE_PREFIX
. "vote WHERE bugid = " . $this- > registry
-> clean ( $this- > bug
[ 'bugid' ], TYPE_UINT
));
169 $this- > roles
[ 'voter' ] = preg_split ( '#,#' , $voters [ 'userids' ], 0 , PREG_SPLIT_NO_EMPTY
);
171 $commenters = $this- > registry
-> db
-> query ( "SELECT userid FROM " . TABLE_PREFIX
. "comment WHERE bugid = " . $this- > registry
-> clean ( $this- > bug
[ 'bugid' ], TYPE_UINT
));
172 while ( $comment = $this- > registry
-> db
-> fetch_array ( $commenters ))
174 $this- > roles
[ 'commenter' ][ " $comment [userid]" ] = $comment [ 'userid' ];
177 $masterids = array_merge ( $this- > roles
[ '-notapplicable-' ], $this- > roles
[ 'reporter' ], $this- > roles
[ 'assignee' ], $this- > roles
[ 'favorite' ], $this- > roles
[ 'voter' ], $this- > roles
[ 'commenter' ]);
178 $masterids = $this- > registry
-> funct
-> array_strip_empty ( array_unique ( $masterids ));
180 if ( is_array ( $masterids ) AND sizeof ( $masterids ) > 0 )
182 $userinfo = $this- > registry
-> db
-> query ( "
183 SELECT user.*, useremail.*
184 FROM " . TABLE_PREFIX
. "useremail AS useremail
185 LEFT JOIN " . TABLE_PREFIX
. "user AS user
186 ON (user.userid = useremail.userid)
187 WHERE useremail.userid IN (" . implode ( ',' , $masterids ) . ")
189 while ( $user = $this- > registry
-> db
-> fetch_array ( $userinfo ))
191 if (! is_array ( $this- > users
[ " $user [userid]" ]))
193 $this- > users
[ " $user [userid]" ] = $user ;
194 unset ( $this- > users
[ " $user [userid]" ][ 'mask' ], $this- > users
[ " $user [userid]" ][ 'relation' ]);
196 $this- > users
[ " $user [userid]" ][ 'options' ][ " $user [relation]" ] = $user [ 'mask' ];
201 // ###################################################################
203 * Sends the appropriate emails for changes to bugs. This function
204 * works a lot like the Logging class by taking BugAPI->objdata and
205 * BugAPI->values and then comparing the two arries and sending emails
206 * with the differences.
210 function send_bug_changes_notice ()
212 if (! isset ( $this- > modified
[ 'bugid' ]))
217 // fields with custom mask information
218 if ( $this- > original
[ 'assignedto' ] != $this- > modified
[ 'assignedto' ])
220 if ( $this- > original
[ 'assignedto' ] != '' )
222 $this- > notice_no_longer_assigned ( $this- > original
[ 'assignedto' ]);
224 if ( $this- > modified
[ 'assignedto' ] != '' )
226 $this- > notice_now_assigned ( $this- > modified
[ 'assignedto' ]);
229 if ( $this- > original
[ 'status' ] != $this- > modified
[ 'status' ])
231 $this- > notice_status_change ( $this- > original
[ 'status' ], $this- > modified
[ 'status' ]);
233 if ( $this- > original
[ 'resolution' ] != $this- > modified
[ 'resolution' ])
235 $this- > notice_resolution_change ( $this- > original
[ 'resolution' ], $this- > modified
[ 'resolution' ]);
237 if ( $this- > original
[ 'duplicates' ] != $this- > modified
[ 'duplicates' ])
239 $this- > notice_duplicates_change ( $this- > original
[ 'duplicates' ], $this- > modified
[ 'duplicates' ]);
242 // other standard fields that don't have custom masks
243 if ( $this- > original
[ 'severity' ] != $this- > modified
[ 'severity' ])
245 $this- > notice_severity_change ( $this- > original
[ 'severity' ], $this- > modified
[ 'severity' ]);
247 if ( $this- > original
[ 'priority' ] != $this- > modified
[ 'priority' ])
249 $this- > notice_priority_change ( $this- > original
[ 'priority' ], $this- > modified
[ 'priority' ]);
251 if (( $this- > original
[ 'product' ] != $this- > modified
[ 'product' ]) OR ( $this- > original
[ 'component' ] != $this- > modified
[ 'component' ]) OR ( $this- > original
[ 'version' ] != $this- > modified
[ 'version' ]))
253 $this- > notice_pcv_change ( array ( $this- > original
[ 'product' ], $this- > original
[ 'component' ], $this- > original
[ 'version' ]), array ( $this- > modified
[ 'product' ], $this- > modified
[ 'component' ], $this- > modified
[ 'version' ]));
261 foreach ( $dofields AS $field => $lookup )
263 if ( $this- > original
[ " $field" ] != $this- >modified[" $field" ])
265 $this- > notice_other_change ( $field , $this- > original
[ " $field" ], $this- >modified[" $field" ]);
270 // ###################################################################
272 * Sends an email to the specified user ID that they are no longer the
273 * person assigned to the bug.
277 * @param integer User ID to send to
279 function notice_no_longer_assigned ( $userid )
281 if ( $this- > users
[ " $userid" ]['options'][0] & $this- >registry->emailoptions['notifications']['assignedto'] AND in_array( $userid , $this- >roles['-notapplicable-']))
283 $user = construct_user_display( $this- >registry->userinfo, false);
284 eval(' $part = " ' . $this- >registry->template->fetch(FetchEmailPath(' notice_unassigned
. part
', $this- >_localeFromUserId( $userid ))) . ' ";');
285 $this- >notices[" $userid" ][] = $part ;
289 // ###################################################################
291 * Informs the user that they have been made the assignee of the bug.
295 * @param integer User ID
297 function notice_now_assigned ( $userid )
299 if ( $this- > users
[ " $userid" ]['options'][0] & $this- >registry->emailoptions['notifications']['assignedto'] AND in_array( $userid , $this- >roles['-notapplicable-']))
301 $user = construct_user_display( $this- >registry->userinfo, false);
302 eval(' $email = " ' . $this- >registry->template->fetch(FetchEmailPath(' notice_assigned
. part
', $this- >_localeFromUserId( $userid ))) . ' ";');
303 $this- >notices[" $userid" ][] = $email ;
307 // ###################################################################
309 * Sends a message to inform users that the status has changed.
313 * @param integer Old status
314 * @param integer New status
316 function notice_status_change ( $old , $new )
318 $userlist = $this- > fetch_users_with_on_bit ( 'statusresolve' );
319 $old = bugdar
:: $datastore [ 'status' ][ $old ][ 'status' ];
320 $new = bugdar
:: $datastore [ 'status' ][ $new ][ 'status' ];
321 foreach ( $userlist AS $userid => $user )
323 eval ( ' $email = "' . $this- > registry
-> template
-> fetch ( FetchEmailPath ( 'notice_status.part' , $this- > _localeFromUserId ( $userid ))) . '";' );
324 $this- > notices
[ " $user [userid]" ][] = $email ;
328 // ###################################################################
330 * Sends an email to inform users that the resolution has changed.
334 * @param integer Old resolution
335 * @param integer New resolution
337 function notice_resolution_change ( $old , $new )
339 $userlist = $this- > fetch_users_with_on_bit ( 'statusresolve' );
340 $old = bugdar
:: $datastore [ 'resolution' ][ $old ][ 'resolution' ];
341 $new = bugdar
:: $datastore [ 'resolution' ][ $new ][ 'resolution' ];
342 foreach ( $userlist AS $userid => $user )
344 eval ( ' $email = "' . $this- > registry
-> template
-> fetch ( FetchEmailPath ( 'notice_resolution.part' , $this- > _localeFromUserId ( $userid ))) . '";' );
345 $this- > notices
[ " $user [userid]" ][] = $email ;
349 // ###################################################################
351 * Informs users that the duplicates list has changed.
355 * @param string Old duplicates list
356 * @param string New duplicates list
358 function notice_duplicates_change ( $old , $new )
360 $userlist = $this- > fetch_useres_with_on_bit ( 'duplicates' );
361 foreach ( $userlist AS $userid => $user )
363 eval ( ' $email = "' . $this- > registry
-> template
-> fetch ( FetchEmailPath ( 'notice_duplicates.part' , $this- > _localeFromUserId ( $userid ))) . '";' );
364 $this- > notices
[ " $user [userid]" ][] = $email ;
368 // ###################################################################
370 * Sends an email to inform users that the severity has changed.
374 * @param integer Old severity
375 * @param integer New severity
377 function notice_severity_change ( $old , $new )
379 $userlist = $this- > fetch_users_with_on_bit ( 'otherfield' );
380 $old = bugdar
:: $datastore [ 'severity' ][ $old ][ 'severity' ];
381 $new = bugdar
:: $datastore [ 'severity' ][ $new ][ 'severity' ];
382 foreach ( $userlist AS $userid => $user )
384 eval ( ' $email = "' . $this- > registry
-> template
-> fetch ( FetchEmailPath ( 'notice_severity.part' , $this- > _localeFromUserId ( $userid ))) . '";' );
385 $this- > notices
[ " $user [userid]" ][] = $email ;
389 // ###################################################################
391 * Informs users that the priority changed.
395 * @param integer Old priority
396 * @param integer New priority
398 function notice_priority_change ( $old , $new )
400 $userlist = $this- > fetch_users_with_on_bit ( 'otherfield' );
401 $old = bugdar
:: $datastore [ 'priority' ][ $old ][ 'priority' ];
402 $new = bugdar
:: $datastore [ 'priority' ][ $new ][ 'priority' ];
403 foreach ( $userlist AS $userid => $user )
405 eval ( ' $email = "' . $this- > registry
-> template
-> fetch ( FetchEmailPath ( 'notice_priority.part' , $this- > _localeFromUserId ( $userid ))) . '";' );
406 $this- > notices
[ " $user [userid]" ][] = $email ;
410 // ###################################################################
412 * Sends an email telling users that the product, component, or version
413 * has changed. This is done all at once because you really need to see
414 * the whole thing in the notice.
418 * @param array Original PCV
419 * @param array Modified PCV
421 function notice_pcv_change ( $old , $new )
423 $userlist = $this- > fetch_users_with_on_bit ( 'otherfield' );
425 $old = bugdar
:: $datastore [ 'product' ][ " $old [0]" ][ 'title' ] . '/' . ( $old [ 1 ] ? bugdar
:: $datastore [ 'product' ][ " $old [1]" ][ 'title' ] . '/' : '' ) . bugdar
:: $datastore [ 'version' ][ " $old [2]" ][ 'version' ];
426 $new = bugdar
:: $datastore [ 'product' ][ " $new [0]" ][ 'title' ] . '/' . ( $new [ 1 ] ? bugdar
:: $datastore [ 'product' ][ " $new [1]" ][ 'title' ] . '/' : '' ) . bugdar
:: $datastore [ 'version' ][ " $new [2]" ][ 'version' ];
428 foreach ( $userlist AS $userid => $user )
430 eval ( ' $email = "' . $this- > registry
-> template
-> fetch ( FetchEmailPath ( 'notice_product.part' , $this- > _localeFromUserId ( $userid ))) . '";' );
431 $this- > notices
[ " $user [userid]" ][] = $email ;
435 // ###################################################################
437 * Sends the appropriate users information about a new comment being
438 * posted to the bug report.
442 * @param array CommentAPI->values array
444 function send_new_comment_notice ( $comment )
446 $userlist = $this- > fetch_users_with_on_bit ( 'newcomment' );
447 foreach ( $userlist AS $userid => $user )
449 $user = construct_user_display ( $this- > registry
-> userinfo
, false );
450 $date = $this- > registry
-> modules
[ 'date' ]-> format ( $this- > registry
-> options
[ 'dateformat' ], $comment [ 'dateline' ]);
452 eval ( ' $email = "' . $this- > registry
-> template
-> fetch ( FetchEmailPath ( 'notice_comment.part' , $this- > _localeFromUserId ( $userid ))) . '";' );
453 $this- > notices
[ " $userid" ][] = $email ;
457 // ###################################################################
459 * A notice for an individual field changing.
463 * @param string Field name
464 * @param mixed Original value
465 * @param mixed Modified value
467 function notice_other_change( $name , $old , $new )
469 $userlist = $this- >fetch_users_with_on_bit('otherfield');
470 foreach ( $userlist AS $userid => $user )
472 eval(' $email = " ' . $this- >registry->template->fetch(FetchEmailPath(' notice_other
. part
', $this- >_localeFromUserId( $userid ))) . ' ";');
473 $this- >notices[" $user [ userid
] "][] = $email ;
477 // ###################################################################
479 * Sends appropriate users a notice when a new attachment has been
484 * @param array AttachmentAPI->values array
485 * @param array List of all attachments made obsolete
486 * @param array Newly-inserted attachment ID
488 function send_new_attachment_notice( $attachment , $obsolete , $id )
490 $userlist = $this- >fetch_users_with_on_bit('newattachment');
491 $url = bugdar:: $options ['trackerurl'] . " / viewattachment
. php
? attachmentid
= $id" ;
492 foreach ( $userlist AS $userid => $user )
494 $user = construct_user_display ( $this- > registry
-> userinfo
, false );
495 $obsoletes = implode ( ', ' , ( array ) $obsolete );
497 eval ( ' $email = "' . $this- > registry
-> template
-> fetch ( FetchEmailPath ( 'notice_attachment.part' , $this- > _localeFromUserId ( $userid ))) . '";' );
498 $this- > notices
[ " $userid" ][] = $email ;
502 // ###################################################################
504 * Sends a new bug notification notice to all those who have the option
505 * turned no. This does not use fetch_users_with_on_bit() because a
506 * query is more effective.
510 * @param array Bug values array
511 * @param array Comment values array
513 function send_new_bug_notice( $bug , $comment )
515 $userinfo = $this- >registry->db->query("
516 SELECT user
.*, useremail
.*
517 FROM
" . TABLE_PREFIX . " useremail
AS useremail
518 LEFT JOIN
" . TABLE_PREFIX . " user
AS user
519 ON ( user
. userid
= useremail
. userid
)
520 WHERE useremail
. relation
= 0
521 AND useremail
. mask
& " . $this- >registry->emailoptions['notifications']['newbug'] . "
523 while ( $userInfo = $this- >registry->db->fetch_array( $userinfo ))
525 if (!is_array( $this- >users[" $userInfo [ userid
] "]))
527 $user = construct_user_display( $this- >registry->userinfo, false);
528 $this- >users[" $userInfo [ userid
] "] = $userInfo ;
529 $product = bugdar:: $datastore ['product'][" $bug [ product
] "]['title'] . '/' . ( $bug ['component'] ? bugdar:: $datastore ['product'][" $bug [ component
] "]['title'] . '/' : '') . bugdar:: $datastore ['version'][" $bug [ version
] "]['version'];
530 eval(' $email = " ' . $this- >registry->template->fetch(FetchEmailPath(' notice_new_bug
. part
', $this- >_localeFromUserId( $userInfo [' userid
']))) . ' ";');
531 $this- >notices[" $userInfo [ userid
] "][] = $email ;
532 unset( $this- >users[" $userInfo [ userid
] "]['mask'], $this- >users[" $userInfo [ userid
] "]['relation']);
534 $this- >users[" $userInfo [ userid
] "]['options'][" $userInfo [ relation
] "] = $userInfo ['mask'];
538 // ###################################################################
540 * Generates an array of users who have a given email notification flag
541 * turned on in their bitfields.
545 * @param string Notification bitfield name
547 * @return array Array of users and their data
549 function fetch_users_with_on_bit( $bitname )
553 foreach ( $this- >users AS $user )
555 foreach ( $this- >registry->emailoptions['relations'] AS $name => $bit )
557 if (in_array( $user ['userid'], $this- >roles[" $name" ]) AND $user [ 'options' ][ " $bit" ] & $this- >registry->emailoptions['notifications'][" $bitname" ])
559 $idlist [] = $user [ 'userid' ];
564 $masters = array_unique ( $idlist );
567 foreach ( $masters AS $userid )
569 $return [ " $userid" ] =& $this- >users[" $userid" ];
575 // ###################################################################
577 * Compiles and sends the actual emails to users.
583 // get the current bug for permissions checks
584 $bug = $this- > registry
-> db
-> query_first ( "SELECT * FROM " . TABLE_PREFIX
. "bug WHERE bugid = " . $this- > bug
[ 'bugid' ]);
585 foreach ( $this- > notices
AS $userid => $noticelist )
587 if ( $userid == $this- > registry
-> userinfo
[ 'userid' ])
589 $this- > registry
-> debug ( "skipping user $userid because they're the one doing the thing" );
593 // we wouldn't want people who favorite bugs getting hidden notices
594 if (! check_bug_permissions ( $bug , $this- > users
[ " $userid" ]))
596 $this- >registry->debug(" skipping user
$userid ({ $this
-> users
[ $userid
][ 'email' ]}) because of permissions
");
600 $parts = implode(" \n\n
", $noticelist );
602 eval(' $email = " ' . $this- >registry->template->fetch(FetchEmailPath(' bugnotification
. xml
', $this- >_localeFromUserId( $userid ))) . ' ";');
603 $email = $this- >registry->xml->parse( $email , true);
604 $this- >registry->mail->setSubject( $email ['email']['subject']['value']);
605 $this- >registry->mail->setBodyText( $email ['email']['bodyText']['value']);
607 if (!empty( $this- >users[" $userid" ][ 'email' ]))
609 $this- > registry
-> mail
-> send ( $this- > users
[ " $userid" ]['email'], $this- >users[" $userid" ][ 'displayname' ]);
613 $this- > registry
-> debug ( "not sending an email to " . $userid . " because they don't have one?" );
618 // ###################################################################
620 * Returns the locale name from a given user ID
622 * @param integer User ID
624 * @return string Locale
626 function _localeFromUserId ( $userid )
628 $langcode = bugdar
:: $datastore [ 'language' ][ $this- > users
[ $userid ][ 'languageid' ]][ 'langcode' ];
631 $langcode = bugdar
:: $datastore [ 'language' ][ $this- > registry
-> options
[ 'defaultlanguage' ]][ 'langcode' ];