/[drupal]/contributions/modules/interact/interact.module
ViewVC logotype

Contents of /contributions/modules/interact/interact.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download) (as text)
Sun Sep 28 16:23:46 2008 UTC (13 months, 4 weeks ago) by prarie
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-5
File MIME type: text/x-php
Initial commit of interaction centre. Allows users to interact within large trusted communities that is more personal.
1 <?php
2
3 // $Id: interact.module 415 2008-05-03 01:35:51Z prarie $
4
5 define('INTERACT_NOTIFY_NO_EMAIL', 1);
6 define('INTERACT_NOTIFY_IMMEDIATE', 2);
7 define('INTERACT_NOTIFY_DIGEST_DAILY', 3);
8 define('INTERACT_NOTIFY_DIGEST_WEEKLY', 4);
9
10 define('INTERACT_EMAIL_NOTIFY_SUBJECT', "[@site_name] Actions taken");
11 define('INTERACT_EMAIL_NOTIFY_BODY', "There @were_#_actions_taken on\n@site_name:\n\n@actions_text\nAbove activity and more:\n@all_activity_url\n\nThis is the latest activity from all site activity you have requested\nnotification. You can change your preferences for receiving email\nor your notifications by clicking the links below.\n\nNotifications:\n@notify_url\n\nEmail:\n@user_prefs_url\n\nThis message sent automatically by @site_url. Please inform us if you feel you should not have received this email.\n");
12
13 define('INTERACT_THICKBOX_QUERY', 'height=300&width=450&modal=true');
14
15 /**
16 * Implementation of menu hook.
17 *
18 * @param bool $may_cache
19 * @return array
20 */
21 function interact_menu($may_cache) {
22 $items = array();
23 if ($may_cache) {
24 $items[] = array(
25 'path' => 'admin/settings/interact',
26 'title' => t('Interaction centre'),
27 'description' => t('Configure user interaction options.'),
28 'access' => user_access('administer interaction centre'),
29 'callback' => 'drupal_get_form',
30 'callback arguments' => array('interact_settings'),
31 );
32 $items[] = array(
33 'path' => 'my-interests',
34 'title' => t('My interests and notifications'),
35 'description' => t('All activity you requested to be notified about or relating to content you posted.'),
36 'access' => user_access('view user actions'),
37 'callback' => 'interact_my_interests',
38 'type' => MENU_SUGGESTED_ITEM,
39 );
40 $items[] = array(
41 'path' => 'my-interests/notify',
42 'title' => t('My notification requests'),
43 'description' => t('Items you have requested to be notified about.'),
44 'access' => user_access('view user actions'),
45 'callback' => 'interact_notification_requests',
46 'type' => MENU_SUGGESTED_ITEM,
47 );
48 $items[] = array(
49 'path' => 'public-messages',
50 'title' => t('Message centre'),
51 'access' => user_access('view public messages'),
52 'callback' => 'interact_view_public_messages',
53 'type' => MENU_CALLBACK,
54 );
55 $items[] = array(
56 'path' => 'user-actions',
57 'title' => t('User actions'),
58 'access' => user_access('view user actions'),
59 'callback' => 'interact_view_actions',
60 'type' => MENU_CALLBACK,
61 );
62 $items[] = array(
63 'path' => 'interact-watch',
64 'title' => t('Request notification'),
65 'access' => user_access('view user actions'),
66 'callback' => 'interact_watch',
67 'type' => MENU_CALLBACK,
68 );
69 }
70 return $items;
71 }
72
73 /**
74 * Implementation of perm hook.
75 *
76 * @return array
77 */
78 function interact_perm() {
79 return array(
80 'administer interaction centre',
81 'view public messages',
82 'post public messages',
83 'view user actions',
84 'add notification requests'
85 // 'create interaction groups',
86 // 'join interaction groups',
87 );
88 }
89
90 /**
91 * Implementation of nodeapi hook.
92 *
93 * @param object $node
94 * @param string $op
95 * @param mixed $a3
96 * @param mixed $a4
97 */
98 function interact_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
99 global $user;
100
101 $action_type = NULL;
102 switch ($op) {
103 case 'insert' :
104 if ($node->status) {
105 $action_type = 'node-new';
106 }
107 break;
108 case 'update' :
109 if ($node->status) {
110 $action_type = 'node-edit';
111 }
112 break;
113 case 'delete' :
114 interact_delete_actions('node', $node->nid);
115 break;
116 }
117 if (isset($action_type)) {
118 $type_name = node_get_types('name', $node);
119 $message = '';
120 $teaser = '';
121 if ('node-new' == $action_type) {
122 $message = t('!user posted a new %type !title', array('!user' => l($user->name, 'user/' . $user->uid), '%type' => $type_name, '!title' => l($node->title, 'node/' . $node->nid)));
123 $teaser = interact_action_teaser($node->teaser);
124 }
125 else {
126 $message = t('!user edited the %type !title', array('!user' => l($user->name, 'user/' . $user->uid), '%type' => $type_name, '!title' => l($node->title, 'node/' . $node->nid)));
127 }
128 if (drupal_strlen($teaser) > variable_get('interact_teaser_length', 100)) {
129 $teaser = drupal_substr($teaser, 0, strrpos($teaser, ' '));
130 }
131 $aid = interact_save_user_action($user->uid, $action_type, $node->nid, $message, $teaser);
132 $notify_types = array();
133 $uid_array = array();
134 if ('node-edit' == $action_type) {
135 $result = db_query('SELECT edit_own_items FROM {interact_preference} WHERE uid = %d', $node->uid);
136 if (0 == db_num_rows($result) || db_result($result)) {
137 // default is to notify of node edits to the user that owns the node
138 $uid_array[$node->uid] = 0;
139 }
140 interact_queue_notification($aid, 'user', 'edit', $user->uid);
141 interact_get_preference_users('edit_nodes', $uid_array);
142 }
143 else {
144 interact_queue_notification($aid, 'user', 'new', $user->uid);
145 interact_get_preference_users('new_nodes', $uid_array);
146 }
147 $result = db_query('SELECT tid FROM {term_node} WHERE nid = %d', $node->nid);
148 while ($row = db_fetch_object($result)) {
149 interact_queue_notification($aid, 'term', 'node-edit' == $action_type ? 'edit' : 'new', $row->tid);
150 }
151 interact_queue_users($uid_array, $aid);
152 interact_immediate_notification();
153 }
154 }
155
156 /**
157 * Implementation of comment hook.
158 *
159 * @param mixed $a1
160 * @param string $op
161 */
162 function interact_comment($a1, $op) {
163 global $user;
164
165 $action_type = NULL;
166 switch ($op) {
167 case 'insert' :
168 $action_type = 'comment-new';
169 break;
170 case 'update' :
171 $action_type = 'comment-edit';
172 break;
173 case 'delete' :
174 // remove any actions related to the node being deleted
175 interact_delete_actions('comment', $a1->cid);
176 break;
177 }
178 if (isset($action_type)) {
179 $node = node_load($a1['nid']);
180 $message = NULL;
181 $uid_array = array();
182 $teaser = '';
183 if ('comment-new' == $action_type) {
184 $message = t('!user posted a new !comment on !title', array('!user' => l($user->name, 'user/' . $user->uid), '!comment' => l(comment, 'node/' . $node->nid, array(), NULL, 'comment-' . $a1['cid']), '!title' => l($node->title, 'node/' . $node->nid)));
185 $teaser = interact_action_teaser($a1['comment']);
186 }
187 else {
188 $message = t('!user edited a !comment on !title', array('!user' => l($user->name, 'user/' . $user->uid), '!comment' => l(comment, 'node/' . $node->nid, array(), NULL, 'comment-' . $a1['cid']), '!title' => l($node->title, 'node/' . $node->nid)));
189 }
190
191 // save the user action
192 $aid = interact_save_user_action($user->uid, $action_type, $a1['cid'], $message, $teaser);
193
194 if ('comment-new' == $action_type) {
195 // do the notification logic on the tree only when it's a new comment
196 $uid_array = array();
197 if (empty($a1['pid'])) {
198 interact_queue_notification($aid, 'node', 'direct_comments', $a1['nid']);
199 }
200 else {
201 interact_queue_notification($aid, 'node', 'all_comments', $a1['nid']);
202 $pid = $a1['pid'];
203 interact_queue_notification($aid, 'comment', 'direct', $pid);
204 while (!empty($pid)) {
205 interact_queue_notification($aid, 'comment', 'all', $pid);
206 $row = db_fetch_object(db_query('SELECT pid, uid, cid FROM {comments} WHERE cid = %d', $pid));
207 $pid = $row->pid;
208
209 // inform the poster of the comment this is a reply to
210 if ($a1['pid'] = $row->cid) {
211 $result = db_query('SELECT new_posts_to_own FROM {interact_preference} WHERE uid = %d', $row->uid);
212 if (0 == db_num_rows($result) || db_result($result)) {
213 // default is to notify of node edits to the user that owns the node
214 $uid_array[$row->uid] = 0;
215 }
216 }
217 }
218 }
219
220 $result = db_query('SELECT new_posts_to_own FROM {interact_preference} WHERE uid = %d', $node->uid);
221 if (0 == db_num_rows($result) || db_result($result)) {
222 // default is to notify of node edits to the user that owns the node
223 $uid_array[$node->uid] = 0;
224 }
225 interact_get_preference_users('new_comments', $uid_array);
226 interact_queue_notification($aid, 'user', 'comment', $user->uid);
227 }
228 else {
229 interact_get_preference_users('edit_comments', $uid_array);
230 }
231 $result = db_query('SELECT tid FROM {term_node} WHERE nid = %d', $node->nid);
232 while ($row = db_fetch_object($result)) {
233 interact_queue_notification($aid, 'term', 'node-edit' == $action_type ? 'edit' : 'new', $row->tid);
234 }
235 interact_queue_users($uid_array, $aid);
236 interact_immediate_notification();
237 }
238 }
239
240 function interact_delete_actions($type, $id) {
241 $aids = array();
242 $result = db_query('SELECT aid FROM {interact_action} WHERE type LIKE \'%s-%%\' AND id = %d', $type, $id);
243 while ($row = db_fetch_object($result)) {
244 $aids[$row->aid] = $row->aid;
245 }
246 $result = db_query('SELECT aid FROM {interact_notify} WHERE type = \'%s\' AND id = %d', $type, $id);
247 while ($row = db_fetch_object($result)) {
248 $aids[$row->aid] = $row->aid;
249 }
250 if (0 < count($aids)) {
251 $aid_string = implode(',', $aids);
252 db_query('DELETE FROM {interact_action} WHERE aid IN (%s)', $aid_string);
253 db_query('DELETE FROM {interact_notify} WHERE aid IN (%s)', $aid_string);
254 db_query('DELETE FROM {interact_notification} WHERE aid IN (%s)', $aid_string);
255 }
256 }
257
258 function interact_action_teaser($text) {
259 $teaser = strip_tags($text);
260 $max_length = variable_get('interact_teaser_length', 150);
261 if (drupal_strlen($teaser) > $max_length) {
262 $teaser = drupal_substr($teaser, 0, $max_length);
263 if (FALSE !== ($pos = strrpos($teaser, ' '))) {
264 $teaser = drupal_substr($teaser, 0, $pos) . t('...');
265 }
266 }
267 return $teaser;
268 }
269
270 /**
271 * Implementation of user hook.
272 *
273 * @param string $op
274 * @param array $edit form values entered
275 * @param object $account user object that is applicable
276 * @param string $category active category
277 * @return mixed
278 */
279 function interact_user($op, &$edit, &$account, $category = NULL) {
280 switch ($op) {
281 case 'view' :
282 $user_actions = interact_view_actions($account->uid, NULL, FALSE);
283 $user_messages = interact_view_public_messages($account->uid, NULL, FALSE);
284 if (!empty($user_actions) || !empty($user_messages)) {
285 drupal_add_css(_interact_get_path() . '/interact.css');
286 return array(t('User interaction') => array('interact' => array(
287 'title' => t('Actions and public messages'),
288 'value' => theme('interact_user_view', $user_actions, $user_messages),
289 'class' => 'interact',
290 )));
291 }
292 break;
293 case 'form' :
294 if ('account' == $category) {
295 $form['interact'] = array(
296 '#type' => 'fieldset',
297 '#title' => t('Interaction centre preferences'),
298 '#weight' => 1,
299 '#collapsible' => TRUE,
300 '#description' => t('<a name="interact"></a>Settings for how you will be informed when items posted show in your !interaction-centre. All comments or edits to content you have !marked will show in your interaction centre and will be emailed to you.', array('!interaction-centre' => l(t('interaction centre'), 'interact'), '!marked' => l(t('marked'), 'interact/notify'))),
301 );
302 $form['interact_form_presented'] = array(
303 '#type' => 'value',
304 '#value' => TRUE,
305 );
306 $prefs = interact_get_user_prefs($account->uid);
307 $form['interact']['interact_notification_email'] = array(
308 '#type' => 'select',
309 '#title' => 'Email notification',
310 '#default_value' => $prefs['email_pref'],
311 '#options' => array(
312 INTERACT_NOTIFY_NO_EMAIL => t('No email'),
313 INTERACT_NOTIFY_IMMEDIATE => t('Send email immediately'),
314 INTERACT_NOTIFY_DIGEST_DAILY => t('Send at most one email per day'),
315 INTERACT_NOTIFY_DIGEST_WEEKLY => t('Send at most one email per week'),
316 ),
317 '#description' => t('Email notifiction will apply for the global preferences below and the items that you have !marked.', array('!marked' => l(t('marked'), 'interact/marked')))
318 );
319 $default = 0;
320 $default = 0;
321 if ($prefs['new_nodes']) {
322 $default = 1;
323 if ($prefs['edit_nodes']) {
324 $default = 3;
325 }
326 }
327 elseif ($prefs['edit_nodes']) {
328 $default = 2;
329 }
330 elseif ($prefs['edit_own_items']) {
331 $default = 4;
332 }
333 $form['interact']['interact_notification_content'] = array(
334 '#type' => 'select',
335 '#title' => t('Global notification of content'),
336 '#default_value' => $default,
337 '#options' => array(
338 t('No notification'),
339 t('All new content'),
340 t('All edits of content'),
341 t('All new content and edits of content'),
342 t('Only edits of content you posted'),
343 ),
344 );
345 $default = 0;
346 if ($prefs['new_comments']) {
347 $default = 1;
348 if ($prefs['edit_comments']) {
349 $default = 3;
350 }
351 }
352 elseif ($prefs['edit_comments']) {
353 $default = 2;
354 }
355 elseif ($prefs['new_posts_to_own']) {
356 $default = 4;
357 }
358 $form['interact']['interact_notification_comment'] = array(
359 '#type' => 'select',
360 '#title' => t('Global notification of comments'),
361 '#default_value' => $default,
362 '#options' => array(
363 t('No notification'),
364 t('All new comments'),
365 t('All edits of comments'),
366 t('All new comments and edits to comments'),
367 t('Only comments on content you posted'),
368 ),
369 );
370 return $form;
371 }
372 break;
373 case 'update' :
374 // only update values if the form was presented
375 if (isset($edit['interact_form_presented']) && $edit['interact_form_presented']) {
376 if (!empty($edit['interact_mini_pic'])) {
377 file_delete($edit['interact_mini_pic']);
378 }
379 $edit['interact_mini_pic'] = NULL;
380 $profile_picture = NULL;
381 if (!empty($edit['picture'])) {
382 $profile_picture = $edit['picture'];
383 }
384 elseif ($account->picture) {
385 $profile_picture = $account->picture;
386 }
387 if (isset($profile_picture)) {
388 $edit['interact_mini_pic'] = interact_mini_pic($profile_picture);
389 }
390
391 $insert_prefs = FALSE;
392 $new_nodes = 0;
393 $new_comments = 0;
394 $edit_nodes = 0;
395 $edit_comments = 0;
396 $edit_own_items = 1;
397 $new_posts_to_own = 1;
398
399 db_query('DELETE FROM {interact_preference} WHERE uid = %d', $account->uid);
400 watchdog('interact-preference', t('Deleted preference record for user %user (if any existed).', array('%user' => $account->uid)));
401 if (isset($edit['interact_notification_email']) && INTERACT_NOTIFY_IMMEDIATE != $edit['interact_notification_email']) {
402 $insert_prefs = TRUE;
403 }
404 if (4 != $edit['interact_notification_content']) {
405 $insert_prefs = TRUE;
406 $edit_own_items = 0;
407 switch ($edit['interact_notification_content']) {
408 case 1 :
409 $new_nodes = 1;
410 break;
411 case 2 :
412 $edit_nodes = 1;
413 break;
414 case 3 :
415 $new_nodes = 1;
416 $edit_nodes = 1;
417 break;
418 }
419 }
420 if (4 != $edit['interact_notification_comment']) {
421 $insert_prefs = TRUE;
422 $new_posts_to_own = 0;
423 switch ($edit['interact_notification_comment']) {
424 case 1 :
425 $new_comments = 1;
426 break;
427 case 2 :
428 $edit_comments = 1;
429 break;
430 case 3 :
431 $new_comments = 1;
432 $edit_comments = 1;
433 break;
434 }
435 }
436 if ($insert_prefs) {
437 db_query('INSERT INTO {interact_preference} (uid, email_pref, new_nodes, new_comments, edit_nodes, edit_comments, edit_own_items, new_posts_to_own) VALUES (%d, %d, %d, %d, %d, %d, %d, %d)', $account->uid, $edit['interact_notification_email'], $new_nodes, $new_comments, $edit_nodes, $edit_comments, $edit_own_items, $edit_own_items, $new_posts_to_own);
438 watchdog('interact-preference', t('Inserted new preference record for user %user', array('%user' => $account->uid)));
439 }
440 $edit['interact_notification_email'] = NULL;
441 $edit['interact_notification_content'] = NULL;
442 $edit['interact_notification_comment'] = NULL;
443 }
444 break;
445 }
446 }
447
448 function interact_get_user_prefs($uid) {
449 $interact_settings = db_fetch_array(db_query('SELECT * FROM {interact_preference} WHERE uid = %d', $uid));
450 if (empty($interact_settings)) {
451 $interact_settings = variable_get('interact_prefs_default', array('email_pref' => INTERACT_NOTIFY_IMMEDIATE, 'edit_own_items' => 1, 'new_posts_to_own' => 1));
452 }
453 return $interact_settings;
454 }
455
456 function interact_mini_pic($profile_picture) {
457 $image = image_get_info($profile_picture);
458 $mini_icon = NULL;
459 if (FALSE !== $image) {
460 $dirname = file_create_path() . '/interact/mini-pics';
461 if (!is_dir($dirname)) {
462 if (!is_file($dirname)) {
463 if (!is_dir(dirname($dirname))) {
464 if (!is_file(dirname($dirname))) {
465 mkdir(dirname($dirname));
466 }
467 else {
468 watchdog('interact', t('File %dir exists so directory cannot be created.', array('%dir' => $dirname)), WATCHDOG_ERROR);
469 }
470 }
471 mkdir($dirname);
472 }
473 else {
474 watchdog('interact', t('File %dir exists so directory cannot be created.', array('%dir' => $dirname)), WATCHDOG_ERROR);
475 }
476 }
477 $filename = $dirname . '/' . basename($profile_picture);
478 if (file_exists($filename)) {
479 file_delete($filename);
480 }
481 $dims = explode('x', variable_get('interact_mini_pic_max_size', '50x100'));
482 if ($image['width'] > $dims[0] || $image['height'] > $dims[1]) {
483 image_scale($profile_picture, $filename, $dims[0], $dims[1]);
484 } else {
485 file_copy($profile_picture, $filename);
486 }
487 $mini_icon = $filename;
488 }
489 return $mini_icon;
490 }
491
492 function interact_form_alter($form_id, &$form) {
493 switch ($form_id) {
494 case 'user_admin_settings' :
495 $form['#submit']['interact_save_default_profile_picture'] = array();
496 break;
497 }
498 }
499
500 function interact_save_default_profile_picture($form_id, $values) {
501 $default_mini_pic = variable_get('interact_mini_pic_default', '');
502 if (!empty($default_mini_pic)) {
503 file_delete($default_mini_pic);
504 }
505 if (!empty($values['user_picture_default'])) {
506 if ($default_mini_pic = interact_mini_pic($values['user_picture_default'])) {
507 variable_set('interact_mini_pic_default', $default_mini_pic);
508 }
509 }
510 }
511
512 function interact_save_user_action($uid, $type, $id, $message, $teaser = '') {
513 $aid = db_next_id('{interact_action}_aid');
514 db_query('INSERT INTO {interact_action} (aid, uid, type, id, create_time, message, teaser) VALUES (%d, %d, \'%s\', %d, %d, \'%s\', \'%s\')', $aid, $uid, $type, $id, time(), $message, $teaser);
515 return $aid;
516 }
517
518 function interact_get_preference_users($field, &$uid_array) {
519 $result = db_query('SELECT uid FROM {interact_preference} WHERE ' . $field . ' = 1');
520 while ($row = db_fetch_object($result)) {
521 $uid_array[$row->uid] = empty($row->aid) ? 0 : $row->aid;
522 }
523 }
524
525 function interact_queue_users($uid_array, $aid) {
526 global $user;
527 if (isset($uid_array[$user->uid])) {
528 // don't notify someone of an action they took
529 unset($uid_array[$user->uid]);
530 }
531 foreach ($uid_array as $uid => $notify_aid) {
532 db_query('REPLACE INTO {interact_notification} (uid, aid, notify_aid) VALUES (%d, %d, %d)', $uid, $aid, $notify_aid);
533 }
534 }
535
536 function interact_immediate_notification() {
537 global $user;
538 // get the actions to report immediately
539 $result = db_query('SELECT a.*, n.uid AS to_uid FROM {interact_action} a JOIN {interact_notification} n ON a.aid = n.aid LEFT JOIN {interact_preference} p ON n.uid = p.uid WHERE (p.email_pref IS NULL OR p.email_pref = %d) AND status = 0 ORDER BY n.uid', INTERACT_NOTIFY_IMMEDIATE);
540 $actions_taken = array();
541 $last_uid = NULL;
542 $start_time = time();
543 $time_limit = variable_get('interact_email_max_time_immediate', 5);
544 while ($row = db_fetch_object($result)) {
545 if ($last_uid != $row->to_uid) {
546 // make sure we don't send notification to the current user
547 if (0 < count($actions_taken)) {
548 interact_mail($last_uid, $actions_taken, INTERACT_NOTIFY_IMMEDIATE);
549 $actions_taken = array();
550 if (time() - $start_time > $time_limit) {
551 break;
552 }
553 }
554 }
555 $last_uid = $row->to_uid;
556 $actions_taken[] = $row;
557 }
558 // make sure we don't send notification to the current user
559 if (0 < count($actions_taken)) {
560 interact_mail($last_uid, $actions_taken, INTERACT_NOTIFY_IMMEDIATE);
561 }
562 }
563
564 function interact_queue_notification($aid, $type, $sub_type, $id) {
565 // add new notifications for users that had previously requested
566 // notifications for the type, sub_type and id given but ignore if
567 // the user is the same as the current user (do not notify the posting
568 // user in any case)
569 global $user;
570 db_query('REPLACE INTO {interact_notification} (uid, aid, notify_aid) SELECT a.uid, %d, n.aid FROM {interact_action} a JOIN {interact_notify} n ON a.aid = n.aid WHERE n.type = \'%s\' AND n.sub_type = \'%s\' AND n.id = %d AND a.uid != %d', $aid, $type, $sub_type, $id, $user->uid);
571 }
572
573 function interact_mail($to_uid, $actions, $notification_type) {
574 $from = variable_get('site_mail', ini_get('sendmail_from'));
575 $subject = t(variable_get('interact_email_subject', INTERACT_EMAIL_NOTIFY_SUBJECT), array('@site_name' => variable_get('site_name', 'Drupal')));
576 $actions_text = '';
577 $aids = array();
578 foreach ($actions as $action) {
579 $actions_text .= strip_tags($action->message) . "\n";
580 $aids[] = $action->aid;
581 }
582 $to_user = interact_get_user($to_uid);
583 if (!empty($to_user->mail)) {
584 $body = t(variable_get('interact_email_body', INTERACT_EMAIL_NOTIFY_BODY), array('@were_#_actions_taken' => format_plural(count($actions), 'was one action taken', 'were @count actions taken'), '@actions_text' => $actions_text, '@site_name' => variable_get('site_name', 'Drupal'), '@site_url' => url('', NULL, NULL, TRUE), '@all_activity_url' => url('interact', NULL, NULL, TRUE), '@notify_url' => url('interact/notify', NULL, NULL, TRUE), '@user_prefs_url' => url('user/' . $to_user->uid . '/edit', NULL, 'interact', TRUE)));
585 if (drupal_mail('interact_mail', $to_user->mail, $subject, $body, $from)) {
586 db_query('UPDATE {interact_notification} SET status = %d WHERE uid = %d AND aid IN (%s)', $notification_type, $to_uid, implode(',', $aids));
587 if (variable_get('interact_log_mail', 1)) {
588 watchdog('interact', t('Sent notification mail of type %type to %mail for actions %action_ids.', array('%type' => $notification_type, '%mail' => $to_user->mail, '%action_ids' => implode(', ', $aids))));
589 }
590 }
591 }
592 else {
593 watchdog('interact', t('Mail attempted to be sent to user %uid with no address for a notification type %type.', array('%uid' => $to_user->uid, '%type' => $notification_type)));
594 }
595 }
596
597 /**
598 * View user interaction actions.
599 *
600 * @param int $uid
601 * @param int $type
602 * @return rendered HTML
603 */
604 function interact_view_actions($uid, $type = NULL, $full_page = TRUE) {
605 $output = '';
606
607 if ($full_page) {
608 drupal_add_css(_interact_get_path() . '/interact.css');
609 $output .= "<div id=\"interact-centre\">\n";
610 }
611
612 if (user_access('view user actions')) {
613 if ($full_page) {
614 // make the callout box
615 $all_types = module_invoke_all('interact_types_text');
616 if (isset($type)) {
617 drupal_set_title(t('@type actions', array('@type' => $all_types[$type])));
618 $breadcrumb = drupal_get_breadcrumb();
619 $breadcrumb[] = l(t('User actions'), 'user-actions/' . $uid);
620 drupal_set_breadcrumb($breadcrumb);
621 }
622 $items = array();
623 $result = db_query('SELECT type, COUNT(*) AS count FROM {interact_action} WHERE uid = %d GROUP BY type', $uid);
624 while ($row = db_fetch_object($result)) {
625 $items[] = theme('interact_action_icon', $row->type) . ' ' . l($all_types[$row->type], 'user-actions/' . $uid . '/' . $row->type, array('style' => 'margin: 0.2em 0 0.2em 0.5em'), NULL, NULL, FALSE, TRUE) . ' (' . $row->count . ')';
626 }
627 $output .= '<div id="interact-callout">';
628 $output .= theme('item_list', $items, t('Action types'));
629 $output .= '</div>';
630 }
631 $output .= interact_get_actions_html($uid, $type, $full_page);
632 }
633 if ($full_page) {
634 $output .= "</div>\n";
635 }
636 return $output;
637 }
638
639 function interact_get_actions_html($uid, $type, $full_page, $show_remove_button = FALSE) {
640 $output = '';
641 $sql = 'SELECT * FROM {interact_action} WHERE uid = %d';
642 $ids = array($uid);
643 if (isset($type)) {
644 $sql .= ' AND type = \'%s\'';
645 $ids[] = $type;
646 }
647 $sql .= ' ORDER BY create_time DESC';
648
649 $result = NULL;
650 if ($full_page) {
651 $result = pager_query($sql, 50, 0, NULL, $ids);
652 }
653 else {
654 $result = db_query_range($sql, $ids, 0, 25);
655 }
656
657 $page = '';
658 $last_date = NULL;
659 while ($row = db_fetch_object($result)) {
660 $date = interact_datetime($row->create_time, TRUE);
661 if ($date != $last_date) {
662 $last_date = $date;
663 }
664 else {
665 $date = NULL;
666 }
667 $page .= theme('interact_user_action', $row, $date);
668 if ($show_remove_button) {
669 $page .= drupal_get_form('interact_remove_action_form', $row->aid);
670 }
671 }
672
673 if (empty($page)) {
674 $user = interact_get_user($uid);
675 $all_types = module_invoke_all('interact_types_text');
676 $page = theme('interact_no_actions', t('No @type_actions have been taken by @user, yet.', array('@type_' => isset($type) ? drupal_strtolower($all_types[$type]) . ' ': '', '@user' => $user->name)));
677 }
678
679 $output .= $page;
680 if ($full_page) {
681 $output .= theme('pager');
682 }
683 else {
684 $output .= '<div class="interact-see-all-link">' . l('Show all user actions', 'user-actions/' . $uid) . '</div>';
685 }
686 return $output;
687 }
688
689 function interact_remove_action_form($aid) {
690 $form = array();
691 $form['aid'] = array(
692 '#type' => 'value',
693 '#value' => $aid,
694 );
695 $form['submit'] = array(
696 '#type' => 'submit',
697 '#value' => t('Remove'),
698 );
699 return $form;
700 }
701
702 function interact_remove_action_form_submit($form_id, $values) {
703 db_query('DELETE FROM {interact_action} WHERE aid = %d', $values['aid']);
704 db_query('DELETE FROM {interact_notify} WHERE aid = %d', $values['aid']);
705 drupal_set_message('You will no longer be notified.');
706 }
707
708 /**
709 * View user interaction messages.
710 *
711 * @param int $to_uid
712 * @param int $from_uid
713 * @return rendered HTML
714 */
715 function interact_view_public_messages($to_uid, $from_uid = NULL, $full_page = TRUE) {
716 global $user;
717
718 $output = '';
719
720 if ($full_page) {
721 drupal_add_css(_interact_get_path() . '/interact.css');
722 $output .= "<div id=\"interact-centre\">\n";
723 }
724
725 if (user_access('view public messages')) {
726 $where = '';
727 $to_user = interact_get_user($to_uid);
728 $ids = NULL;
729 $sql = 'SELECT * FROM {interact_public_message} WHERE';
730 if (isset($from_uid)) {
731 // include only messages from or to the other user
732 $sql .= ' (to_uid = %d AND from_uid = %d) OR (to_uid = %d AND from_uid = %d)';
733 $ids = array($to_uid, $from_uid, $from_uid, $to_uid);
734 $from_user = interact_get_user($from_uid);
735 $output .= t('Public messages between !to_user and !from_user.', array('!to_user' => l($to_user->name, 'user/' . $to_user->uid), '!from_user' => l($from_user->name, 'user/' . $from_user->uid)));
736 if (user_access('post public messages') && ($user->uid == $from_uid || $user->uid == $to_uid)) {
737 $output .= drupal_get_form('interact_public_message_form', $to_uid == $user->uid ? $from_uid : $to_uid);
738 }
739 }
740 else {
741 // include all messages to this user
742 $sql .= ' to_uid = %d';
743 $ids = array($to_uid);
744 if ($full_page) {
745 $output .= t('Public messages to !to_user', array('!to_user' => l($to_user->name, 'user/' . $to_user->uid)));
746 }
747 if (user_access('post public messages')) {
748 $output .= drupal_get_form('interact_public_message_form', $to_uid);
749 }
750 }
751 $sql .= ' ORDER BY create_time DESC';
752 $result = NULL;
753 if ($full_page) {
754 $result = pager_query($sql, 25, 0, NULL, $ids);
755 }
756 else {
757 $result = db_query_range($sql, $ids, 0, 8);
758 }
759 $page = '';
760 while ($row = db_fetch_object($result)) {
761 $from_user = interact_get_user($row->from_uid);
762 $page .= theme('interact_public_message', $from_user, $to_user, $row, isset($from_uid));
763 }
764 if (empty($page)) {
765 $page = theme('interact_no_public_message', t('No one has sent @user a public message.', array('@user' => $to_user->name)));
766 }
767 $output .= theme('interact_public_messages', $page);
768 if ($full_page) {
769 $output .= theme('pager');
770 }
771 else {
772 $output .= '<div class="interact-see-all-link">' . l('Show all public messages', 'public-messages/' . $to_uid) . '<div>';
773 }
774 }
775 if ($full_page) {
776 $output .= "</div>\n";
777 }
778 return $output;
779 }
780
781 function interact_public_message_form($to_uid) {
782 global $user;
783 $form = array();
784 $form['from_uid'] = array(
785 '#type' => 'value',
786 '#value' => $user->uid,
787 );
788 $form['to_uid'] = array(
789 '#type' => 'value',
790 '#value' => $to_uid,
791 );
792 $form['message'] = array(
793 '#type' => 'textarea',
794 '#title' => t('New message'),
795 '#rows' => 2,
796 '#required' => TRUE,
797 );
798 $form['post'] = array(
799 '#type' => 'submit',
800 '#value' => t('Post'),
801 );
802 return $form;
803 }
804
805 function interact_public_message_form_submit($form_id, $values) {
806 $mid = db_next_id('{interact_public_message}_mid');
807 db_query("INSERT INTO {interact_public_message} (mid, from_uid, to_uid, create_time, message) VALUES (%d, %d, %d, %d, '%s')", $mid, $values['from_uid'], $values['to_uid'], time(), $values['message']);
808 drupal_set_message('Public message posted.');
809 $from_user = interact_get_user($values['from_uid']);
810 $to_user = interact_get_user($values['to_uid']);
811 $message = t('!from posted a public !message for !to', array('!from' => l($from_user->name, 'user/' . $from_user->uid), '!message' => l(t('message'), 'interact/public-messages/' . $to_user->uid, array(), NULL, 'message-' . $mid), '!to' => l($to_user->name, 'user/' . $to_user->uid)));
812 $teaser = interact_action_teaser($values['message']);
813 $aid = interact_save_user_action($values['from_uid'], 'public-message', $mid, $message, $teaser);
814 $user_array = array($values['to_uid'] => 0);
815 interact_queue_notification($aid, 'user', 'public_message', $to_user->uid);
816 interact_queue_notification($aid, 'user', 'public_message', $from_user->uid);
817 interact_queue_users($user_array, $aid);
818 interact_immediate_notification();
819 }
820
821 function interact_get_user($uid) {
822 static $users = array();
823 if (!isset($users[$uid])) {
824 $users[$uid] = user_load(array('uid' => $uid));
825 if (variable_get('user_pictures', 0)) {
826 if (empty($users[$uid]->interact_mini_pic)) {
827 $default_mini_pic = variable_get('interact_mini_pic_default', '');
828 if (!empty($default_mini_pic)) {
829 $users[$uid]->interact_mini_pic = $default_mini_pic;
830 }
831 }
832 }
833 else {
834 unset($users[$uid]->interact_mini_pic);
835 }
836 }
837 return $users[$uid];
838 }
839
840 function interact_datetime($time, $date_only = FALSE) {
841 $format = variable_get('date_format_long', 'l, F j, Y - H:i');
842 list($date_format, $time_format) = explode(' - ', $format);
843 $date = format_date($time, 'custom', $date_format);
844 $time_yesterday = time() - 86400;
845 $yesterday = format_date($time_yesterday, 'custom', $date_format);
846 if ($date == $yesterday) {
847 $date = t('Yesterday');
848 }
849 elseif ($time > $time_yesterday) {
850 $date = t('Today');
851 }
852 $datetime = $date;
853 if (!$date_only) {
854 $datetime .= t(' at ') . format_date($time, 'custom', $time_format);
855 }
856 return $datetime;
857 }
858
859 /**
860 * Show a list of notifications.
861 *
862 * @param int $uid user id
863 * @param int $type what type of things to show
864 * @return string rendered HTML
865 */
866 function interact_my_interests($uid = 0, $type = NULL) {
867 global $user;
868
869 drupal_add_css(_interact_get_path() . '/interact.css');
870
871 $output = "<div id=\"interact-centre\">\n";
872
873 if (empty($uid)) {
874 $uid = $user->uid;
875 }
876 elseif ($uid != $user->uid) {
877 if (user_access('administer interaction centre')) {
878 $other_user = user_load(array('uid' => $uid));
879 $output .= '<p>' . t('Interest list for !user.', array('!user' => l($other_user->name, 'user/' . $uid))) . "</p>\n";
880 }
881 else {
882 drupal_access_denied();
883 exit();
884 }
885 }
886
887 // make the callout box
888 $all_types = module_invoke_all('interact_types_text');
889 if (isset($type)) {
890 drupal_set_title(t('@type notifications', array('@type' => $all_types[$type])));
891 $breadcrumb = drupal_get_breadcrumb();
892 $breadcrumb[] = l(t('My interests'), 'my-interests/' . $uid);
893 drupal_set_breadcrumb($breadcrumb);
894 }
895 $items = array();
896 $result = db_query('SELECT a.type, COUNT(*) AS count FROM {interact_action} a JOIN {interact_notification} n ON a.aid = n.aid WHERE n.uid = %d GROUP BY a.type', $uid);
897 while ($row = db_fetch_object($result)) {
898 $items[] = theme('interact_action_icon', $row->type) . ' ' . l($all_types[$row->type], 'my-interests/' . $uid . '/' . $row->type, array('style' => 'margin: 0.2em 0 0.2em 0.5em'), NULL, NULL, FALSE, TRUE) . ' (' . $row->count . ')';
899 }
900 $output .= '<div id="interact-callout">';
901 $output .= theme('item_list', $items, t('Notification types'));
902 $items = array(
903 l(t('Your requests to be notified'), 'my-interests/notify/' . $uid),
904 l(t('General settings'), 'user/' . $uid . '/edit', array(), NULL, 'interact'),
905 );
906 $output .= theme('item_list', $items, t('Settings'));
907 $output .= '</div>';
908
909
910 // make the main list
911 $sql = 'SELECT * FROM {interact_action} a JOIN {interact_notification} n ON a.aid = n.aid WHERE n.uid = %d';
912 $args = array($uid);
913 if (isset($type)) {
914 $sql .= ' AND a.type = \'%s\'';
915 $args[] = $type;
916 }
917 $sql .= ' ORDER BY create_time DESC';
918 $result = pager_query($sql, 25, 0, NULL, $args);
919 if (0 < db_num_rows($result)) {
920 // output each action
921 while ($row = db_fetch_object($result)) {
922 $date = interact_datetime($row->create_time, TRUE);
923 if ($date != $last_date) {
924 $last_date = $date;
925 }
926 else {
927 $date = NULL;
928 }
929 $output .= theme('interact_user_action', $row, $date, TRUE);
930 }
931
932 // mark them as seen if the actual user looked at the list
933 if ($uid == $user->uid) {
934 db_query('UPDATE {interact_notification} SET status = %d WHERE uid = %d AND status = 0', INTERACT_NOTIFY_NO_EMAIL, $uid);
935 }
936 }
937 else {
938 $path = _interact_get_path();
939 $output .= t('Nothing has happened on the site that you have expressed interest in being notified about. If you would like to express interest in any part of the site keep an eye out for the grey stars (!image). Click on the star to be notified when activity takes place for that item.', array('!image' => '<img src="' . url($path . '/icons/star-none.png') . '" alt="Grey star" />'));
940 }
941 $output .= "</div>\n";
942 return $output;
943 }
944
945 function interact_notification_requests($uid) {
946 global $user;
947 $output = '';
948
949 drupal_add_css(_interact_get_path() . '/interact.css');
950
951 $output = "<div id=\"interact-centre\">\n";
952
953 if (empty($uid)) {
954 $uid = $user->uid;
955 }
956 elseif ($uid != $user->uid) {
957 if (user_access('administer interaction centre')) {
958 $other_user = user_load(array('uid' => $uid));
959 $output .= '<p>' . t('Notifications requested by !user.', array('!user' => l($other_user->name, 'user/' . $uid))) . "</p>\n";
960 }
961 else {
962 drupal_access_denied();
963 exit();
964 }
965 }
966
967 $output .= interact_get_actions_html($uid, 'notification-requested', TRUE, TRUE);
968
969 $output .= "</div>\n";
970
971 return $output;
972 }
973
974 function interact_interact_types_text() {
975 return array(
976 'node-new' => t('New content'),
977 'node-edit' => t('Content edit'),
978 'comment-new' => t('New comment'),
979 'comment-edit' => t('Comment edit'),
980 'notification-requested' => t('Notification request'),
981 'public-message' => t('Public message'),
982 );
983 }
984
985 function interact_notify_link($type, $obj = NULL) {
986 global $user;
987 $content = NULL;
988 if (user_access('add notification requests')) {
989 $url = NULL;
990 $thickbox_query = INTERACT_THICKBOX_QUERY . '&destination=' . drupal_urlencode($_GET['q']);
991 $active_notify = array();
992 switch ($type) {
993 case 'page' :
994 if ('taxonomy' == arg(0) && 'term' == arg(1)) {
995 $active_notify = interact_get_notify('term', arg(2));
996 $url = url('interact-watch/term/' . arg(2), $thickbox_query);
997 $type = 'term';
998 }
999 elseif ('node' == arg(0) && is_numeric(arg(1)) && !arg(2)) {
1000 $node = node_load(arg(1));
1001 if ($user->uid == $node->uid) {
1002 $thickbox_query .=