Extension talk:DocumentApproval

Multiple approvals not working
I had to make some changes to get multiple approvals to work. Below is the diff to show what I changed.

214a215 > 303,304c304 <              $req_userid = 0; < --- > 306,307c306,307 <                $sql =  "SELECT description FROM ". $dbr->tableName('approval_request'); <                $sql .= " WHERE page_id = ". $pageid. " AND user_id = ". $userid; --- >                $sql =  "SELECT user_id, description FROM ". $dbr->tableName('approval_request'); >                $sql .= " WHERE page_id = ". $pageid; 313,314c313,314 <                    $req_userid = $userid; <                    $req_description = $row[0]; --- >                    $req_userid = $row[0]; >                    $req_description = $row[1]; 563d562 < ?>

Hope that helps. It's a good extension. --Paul 01:27, 12 February 2008 (UTC)

Question about roles
How do I set the roles? And does it work that any user with that role can sign a document or does the user have to be defined as well as the role?

Issue with linefeeds (/n)
I modified the function fnDocumentApproval and moved the assignment of $function inside the if check for $login because when $requests was assigned from splitting $inputs on "\n" the first and last value in the array is blank and thus there is no value for $function = $request[1].

.. FROM .. function fnDocumentApproval( $input, $argv, &$parser ) {

daTableCheck; $requests=split("\n",$input); .. ..  foreach($requests as $request) {       $request=split(";",trim($request)); $login = $request[0]; $function = $request[1]; if ($login != "") {           $counter++; // Gets userid $userid = getUserIDFromUserText($login);

.. TO .. function fnDocumentApproval( $input, $argv, &$parser ) {

daTableCheck; $requests=split("\n",$input); .. ..  foreach($requests as $request) {       $request=split(";",trim($request)); $login = $request[0]; if ($login != "") {           $function = $request[1]; $counter++; // Gets userid $userid = getUserIDFromUserText($login);

--Chris Wolcott, May 2008 (UTC)

Sign Tab displayed incorrectly
If a user is not logged in the sign tab is being displayed. We are currently using Mediawiki 1.12.0 and php 5.2.0

Changed the daSkinTemplateTabs function in the file DocumentApproval.body.php to check if a user is current logged in.

.. FROM ..

function daSkinTemplateTabs( &$skin, &$content_actions ) { global $wgRequest, $wgTitle; $action = $wgRequest->getText( 'action' ); // Check if the user are elegible for singing this page $revisionid = $wgTitle->getLatestRevID; $revision = Revision::newFromID($revisionid); if ($revision) {       //    $revisionid = $revision->getId; $pageid = $revision->getPage; $user = User::newFromSession; $userid = $user->getID; $dbr = wfGetDB( DB_SLAVE ); // Check if this user can sign the document $sql = "SELECT user_id FROM ". $dbr->tableName('approval_request'); $sql .= " WHERE page_id = ". $pageid; $sql .= " AND user_id = ". $userid; $reqUserId = ""; $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) {               $row = $dbr->fetchRow($res); $reqUserID = $row[0]; }           $dbr->freeResult($res); // If user is elegible for singning, displays the sign tab if ($reqUserID == $userid) {                       $content_actions['sign'] = array(                                'class' => ($action == 'sign') ? 'selected' : false,                                'text' => "sign",                                'href' => $skin->mTitle->getLocalURL( 'action=sign' )                        ); }       }        return true; }

.. TO ..

function daSkinTemplateTabs( &$skin, &$content_actions ) { global $wgRequest, $wgTitle; $action = $wgRequest->getText( 'action' ); // Check if the user are elegible for singing this page $revisionid = $wgTitle->getLatestRevID; $revision = Revision::newFromID($revisionid); if ($revision) {       // $revisionid = $revision->getId; $pageid = $revision->getPage; $user = User::newFromSession; $userid = $user->getID; // MOD - Check if there is a user logged-on if ($userid) { $dbr = wfGetDB( DB_SLAVE ); // Check if this user can sign the document $sql = "SELECT user_id FROM ". $dbr->tableName('approval_request'); $sql .= " WHERE page_id = ". $pageid; $sql .= " AND user_id = ". $userid; $reqUserId = ""; $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) { $row = $dbr->fetchRow($res); $reqUserID = $row[0]; }

$dbr->freeResult($res); // If user is elegible for singning, displays the sign tab if ($reqUserID == $userid) { $content_actions['sign'] = array(                               'class' => ($action == 'sign') ? 'selected' : false,                                'text' => "sign",                                'href' => $skin->mTitle->getLocalURL( 'action=sign' )); }          }        }        return true; }

--Chris Wolcott 12:48, 27 May 2008 (UTC)

No Sign tab displayed
As of MediaWiki 1.18, the SkinTemplateTabs Hook is deprecated.

In DocumentApproval.php I had to change  to

And in DocumentApproval.body.php I had to change the Array name  to   (just added the   hierarchy). also doesn't seem to work anymore, so the whole block to add the "Sign"-tab is for me: $href = $skin->makeArticleUrlDetails($skin->getTitle->getFullText, 'action=sign' ); $content_actions['views']['sign'] = array( // was $content_actions['sign'] before         'class' => ($action == 'sign') ? 'selected' : false,          'text' => wfMsg('sign-tab-text'),          'href' => $href['href']); // was $skin->mTitle->getLocalURL( 'action=sign' ) before

First page save issue
If is added to a new document the I function fnDocumentApproval fails because there is no revision for this page yet (because it has not been saved). Thus I modified fnDocumentApproval to check for a null $revision and return false.

.. FROM .. function fnDocumentApproval( $input, $argv, &$parser ) {

daTableCheck;

$requests=split("\n",$input);

// get document full title $title = $parser->getTitle;

$revision = Revision::newFromTitle($title); $revisionid = $revision->getId; $pageid = $revision->getPage; .. ..

.. TO .. function fnDocumentApproval( $input, $argv, &$parser ) {

daTableCheck;

$requests=split("\n",$input);

// get document full title $title = $parser->getTitle;

$revision = Revision::newFromTitle($title); if (is_null($revision)) return false;

$revisionid = $revision->getId; $pageid = $revision->getPage; .. ..

--Chris Wolcott 09:48, 29 May 2008 (UTC)

An improvement but still not perfect
I have made the above modification in the DocumentApproval.body.php file which does allow me to at least save the newly created page with the approval details included (instead of it not saving as before). However the approval table and sign tab don't appear on the initial save. If I go back into the page and simply hit save page again they appear.

Is there any other fixes for this behaviour? Is this what other people have encountered?

Cameron.moody 23:01, 2 July 2008 (UTC)

I'm having the exact same problem. So far i've not been able to come up with a fix since I can't get the pageID from the uncreated page.

Logging of the approvals?
I can't seem to see anywhere that the actual signing is logged? I have checked under Special:Log but can't find any entries there. I also can't see anything under the page history to indicate that it had been signed. Is this sort of functionality available from somewhere, or can it be added at all?

Cameron.moody 04:38, 2 July 2008 (UTC)

How does an approver know that they have a request to approve a page?
Is there some sort of notification email that is sent? I have done some test pages listing email-confirmed users as approvers but they get no email. I also cannot see anywhere that they are notified of a pending request?

Cam

Return from fnSign hook incorrect
I changed the final else portion of the code to return true. The allows other UnknownHook calls to still execute.

Wolcott 20:36, 14 July 2008 (UTC)

Possible that a notification be sent to confirmed email address?
I am helping set up an internal wiki that only allows access to users with confirmed email addresses. With this extension there does not appear to be any notification.

Is it possible to add something to the code that whenever a page is saved that an email notification is sent to each of the users specified (ie their confirmed email address) to let them know? Ideally with a link to the page or the page title etc.

Enforce Approval as "required". Choose approver by clicking. Email notification

 * 1) Is there a feature that to set "approval" procedure as "required" and the user can't save the page without set approval assigner? no --Jostar 14:05, 9 February 2010 (UTC)
 * 2) Is there a way to let the users to click one of the user from one of predefined user groups instead of to type in the approval markup section? no --Jostar 14:05, 9 February 2010 (UTC)
 * 3) It seems that several users requested email notification before. Is it available yet? no but I like this option and I will think on this --Jostar 14:05, 9 February 2010 (UTC)
 * 4) * Every "sign"-action should be logged (easy to do)
 * 5) * A special page can show "pages waiting to sign" (easy to do) This list has to be checked from every user every day... better version 3:
 * 6) * Once someone added a user to the aproval list, the system sends him a message.

I did your second version because if you have very much pages to sign, getting a message for every single page is not fun. The code is listed below. --Daniel Gerber 09:28, 6 March 2010 (UTC)

Internationalisation
I removed the follwoing code and changed to the other part of the code for Internationalizing. --Jostar 16:19, 9 February 2010 (UTC)

problems with "undefined Variable" due to extension:dpl
using Extension dpl an error accured only on pages usind dpl: 'undefined Variable:$reqUserID' in line 156

I could not find the real reason, but I changed this line (Number 156) to avoid the error message: if ($reqUserID == $userid) { to: if (isset($reqUserID) && $reqUserID == $userid) { # isset avoids error: 'undefined Variable:$reqUserID' occuring with Extension:PDL for example

--Jostar 12:32, 10 February 2010 (UTC)

special page that lists all approval requests
I added a special page, that lists all pages where the user is requested for approval and all pages he already approved. Maybe we could integrate something like this in the next version of the extension? My Code:

File: DocumentApproval.php Class definition in file: DocumentApproval.body.php ";			if (!$not_approved_tab_empty) {				$output .= $not_approved_tab;			}			else{				# = no pending requests for approval				$output = wfMsg('daNotRequested');			}		}		else{ 			# = no requests for approval			$output = wfMsg('daNotRequested');       }        $dbr->freeResult($res);		$output .= ' '. wfMsg('daApprovedPages') .' ';		if (!$approved_tab_empty) {			# generate table with approved pages			$output .= ' ';		}		else {			# procedure if there are no approved pages at all			$output .= wfMsg('daNoPagesApproved');		}		$wgOut->addHTML( $output );	} } Internationalization in file: DocumentApproval.i18n.php  I did only the German and English internationalization.  Parserfunktion zur Dokumentengenehmigung ein',  'daTableTitle'	 	=> '&#xDC;berarbeitungstabelle der Bewilligung',  'daApprovalDate' 		=> 'Genehmigungsdatum',  'daSign'		 		=> 'Signatur',  'daFunction'			=> 'Funktion',  'daPending'			=> 'offen', 'daUserNotFound'		=> 'Benutzer nicht gefunden', 'daNotNecessary'		=> 'Deine Unterschrift ist für dieses Dokument nicht erforderlich.', 'daPreviouslySigned'	=> 'Das Dokument wurde schon am $1 von dir unterzeichnet und kann nicht noch ein mal unterzeichnet werden.', 'sign-tab-text'	=> 'Unterzeichnen', 'daNotApprovedPages'	=> 'Nicht unterzeichnete Seiten', 'daApprovedPages'		=> 'Unterzeichnete Seiten', 'daNotRequested'		=> 'Du bist f&uuml;r keine Unterzeichnung angefragt.', 'daPage'				=> 'Seite', 'daNoPagesApproved'	=> 'Du hast keine Seiten unterzeichnet.', 'daWrongId'			=> 'Falsche Id', ); $messages['de-formal'] = array( 'daNotNecessary'		=> 'Ihre Unterschrift ist für dieses Dokument nicht erforderlich.', 'daPreviouslySigned'	=> 'Das Dokument wurde schon am $1 von Ihnen unterzeichnet und kann nicht noch ein mal unterzeichnet werden.', ); /** English $messages['en'] = array( 'documentapproval'	=> 'DocumentApproval', 'da-desc' 			=> 'adds  parser function document approval', 'daTableTitle'	 	=> 'Approval table of revision', 'daApprovalDate' 		=> 'Approval date', 'daSign'		 		=> 'Sign', 'daFunction'			=> 'Role', 'daPending'			=> 'pending', 'daUserNotFound'		=> 'user not found', 'daNotNecessary'		=> 'Your sign is not necessary to this document.', 'daPreviouslySigned'	=> 'Document previously signed at $1', 'sign-tab-text'	=> 'Sign', 'daNotApprovedPages'	=> 'Not approved Pages', 'daApprovedPages'		=> 'Approved Pages', 'daNotRequested'		=> 'You are not requested for approval of a page.', 'daPage'				=> 'Page', 'daNoPagesApproved'	=> 'You have not approved any pages.', 'daWrongId'			=> 'Wrong Id', ); --Daniel Gerber 09:28, 6 March 2010 (UTC)
 * @author João Artur Gramacho
 * @updates Daniel Gerber

New Version 0.0.3
To adress logbook, special summary page, css format and order of signing.

My edits:
 * 1) 09.02.2010 internalisation changed to standard procedures
 * 2) 01.03.2010 Table in Wikiformat, use class = "wikitable"
 * 3) 02.03.2010 The order of signing must be correct, use order = "strict"
 * 4) 03.03.2010 Logbuch aktivated
 * 5) 03.03.2010 Table header is multilang

to-do:
 * 1) parameter reset="strict"...
 * 2) wenn in nowiki-tags, ignorieren!

