From 22e846cde22756790e20e1f3f466c743bb9a980c Mon Sep 17 00:00:00 2001 From: sam_marshall Date: Mon, 25 Sep 2006 17:42:32 +0000 Subject: [PATCH] Wiki enhancement: edit locking (uses AJAX) --- lang/en_utf8/wiki.php | 5 ++ mod/wiki/confirmlock.php | 31 ++++++++++ mod/wiki/db/access.php | 16 ++++++ mod/wiki/db/install.xml | 28 ++++++++- mod/wiki/db/mysql.php | 16 +++++- mod/wiki/db/postgres7.php | 15 +++++ mod/wiki/lib.php | 18 +++++- mod/wiki/overridelock.php | 51 ++++++++++++++++ mod/wiki/version.php | 4 +- mod/wiki/view.php | 118 ++++++++++++++++++++++++++++++++++++-- 10 files changed, 291 insertions(+), 11 deletions(-) create mode 100644 mod/wiki/confirmlock.php create mode 100644 mod/wiki/overridelock.php diff --git a/lang/en_utf8/wiki.php b/lang/en_utf8/wiki.php index e6b51e3d13..9e8b6e620f 100644 --- a/lang/en_utf8/wiki.php +++ b/lang/en_utf8/wiki.php @@ -94,6 +94,7 @@ $string['linkok'] = 'OK'; $string['linkschecked'] = 'Links checked'; $string['listall'] = 'List all'; $string['listcandidates'] = 'List candidates'; +$string['lockcancelled'] = 'Your editing lock has been overridden and somebody else is now editing this page. If you wish to keep your changes, please select and copy them before clicking Cancel; then try to edit again.'; $string['meta'] = 'Meta data'; $string['moduledirectory'] = 'Module Directory'; $string['modulename'] = 'Wiki'; @@ -116,10 +117,13 @@ $string['optional'] = 'Optional'; $string['orphanedpage'] = 'Orphaned page'; $string['orphanedpages'] = 'Orphaned pages'; $string['otherwikis'] = 'Other Wikis'; +$string['overrideinfo'] = 'You can override this user\'s lock, but doing so may cause them to lose their changes! Please take care.'; +$string['overridebutton'] = 'Override lock'; $string['ownerunknown'] = 'unknown'; $string['pageactions'] = 'Page actions'; $string['pageindex'] = 'Page Index'; $string['pageinfo'] = 'Page information'; +$string['pagelocked'] = '

This page is being edited by $a->name. They began editing at $a->since and still have the window open as of $a->seen.

You need to wait for them to finish before you can edit this page.

