Ticket #18515: locking_first_pass.diff
File locking_first_pass.diff, 18.2 KB (added by , 12 years ago) |
---|
-
wp-includes/post-template.php
1267 1267 * @since 2.6.0 1268 1268 * 1269 1269 * @uses date_i18n() 1270 * @uses human_time_diff 1270 1271 * 1271 1272 * @param int|object $revision Revision ID or revision object. 1272 1273 * @param bool $link Optional, default is true. Link to revisions's page? … … 1278 1279 1279 1280 if ( !in_array( $revision->post_type, array( 'post', 'page', 'revision' ) ) ) 1280 1281 return false; 1281 1282 1283 //returns i18n'd string e.g., "5 min" 1284 $diff = human_time_diff( strtotime( $revision->post_date ) ); 1285 $diff = sprintf( __( '%s ago' ), $diff ); 1286 1282 1287 /* translators: revision date format, see http://php.net/date */ 1283 1288 $datef = _x( 'j F, Y @ G:i', 'revision date format'); 1284 /* translators: 1: date */1285 $autosavef = __( '%1$s [Autosave]' );1286 /* translators: 1: date */1287 $currentf = __( '%1$s [Current Revision]' );1288 1289 1289 $date = date_i18n( $datef, strtotime( $revision->post_modified ) ); 1290 1290 1291 if ( $link && current_user_can( 'edit_post', $revision->ID ) && $link = get_edit_post_link( $revision->ID ) ) 1291 $date = "<a href='$link'>$date</a>"; 1292 $timestamp = '<a href="' . $link . '" class="timestamp" title="' . $date . '" id="' . strtotime( $revision->post_date ) .'">' . $diff . '</a>'; 1293 else 1294 $timestamp = '<span class="timestamp" title="' . $date . '" id="' . strtotime( $revision->post_date ) .'">' . $diff . '</span>'; 1292 1295 1293 1296 if ( !wp_is_post_revision( $revision ) ) 1294 $ date = sprintf( $currentf, $date);1297 $timestamp .= __( ' [Autosave]' ); 1295 1298 elseif ( wp_is_post_autosave( $revision ) ) 1296 $date = sprintf( $autosavef, $date ); 1299 $timestamp .= __( ' [Current Revision]' ); 1300 elseif ( wp_is_post_conflicted( $revision ) ) 1301 $timestamp .= __( ' [Conflicted Revision]' ); 1297 1302 1298 return $ date;1303 return $timestamp; 1299 1304 } 1300 1305 1301 1306 /** -
wp-includes/post.php
4709 4709 $return['post_status'] = 'inherit'; 4710 4710 $return['post_type'] = 'revision'; 4711 4711 $return['post_name'] = $autosave ? "$post[ID]-autosave" : "$post[ID]-revision"; 4712 4713 if ( wp_check_post_lock( $post->ID ) ) 4714 $return['post_name'] .= "-conflicted"; 4715 4712 4716 $return['post_date'] = isset($post['post_modified']) ? $post['post_modified'] : ''; 4713 4717 $return['post_date_gmt'] = isset($post['post_modified_gmt']) ? $post['post_modified_gmt'] : ''; 4714 4718 … … 4856 4860 } 4857 4861 4858 4862 /** 4863 * Determines if the specified post is a conflicted revision 4864 * 4865 * @package WordPress 4866 * @subpackage Post_Revisions 4867 * @since 3.3 4868 * 4869 * @param int|object $post Post ID or post object. 4870 * @return bool|int False if not a revision, ID of conflicted revision's parent otherwise 4871 */ 4872 function wp_is_post_conflicted( $post ) { 4873 if ( !$post = wp_get_post_revision( $post ) ) 4874 return false; 4875 if ( strrpos( $post->post_name, 'conflicted' ) === false ) 4876 return false; 4877 return (int) $post->post_parent; 4878 } 4879 4880 /** 4859 4881 * Inserts post data into the posts table as a post revision. 4860 4882 * 4861 4883 * @package WordPress -
wp-includes/js/autosave.dev.js
87 87 delayed_autosave(); 88 88 }); 89 89 } 90 91 //lock override toggle 92 $('#lock_override').click( function( event ) { 93 event.preventDefault(); 94 95 jQuery.post( ajaxurl, { 96 action: 'override_edit_lock', 97 post_ID: $("#post_ID").val() || 0, 98 autosavenonce: $('#autosavenonce').val() || 0 99 },function(data) { 100 if ( data ) { 101 //hide the lock notice 102 $('#lock_override').parent().parent().fadeOut( 'slow' ); 103 104 autosaveL10n.hasLock = true; 105 delayed_autosave(); 106 107 } else { 108 alert( lockError ); 109 } 110 } 111 ); 112 113 }); 114 115 //HTML5 Lock Override Notifications permission check 116 //must be performed concurrent with a user action 117 $('input').keyup( function() { 118 if ( window.webkitNotifications ) 119 window.webkitNotifications.requestPermission( ); 120 }); 121 122 123 //automatically refresh all timestamps every minute with actual human time diff 124 setInterval( "updateTimestamps()", 60000 ); //60k = 1 minute 125 126 // remove the post lock on unload 127 window.onbeforeunload = function () { 128 129 if ( autosaveL10n.hasLock == false ) 130 return; 131 132 $.ajax({ 133 type: 'POST', 134 url: ajaxurl, 135 async: false, 136 data: { 137 action: 'wp-remove-post-lock', 138 _wpnonce: $('#_wpnonce').val(), 139 post_ID: $('#post_ID').val(), 140 user_ID: $('#user_ID').val(), 141 } 142 }); 143 144 }; 145 90 146 }); 91 147 148 //Javscript version of the WP human time diff PHP function, allows time stamps to by dynamically updated 149 function human_time_diff( from, to ) { 150 151 //allow $to to be optional; adjust to server's GMT offset so timezones stay in sync 152 d = new Date(); 153 to = to || ( d.getTime() / 1000 ) + parseInt( autosaveL10n.offset ); 154 155 //caclulate difference in seconds 156 diff = Math.abs(to - from); 157 158 //less than one hour; therefore display minutes 159 if (diff <= 3600) { 160 161 //convert seconds to minutes 162 mins = Math.floor(diff / 60); 163 164 //roundup 165 if (mins <= 1) { 166 mins = 1; 167 } 168 169 if ( mins == 1) //singular 170 return autosaveL10n.minute.replace( '%d', mins); 171 else //plural 172 return autosaveL10n.minutes.replace( '%d', mins); 173 174 //if greater than an hour but less than a day, display as hours 175 } else if ((diff <= 86400) && (diff > 3600)) { 176 177 //convert seconds to hours 178 hours = Math.floor(diff / 3600); 179 180 //roundup 181 if (hours <= 1) { 182 hours = 1; 183 } 184 185 if ( hours == 1) //singular 186 return autosaveL10n.hour.replace( '%d', hours); 187 else //plural 188 return autosaveL10n.hours.replace( '%d', hours); 189 190 //if it's more than a day, display as days 191 } else if (diff >= 86400) { 192 193 //convert seconds to days 194 days = Math.floor(diff / 86400); 195 196 //roundup 197 if (days <= 1) { 198 days = 1; 199 } 200 201 if ( days == 1) //singular 202 return autosaveL10n.day.replace( '%d', days); 203 else //plural 204 return autosaveL10n.days.replace( '%d', days); 205 } 206 } 207 208 //loop through all timestamps and update 209 function updateTimestamps() { 210 211 //loop through all timestamps and update the timestamp 212 jQuery('.timestamp').each( function(){ 213 jQuery(this).text( human_time_diff( jQuery(this).attr('id') ) ); 214 }); 215 216 } 217 218 //HTML5 Lock Override Notifications 219 function lock_override_notice( notice ) { 220 if ( window.webkitNotifications.checkPermission() > 0 ) { 221 window.webkitNotifications.RequestPermission( notice ); 222 } else { 223 window.webkitNotifications.createNotification( 224 autosaveL10n.logoURL, autosaveL10n.lostLockNoticeTitle, notice ).show(); 225 } 226 } 227 228 92 229 function autosave_parse_response(response) { 93 230 var res = wpAjax.parseAjaxResponse(response, 'autosave'), message = '', postID, sup; 94 231 … … 102 239 res = { errors: true }; 103 240 } 104 241 105 if ( sup['alert'] ) { 242 //if the #locknotice is present, this is a refresh, no need to alert again 243 if ( sup['alert'] && jQuery('#locknotice').length == 0 ) { 106 244 jQuery('#autosave-alert').remove(); 107 245 jQuery('#titlediv').after('<div id="autosave-alert" class="error below-h2"><p>' + sup['alert'] + '</p></div>'); 246 247 //Lock Override alert 248 //todo: right now the only possible alert is file lock loss, but probably should confirm here 249 if ( window.webkitNotifications ) { 250 //browser supports html5 Notifications 251 lock_override_notice( sup['alert'] ); 252 } else { 253 //browser does not support lock override notice, send old school alert 254 alert( sup['alert'] ); 255 } 256 257 //submit the form so that we can save whatever we've got 258 //and then reload the page with the lock 259 jQuery('#post').submit(); 260 108 261 } 109 262 110 263 jQuery.each(sup, function(selector, value) { -
wp-includes/script-loader.php
285 285 286 286 $scripts->add( 'postbox', "/wp-admin/js/postbox$suffix.js", array('jquery-ui-sortable'), '20110916', 1 ); 287 287 288 $scripts->add( 'post', "/wp-admin/js/post$suffix.js", array('suggest', 'wp-lists', 'postbox'), '20110 524', 1 );288 $scripts->add( 'post', "/wp-admin/js/post$suffix.js", array('suggest', 'wp-lists', 'postbox'), '20110824', 1 ); 289 289 $scripts->add_script_data( 'post', 'postL10n', array( 290 290 'ok' => __('OK'), 291 291 'cancel' => __('Cancel'), … … 472 472 * @since 2.5.0 473 473 */ 474 474 function wp_just_in_time_script_localization() { 475 475 global $post; 476 476 477 wp_localize_script( 'autosave', 'autosaveL10n', array( 477 478 'autosaveInterval' => AUTOSAVE_INTERVAL, 478 479 'savingText' => __('Saving Draft…'), 479 'saveAlert' => __('The changes you made will be lost if you navigate away from this page.') 480 ) ); 480 'saveAlert' => __('The changes you made will be lost if you navigate away from this page.'), 481 'logoURL' => admin_url('images/logo.gif'), 482 'lockOverrideError' => __('There was an error overriding the lock.'), 483 'lostLockNoticeTitle' => __('Lost Lock'), 484 'unlockNotice' => __('Releasing so that others can edit...'), 485 'hasLock' => ( function_exists( 'wp_check_post_lock') && !wp_check_post_lock( $post->ID ) ) ? true : false, 486 'offset' => get_option( 'gmt_offset' ) * 3600, 487 'minute' => __('%d mins'), 488 'minutes' => __('%d mins'), 489 'hour' => __('%d hour'), 490 'hours' => __('%d hours'), 491 'day' => __('%d day'), 492 'days' => __('%d days'), 493 ) ); 481 494 482 495 } 483 496 -
wp-admin/admin-ajax.php
958 958 $data = __( 'Autosave disabled.' ); 959 959 960 960 $supplemental['disable_autosave'] = 'disable'; 961 $alert .= sprintf( __( '%s is currently editing this article. If you update it, you will overwrite the changes.' ), esc_html( $last_user_name ) ); 961 962 //TODO: this language needs to be updated 963 $alert .= sprintf( __( '%1$s currently has the post "%2$s" checked out. Your changes will be saved as a conflicted revision.' ), esc_html( $last_user_name ), $post->post_title ); 964 962 965 } 963 966 964 967 if ( 'page' == $post->post_type ) { … … 988 991 $id = $post->ID; 989 992 } 990 993 991 if ( $do_lock && ( isset( $_POST['auto_draft'] ) && ( $_POST['auto_draft'] != '1' ) ) && $id && is_numeric($id) ) 994 //auto_draft will either be 1 (and thus ID ='s 0) or not POST'd at all 995 if ( $do_lock && !isset( $_POST['auto_draft'] ) && $id && is_numeric($id) ) 992 996 wp_set_post_lock( $id ); 993 997 994 998 if ( $nonce_age == 2 ) { … … 1548 1552 1549 1553 echo json_encode( array( 'message' => $message, 'last_edited' => $last_edited ) ); 1550 1554 die(); 1555 break; 1556 case 'override_edit_lock': 1557 1558 //TODO: Does this exist if not in edit mode? 1559 check_ajax_referer( 'autosave', 'autosavenonce' ); 1560 1561 $post_id = isset($_POST['post_ID']) ? (int) $_POST['post_ID'] : 0; 1562 1563 if ( !current_user_can('edit_post', $post_id) ) 1564 die('-1'); 1565 1566 1567 if ( !$post_id || 1568 !current_user_can( 'edit_post' , $post_id ) || 1569 !current_user_can( 'override_edit_lock' ) 1570 ) 1571 wp_die( __( 'Not authorized' ) ); 1572 1573 //not locked or locked to self 1574 if ( !( $current_owner = wp_check_post_lock( $post_id) ) ) 1575 die( '-1' ); 1576 1577 wp_set_post_lock( $post_id ); 1578 1579 $current_user = wp_get_current_user(); 1580 1581 //if ( apply_filters( 'send_document_override_notice', $send_notice ) ) 1582 // $this->send_override_notice( $postID, $current_owner, $current_user->ID ); 1583 1584 do_action( 'edit_lock_override', $post_id, $current_user->ID, $current_owner ); 1585 1586 die( '1' ); 1587 1551 1588 break; 1589 case 'wp-remove-post-lock' : 1590 1591 $post_id = isset($_POST['post_ID']) ? (int) $_POST['post_ID'] : 0; 1592 if ( !current_user_can('edit_post', $post_id) ) 1593 die(); 1594 1595 $post = $post_type = null; 1596 1597 if ( $post_id ) { 1598 $post = get_post($post_id); 1599 if ( $post ) 1600 $post_type = $post->post_type; 1601 } 1602 1603 check_ajax_referer('update-' . $post_type . '_' . $post_id); 1604 1605 sleep(4); //why are we sleeping? 1606 1607 //TODO: Can this be simplified with wp_check_post_lock? 1608 1609 if ( !$lock = get_post_meta( $post_id, '_edit_lock', true ) ) 1610 die('-1'); 1611 1612 $lock = explode( ':', $lock ); 1613 $user_id = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post_id, '_edit_last', true ); 1614 $locked = (int) $lock[0]; 1615 1616 if ( time() - $locked < 5 ) // give a few seconds for the lock to be refreshed if the user reloaded the page 1617 die('0'); 1618 1619 if ( $user_id == get_current_user_id() ) 1620 delete_post_meta( $post_id, '_edit_lock' ); 1621 1622 die('1'); 1623 break; 1552 1624 default : 1553 1625 do_action( 'wp_ajax_' . $_POST['action'] ); 1554 1626 die('0'); -
wp-admin/includes/post.php
189 189 break; 190 190 } 191 191 } 192 192 193 //above this point has been read only, starting now, we're going to begin writing, 194 //so do checks here if we do want to break stuff 195 196 //if there's a post lock, and we're not the owner, hijack the save and save a revision instead 197 $lock_owner = wp_check_post_lock( $post_ID ); 198 if ( $lock_owner ) { 199 $revision_ID = _wp_put_post_revision( $post_data ); //TODO: IS this properly sanitized? 200 return false; //maybe we want to return revision_ID here? 201 } 202 193 203 // Post Formats 194 204 if ( current_theme_supports( 'post-formats' ) && isset( $post_data['post_format'] ) ) { 195 205 $formats = get_theme_support( 'post-formats' ); … … 1270 1280 $message = __( 'Warning: %s is currently editing this page' ); 1271 1281 break; 1272 1282 default: 1273 $message = __( 'Warning: %s is currently editing this.' ); 1283 $cpt = get_post_type_object( $post->post_type ); 1284 $message = __( 'Warning: %s is currently editing this ' . $cpt->labels->singular_name . '.' ); 1274 1285 } 1286 1287 if ( current_user_can( 'override_edit_lock' ) ) 1288 $message .= '. If you believe this is in error, you can <a href="#" id="lock_override">override the lock</a>, but their changes will be lost.'; 1275 1289 1276 1290 $message = sprintf( $message, esc_html( $last_user_name ) ); 1277 echo "<div class='error' ><p>$message</p></div>";1291 echo "<div class='error' id=\"locknotice\"><p>$message</p></div>"; 1278 1292 } 1279 1293 1280 1294 /** -
wp-admin/includes/schema.php
382 382 populate_roles_270(); 383 383 populate_roles_280(); 384 384 populate_roles_300(); 385 populate_roles_330(); 385 386 } 386 387 387 388 /** … … 623 624 } 624 625 } 625 626 627 function populate_roles_330() { 628 629 $roles = array('administrator', 'editor'); 630 foreach ($roles as $role) { 631 $role =& get_role($role); 632 if ( empty($role) ) 633 continue; 634 635 $role->add_cap('override_edit_lock'); 636 } 637 638 } 639 626 640 /** 627 641 * populate network settings 628 642 * -
wp-admin/post.php
51 51 * @param int $post_id Optional. Post ID. 52 52 */ 53 53 function redirect_post($post_id = '') { 54 if ( isset($_POST['save']) || isset($_POST['publish']) ) { 54 55 if ( wp_check_post_lock( $post_id ) ) { 56 $location = add_query_arg( 'message', 11, get_edit_post_link( $post_id, 'url' ) ); 57 } else if ( isset($_POST['save']) || isset($_POST['publish']) ) { 55 58 $status = get_post_status( $post_id ); 56 57 if ( isset( $_POST['publish'] ) ) {59 60 if ( isset( $_POST['publish'] ) ) { 58 61 switch ( $status ) { 59 62 case 'pending': 60 63 $message = 8; … … 69 72 $message = 'draft' == $status ? 10 : 1; 70 73 } 71 74 75 76 72 77 $location = add_query_arg( 'message', $message, get_edit_post_link( $post_id, 'url' ) ); 73 78 } elseif ( isset($_POST['addmeta']) && $_POST['addmeta'] ) { 74 79 $location = add_query_arg( 'message', 2, wp_get_referer() ); … … 175 180 add_action('admin_notices', '_admin_notice_post_locked' ); 176 181 } else { 177 182 wp_set_post_lock( $post->ID ); 178 wp_enqueue_script('autosave');179 183 } 184 185 wp_enqueue_script('autosave'); 180 186 181 187 $title = $post_type_object->labels->edit_item; 182 188 $post = get_post_to_edit($post_id); -
wp-admin/js/post.dev.js
643 643 } 644 644 645 645 wptitlehint(); 646 646 647 }); -
wp-admin/edit-form-advanced.php
27 27 $user_ID = isset($user_ID) ? (int) $user_ID : 0; 28 28 $action = isset($action) ? $action : ''; 29 29 30 if ( $user = wp_check_post_lock( $post_ID ) ) 31 $user = get_user_by( 'id' , $user ); 32 30 33 $messages = array(); 31 34 $messages['post'] = array( 32 35 0 => '', // Unused. Messages start at index 1. … … 43 46 // translators: Publish box date format, see http://php.net/date 44 47 date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ), 45 48 10 => sprintf( __('Post draft updated. <a target="_blank" href="%s">Preview post</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ), 49 11 => sprintf( __( 'Your save conflicted against %s\'s version. Your copy was saved as conflicted.'), $user->display_name ), //TODO: This need better language 46 50 ); 47 51 $messages['page'] = array( 48 52 0 => '', // Unused. Messages start at index 1. … … 56 60 8 => sprintf( __('Page submitted. <a target="_blank" href="%s">Preview page</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ), 57 61 9 => sprintf( __('Page scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview page</a>'), date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ), 58 62 10 => sprintf( __('Page draft updated. <a target="_blank" href="%s">Preview page</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ), 63 11 => sprintf( __( 'Your save conflicted against %s\'s version. Your copy was saved as conflicted.'), $user->display_name ), //TODO: This need better language 59 64 ); 60 65 61 66 $messages = apply_filters( 'post_updated_messages', $messages );