--Jostar 18:53, 8 March 2010 (UTC)

Parameter
sorry, has to be translated

Innerhalb des tags ist die Angabe weiterer Parameter möglich.
 * Parameter 'class' im approval-tag
 * erlaubt die Tabellenformatierung, angegeben wird einfach die CSS-Klasse
 * Beispiel: class="wikitable sortable" erzeugt die Tabellenformatierung im wiki-Style und eine Sortiermöglichkeit der Tabelle


 * Parameter 'order' im approval-tag
 * legt die Reihenfolge der Abarbeitung für die Listeneinträge fest
 * Beispiel: order="strict" zeigt eine Nummerierungsspalte an mit der Spaltenüberschrift "!" und erlaubt "Unterschreiben" nur wenn man an der Reihe ist, also alle Anfragen vor dem eigenen Eintrag schon erfolgreich waren


 * Parameter 'reset' im approval-tag
 * legt das Zurücksetzten einmal abgegebener Unterschriften fest. Standardmäßig setzt jede Seitenänderung alle Unterschriften zurück, was zum Beispiel beim Ausfüllen von Formularen nicht der gewünschte Effekt ist.
 * Beispiel: reset="all" ist die Standardeinstellung
 * Beispiel: reset="form" es werden nur Unterschriften zurückgesetzt wenn eine Änderung außerhalb von Feldern (Parameter in Vorlage) erfolgt
 * Beispiel: reset="none" es werden nie Unterschriften zurückgesetzt (eigentlich sind sie dann auch sinnlos, anzuwenden vielleicht wenn es um Rechtschreibfehler etc. geht... es gibt im wiki die Möglichkeit Änderungen als "klein" zu markieren)