'; $string['pagename'] = 'Page name'; $string['pagenamechoice'] = '- or -'; $string['pageslinkingto'] = 'Pages linking to this page'; @@ -179,6 +183,7 @@ $string['viewsmfor'] = 'View sitemap for'; $string['wantedpages'] = 'Wanted pages'; $string['wiki:participate'] = 'Edit wiki pages'; $string['wiki:manage'] = 'Manage wiki settings'; +$string['wiki:overridelock'] = 'Override locked pages'; $string['wikidefaultpagename'] = 'WikiIndex'; $string['wikiexport'] = 'Export pages'; $string['wikiexportcomment'] = 'Here you can configure the export to your needs.'; diff --git a/mod/wiki/confirmlock.php b/mod/wiki/confirmlock.php new file mode 100644 index 0000000000..ce8f924aad --- /dev/null +++ b/mod/wiki/confirmlock.php @@ -0,0 +1,31 @@ +lockedseen=time(); + update_record('wiki_locks',$lock); + print 'ok'; +} else { + print 'cancel'; // Tells user their lock has been cancelled. +} + +?> \ No newline at end of file diff --git a/mod/wiki/db/access.php b/mod/wiki/db/access.php index 135edf6457..13acf5b9ed 100644 --- a/mod/wiki/db/access.php +++ b/mod/wiki/db/access.php @@ -36,5 +36,21 @@ $mod_wiki_capabilities = array( 'coursecreator' => CAP_PREVENT, 'admin' => CAP_ALLOW ) + ), + + 'mod/wiki:overridelock' => array( + + 'riskbitmask' => 0, + + 'captype' => 'write', + 'contextlevel' => CONTEXT_MODULE, + 'legacy' => array( + 'guest' => CAP_PREVENT, + 'student' => CAP_PREVENT, + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'coursecreator' => CAP_ALLOW, + 'admin' => CAP_ALLOW + ) ) ); diff --git a/mod/wiki/db/install.xml b/mod/wiki/db/install.xml index 38f800ba23..35c479d7d9 100644 --- a/mod/wiki/db/install.xml +++ b/mod/wiki/db/install.xml @@ -48,7 +48,7 @@ - +
@@ -66,11 +66,37 @@ +
+ + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/mod/wiki/db/mysql.php b/mod/wiki/db/mysql.php index a75660d6bb..32884a54d5 100644 --- a/mod/wiki/db/mysql.php +++ b/mod/wiki/db/mysql.php @@ -160,7 +160,21 @@ function wiki_upgrade($oldversion) { execute_sql("UPDATE {$CFG->prefix}wiki SET initialcontent='' WHERE initialcontent IS NULL"); table_column('wiki','initialcontent','initialcontent','varchar','255','','','not null'); } - + if ($oldversion < 2006092502) { + modify_database(""," +CREATE TABLE prefix_wiki_locks +( + id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + wikiid INT(10) UNSIGNED NOT NULL, + pagename VARCHAR(160) NOT NULL DEFAULT '', + lockedby INT(10) NOT NULL DEFAULT 0, + lockedsince INT(10) NOT NULL DEFAULT 0, + lockedseen INT(10) NOT NULL DEFAULT 0, + PRIMARY KEY(id), + UNIQUE KEY wiki_locks_uk(wikiid,pagename), + INDEX wiki_locks_ix(lockedseen) +);"); + } return true; } diff --git a/mod/wiki/db/postgres7.php b/mod/wiki/db/postgres7.php index da338e649f..2d89821c33 100644 --- a/mod/wiki/db/postgres7.php +++ b/mod/wiki/db/postgres7.php @@ -155,6 +155,21 @@ function wiki_upgrade($oldversion) { modify_database('', 'ALTER TABLE prefix_wiki_pages ALTER COLUMN refs DROP NOT NULL'); } + + if ($oldversion < 2006092502) { + modify_database(""," +CREATE TABLE prefix_wiki_locks +( + id SERIAL PRIMARY KEY, + wikiid INTEGER NOT NULL, + pagename VARCHAR(160) NOT NULL DEFAULT '', + lockedby INTEGER NOT NULL DEFAULT 0, + lockedsince INTEGER NOT NULL DEFAULT 0, + lockedseen INTEGER NOT NULL DEFAULT 0 +);"); + modify_database("","CREATE INDEX prefix_wikilock_loc_ix ON prefix_wiki_locks (lockedseen);"); + modify_database("","CREATE UNIQUE INDEX prefix_wikilock_wikpag_uix ON prefix_wiki_locks (wikiid, pagename);"); + } return true; } diff --git a/mod/wiki/lib.php b/mod/wiki/lib.php index 57e0348ea6..384091f967 100644 --- a/mod/wiki/lib.php +++ b/mod/wiki/lib.php @@ -11,6 +11,13 @@ $WIKI_TYPES = array ('teacher' => get_string('defaultcourseteacher'), 'student' => get_string('defaultcoursestudent') ); define("EWIKI_ESCAPE_AT", 0); # For the algebraic filter +// How long locks stay around without being confirmed (seconds) +define(WIKI_LOCK_PERSISTENCE,60); + +// How often to confirm that you still want a lock +define(WIKI_LOCK_RECONFIRM,30); + + /*** Moodle 1.7 compatibility functions ***** * ********************************************/ @@ -135,6 +142,10 @@ function wiki_delete_instance($id) { } # Delete any dependent records here # + if(!delete_records("wiki_locks","wikiid",$wiki->id)) { + $result = false; + } + if (! delete_records("wiki", "id", $wiki->id)) { $result = false; } @@ -225,9 +236,10 @@ function wiki_cron () { /// This function searches for things that need to be done, such /// as sending out mail, toggling flags etc ... - global $CFG; + // Delete expired locks + $result=delete_records_select('wiki_locks','lockedseen < '.(time()-WIKI_LOCK_PERSISTENCE)); - return true; + return $result; } function wiki_grades($wikiid) { @@ -1550,4 +1562,4 @@ function wiki_get_post_actions() { } -?> +?> \ No newline at end of file diff --git a/mod/wiki/overridelock.php b/mod/wiki/overridelock.php new file mode 100644 index 0000000000..0b83b9bed5 --- /dev/null +++ b/mod/wiki/overridelock.php @@ -0,0 +1,51 @@ +course)) { + error("Course is misconfigured"); +} +if (! $wiki = get_record("wiki", "id", $cm->instance)) { + error("Course module is incorrect"); +} + +if(!confirm_sesskey()) { + error("Session key not set"); +} +if(!data_submitted()) { + error("Only POST requests accepted"); +} + +require_course_login($course, true, $cm); + +$modcontext = get_context_instance(CONTEXT_MODULE, $cm->id); +if(!has_capability('mod/wiki:overridelock', $modcontext)) { + error("You do not have the capability to override editing locks"); +} + +$actions = explode('/', $page,2); +if(count($actions)!=2) { + error("Unsupported page value"); +} +$pagename=addslashes($actions[1]); +if(!delete_records('wiki_locks','pagename',$pagename,'wikiid', $wiki->id)) { + error('Unable to delete lock record'); +} + +redirect("view.php?id=$id&page=".urlencode($page)); +?> \ No newline at end of file diff --git a/mod/wiki/version.php b/mod/wiki/version.php index 87b1847a9d..392193bc76 100644 --- a/mod/wiki/version.php +++ b/mod/wiki/version.php @@ -5,8 +5,8 @@ /// This fragment is called by moodle_needs_upgrading() and /admin/index.php ///////////////////////////////////////////////////////////////////////////////// -$module->version = 2006091800; // The current module version (Date: YYYYMMDDXX) +$module->version = 2006092502; // The current module version (Date: YYYYMMDDXX) $module->requires = 2006080900; // The current module version (Date: YYYYMMDDXX) -$module->cron = 0; // Period for cron to check this module (secs) +$module->cron = 3600; // Period for cron to check this module (secs) ?> diff --git a/mod/wiki/view.php b/mod/wiki/view.php index cfea9ca33b..72381ea254 100644 --- a/mod/wiki/view.php +++ b/mod/wiki/view.php @@ -2,11 +2,12 @@ /// Extended by Michael Schneider /// This page prints a particular instance of wiki - global $CFG; + global $CFG,$USER; require_once("../../config.php"); require_once("lib.php"); - #require_once("$CFG->dirroot/course/lib.php"); // For side-blocks + #require_once("$CFG->dirroot/course/lib.php"); // For side-blocks + require_once(dirname(__FILE__).'/../../lib/ajax/ajaxlib.php'); $ewiki_action = optional_param('ewiki_action', '', PARAM_ALPHA); // Action on Wiki-Page $id = optional_param('id', 0, PARAM_INT); // Course Module ID, or @@ -21,6 +22,27 @@ // Only want to add edit log entries if we have made some changes ie submitted a form $editsave = optional_param('thankyou', ''); + if($page) { + // Split page command into action and page + $actions = explode('/', $page,2); + if(count($actions)==2) { + $pagename=$actions[1]; + } + } 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"); @@ -370,12 +392,100 @@ /// actions will have the form [action]/[pagename]. If the action is 'view' or the '/' /// isn't there (so the action defaults to 'view'), filter it. /// If the page does not yet exist, the display will default to 'edit'. - $actions = explode('/', $page); if((count($actions) < 2 || $actions[0] == "view") && record_exists('wiki_pages', 'pagename', addslashes($page), 'wiki', $wiki_entry->id)) { print(format_text($content, $moodle_format)); + } 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); + + if($canoverridelock) { + $pageesc=htmlspecialchars($page); + $stroverrideinfo=get_string('overrideinfo','wiki'); + $stroverridebutton=get_string('overridebutton','wiki'); + $sesskey=sesskey(); + print " +
+ + + + $stroverrideinfo + +
+"; + } + $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 + print_require_js(array('yui_yahoo','yui_connection')); + $strlockcancelled=get_string('lockcancelled','wiki'); + $intervalms=WIKI_LOCK_RECONFIRM*1000; + print " + +"; + + // Print editor etc + print $content; + } + } else { print $content; } print $content2; -- 2.39.5