/[drupal]/drupal/modules/tracker/tracker.module
ViewVC logotype

Contents of /drupal/modules/tracker/tracker.module

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


Revision 1.166 - (show annotations) (download) (as text)
Sun Nov 1 12:11:10 2009 UTC (4 weeks ago) by dries
Branch: MAIN
Changes since 1.165: +4 -4 lines
File MIME type: text/x-php
- Patch #595084 by c960657: use type hinting for .
1 <?php
2 // $Id: tracker.module,v 1.165 2009/10/29 07:18:55 webchick Exp $
3
4 /**
5 * @file
6 * Enables tracking of recent posts for users.
7 */
8
9 /**
10 * Implement hook_help().
11 */
12 function tracker_help($path, $arg) {
13 switch ($path) {
14 case 'admin/help#tracker':
15 $output = '<p>' . t('The tracker module displays the most recently added or updated content on your site, and provides user-level tracking to follow the contributions of particular authors.') . '</p>';
16 $output .= '<p>' . t("The <em>Recent posts</em> page is available via a link in the navigation menu block and displays new and recently-updated content (including the content type, the title, the author's name, number of comments, and time of last update) in reverse chronological order. Posts are marked updated when changes occur in the text, or when new comments are added. To use the tracker module to follow a specific user's contributions, select the <em>Track</em> tab from the user's profile page.") . '</p>';
17 $output .= '<p>' . t('For more information, see the online handbook entry for <a href="@tracker">Tracker module</a>.', array('@tracker' => 'http://drupal.org/handbook/modules/tracker/')) . '</p>';
18 return $output;
19 }
20 }
21
22 /**
23 * Implement hook_menu().
24 */
25 function tracker_menu() {
26 $items['tracker'] = array(
27 'title' => 'Recent posts',
28 'page callback' => 'tracker_page',
29 'access arguments' => array('access content'),
30 'weight' => 1,
31 'file' => 'tracker.pages.inc',
32 );
33 $items['tracker/all'] = array(
34 'title' => 'All recent posts',
35 'type' => MENU_DEFAULT_LOCAL_TASK,
36 );
37 $items['tracker/%user_uid_optional'] = array(
38 'title' => 'My recent posts',
39 'page callback' => 'tracker_page',
40 'access callback' => '_tracker_myrecent_access',
41 'access arguments' => array(1),
42 'page arguments' => array(1),
43 'type' => MENU_LOCAL_TASK,
44 'file' => 'tracker.pages.inc',
45 );
46
47 $items['user/%user/track'] = array(
48 'title' => 'Track',
49 'page callback' => 'tracker_page',
50 'page arguments' => array(1, TRUE),
51 'access callback' => '_tracker_user_access',
52 'access arguments' => array(1),
53 'type' => MENU_LOCAL_TASK,
54 'file' => 'tracker.pages.inc',
55 );
56 $items['user/%user/track/posts'] = array(
57 'title' => 'Track posts',
58 'type' => MENU_DEFAULT_LOCAL_TASK,
59 );
60
61 return $items;
62 }
63
64 /**
65 * Implement hook_cron().
66 */
67 function tracker_cron() {
68 $max_nid = variable_get('tracker_index_nid', 0);
69 $batch_size = variable_get('tracker_batch_size', 1000);
70 if ($max_nid > 0) {
71 $last_nid = FALSE;
72 $result = db_query_range('SELECT nid, uid, status FROM {node} WHERE nid <= :max_nid ORDER BY nid DESC', 0, $batch_size, array(':max_nid' => $max_nid), array('target' => 'slave'));
73
74 $count = 0;
75
76 foreach ($result as $row) {
77 // Calculate the changed timestamp for this node.
78 $changed = _tracker_calculate_changed($row->nid);
79
80 // Remove existing data for this node.
81 db_delete('tracker_node')
82 ->condition('nid', $row->nid)
83 ->execute();
84 db_delete('tracker_user')
85 ->condition('nid', $row->nid)
86 ->execute();
87
88 // Insert the node-level data.
89 db_insert('tracker_node')
90 ->fields(array(
91 'nid' => $row->nid,
92 'published' => $row->status,
93 'changed' => $changed,
94 ))
95 ->execute();
96
97 // Insert the user-level data for the node's author.
98 db_insert('tracker_user')
99 ->fields(array(
100 'nid' => $row->nid,
101 'published' => $row->status,
102 'changed' => $changed,
103 'uid' => $row->uid,
104 ))
105 ->execute();
106
107 $query = db_select('comment', 'c', array('target' => 'slave'));
108 // Force PostgreSQL to do an implicit cast by adding 0.
109 $query->addExpression('0 + :changed', 'changed', array(':changed' => $changed));
110 $query->addField('c', 'status', 'published');
111 $query
112 ->distinct()
113 ->fields('c', array('uid', 'nid'))
114 ->condition('c.nid', $row->nid)
115 ->condition('c.uid', $row->uid, '<>')
116 ->condition('c.status', COMMENT_PUBLISHED);
117
118 // Insert the user-level data for the commenters (except if a commenter
119 // is the node's author).
120 db_insert('tracker_user')
121 ->from($query)
122 ->execute();
123
124 // Note that we have indexed at least one node.
125 $last_nid = $row->nid;
126
127 $count++;
128 }
129
130 if ($last_nid !== FALSE) {
131 // Prepare a starting point for the next run.
132 variable_set('tracker_index_nid', $last_nid - 1);
133
134 watchdog('tracker', t('Indexed %count nodes for tracking.', array('%count' => $count)));
135 }
136 else {
137 // If all nodes have been indexed, set to zero to skip future cron runs.
138 variable_set('tracker_index_nid', 0);
139 }
140 }
141 }
142
143 /**
144 * Access callback for tracker/%user_uid_optional.
145 */
146 function _tracker_myrecent_access($account) {
147 // This path is only allowed for authenticated users looking at their own posts.
148 return $account->uid && ($GLOBALS['user']->uid == $account->uid) && user_access('access content');
149 }
150
151 /**
152 * Access callback for user/%user/track.
153 */
154 function _tracker_user_access($account) {
155 return user_view_access($account) && user_access('access content');
156 }
157
158 /**
159 * Implement hook_nodeapi_insert().
160 */
161 function tracker_node_insert(stdClass $node, $arg = 0) {
162 _tracker_add($node->nid, $node->uid, $node->changed);
163 }
164
165 /**
166 * Implement hook_nodeapi_update().
167 */
168 function tracker_node_update(stdClass $node, $arg = 0) {
169 _tracker_add($node->nid, $node->uid, $node->changed);
170 }
171
172 /**
173 * Implement hook_nodeapi_delete().
174 */
175 function tracker_node_delete(stdClass $node, $arg = 0) {
176 _tracker_remove($node->nid, $node->uid, $node->changed);
177 }
178
179 /**
180 * Implement hook_comment_update().
181 *
182 * Comment module doesn't call hook_comment_unpublish() when saving individual
183 * comments so we need to check for those here.
184 */
185 function tracker_comment_update($comment) {
186 $comment = (array) $comment;
187 // comment_save() calls hook_comment_publish() for all published comments
188 // so we to handle all other values here.
189 if ($comment['status'] != COMMENT_PUBLISHED) {
190 _tracker_remove($comment['nid'], $comment['uid'], $comment['timestamp']);
191 }
192 }
193
194 /**
195 * Implement hook_comment_publish().
196 *
197 * This actually handles the insert and update of published nodes since
198 * comment_save() calls hook_comment_publish() for all published comments.
199 */
200 function tracker_comment_publish($comment) {
201 _tracker_add($comment->nid, $comment->uid, $comment->changed);
202 }
203
204 /**
205 * Implement hook_comment_unpublish().
206 */
207 function tracker_comment_unpublish($comment) {
208 _tracker_remove($comment->nid, $comment->uid, $comment->changed);
209 }
210
211 /**
212 * Implement hook_comment_delete().
213 */
214 function tracker_comment_delete($comment) {
215 _tracker_remove($comment->nid, $comment->uid, $comment->changed);
216 }
217
218 /**
219 * Update indexing tables when a node is added, updated or commented on.
220 *
221 * @param $nid
222 * A node ID.
223 * @param $uid
224 * The node or comment author.
225 * @param $changed
226 * The node updated timestamp or comment timestamp.
227 */
228 function _tracker_add($nid, $uid, $changed) {
229 $node = db_query('SELECT nid, status, uid, changed FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject();
230
231 // Adding a comment can only increase the changed timestamp, so our
232 // calculation here is simple.
233 $changed = max($node->changed, $changed);
234
235 // Update the node-level data.
236 db_merge('tracker_node')
237 ->key(array('nid' => $nid))
238 ->fields(array(
239 'changed' => $changed,
240 'published' => $node->status,
241 ))
242 ->execute();
243
244 // Create or update the user-level data.
245 db_merge('tracker_user')
246 ->key(array(
247 'nid' => $nid,
248 'uid' => $uid,
249 ))
250 ->fields(array(
251 'changed' => $changed,
252 'published' => $node->status,
253 ))
254 ->execute();
255 }
256
257 /**
258 * Determine the max timestamp between $node->changed and the last comment.
259 *
260 * @param $nid
261 * A node ID.
262 *
263 * @return
264 * The $node->changed timestamp, or most recent comment timestamp, whichever
265 * is the greatest.
266 */
267 function _tracker_calculate_changed($nid) {
268 $changed = db_query('SELECT changed FROM {node} WHERE nid = :nid', array(':nid' => $nid), array('target' => 'slave'))->fetchField();
269 $latest_comment = db_query_range('SELECT cid, changed FROM {comment} WHERE nid = :nid AND status = :status ORDER BY changed DESC', 0, 1, array(
270 ':nid' => $nid,
271 ':status' => COMMENT_PUBLISHED,
272 ), array('target' => 'slave'))->fetchObject();
273 if ($latest_comment && $latest_comment->changed > $changed) {
274 $changed = $latest_comment->changed;
275 }
276 return $changed;
277 }
278
279 /**
280 * Clean up indexed data when nodes or comments are removed.
281 *
282 * @param $nid
283 * The node ID.
284 * @param $uid
285 * The author of the node or comment.
286 * @param $changed
287 * The last changed timestamp of the node.
288 */
289 function _tracker_remove($nid, $uid = NULL, $changed = NULL) {
290 $node = db_query('SELECT nid, status, uid, changed FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject();
291
292 // The user only keeps his or her subscription if both of the following are true:
293 // (1) The node exists.
294 // (2) The user is either the node author or has commented on the node.
295 $keep_subscription = FALSE;
296
297 if ($node) {
298 // Self-authorship is one reason to keep the user's subscription.
299 $keep_subscription = ($node->uid == $uid);
300
301 // Comments are a second reason to keep the user's subscription.
302 if (!$keep_subscription) {
303 // Check if the user has commented at least once on the given nid
304 $keep_subscription = db_query_range('SELECT COUNT(*) FROM {comment} WHERE nid = :nid AND uid = :uid AND status = 0', 0, 1, array(
305 ':nid' => $nid,
306 ':uid' => $uid,
307 ))->fetchField();
308 }
309
310 // If we haven't found a reason to keep the user's subscription, delete it.
311 if (!$keep_subscription) {
312 db_delete('tracker_user')
313 ->condition('nid', $nid)
314 ->condition('uid', $uid)
315 ->execute();
316 }
317
318 // Now we need to update the (possibly) changed timestamps for other users
319 // and the node itself.
320
321 // We only need to do this if the removed item has a timestamp that equals
322 // or exceeds the listed changed timestamp for the node
323 $tracker_node = db_query('SELECT nid, changed FROM {tracker_node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject();
324 if ($tracker_node && $changed >= $tracker_node->changed) {
325 // If we're here, the item being removed is *possibly* the item that
326 // established the node's changed timestamp.
327
328 // We just have to recalculate things from scratch.
329 $changed = _tracker_calculate_changed($nid);
330
331 // And then we push the out the new changed timestamp to our denormalized
332 // tables.
333 db_update('tracker_node')
334 ->fields(array(
335 'changed' => $changed,
336 'published' => $node->status,
337 ))
338 ->condition('nid', $nid)
339 ->execute();
340 db_update('tracker_node')
341 ->fields(array(
342 'changed' => $changed,
343 'published' => $node->status,
344 ))
345 ->condition('nid', $nid)
346 ->execute();
347 }
348 }
349 else {
350 // If the node doesn't exist, remove everything.
351 db_delete('tracker_node')
352 ->condition('nid', $nid)
353 ->execute();
354 db_delete('tracker_user')
355 ->condition('nid', $nid)
356 ->execute();
357 }
358 }

  ViewVC Help
Powered by ViewVC 1.1.2