DocumentApproval.body.php
';       }        $wgOut->addwikitext ( '==' . wfMsg('da-signlist', $db->numRows($result)) . '==' ); $wgOut->addHTML( $output ); } # Ende alle Benutzer return false; } # end function } # end of special page --

function DocumentApprovalLoadMessages { static $messagesLoaded = false; global $wgMessageCache; if ($messagesLoaded) return; $messagesLoaded = true; require(dirname(__FILE__) . '/DocumentApproval.i18n.php' ); foreach ( $allMessages as $lang => $langMessages ) { $wgMessageCache->addMessages( $langMessages, $lang ); }   return true; } function daTableCheck {	global $wgDBprefix; $dbr = wfGetDB( DB_SLAVE ); // Check if 'approval_request' database tables exists if (!$dbr->tableExists('approval_request')) {		$sql = "CREATE TABLE `". $wgDBprefix. "approval_request` (";		$sql .= "`page_id` int(10) unsigned NOT NULL,";		$sql .= "`user_id` int(10) unsigned NOT NULL,";		$sql .= "`description` varchar(255) default NULL,";	 $sql .= "`position` int(10) unsigned NOT NULL,";	  $sql .= "`order` int(10) unsigned NOT NULL,";		$sql .= "PRIMARY KEY  (`page_id`,`user_id`),";		$sql .= "KEY `FK_" . $wgDBprefix . "_approval_request_user` (`user_id`),";		$sql .= "CONSTRAINT `FK_" . $wgDBprefix . "_approval_request_page` FOREIGN KEY (`page_id`) REFERENCES `" . $wgDBprefix . "_page` (`page_id`),";		$sql .= "CONSTRAINT `FK_" . $wgDBprefix . "_approval_request_user` FOREIGN KEY (`user_id`) REFERENCES `" . $wgDBprefix . "_user` (`user_id`)";		$sql .= ") ENGINE=InnoDB DEFAULT CHARSET=latin1;"; $res = $dbr->query( $sql, __METHOD__ ); }	// Check if 'approval' database tables exists if (!$dbr->tableExists('approval')) {		$sql = "CREATE TABLE `". $wgDBprefix. "approval` (";		$sql .= "`rev_id` int(10) unsigned NOT NULL,";		$sql .= "`rev_page` int(10) unsigned NOT NULL,";		$sql .= "`user_id` int(10) unsigned NOT NULL,";		$sql .= "`date` timestamp NOT NULL default CURRENT_TIMESTAMP,";		$sql .= "PRIMARY KEY (`rev_id`,`rev_page`,`user_id`),";		$sql .= "KEY `FK_" . $wgDBprefix . "_approval_user` (`user_id`),";		$sql .= "CONSTRAINT `FK_" . $wgDBprefix . "_approval_revision` FOREIGN KEY (`rev_id`, `rev_page`) REFERENCES `" . $wgDBprefix . "_revision` (`rev_id`, `rev_page`),";		$sql .= "CONSTRAINT `FK_" . $wgDBprefix . "_approval_user` FOREIGN KEY (`user_id`) REFERENCES `" . $wgDBprefix . "_user` (`user_id`)";		$sql .= ") ENGINE=InnoDB DEFAULT CHARSET=latin1;"; $res = $dbr->query( $sql, __METHOD__ ); }	// Check if 'approval_version' database tables exists if (!$dbr->tableExists('approval_version')) {		$sql = "CREATE TABLE `". $wgDBprefix. "approval_version` (";		$sql .= "`page_id` int(10) unsigned NOT NULL,";		$sql .= "`last_approved_revision_id` int(10) unsigned default NULL,";		$sql .= "`version` int(10) unsigned NOT NULL default '0',";		$sql .= "`subversion` int(10) unsigned NOT NULL default '0',";		$sql .= "PRIMARY KEY (`page_id`),";		$sql .= "KEY `FK_" . $wgDBprefix . "_approval_version_revision_id` (`last_approved_revision_id`,`page_id`),";		$sql .= "CONSTRAINT `FK_" . $wgDBprefix . "_approval_version_page_id` FOREIGN KEY (`page_id`) REFERENCES `" . $wgDBprefix . "_page` (`page_id`),";		$sql .= "CONSTRAINT `FK_" . $wgDBprefix . "_approval_version_revision_id` FOREIGN KEY (`last_approved_revision_id`, `page_id`) REFERENCES `" . $wgDBprefix . "_revision` (`rev_id`, `rev_page`)";				$sql .= ") ENGINE=InnoDB DEFAULT CHARSET=latin1;"; $res = $dbr->query( $sql, __METHOD__ ); } } if (!function_exists('getUserIDFromUserText')) { function getUserIDFromUserText($user) { $dbr = wfGetDB( DB_SLAVE ); $userid = 0; if (preg_match('/^\s*(.*?)\s*$/', $user, $matches)) $user = $matches[1]; $u = User::newFromName($user); if ($u) { $userid = $u->idForName;              // valid userName }       if (!$userid) {                              // if not a valid userName, try as a userRealName $userid = $dbr->selectField( 'user', 'user_id', array( 'user_real_name' => $user ), 'renderTodo' ); if (!$userid) {                         // if not valid userRealName, try case insensitive userRealName $sql = "SELECT user_id FROM ". $dbr->tableName('user') ." WHERE UPPER(user_real_name) LIKE '%". strtoupper($user). "%'";               $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) { $row = $dbr->fetchRow($res); $userid = $row[0]; }               $dbr->freeResult($res); if (!$userid) {                     // if not case insensitive userRealName, try case insensitive lastname list ($first, $last) = preg_split('/\s+/', $user); if ($last != '') { $sql = "SELECT user_id FROM ". $dbr->tableName('user') ." WHERE UPPER(user_real_name) LIKE '%". strtoupper($last). "%'";                       $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) { $row = $dbr->fetchRow($res); $userid = $row[0]; }                       $dbr->freeResult($res); }               }            }        }        return $userid; } } function daSkinTemplateTabs( &$skin, &$content_actions ) { global $wgRequest, $wgTitle; $action = $wgRequest->getText( 'action' ); // Check if the user are elegible for singing this page $revisionid = $wgTitle->getLatestRevID; $revision = Revision::newFromID($revisionid); if ($revision) {	//	$revisionid = $revision->getId; $pageid = $revision->getPage; $user = User::newFromSession; $userid = $user->getID; // MOD - Check if there is a user logged-on if ($userid) { $dbr = wfGetDB( DB_SLAVE ); // Check if this user can sign the document $sql = "SELECT user_id FROM ". $dbr->tableName('approval_request'); $sql .= " WHERE page_id = ". $pageid; $sql .= " AND user_id = ". $userid;

$reqUserId = ""; $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) {           $row = $dbr->fetchRow($res); $reqUserID = $row[0]; }       $dbr->freeResult($res); // If user is elegible for singning, displays the sign tab if (isset($reqUserID) && $reqUserID == $userid) { # isset avoids error: 'undefined Variable:$reqUserID' occuring with Extension:PDL for example $content_actions['sign'] = array(         'class' => ($action == 'sign') ? 'selected' : false,          'text' => wfMsg('sign-tab-text'),          'href' => $skin->mTitle->getLocalURL( 'action=sign' ),          ); }       }	}	return true; } function fnDocumentApprovalDelete( &$article, &$user, &$reason ) { daTableCheck; // get page_id $pageid = $article->getID; $dbr = wfGetDB( DB_SLAVE ); // delete $sql = "DELETE "; $sql .= " FROM ". $dbr->tableName('approval_version'); $sql .= " WHERE page_id = ". $pageid; $res = $dbr->query( $sql, __METHOD__ ); // delete $sql = "DELETE "; $sql .= " FROM ". $dbr->tableName('approval_request'); $sql .= " WHERE page_id = ". $pageid; $res = $dbr->query( $sql, __METHOD__ ); // delete $sql = "DELETE "; $sql .= " FROM ". $dbr->tableName('approval'); $sql .= " WHERE rev_page = ". $pageid; $res = $dbr->query( $sql, __METHOD__ ); return true; } function fnDocumentApproval( $input, $argv, &$parser ) { daTableCheck;

