1 | <?php |
---|
2 | |
---|
3 | /** |
---|
4 | * @file |
---|
5 | * API functions of Revisioning module |
---|
6 | * |
---|
7 | * Reusable functions that do the dirty work. |
---|
8 | */ |
---|
9 | |
---|
10 | define('REVISION_ARCHIVED', 0); |
---|
11 | define('REVISION_CURRENT', 1); |
---|
12 | define('REVISION_PENDING', 2); |
---|
13 | |
---|
14 | /** |
---|
15 | * Some naming conventions |
---|
16 | * |
---|
17 | * Pending: |
---|
18 | * - revision with (vid > current_vid) of ANY node |
---|
19 | * OR single revision of UNPUBLISHED node |
---|
20 | * Current, published: |
---|
21 | * - revision with (vid == current_vid) of PUBLISHED node |
---|
22 | * Archived: |
---|
23 | * - all other revisions, i.e. |
---|
24 | * revision with (vid < current_vid) of ANY node |
---|
25 | * OR revision with (vid == current_vid) of UNPUBLISHED node |
---|
26 | * |
---|
27 | * Note: these will change when Revisioning is going to store revision states |
---|
28 | * independently from vid number (e.g. in different table). |
---|
29 | */ |
---|
30 | |
---|
31 | /** |
---|
32 | * Return a single or all possible revision state names. |
---|
33 | * |
---|
34 | * @param $state |
---|
35 | * optional state id, as defined in revisioning_api.inc |
---|
36 | * @return |
---|
37 | * if $state is provided, state name. Otherwise, state names array keyed by state id. |
---|
38 | */ |
---|
39 | function revisioning_revision_states($state = NULL) { |
---|
40 | static $states; |
---|
41 | $states = array( |
---|
42 | REVISION_ARCHIVED => t('Archived'), |
---|
43 | REVISION_CURRENT => t('Current, published'), |
---|
44 | REVISION_PENDING => t('Pending'), |
---|
45 | ); |
---|
46 | return $state === NULL ? $states : $states[$state]; |
---|
47 | } |
---|
48 | |
---|
49 | /** |
---|
50 | * Return TRUE when either of the following is true: |
---|
51 | * o the supplied node has at least one revision more recent than the current |
---|
52 | * o the node is not yet published and consists of a single revision |
---|
53 | * |
---|
54 | * Relies on vid, current_revision_id and num_revisions set on the node object, |
---|
55 | * see function node_tools_nodeapi() |
---|
56 | * |
---|
57 | * @param $node |
---|
58 | * @return TRUE, if node is pending according to the above definition |
---|
59 | */ |
---|
60 | function _revisioning_node_is_pending($node) { |
---|
61 | return ($node->vid > $node->current_revision_id) || (!$node->status && $node->num_revisions == 1); |
---|
62 | } |
---|
63 | |
---|
64 | /** |
---|
65 | * Implementation of hook_revisionapi(). |
---|
66 | * |
---|
67 | * Act on various revision events. |
---|
68 | * |
---|
69 | * @param $op |
---|
70 | * Operation |
---|
71 | * @param $node |
---|
72 | * Node of current operation (loaded with vid of the operation). |
---|
73 | * |
---|
74 | * "Pre" operations can be useful to get values before they are lost or changed, |
---|
75 | * for example, to save a backup of revision before it's deleted. |
---|
76 | * Also, for "pre" operations vetoing mechanics could be implemented, so it |
---|
77 | * would be possible to veto an operation via hook_revisionapi(). For example, |
---|
78 | * when the hook is returning FALSE, operation will be vetoed. |
---|
79 | * |
---|
80 | * @TODO: Add more operations if needed. |
---|
81 | */ |
---|
82 | function revisioning_revisionapi($op, $node) { |
---|
83 | switch ($op) { |
---|
84 | case 'pre revert': |
---|
85 | // Invoke corresponding Rules event |
---|
86 | if (module_exists('rules')) { |
---|
87 | rules_invoke_event('revisioning_pre_revert', $node); |
---|
88 | } |
---|
89 | break; |
---|
90 | |
---|
91 | case 'post revert': |
---|
92 | // Invoke the revisioning trigger passing 'revert' as the operation |
---|
93 | if (module_exists('trigger')) { |
---|
94 | module_invoke_all('revisioning', 'revert', $node, $node->vid); |
---|
95 | } |
---|
96 | // Invoke corresponding Rules event |
---|
97 | if (module_exists('rules')) { |
---|
98 | rules_invoke_event('revisioning_post_revert', $node); |
---|
99 | } |
---|
100 | break; |
---|
101 | |
---|
102 | case 'pre publish': |
---|
103 | // Invoke corresponding Rules event |
---|
104 | if (module_exists('rules')) { |
---|
105 | rules_invoke_event('revisioning_pre_publish', $node); |
---|
106 | } |
---|
107 | break; |
---|
108 | |
---|
109 | case 'post publish': |
---|
110 | // Invoke the revisioning trigger passing 'publish' as the operation |
---|
111 | if (module_exists('trigger')) { |
---|
112 | module_invoke_all('revisioning', 'publish', $node); |
---|
113 | } |
---|
114 | // Invoke corresponding Rules event |
---|
115 | if (module_exists('rules')) { |
---|
116 | rules_invoke_event('revisioning_post_publish', $node); |
---|
117 | } |
---|
118 | break; |
---|
119 | |
---|
120 | //case 'pre unpublish': |
---|
121 | // Not implemented: do we really need it ? |
---|
122 | |
---|
123 | case 'post unpublish': |
---|
124 | // Invoke the revisioning trigger passing 'unpublish' as the operation |
---|
125 | if (module_exists('trigger')) { |
---|
126 | module_invoke_all('revisioning', 'unpublish', $node); |
---|
127 | } |
---|
128 | // Invoke corresponding Rules event |
---|
129 | if (module_exists('rules')) { |
---|
130 | rules_invoke_event('revisioning_post_unpublish', $node); |
---|
131 | } |
---|
132 | break; |
---|
133 | |
---|
134 | case 'pre delete': |
---|
135 | // Invoke corresponding Rules event |
---|
136 | if (module_exists('rules')) { |
---|
137 | rules_invoke_event('revisioning_pre_delete', $node); |
---|
138 | } |
---|
139 | break; |
---|
140 | |
---|
141 | case 'post delete': |
---|
142 | break; |
---|
143 | } |
---|
144 | } |
---|
145 | |
---|
146 | /** |
---|
147 | * Get the id of the latest revision belonging to a node. |
---|
148 | * @param |
---|
149 | * $nid, id of the node |
---|
150 | * @return |
---|
151 | * ID of the latest revision. |
---|
152 | */ |
---|
153 | function revisioning_get_latest_revision_id($nid) { |
---|
154 | return db_result(db_query('SELECT MAX(vid) FROM {node_revisions} WHERE nid=%d', $nid)); |
---|
155 | } |
---|
156 | |
---|
157 | /** |
---|
158 | * Get the id of the user who last edited the supplied node, ie. the author |
---|
159 | * of the latest revision. |
---|
160 | * This is irrespective of whether this latest revision is pending or not, |
---|
161 | * unless TRUE is specified for the second argument, in which case the uid |
---|
162 | * of the creator of the current revision (published or not) is returned. |
---|
163 | * |
---|
164 | * @param $nid |
---|
165 | * The id of the node whose most recent editor id is to be returned. |
---|
166 | * @param $current |
---|
167 | * Whether the uid of the current or very latest revision should be returned. |
---|
168 | * @return |
---|
169 | * A single number being the user id (uid). |
---|
170 | */ |
---|
171 | function revisioning_get_last_editor($nid, $current = FALSE) { |
---|
172 | $sql = ($current) |
---|
173 | ? "SELECT vid FROM {node} WHERE nid = %d" |
---|
174 | : "SELECT MAX(vid) FROM {node_revisions} WHERE nid = %d"; |
---|
175 | $vid = db_result(db_query($sql, $nid)); |
---|
176 | return db_result(db_query("SELECT uid FROM {node_revisions} WHERE vid = %d", $vid)); |
---|
177 | } |
---|
178 | |
---|
179 | /** |
---|
180 | * Revert node to selected revision without changing its publication status. |
---|
181 | * |
---|
182 | * @param $node |
---|
183 | * Target $node object (loaded with target revision) or nid of target node |
---|
184 | * @param $vid |
---|
185 | * Optional vid of revision to revert to, if provided $node must not be an object. |
---|
186 | */ |
---|
187 | function _revisioning_revertpublish_revision(&$node, $vid = NULL) { |
---|
188 | $node_revision = is_object($node) ? $node : node_load($node, $vid); |
---|
189 | $return = module_invoke_all('revisionapi', 'pre revert', $node_revision); |
---|
190 | if (in_array(FALSE, $return)) { |
---|
191 | drupal_goto('node/'. $node_revision->nid .'/revisions/'. $node_revision->vid .'/view'); |
---|
192 | die; |
---|
193 | } |
---|
194 | _revisioning_revert_revision($node_revision); |
---|
195 | module_invoke_all('revisionapi', 'post revert', $node_revision); |
---|
196 | } |
---|
197 | |
---|
198 | /** |
---|
199 | * Revert node to selected revision without publishing it. |
---|
200 | * |
---|
201 | * This is same as node_revision_revert_confirm_submit() in node_pages.inc, |
---|
202 | * except it doesn't put any messages on screen. |
---|
203 | * |
---|
204 | * @param $node |
---|
205 | * Target $node object (loaded with target revision) or nid of target node |
---|
206 | * @param $vid |
---|
207 | * optional vid of revision to revert to, if provided $node is not an object. |
---|
208 | */ |
---|
209 | function _revisioning_revert_revision(&$node, $vid = NULL) { |
---|
210 | $node_revision = is_object($node) ? $node : node_load($node, $vid); |
---|
211 | $node_revision->revision = 1; |
---|
212 | $node_revision->log = t('Copy of the revision from %date.', array('%date' => format_date($node_revision->revision_timestamp))); |
---|
213 | if (module_exists('taxonomy')) { |
---|
214 | $node_revision->taxonomy = array_keys($node_revision->taxonomy); |
---|
215 | } |
---|
216 | node_save($node_revision); |
---|
217 | watchdog('content', '@type: reverted %title revision %revision.', array('@type' => $node_revision->type, '%title' => $node_revision->title, '%revision' => $node_revision->vid)); |
---|
218 | } |
---|
219 | |
---|
220 | /** |
---|
221 | * Publish node, without calling node_save(). |
---|
222 | * @obsolete |
---|
223 | * This function is no longer used. Use _revisioning_publish_revision(). |
---|
224 | * |
---|
225 | * @param $node |
---|
226 | * Target $node object or nid of target node |
---|
227 | * @param $clear_cache |
---|
228 | * Whether to clear the cache afterwards or not. Clearing the cache on every |
---|
229 | * node during bulk operations can be time-consuming. |
---|
230 | * |
---|
231 | function _revisioning_publish_node($node, $clear_cache = TRUE) { |
---|
232 | if (is_numeric($node)) { |
---|
233 | $node = node_load($node); |
---|
234 | } |
---|
235 | db_query("UPDATE {node} SET status=1 WHERE nid=%d", $node->nid); |
---|
236 | // Let other modules know there was an update on the node, just like |
---|
237 | // node_save() does. |
---|
238 | $node->status = 1; |
---|
239 | node_invoke_nodeapi($node, 'update'); |
---|
240 | // Update the node access table for this node. |
---|
241 | node_access_acquire_grants($node); |
---|
242 | if ($clear_cache) { |
---|
243 | cache_clear_all(); |
---|
244 | } |
---|
245 | } |
---|
246 | */ |
---|
247 | |
---|
248 | /** |
---|
249 | * Unpublish node, without calling node_save(). |
---|
250 | * |
---|
251 | * @param $node |
---|
252 | * Target $node object or nid. |
---|
253 | * @param $clear_cache |
---|
254 | * Whether to clear the cache afterwards or not. Clearing the cache on every |
---|
255 | * node during bulk operations can be time-consuming. |
---|
256 | */ |
---|
257 | function _revisioning_unpublish_node($node, $clear_cache = TRUE) { |
---|
258 | if (is_numeric($node)) { |
---|
259 | $node = node_load($node); |
---|
260 | } |
---|
261 | db_query("UPDATE {node} SET status=0 WHERE nid=%d", $node->nid); |
---|
262 | // Let other modules know there was an update on the node, just like |
---|
263 | // node_save() does. |
---|
264 | $node->status = 0; |
---|
265 | $node->bypass_nodeapi = TRUE; // avoid revisioning_nodeapi() doing stuff |
---|
266 | $node->pathauto_perform_alias = FALSE; // avoid pathauto_nodeapi() doing stuff |
---|
267 | node_invoke_nodeapi($node, 'update'); |
---|
268 | // Update the node access table for this node. |
---|
269 | node_access_acquire_grants($node); |
---|
270 | |
---|
271 | if ($clear_cache) { |
---|
272 | cache_clear_all(); |
---|
273 | } |
---|
274 | } |
---|
275 | |
---|
276 | /** |
---|
277 | * Delete selected revision of node, provided it's not current. |
---|
278 | * |
---|
279 | * This is same as node_revision_delete_confirm_submit() in node_pages.inc, |
---|
280 | * except it doesn't put any messages on the screen. This way it becomes |
---|
281 | * reusable (eg. in actions). |
---|
282 | * Since we are calling nodeapi as in node_revision_delete_confirm_submit(), we |
---|
283 | * invoke our "post delete" revisionapi hook in nodeapi. This way revisionapi |
---|
284 | * hooks work the same way both with "delete revision" submit handler and when |
---|
285 | * this function is called, and we don't invoke revisionapi "post delete" hook |
---|
286 | * twice. |
---|
287 | * |
---|
288 | * @param $node |
---|
289 | * Target $node object (loaded with target revision) or nid of target node |
---|
290 | * @param $vid |
---|
291 | * optional vid of revision to delete, if provided $node is not object. |
---|
292 | * |
---|
293 | * @TODO: Insert check to prevent deletion of current revision of node. |
---|
294 | */ |
---|
295 | function _revisioning_delete_revision(&$node, $vid = NULL) { |
---|
296 | $node_revision = is_object($node) ? $node : node_load($node, $vid); |
---|
297 | module_invoke_all('revisionapi', 'pre delete', $node_revision); |
---|
298 | db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $node_revision->nid, $node_revision->vid); |
---|
299 | db_query("DELETE FROM {term_node} WHERE nid = %d AND vid = %d", $node_revision->nid, $node_revision->vid); |
---|
300 | node_invoke_nodeapi($node_revision, 'delete revision'); |
---|
301 | watchdog('content', '@type: deleted %title revision %revision.', array('@type' => $node_revision->type, '%title' => $node_revision->title, '%revision' => $node_revision->vid)); |
---|
302 | } |
---|
303 | |
---|
304 | /** |
---|
305 | * Unpublish revision (i.e. the node). |
---|
306 | * |
---|
307 | * Note that no check is made as to whether the initiating user has permission |
---|
308 | * to unpublish this node. |
---|
309 | * |
---|
310 | * @param $node |
---|
311 | * Target $node object or nid of target node |
---|
312 | */ |
---|
313 | function _revisioning_unpublish_revision(&$node) { |
---|
314 | $node_revision = is_object($node) ? $node : node_load($node); |
---|
315 | module_invoke_all('revisionapi', 'pre unpublish', $node_revision); |
---|
316 | _revisioning_unpublish_node($node_revision); |
---|
317 | watchdog('content', 'Unpublished @type %title', array('@type' => $node_revision->type, '%title' => $node_revision->title), WATCHDOG_NOTICE, l(t('view'), "node/$node_revision->nid")); |
---|
318 | module_invoke_all('revisionapi', 'post unpublish', $node_revision); |
---|
319 | } |
---|
320 | |
---|
321 | /** |
---|
322 | * Make the supplied revision of the node current and publish it. |
---|
323 | * It is the caller's responsibility to provide proper revision. |
---|
324 | * Note that no check is made as to whether the initiating user has permission |
---|
325 | * to publish this revision. |
---|
326 | * |
---|
327 | * @param $node |
---|
328 | * Target $node object (loaded with target revision) or nid of target node |
---|
329 | * @param $vid |
---|
330 | * optional vid of revision to make current, if provided $node is not object. |
---|
331 | * @param $clear_cache |
---|
332 | * Whether to clear the cache afterwards or not. Clearing the cache on every |
---|
333 | * node during bulk operations can be time-consuming. |
---|
334 | */ |
---|
335 | function _revisioning_publish_revision(&$node, $vid = NULL, $clear_cache = TRUE) { |
---|
336 | $node_revision = is_object($node) ? $node : node_load($node, $vid); |
---|
337 | $return = module_invoke_all('revisionapi', 'pre publish', $node_revision); |
---|
338 | if (in_array(FALSE, $return)) { |
---|
339 | drupal_goto('node/'. $node_revision->nid .'/revisions/'. $node_revision->vid .'/view'); |
---|
340 | die; |
---|
341 | } |
---|
342 | // Update node table, making sure the "published" (ie. status) flag is set |
---|
343 | db_query("UPDATE {node} SET vid=%d, title='%s', status=1 WHERE nid=%d", $node_revision->vid, $node_revision->title, $node_revision->nid); |
---|
344 | if ($clear_cache) { |
---|
345 | cache_clear_all(); |
---|
346 | } |
---|
347 | $node_revision->status = 1; |
---|
348 | $node_revision->bypass_nodeapi = TRUE; // avoid revisioning_nodeapi() doing stuff |
---|
349 | $node_revision->nodewords = FALSE; // avoid nodewords_nodeapi() doing stuff |
---|
350 | // On the first save of a node we should allow pathauto_nodeapi() to create the |
---|
351 | // alias as normal. Otherwise, the alias will not be created if a node is set |
---|
352 | // to be immediately published during creation. See [#1635542]. |
---|
353 | if (empty($node->is_new)) { |
---|
354 | $node_revision->pathauto_perform_alias = FALSE; // avoid pathauto_nodeapi() doing stuff |
---|
355 | } |
---|
356 | |
---|
357 | node_invoke_nodeapi($node_revision, 'update'); |
---|
358 | // Update the node access table for this node. |
---|
359 | node_access_acquire_grants($node_revision); |
---|
360 | |
---|
361 | watchdog('content', 'Published rev #%revision of @type %title', array('@type' => $node_revision->type, '%title' => $node_revision->title, '%revision' => $node_revision->vid), WATCHDOG_NOTICE, l(t('view'), "node/$node_revision->nid/revisions/$node_revision->vid/view")); |
---|
362 | module_invoke_all('revisionapi', 'post publish', $node_revision); |
---|
363 | } |
---|
364 | |
---|
365 | /** |
---|
366 | * Find the most recent pending revision, make it current, unless it already is |
---|
367 | * and publish node. |
---|
368 | * Note that no check is made as to whether the initiating user has permission |
---|
369 | * to publish this node. |
---|
370 | * |
---|
371 | * @param $node |
---|
372 | * The node object whose latest pending revision is to be published |
---|
373 | * @return |
---|
374 | * TRUE if operation was successful, FALSE if there is no pending revision to |
---|
375 | * publish |
---|
376 | */ |
---|
377 | function _revisioning_publish_latest_revision(&$node) { |
---|
378 | // Get latest pending revision or take the current provided it's UNpublished |
---|
379 | $latest_pending = array_shift(_revisioning_get_pending_revisions($node->nid)); |
---|
380 | if (!$latest_pending) { |
---|
381 | if (!$node->status && $node->is_current) { |
---|
382 | _revisioning_publish_revision($node); |
---|
383 | return TRUE; |
---|
384 | } |
---|
385 | } |
---|
386 | else { |
---|
387 | _revisioning_publish_revision($node->nid, $latest_pending->vid); |
---|
388 | return TRUE; |
---|
389 | } |
---|
390 | return FALSE; |
---|
391 | } |
---|
392 | |
---|
393 | /** |
---|
394 | * Return a count of the number of revisions newer than the supplied vid. |
---|
395 | * |
---|
396 | * @param $vid |
---|
397 | * The reference vid. |
---|
398 | * @param $nid |
---|
399 | * The id of the node. |
---|
400 | * @return |
---|
401 | * integer |
---|
402 | */ |
---|
403 | function _revisioning_get_number_of_revisions_newer_than($vid, $nid) { |
---|
404 | return db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {node_revisions} r ON n.nid=r.nid WHERE (r.vid>%d AND n.nid=%d)", $vid, $nid)); |
---|
405 | } |
---|
406 | |
---|
407 | /** |
---|
408 | * Return a count of the number of revisions newer than the current revision. |
---|
409 | * |
---|
410 | * @param $nid |
---|
411 | * The id of the node. |
---|
412 | * @return |
---|
413 | * integer |
---|
414 | */ |
---|
415 | function _revisioning_get_number_of_pending_revisions($nid) { |
---|
416 | return db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {node_revisions} r ON n.nid=r.nid WHERE (r.vid>n.vid AND n.nid=%d)", $nid)); |
---|
417 | } |
---|
418 | |
---|
419 | /** |
---|
420 | * Get the number of archived revisions belonging to a node. |
---|
421 | * @param |
---|
422 | * $nid, id of the node |
---|
423 | * @return |
---|
424 | * A count representing the number of archived revisions for the node |
---|
425 | * Returns zero if there is only one (i.e. the current) revision. |
---|
426 | */ |
---|
427 | function revisioning_get_number_of_archived_revisions($node) { |
---|
428 | return db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d AND vid < %d', $node->nid, $node->current_revision_id)); |
---|
429 | } |
---|
430 | |
---|
431 | /** |
---|
432 | * Delete all revisions with a vid less than the current. |
---|
433 | */ |
---|
434 | function revisioning_delete_archived_revisions($node) { |
---|
435 | db_query('DELETE FROM {term_node} WHERE nid = %d AND vid < %d', $node->nid, $node->current_revision_id); |
---|
436 | return db_query('DELETE FROM {node_revisions} WHERE nid = %d AND vid < %d', $node->nid, $node->current_revision_id); |
---|
437 | } |
---|
438 | |
---|
439 | /** |
---|
440 | * Retrieve a list of revisions with a vid greater than the current. |
---|
441 | * |
---|
442 | * @param $nid |
---|
443 | * The node id to retrieve. |
---|
444 | * @return |
---|
445 | * An array of revisions (latest first), each containing vid, title and |
---|
446 | * content type. |
---|
447 | */ |
---|
448 | function _revisioning_get_pending_revisions($nid) { |
---|
449 | $sql = "SELECT r.vid, r.title, n.type FROM {node} n INNER JOIN {node_revisions} r ON n.nid=r.nid WHERE (r.vid>n.vid AND n.nid=%d) ORDER BY r.vid DESC"; |
---|
450 | $result = db_query($sql, $nid); |
---|
451 | $revisions = array(); |
---|
452 | while ($revision = db_fetch_object($result)) { |
---|
453 | $revisions[$revision->vid] = $revision; |
---|
454 | } |
---|
455 | return $revisions; |
---|
456 | } |
---|
457 | |
---|
458 | /** |
---|
459 | * Retrieve a list of all revisions (archive, current, pending) belonging to |
---|
460 | * the supplied node. |
---|
461 | * |
---|
462 | * @param $nid |
---|
463 | * The node id to retrieve. |
---|
464 | * @param $include_taxonomy_terms |
---|
465 | * Whether to also retrieve the taxonomy terms for each revision |
---|
466 | * @return |
---|
467 | * An array of revision objects, each with published flag, log message, vid, |
---|
468 | * title, timestamp and name of user that created the revision |
---|
469 | */ |
---|
470 | function _revisioning_get_all_revisions_for_node($nid, $include_taxonomy_terms = FALSE) { |
---|
471 | $sql_select = 'SELECT n.type, n.status, r.vid, r.title, r.log, r.uid, r.timestamp, u.name'; |
---|
472 | $sql_from = ' FROM {node_revisions} r LEFT JOIN {node} n ON n.vid=r.vid INNER JOIN {users} u ON u.uid=r.uid'; |
---|
473 | $sql_where = ' WHERE r.nid=%d ORDER BY r.vid DESC'; |
---|
474 | if ($include_taxonomy_terms) { |
---|
475 | $sql_select .= ', td.name AS term'; |
---|
476 | $sql_from .= ' LEFT JOIN {term_node} tn ON r.vid=tn.vid LEFT JOIN {term_data} td ON tn.tid=td.tid'; |
---|
477 | $sql_where .= ', term ASC'; |
---|
478 | } |
---|
479 | $sql = $sql_select . $sql_from . $sql_where; |
---|
480 | $result = db_query($sql, $nid); |
---|
481 | $revisions = array(); |
---|
482 | while ($revision = db_fetch_object($result)) { |
---|
483 | if (empty($revisions[$revision->vid])) { |
---|
484 | $revisions[$revision->vid] = $revision; |
---|
485 | } |
---|
486 | elseif ($include_taxonomy_terms) { |
---|
487 | // If a revision has more than one taxonomy term, these will be returned |
---|
488 | // by the query as seperate objects differing only in their term fields. |
---|
489 | $existing_revision = $revisions[$revision->vid]; |
---|
490 | $existing_revision->term .= '/'. $revision->term; |
---|
491 | } |
---|
492 | } |
---|
493 | return $revisions; |
---|
494 | } |
---|
495 | |
---|
496 | /** |
---|
497 | * Return revision type of the supplied node. |
---|
498 | * |
---|
499 | * @param &$node |
---|
500 | * Node object to check |
---|
501 | * @return |
---|
502 | * Revision type |
---|
503 | */ |
---|
504 | function _revisioning_revision_is(&$node) { |
---|
505 | if ($node->is_pending) { |
---|
506 | return REVISION_PENDING; |
---|
507 | } |
---|
508 | return ($node->is_current && $node->status) ? REVISION_CURRENT : REVISION_ARCHIVED; |
---|
509 | } |
---|
510 | |
---|
511 | /** |
---|
512 | * Return a string with details about the node that is about to be displayed. |
---|
513 | * |
---|
514 | * Called from revisioning_nodeapi(). |
---|
515 | * |
---|
516 | * @param $node |
---|
517 | * The node that is about to be viewed |
---|
518 | * @return |
---|
519 | * A translatable message containing details about the node |
---|
520 | */ |
---|
521 | function _revisioning_node_info_msg($node) { |
---|
522 | // Get username for the revision, not the creator of the node |
---|
523 | $revision_author = user_load($node->revision_uid); |
---|
524 | $placeholder_data = array( |
---|
525 | '@content_type' => $node->type, |
---|
526 | '%title' => $node->title, |
---|
527 | '!author' => theme('username', $revision_author), |
---|
528 | '@date' => format_date($node->revision_timestamp, 'small'), |
---|
529 | ); |
---|
530 | $revision_type = _revisioning_revision_is($node); |
---|
531 | switch ($revision_type) { |
---|
532 | case REVISION_PENDING: |
---|
533 | return t('Displaying <em>pending</em> revision of @content_type %title, last modified by !author on @date', $placeholder_data); |
---|
534 | |
---|
535 | case REVISION_CURRENT: |
---|
536 | return t('Displaying <em>current, published</em> revision of @content_type %title, last modified by !author on @date', $placeholder_data); |
---|
537 | |
---|
538 | case REVISION_ARCHIVED: |
---|
539 | return t('Displaying <em>archived</em> revision of @content_type %title, last modified by !author on @date', $placeholder_data); |
---|
540 | } |
---|
541 | } |
---|
542 | |
---|
543 | /** |
---|
544 | * Return TRUE only if the user account has ALL of the supplied permissions. |
---|
545 | * |
---|
546 | * @param $permissions |
---|
547 | * An array of permissions (strings) |
---|
548 | * @param $account |
---|
549 | * The user account object. Defaults to the current user if omitted. |
---|
550 | * @return bool |
---|
551 | */ |
---|
552 | function revisioning_user_all_access($permissions, $account = NULL) { |
---|
553 | foreach ($permissions as $permission) { |
---|
554 | if (!user_access($permission, $account)) { |
---|
555 | return FALSE; |
---|
556 | } |
---|
557 | } |
---|
558 | return TRUE; |
---|
559 | } |
---|
560 | |
---|
561 | /** |
---|
562 | * Return an array of names of content types that are subject to moderation. |
---|
563 | * |
---|
564 | * @return array of strings, may be empty |
---|
565 | */ |
---|
566 | function revisioning_moderated_content_types() { |
---|
567 | $moderated_content_types = array(); |
---|
568 | foreach (node_get_types() as $type) { |
---|
569 | $content_type = check_plain($type->type); |
---|
570 | if (node_tools_content_is_moderated($content_type)) { |
---|
571 | $moderated_content_types[] = $content_type; |
---|
572 | } |
---|
573 | } |
---|
574 | return $moderated_content_types; |
---|
575 | } |
---|
576 | |
---|
577 | /** |
---|
578 | * Return the id of the user who created the revision by the supplied vid. |
---|
579 | */ |
---|
580 | function revisioning_get_revision_uid($vid) { |
---|
581 | return db_result(db_query('SELECT uid FROM {node_revisions} WHERE vid = %d', $vid)); |
---|
582 | } |
---|