Permalink
Browse files

Wiki: Improve page locking to make it more robust and support non-jav…

…ascript users (not very friendlily, though...)
  • Loading branch information...
1 parent 5c135dd commit 4db1861a8dc06b5ae608144b3f3a567974dd7148 sam_marshall committed Sep 27, 2006
Showing with 129 additions and 64 deletions.
  1. +2 −0 lang/en_utf8/wiki.php
  2. +82 −2 mod/wiki/lib.php
  3. +45 −62 mod/wiki/view.php
@@ -106,6 +106,7 @@
$string['nocandidatestoremove'] = 'No candidate pages to remove, choose \'$a\' to show all pages.';
$string['nochangestorevert'] = 'No changes to revert.';
$string['nohtml'] = 'No HTML';
+$string['nojslockwarning'] = 'Because Javascript is disabled in your browser, it is possible that somebody else could edit this page. If that happens, you won\'t be able to save your changes. Please try to make your edits quickly, or turn Javascript on and reload this page.';
$string['nolinksfound'] = 'No links found on page.';
$string['noregexp'] = 'This must be a fixed string (you cannot use * or regex), at best use the attackers` IP address or host name, but do not include the port number (because it increased with every http access).';
$string['notadministratewiki'] = 'You are not allowed to administrate this wiki !';
@@ -148,6 +149,7 @@
$string['revertthe'] = 'Version diving, but only purge the affected one';
$string['safehtml'] = 'Safe HTML';
$string['save'] = 'Save';
+$string['savenolock'] = 'You cannot save the page because you do not have an editing lock. This can happen if your browser has Javascript turned off, or if another user overrides your lock.<br/><br/>You can return to the previous screen using your browser\'s Back button and copy the text of any changes you made, then try editing again.';
$string['searchwiki'] = 'Search Wiki';
$string['setpageflags'] = 'Set page flags';
$string['showversions'] = 'Show versions:';
View
@@ -12,11 +12,13 @@
define("EWIKI_ESCAPE_AT", 0); # For the algebraic filter
// How long locks stay around without being confirmed (seconds)
-define("WIKI_LOCK_PERSISTENCE",60);
+define("WIKI_LOCK_PERSISTENCE",120);
// How often to confirm that you still want a lock
-define("WIKI_LOCK_RECONFIRM",30);
+define("WIKI_LOCK_RECONFIRM",60);
+// Session variable used to store wiki locks
+define('SESSION_WIKI_LOCKS','wikilocks');
/*** Moodle 1.7 compatibility functions *****
*
@@ -1562,4 +1564,82 @@ function wiki_get_post_actions() {
}
+/**
+ * Obtains an editing lock on a wiki page.
+ * @param int $wikiid ID of wiki object.
+ * @param string $pagename Name of page.
+ * @return array Two-element array with a boolean true (if lock has been obtained)
+ * or false (if lock was held by somebody else). If lock was held by someone else,
+ * the values of the wiki_locks entry are held in the second element.
+ */
+function wiki_obtain_lock($wikiid,$pagename) {
+ global $USER;
+
+ // Check for lock
+ $alreadyownlock=false;
+ if($lock=get_record('wiki_locks','pagename',$pagename,'wikiid', $wikiid)) {
+ // Consider the page locked if the lock has been confirmed within WIKI_LOCK_PERSISTENCE seconds
+ if($lock->lockedby==$USER->id) {
+ // Cool, it's our lock, do nothing except remember it in session
+ $lockid=$lock->id;
+ $alreadyownlock=true;
+ } else if(time()-$lock->lockedseen < WIKI_LOCK_PERSISTENCE) {
+ return array(false,$lock);
+ } else {
+ // Not locked any more. Get rid of the old lock record.
+ if(!delete_records('wiki_locks','pagename',$pagename,'wikiid', $wikiid)) {
+ error('Unable to delete lock record');
+ }
+ }
+ }
+
+ // Add lock
+ if(!$alreadyownlock) {
+ // Lock page
+ $newlock=new stdClass;
+ $newlock->lockedby=$USER->id;
+ $newlock->lockedsince=time();
+ $newlock->lockedseen=$newlock->lockedsince;
+ $newlock->wikiid=$wikiid;
+ $newlock->pagename=$pagename;
+ if(!$lockid=insert_record('wiki_locks',$newlock)) {
+ error('Unable to insert lock record');
+ }
+ }
+
+ // Store lock information in session so we can clear it later
+ if(!array_key_exists(SESSION_WIKI_LOCKS,$_SESSION)) {
+ $_SESSION[SESSION_WIKI_LOCKS]=array();
+ }
+ $_SESSION[SESSION_WIKI_LOCKS][$wikiid.'_'.$pagename]=$lockid;
+ return array(true,null);
+}
+
+/**
+ * If the user has an editing lock, releases it. Has no effect otherwise.
+ * Note that it doesn't matter if this isn't called (as happens if their
+ * browser crashes or something) since locks time out anyway. This is just
+ * to avoid confusion of the 'what? it says I'm editing that page but I'm
+ * not, I just saved it!' variety.
+ * @param int $wikiid ID of wiki object.
+ * @param string $pagename Name of page.
+ */
+function wiki_release_lock($wikiid,$pagename) {
+ if(!array_key_exists(SESSION_WIKI_LOCKS,$_SESSION)) {
+ // No locks at all in session
+ return;
+ }
+
+ $key=$wikiid.'_'.$pagename;
+
+ if(array_key_exists($key,$_SESSION[SESSION_WIKI_LOCKS])) {
+ $lockid=$_SESSION[SESSION_WIKI_LOCKS][$key];
+ unset($_SESSION[SESSION_WIKI_LOCKS][$key]);
+ if(!delete_records('wiki_locks','id',$lockid)) {
+ error("Unable to delete lock record.");
+ }
+ }
+}
+
+
?>
View
@@ -27,22 +27,14 @@
$actions = explode('/', $page,2);
if(count($actions)==2) {
$pagename=$actions[1];
+ } else {
+ $pagename=$actions[0];
}
} else {
$actions=array('');
$pagename='';
}
- // If true, we are 'really' on an editing page, not just on edit/something
- $reallyedit=$actions[0]=='edit' && !$editsave && !$canceledit;
- if(!$reallyedit && isset($_SESSION['lockid'])) {
- if(!delete_records('wiki_locks','id',$_SESSION['lockid'])) {
- unset($_SESSION['lockid']);
- error("Unable to delete lock record. ".$_SESSION['lockid']);
- }
- unset($_SESSION['lockid']);
- }
-
if ($id) {
if (! $cm = get_coursemodule_from_id('wiki', $id)) {
error("Course Module ID was incorrect");
@@ -71,8 +63,24 @@
}
require_course_login($course, true, $cm);
-
-
+
+ // If true, we are 'really' on an editing page, not just on edit/something
+ $reallyedit=$actions[0]=='edit' && !$canceledit && !$editsave;
+
+ // Remove lock when we go to another wiki page (such as the cancel page)
+ if(!$reallyedit) {
+ wiki_release_lock($wiki->id,$pagename);
+ }
+
+ // We must have the edit lock in order to be permitted to save
+ if(!empty($_POST['content'])) {
+ list($ok,$lock)=wiki_obtain_lock($wiki->id,$pagename);
+ if(!$ok) {
+ $strsavenolock=get_string('savenolock','wiki');
+ error($strsavenolock,$CFG->wwwroot.'/mod/wiki/view.php?id='.$cm->id.'&page=view/'.urlencode($pagename));
+ }
+ }
+
/// Add the course module 'groupmode' to the wiki object, for easy access.
$wiki->groupmode = $cm->groupmode;
@@ -398,33 +406,26 @@
} else if($actions[0]=='edit' && $reallyedit) {
// Check the page isn't locked before printing out standard wiki content. (Locking
// is implemented as a wrapper over the existing wiki.)
- $goahead=true;
- $alreadyownlock=false;
- if($lock=get_record('wiki_locks','pagename',$pagename,'wikiid', $wiki->id)) {
- // Consider the page locked if the lock has been confirmed within WIKI_LOCK_PERSISTENCE seconds
- if($lock->lockedby==$USER->id) {
- // Cool, it's our lock, do nothing
- $alreadyownlock=true;
- $lockid=$lock->id;
- } else if(time()-$lock->lockedseen < WIKI_LOCK_PERSISTENCE) {
- $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
- $canoverridelock = has_capability('mod/wiki:overridelock', $modcontext);
-
- $a=new stdClass;
- $a->since=userdate($lock->lockedsince);
- $a->seen=userdate($lock->lockedseen);
- $user=get_record('user','id',$lock->lockedby);
- $a->name=fullname($user,
- has_capability('moodle/site:viewfullnames', $modcontext));
-
- print_string('pagelocked','wiki',$a);
+ list($gotlock,$lock)=wiki_obtain_lock($wiki->id,$pagename);
+ if(!$gotlock) {
+ $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
+ $canoverridelock = has_capability('mod/wiki:overridelock', $modcontext);
+
+ $a=new stdClass;
+ $a->since=userdate($lock->lockedsince);
+ $a->seen=userdate($lock->lockedseen);
+ $user=get_record('user','id',$lock->lockedby);
+ $a->name=fullname($user,
+ has_capability('moodle/site:viewfullnames', $modcontext));
- if($canoverridelock) {
- $pageesc=htmlspecialchars($page);
- $stroverrideinfo=get_string('overrideinfo','wiki');
- $stroverridebutton=get_string('overridebutton','wiki');
- $sesskey=sesskey();
- print "
+ print_string('pagelocked','wiki',$a);
+
+ if($canoverridelock) {
+ $pageesc=htmlspecialchars($page);
+ $stroverrideinfo=get_string('overrideinfo','wiki');
+ $stroverridebutton=get_string('overridebutton','wiki');
+ $sesskey=sesskey();
+ print "
<form id='overridelock' method='post' action='overridelock.php'>
<input type='hidden' name='sesskey' value='$sesskey' />
<input type='hidden' name='id' value='$id' />
@@ -433,33 +434,12 @@
<input type='submit' value='$stroverridebutton' />
</form>
";
- }
- $goahead=false;
- } else {
- // Not locked any more. Get rid of the lock record.
- if(!delete_records('wiki_locks','pagename',$pagename,'wikiid', $wiki->id)) {
- error('Unable to delete lock record');
- }
- }
- }
- if($goahead) {
- if(!$alreadyownlock) {
- // Lock page
- $newlock=new stdClass;
- $newlock->lockedby=$USER->id;
- $newlock->lockedsince=time();
- $newlock->lockedseen=$newlock->lockedsince;
- $newlock->wikiid=$wiki->id;
- $newlock->pagename=$pagename;
- if(!$lockid=insert_record('wiki_locks',$newlock)) {
- error('Unable to insert lock record');
- }
}
- $_SESSION['lockid']=$lockid;
-
- // Require AJAX library
+ } else {
+ // OK, the page is now locked to us. Put in the AJAX for keeping the lock
print_require_js(array('yui_yahoo','yui_connection'));
$strlockcancelled=get_string('lockcancelled','wiki');
+ $strnojslockwarning=get_string('nojslockwarning','wiki');
$intervalms=WIKI_LOCK_RECONFIRM*1000;
print "
<script type='text/javascript'>
@@ -480,6 +460,9 @@ function handleFailure(o) {
{success:handleResponse,failure:handleFailure},'lockid=$lockid');
},$intervalms);
</script>
+<noscript><p>
+$strnojslockwarning
+</p></noscript>
";
// Print editor etc

0 comments on commit 4db1861

Please sign in to comment.