$requests=split("\n",$input); // get document full title $title = $parser->getTitle; $revision = Revision::newFromTitle($title); if (is_null($revision)) return false; # if there is no revision for a new page (because it has not been saved) $revisionid = $revision->getId; $pageid = $revision->getPage; $dbr = wfGetDB( DB_SLAVE ); $output = ""; $counter = 0; $listOfUsers = ""; $page_version = 0; $page_subversion = 0; $page_last_revision = 0; // gets document last version and subversion $sql = "SELECT version, subversion, last_approved_revision_id"; $sql .= " FROM ". $dbr->tableName('approval_version'); $sql .= " WHERE page_id = ". $pageid; $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) {		$row = $dbr->fetchRow($res); $page_version = $row[0]; $page_subversion = $row[1]; $page_last_revision = $row[2]; }	$dbr->freeResult($res); $revcount = 0; // Gets the amount of changes since last approval $sql = "SELECT count(*) as changes FROM ". $dbr->tableName('revision'); $sql .= " WHERE rev_page = ". $pageid; $sql .= " AND rev_id > ". $page_last_revision; $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) {		$row = $dbr->fetchRow($res); $revcount = $row[0]; }	$dbr->freeResult($res); // Gets the options inside the -tag foreach ($argv as $key => $value) { switch ($key) { case 'class': $tableclass = $value; // Gets the display option for a wiki format table, e.g.  break; case 'order': $order = $value; // Gets the option for correct order signing (z.B. ) break; case 'reset': $reset = $value; // Gets the option for sign reset (z.B. ) break; default : wfDebug( __METHOD__.": Requested '$key ==> $value'\n" ); break; }   }

