]> git.mjollnir.org Git - moodle.git/commitdiff
Wiki: Improve page locking to make it more robust and support non-javascript users...
authorsam_marshall <sam_marshall>
Wed, 27 Sep 2006 11:22:57 +0000 (11:22 +0000)
committersam_marshall <sam_marshall>
Wed, 27 Sep 2006 11:22:57 +0000 (11:22 +0000)
lang/en_utf8/wiki.php
mod/wiki/lib.php
mod/wiki/view.php

index 9e8b6e620f08a308f98bfdfaff2f772b8248ae79..91d334d4f798dcec6e56f8149654f0ab353e539f 100644 (file)
@@ -106,6 +106,7 @@ $string['noadministrationaction'] = 'No administration action given.';
 $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['revertpagescheck'] = 'Do you really want to revert the following change
 $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:';
index 98b327e494bcca297d21e37e8d62d9d1d5c24caa..8e6188067d9aecf2943a9f3a7b350e8f98a37db8 100644 (file)
@@ -12,11 +12,13 @@ $WIKI_TYPES = array ('teacher' =>   get_string('defaultcourseteacher'),
 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.");
+        }
+    }    
+}
+
+
 ?>
\ No newline at end of file
index 72381ea25483f2c6788b90ec3b0495a7eb7fb63d..5372bb7b606d7fa7d4ca3501beb931cf17abc47e 100644 (file)
         $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");
     }
 
     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;
 
     } 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' />
   <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 @@ intervalID=setInterval(function() {
         {success:handleResponse,failure:handleFailure},'lockid=$lockid');    
     },$intervalms);
 </script>
+<noscript><p>
+$strnojslockwarning
+</p></noscript>
 ";
             
             // Print editor etc