//creates table caption and header in html format and if option 'class' is found in wiki-like format $output .= "\n"; $output .= ''."\n";   $output .= " \n";    $output .= wfMsg("daTableTitle") . " #$page_version.$page_subversion.$revcount\n";    $output .= " \n";    $output .= "\n";    if ((isset($tableclass) && strpos('sortable', $tableclass) > 0 && $order != 'strict') || $order == 'strict')    $output .= " ".($order == 'strict' ? '!' : '#')." \n";   $output .= " " . wfMsg("daApprovalDate") . " \n";    $output .= " " . wfMsg("daSign") . " \n";    $output .= " " . wfMsg("daFunction") . " \n";    $output .= " \n";

foreach($requests as $request) {       $request=split(";",trim($request)); $login = $request[0]; if ($login != "") {           $function = $request[1]; $counter++; // Gets userid $userid = getUserIDFromUserText($login); if ($userid != 0) // if user exists {               // Put user on the temporary approval list if ($listOfUsers == "") $listOfUsers .= $userid; else $listOfUsers .= ", ". $userid; $req_userid = 0; // Gets user information $u = User::newFromId($userid); $username = $u->getName; $fullname = $u->getRealName; // Check if this user is in the approval list on database $sql = "SELECT description, position, `order` FROM ". $dbr->tableName('approval_request'); $sql .= " WHERE page_id = ". $pageid. " AND user_id = ". $userid;

$res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) {                   $row = $dbr->fetchRow($res); $req_userid = $userid; $req_description = $row[0]; $req_position = $row['position']; $req_order = $row['order'];

}               $dbr->freeResult($res); // If not, insert it               if ($req_userid == 0) {                   $sql =  "INSERT INTO ". $dbr->tableName('approval_request'); $sql .= " (page_id, user_id, description, position, `order`) VALUES"; $sql .= " ($pageid, $userid, '" . trim($function) . "', $counter, '" . $order . "')"; $res = $dbr->query( $sql, __METHOD__ ); $req_userid = $userid; $req_description = $function; # log $log = new LogPage( 'dalog' ); $log->addEntry( 'sentok', $title, $username.': '.trim($function)); #email }               // If position changed? if ($req_position != $counter) { $sql = "UPDATE ". $dbr->tableName('approval_request'); $sql .= " SET position = '". $counter. "'";                   $sql .= " WHERE page_id = $pageid AND user_id = $userid"; $res = $dbr->query( $sql, __METHOD__ ); $req_position = $position; }               // If order changed? if ($req_order != $order && $order != '') { $sql = "UPDATE ". $dbr->tableName('approval_request'); $sql .= " SET `order` = '". $order. "'";                   $sql .= " WHERE page_id = $pageid AND user_id = $userid"; $res = $dbr->query( $sql, __METHOD__ ); $req_order = $order; }               // If user role changed, update database if ($req_description != $function) { $sql = "UPDATE ". $dbr->tableName('approval_request'); $sql .= " SET description = '". $function. "'";                   $sql .= " WHERE page_id = $pageid AND user_id = $userid"; $res = $dbr->query( $sql, __METHOD__ ); $req_description = $function; # log $log = new LogPage( 'dalog' ); $log->addEntry( 'sentok', $title, $username.': '.trim($function)); #Add to watch #$u->addWatch( $title ); fuegt das Logbuch hinzu! #send email $u->sendMail ( wfMsg('da-emailtitle'), wfMsg('da-emailtext', ($fullname ? $fullname : $username), $title, trim($function), $title->GetFullURL ). " (http://fywiki/wiki/Spezial:DocumentApproval)"); }               // check if the user already signed this document $sql = "SELECT date FROM ". $dbr->tableName('approval'); $sql .= " WHERE rev_page = ". $pageid; $sql .= " AND user_id = ". $userid; $sql .= " AND rev_id = ". $revisionid; $signDate = " ". wfMsg("daPending"). " ";               $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) {                   $row = $dbr->fetchRow($res); $signDate = $row[0]; }               $dbr->freeResult($res); $output .= " \n"; if ((isset($tableclass) && strpos('sortable', $tableclass) > 0 && $order != 'strict') || $order == 'strict') $output .= " $counter \n"; $output .= " $signDate \n"; $output .= " $fullname \n"; $output .= " $function \n"; $output .= " \n"; }           else // If the user was not found {               $output .= " \n"; if ((isset($tableclass) && strpos('sortable', $tableclass) > 0 && $order != 'strict') || $order == 'strict') $output .= " $counter \n"; $output .= " ". wfMsg("daUserNotFound"). " \n"; $output .= " $login \n"; $output .= " $function \n"; $output .= " \n"; }       }    }    if ($listOfUsers != "") {	   // Remove users that do not have to sign the document from database $sql = "DELETE FROM ". $dbr->tableName('approval_request'); $sql .= " WHERE page_id = $pageid AND user_id NOT IN (" . $listOfUsers . ")"; $res = $dbr->query( $sql, __METHOD__ ); }   $output .= " \n"; return $output; } function fnSign($action, $article) { global $wgOut, $wgLang, $wgContLang; daTableCheck; if ($action == 'sign') {       $title = $article->getTitle; $revision = Revision::newFromTitle($title); $revisionid = $revision->getId; $pageid = $revision->getPage; $user = User::newFromSession; $userid = $user->getID;

$dbr = wfGetDB( DB_SLAVE ); // Check if this user can sign the document $sql = "SELECT user_id, position, `order` FROM ". $dbr->tableName('approval_request'); $sql .= " WHERE page_id = ". $pageid; $sql .= " AND user_id = ". $userid; $reqUserId = ""; $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) {           $row = $dbr->fetchRow($res); $reqUserID = $row[0]; $position = $row['position']; $order = $row['order']; }       $dbr->freeResult($res); if ( ($reqUserID != $userid) || ($userid == 0) ) # avoid signing for unknown user (only IP availible) {           $wgOut->addWikiText(wfMsg("da-NotNecessary")); return false; }       // Check if document is already signed $sql = "SELECT date FROM ". $dbr->tableName('approval'); $sql .= " WHERE rev_page = ". $pageid; $sql .= " AND user_id = ". $userid; $sql .= " AND rev_id = ". $revisionid; $signDate = ""; $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) {           $row = $dbr->fetchRow($res); $signDate = $row[0]; }       $dbr->freeResult($res); // If it is not signed yet if ($signDate == "") {         // Check if this user is in the order of signing if ($order == 'strict') { // Check how many already signed it             $sql =  "SELECT count(*) as approvals FROM ". $dbr->tableName('approval'); $sql .= " WHERE rev_page = ". $pageid; $sql .= " AND rev_id = ". $revisionid;

$approvals = 0; $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) {                 $row = $dbr->fetchRow($res); $approvals = $row[0]; }             $dbr->freeResult($res); if ( $position != $approvals+1) { // nicht an der Reihe $wgOut->setPagetitle($title); # Add the actual page name to the message page $wgOut->addWikiText(wfMsgExt('da-NotYourTurn', 'parsemag', $position-$approvals-1).' ('.str_replace('.','',wfMsg('returnto', $title)).'.)'); return false; }          }          // Sign it                  $sql =  "INSERT INTO ". $dbr->tableName('approval'); $sql .= " (rev_id, rev_page, user_id) VALUES"; $sql .= " ($revisionid, $pageid, $userid)"; $res = $dbr->query( $sql, __METHOD__ );

// Log Signing $log = new LogPage( 'dalog' ); #$log->addEntry( 'sign', $title, '|'.$revisionid.''); # unklar wie Links gehen $log->addEntry( 'sign', $title, $revisionid); // Check how many already signed it         $sql =  "SELECT count(*) as approvals FROM ". $dbr->tableName('approval'); $sql .= " WHERE rev_page = ". $pageid; $sql .= " AND rev_id = ". $revisionid;

$approvals = 0; $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) {	           $row = $dbr->fetchRow($res); $approvals = $row[0]; }	       $dbr->freeResult($res); // Check how many must sign it $sql = "SELECT count(*) as signers FROM ". $dbr->tableName('approval_request'); $sql .= " WHERE page_id = ". $pageid; $signers = 0; $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) {	           $row = $dbr->fetchRow($res); $signers = $row[0]; }	       $dbr->freeResult($res); // If all signer already signed, generate a new version (or subversion) if (($signers > 0) && ($approvals == $signers)) {           // Check if page already have a version $sql = "SELECT last_approved_revision_id, version, subversion"; $sql .= " FROM ". $dbr->tableName('approval_version'); $sql .= " WHERE page_id = ". $pageid; $page_version = 0; $page_subversion = 0; $page_last_revision = 0; $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) {		           $row = $dbr->fetchRow($res); $page_last_revision = $row[0]; $page_version = $row[1]; $page_subversion = $row[2]; }		       else {		           $sql =  "INSERT INTO ". $dbr->tableName('approval_version'); $sql .= " (page_id) VALUES"; $sql .= " ($pageid)"; $resInsert = $dbr->query( $sql, __METHOD__ ); }		       $dbr->freeResult($res); // Check the amount of changes $sql = "SELECT count(*) as edits"; $sql .= " FROM ". $dbr->tableName('revision'); $sql .= " WHERE rev_page = ". $pageid; $sql .= " AND rev_id > ". $page_last_revision; $sql .= " AND rev_minor_edit = 0"; $page_edits = 0; $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) {		         $row = $dbr->fetchRow($res); $page_edits = $row[0]; }		       $dbr->freeResult($res); // If not all of the changes are minor if ($page_edits > 0) {		       	$page_version++; $page_subversion = 0; }		       else {		       	$page_subversion++; }           // Update version in database $sql = "UPDATE ". $dbr->tableName('approval_version'). " SET"; $sql .= " last_approved_revision_id = $revisionid,"; $sql .= " version = $page_version,"; $sql .= " subversion = $page_subversion"; $sql .= " WHERE page_id = ". $pageid; $res = $dbr->query( $sql, __METHOD__ ); // log kompleted request $log = new LogPage( 'dalog' ); $log->addEntry( 'komplett', $title, 'v'.$page_version); }	       // Clear document cache $article->purge; }       else {           $wgOut->setPagetitle($title); # Add the actual page name to the message page $wgOut->addWikiText(wfMsg('da-PreviouslySigned', $wgLang->date( $signDate, true, true ), $wgLang->time( $signDate, true, true )).' ('.str_replace('.','',wfMsg('returnto', $title)).')'); }       return false; }   else return true; # 'true' allows other UnknownHook calls to still execute }

DocumentApproval.i18n.php
Parserfunktion zur Dokumentengenehmigung ein", 'da-sdesc' => 'Seite für die Extension DocumentApproval um weitere Unterschriftenanfragen zu sehen',  'da-NotYourTurn' => "Du darfst diese Seite unterschreiben, bist aber noch nicht an der Reihe zu unterschreiben. Du musst noch auf NaN $1 Unterschriftens warten.", 'da-keineanfrage' => "Derzeit liegen keine Anfragen zum Unterschreiben für Benutzer $1 vor.",  'da-keineunterschriften' => "Es wurden keine von Benutzer $1 unterschriebenen Seiten gefunden.",  'daloglogpage' => 'Document Approval Logbuch',  'daloglogpagetext'		=> 'Dieses Logbuch protokolliert Änderungen von Unterschriften.',  'dalogtext' => 'Document Approval',	'dalog-sentok-entry'		=> 'hat auf der Seite $1 eine Unterschrift-Anfrage geändert',	'dalog-komplett' => 'hat die Unterschrift-Anfrage der Seite $1 vervollständigt',	'dalog-sign'		=> 'hat die Seite $1 unterschrieben',	'da-emailtext' => "Lieber $1,\n\nDie Seite $2 wartet auf deine Unterschrift als $3 ($4).\n\nDein freundliches \n\nPS:\nAlle Anfragen kannst du auf der Seite Spezial:DocumentApproval einsehen\nEine ausführliche Beschreibung enthält die Seite Hilfe:DocumentApproval",	'da-emailtitle' => 'Neue Anfrage zur Unterschrift', 'daTableTitle'	 		=> 'Überarbeitungstabelle der Bewilligung', 'daApprovalDate' 		=> 'Genehmigungsdatum', 'daSign'		 		=> 'Signatur', 'da-function'			=> 'Funktion', 'da-pageID' => 'Seiten-ID', 'da-createarticledate' => 'Erstelldatum', 'da-signer' => 'Unterschreiber', 'da-requests' => 'Anfragen', 'daPending'				=> 'offen', 'daUserNotFound'		=> 'Benutzer nicht gefunden', 'da-head' => 'Liste aller Unterschriften für Benutzer $1', 'da-signsum' => 'Alle Anfragen: $1', 'da-signalready' => 'Schon unterschriebene Anfragen: $1', 'da-signwish' => "Offene Anfragen zum Unterschreiben: $1", 'da-signlist'  => 'Alle Anfragen nach Unterschriften: $1', 'da-NotNecessary'		=> 'Deine Unterschrift ist für dieses Dokument nicht erforderlich.', 'da-PreviouslySigned'	=> 'Das Dokument wurde schon am $1 um $2 von dir unterzeichnet und kann nicht noch ein mal unterzeichnet werden.', 'sign-tab-text'	=> 'Unterzeichnen', ); $messages['de-formal'] = array( 'da-NotYourTurn' => "Sie dürfen die Seite unterschreiben, sind aber noch nicht an der Reihe zu unterschreiben", 'da-NotNecessary'		=> 'Ihre Unterschrift ist für dieses Dokument nicht erforderlich.', 'daPreviouslySigned'	=> 'Das Dokument wurde schon am $1 um $2 von Ihnen unterzeichnet und kann nicht noch ein mal unterzeichnet werden.', 'da-NotYourTurn' => "Du darfst die Seite unterschreiben, bist aber noch nicht an der Reihe zu unterschreiben", 'da-emailtext' => "Sehr geehrter $1,\n\nDie Seite $2 wartet auf Ihre Unterschrift als $3 ($4).\n\nIhr freundliches \n\nPS:\nAlle Anfragen können Sie auf der Seite Spezial:DocumentApproval einsehen\nEine ausführliche Beschreibung enthält die Seite Hilfe:DocumentApproval", );

/** English
 * @author João Artur Gramacho

$messages['en'] = array( 'documentapproval' => 'Document Approval',  'da-desc' => 'adds   parser function document approval',  'da-sdesc' => 'Page for extension DocumentApproval to see further request information',  'da-NotYourTurn' => "You may sign this page, but you are not yet signed on the series. You still have to wait for NaN $1 signaturess.",  'da-keineanfrage' => "Currently, no requests are available to sign for user $1.",  'da-keineunterschriften' => "There are no user $1 signed pages.",  'daloglogpage' => 'Document Approval Log',  'daTableTitle'	 		=> 'Approval table of revision',  'daApprovalDate' 		=> 'Approval date',  'daSign'		 		=> 'Sign',  'daFunction'			=> 'Role',  'daPending'				=> 'pending',  'daUserNotFound'		=> 'user not found',  'da-NotNecessary'		=> 'Your sign is not necessary to this document.',  'da-PreviouslySigned'	=> 'Document previously signed at $1',  'sign-tab-text'	=> 'Sign', 'da-function'			=> 'Function', 'da-pageID' => 'Page-ID', 'da-createarticledate' => 'Create Date', 'da-signer' => 'Signer', 'da-requests' => 'Requests', 'da-head' => 'List of signatures for user $1', 'da-signwish' => 'Open requests to sign: $1', 'da-signalready' => 'Already signed requests: $1', 'da-signsum' => 'All requests: $1', 'da-signlist' => 'All requests for signatures: $1', );

/** French
 * @author João Artur Gramacho

$messages['fr'] = array( 'documentapproval' => 'Document Approval',  'da-desc' => "Ajoute   fonction analyseur document d'approbation",

'daloglogpage' => 'Document Approval carnet', 'daTableTitle'	 		=> "Table d'approbation de la révision", 'daApprovalDate' 		=> "Date d'approbation", 'daSign'		 		=> "Signature", 'daFunction'			=> "Rôle", 'daPending'				=> "en attente", 'daUserNotFound'		=> "utilisateur non trouvée", 'da-NotNecessary'		=> "Votre enseigne n'est pas nécessaire à ce document.", 'da-PreviouslySigned'	=> "Le document a été signé le $1 par vous et ne peut être une autre fois signé.", 'sign-tab-text'	=> 'Signe', 'da-signsum' => 'All requests: $1', 'da-signalready' => "Déjà signé des demandes: $1", 'da-signwish' => 'Open requests to sign: $1', 'da-signlist' => 'All requests for signatures: $1', ); /** Português (Portuguese)
 * @author João Artur Gramacho

$messages['pt-br'] = array( 'da-desc' => 'acrescenta   função do analisador de aprovação do documento',  'daTableTitle'	 		=> 'Tabela de aprovações da revisão',  'daApprovalDate' 		=> 'Data da aprovação',  'daSign' 				=> 'Assinatura eletrônica',  'daFunction'			=> 'Função',  'daPending'				=> 'pendente',  'daUserNotFound'		=> 'usuário não encontrado',  'da-NotNecessary'		=> 'Sua assinatura não é necessária para esse documento.',  'da-PreviouslySigned'	=> 'Documento assinado previamente em $1',  'sign-tab-text'	=> 'Signo', );

Error message
Hello,

With nex version 0.3, I have a problem with SQL : from function « fnDocumentApproval ». Databe send error message :« 1054 : Unknown column 'position' in 'field list' (localhost) ».
 * Hello! Probably this column does not exist in your table 'approval_request'. You can add this with phpMyAdmin. The extension should create a new table correctly if it is not there but can not check if there is missing a column (function daTableCheck). This should be improved. Anyone can help? --Jostar 12:04, 16 April 2010 (UTC)

Hello, I think there is some namespace problem. I get 1146: Table 'db.mw_user' doesn't exist (localhost). when I call Spezial:DocumentApproval

You have Hardcoded the namespace.
 * True. The prefix is should be adapted. I will look for this ... --Jostar 13:29, 8 June 2010 (UTC) Done today, should work now. --Jostar 21:48, 2 August 2010 (UTC)

Hello, I have a problem when activation this 0.3 version on a MW 1.16 with Apache/Windows. The error is: "MediaWiki internal error. Exception caught inside exception handler". When I remove the "require once"-line from my LocalSettings.php (not activate the Document Approval), everything is working... --DaJohnB 13:17, 30 March 2011 (UTC)
 * It was not written for Version 1.16 and need to be updated. Sorry. --Jostar 15:17, 30 March 2011 (UTC)
 * Thanks for this info. Now I know it's not me...--DaJohnB 06:36, 6 April 2011 (UTC)
 * It might as well be a problem of your database engine. I encountered the same problem, after deleting

ENGINE=innodb
 * in function daTableCheck and adding daTableCheck in the daSkinTemplateTabs-Routine, everything worked fine for me. You then just have to make shure, that the columns position and order are created in approval_request.--Daniel Gerber 16:20, 29 April 2011 (UTC)

Doesn't seem to call fnDocumentApproval
Great extension. I really want to get it working.

MW 1.15.4 php 5.3.2 MySQL 5.1.48

I'm having difficulty though- fnDocumentApproval doesn't appear to be called. I have an existing page. I added the tag with a valid user name inside. If I comment out everything and tell fnDocumentApproval to return "output = 'test'" I get nothing.

The extension shows up on Version. I've manually input data into the approval_request table, and it returns results on the Special page. Am I missing something? Is there anything that might be interfering? Is there a way to step through and see what's going on? Thanks for your help, Phil. --12.234.65.231 23:05, 30 July 2010 (UTC)
 * Do you use version 0.0.3? What is your database prefix? Do you tried only  or also  ?


 * I use 0.3. Actually I got it to work.  I changed the function definition in DocumentApproval.body.php from "function fnDocumentApproval( $input, $argv, &$parser )" to "function fnDocumentApproval( $input, $argv, $parser )" (removed the ampersand).  Not sure if this is a good idea, but it seems to work, and I've noticed other extension functions with the same pattern. Phil--12.234.65.231 22:08, 2 August 2010 (UTC)


 * I had the same problem to fix after moving from windows to linux based mediawiki installation. Linux do not like the "&"s... functions are still working. --Jostar 12:00, 3 August 2010 (UTC)

Failed to use the CONSTRAINTS
I tried to use the SQL statements on the article page to create the database tables required for this extension. (Adding the "position" and "order" needed for version 0.3 of DocumentApproval.) But I failed miserably getting only the somewhat obscure failure message:

ERROR 1005 (HY000) at line 35: Can't create table 'wikidb.approval_version' (errno: 150)

By trial and error, I figured out that if I commented out two of the  (as below) the table creation works just fine.

Do I risk something bad by excluding the CONTSTRAINTs when creating my tables?

I'm using:

mysql Ver 14.14 Distrib 5.1.49, for debian-linux-gnu (x86_64) using readline 6.1
 * 1) mysql --version

Above is the is the modified table creation statements (as applicable to my database) from the article page. Note that I don't have a  part, so if you want to use this to create your own tables, you'll have to put that back in.

/Zrajm 12:39, 15 April 2011 (UTC)


 * As provided by a1ex07 at Error No 150 mySQL - Stack Overflow
 * it will work if you change the order of columns in constraint definition:


 * Original query doesn't work because the order of fields must be the same as in unique index. However, adding rev_page column to constraint is superfluous (revision.rev_id + revision.rev_page is 100% unique without a unique constraint, since revision.rev_id unique by itself). So you don't need unique key on (revision.rev_id + revision.rev_page), and it would be much better if you change your constraint to