Extension:DocumentApproval
From MediaWiki.org
|
DocumentApproval Release status: beta |
|
|---|---|
| Implementation | Parser extension, Hook, Database |
| Description | Allows a page to be "electronic" approved by some users |
| Author(s) | Jgramacho Talk |
| Version | 0.2 (06/Dec/2007) |
| MediaWiki | 1.11 (but may work in versions 1.9 and above) |
| Download | See below |
| Hooks used | |
Contents |
[edit] What can this extension do?
[edit] Goal
Allows electronic signing of pages with approval versioning.
[edit] Motivation
This extension allows the users writing a page to put the approval need (managers, consultants, team members) on it, and also allow the users sign the page, certifying that they already read the page and signed it.
Some times you need to show that a certain group of people 'certify' that what you wrote is right. It means that this 'approved' page is certified for use (like a checkpoint in a document).
[edit] Usage
[edit] Requesting Approval
To request an approval in a page use the <approval> tag like this:
<approval> username1; job/role1 username2; job/role2 usernameN; job/roleN </approval>
When the page is saved, the extension updates de approval request table and put it in the page. For example:
<approval> Jgramacho; Project Leader </approval>
Will result in:
| # | Approval date | Sign | Role |
|---|---|---|---|
| 1 | pending | João Artur Dias Lima Gramacho | Projet Leader |
When the user signs the page, the table will show like:
| # | Approval date | Sign | Role |
|---|---|---|---|
| 1 | 2007-12-06 10:09:58 | João Artur Dias Lima Gramacho | Project Leader |
[edit] Approval Versioning
Every page for approval has three numbers about its revision: the version, the subversion and the editing counter.
When you have only 'minor edits' between two document approvals, its subversion will be added by one.
When you have at least one non 'minor edits' between two document approvals, its version will be added by one.
The editing counter registers how many times the page was changed since last approval. In all fully signed versions the editing counter is zero!
[edit] Signing
If a page has an approval request to the user, a 'sign' tab will be displayed. By clicking on this tab, the user will trigger the page signature.
Also, to sign a page you may use the 'sign' action (just like the 'edit' action).
[edit] Download instructions
Please cut and paste the codes found below and place it in $IP/extensions/. Note: $IP stands for the root directory of your MediaWiki installation, the same directory that holds LocalSettings.php.
Remember: there are three files to install:
[edit] Installation
First of all, check the MySQL database table creation script below. You must substitute the <PREFIX> by your database table prefix before running it on your database.
To install this extension, add the following to LocalSettings.php:
require_once("$IP/extensions/DocumentApproval.php");
[edit] Database Script
Remember to substitute the <PREFIX> by your table prefix!
-- -- Table structure for table `<PREFIX>_approval_request` -- DROP TABLE IF EXISTS `<PREFIX>_approval_request`; CREATE TABLE `<PREFIX>_approval_request` ( `page_id` int(10) UNSIGNED NOT NULL, `user_id` int(10) UNSIGNED NOT NULL, `description` varchar(255) DEFAULT NULL, PRIMARY KEY (`page_id`,`user_id`), KEY `FK_<PREFIX>_approval_request_user` (`user_id`), CONSTRAINT `FK_<PREFIX>_approval_request_page` FOREIGN KEY (`page_id`) REFERENCES `<PREFIX>_page` (`page_id`), CONSTRAINT `FK_<PREFIX>_approval_request_user` FOREIGN KEY (`user_id`) REFERENCES `<PREFIX>_user` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Table structure for table `<PREFIX>_approval` -- DROP TABLE IF EXISTS `<PREFIX>_approval`; CREATE TABLE `<PREFIX>_approval` ( `rev_id` int(10) UNSIGNED NOT NULL, `rev_page` int(10) UNSIGNED NOT NULL, `user_id` int(10) UNSIGNED NOT NULL, `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`rev_id`,`rev_page`,`user_id`), KEY `FK_<PREFIX>_approval_user` (`user_id`), CONSTRAINT `FK_<PREFIX>_approval_revision` FOREIGN KEY (`rev_id`, `rev_page`) REFERENCES `<PREFIX>_revision` (`rev_id`, `rev_page`), CONSTRAINT `FK_<PREFIX>_approval_user` FOREIGN KEY (`user_id`) REFERENCES `<PREFIX>_user` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Table structure for table `<PREFIX>_approval_version` -- DROP TABLE IF EXISTS `<PREFIX>_approval_version`; CREATE TABLE `<PREFIX>_approval_version` ( `page_id` int(10) UNSIGNED NOT NULL, `last_approved_revision_id` int(10) UNSIGNED DEFAULT NULL, `version` int(10) UNSIGNED NOT NULL DEFAULT '0', `subversion` int(10) UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY (`page_id`), KEY `FK_<PREFIX>_approval_version_revision_id` (`last_approved_revision_id`,`page_id`), CONSTRAINT `FK_<PREFIX>_approval_version_page_id` FOREIGN KEY (`page_id`) REFERENCES `<PREFIX>_page` (`page_id`), CONSTRAINT `FK_<PREFIX>_approval_version_revision_id` FOREIGN KEY (`last_approved_revision_id`, `page_id`) REFERENCES `<PREFIX>_revision` (`rev_id`, `rev_page`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
[edit] Code
[edit] DocumentApproval.php
<?php /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ if (!defined('MEDIAWIKI')) die(); $wgDocumentApprovalExtensionVersion = '0.2'; $wgExtensionCredits['parserhook'][] = array( 'version' => $wgDocumentApprovalExtensionVersion, 'name' => 'Document Approval', 'author' => 'João Artur Gramacho', 'email' => 'jgramacho at gmail dot com', 'url' => 'http://www.mediawiki.org/wiki/Extension:DocumentApproval', 'description' => 'adds <nowiki><approval></nowiki> parser function document approval' ); $wgExtensionCredits['hook'][] = array( 'name' => 'Document Approval', 'version' => $wgDocumentApprovalExtensionVersion, 'author' => 'João Artur Gramacho', 'email' => 'jgramacho at gmail dot com', 'url' => 'http://www.mediawiki.org/wiki/Extension:DocumentApproval', 'description' => 'Adds a hook for signing documents for approval' ); $wgHooks['UnknownAction'][] = 'fnSign'; $wgHooks['SkinTemplateTabs'][] = 'daSkinTemplateTabs'; $wgHooks['ArticleDelete'][] = 'fnDocumentApprovalDelete'; $wgExtensionFunctions[] = "wfDocumentApprovalExtension"; require_once(dirname(__FILE__) . '/DocumentApproval.body.php'); require_once(dirname(__FILE__) . '/DocumentApproval.i18n.php' ); $wgHooks['LoadAllMessages'][] = 'DocumentApproval::loadMessages'; function wfDocumentApprovalExtension() { global $wgParser; # Defines the tag <approval> ... </approval> $wgParser->setHook( "approval", "fnDocumentApproval" ); }
[edit] DocumentApproval.body.php
<?php 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; } class DocumentApproval { function loadMessages() { 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 wfMsgDA($key) { DocumentApprovalLoadMessages(); return wfMsg($key); } 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 .= "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(); $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; } 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); $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); $output .= "\n"; $output .= "<table border=1>\n"; $output .= "<caption>\n"; $output .= wfMsgDA("daTableTitle") . " #$page_version.$page_subversion.$revcount\n"; $output .= "</caption>\n"; $output .= "<tr>\n"; $output .= "<th>#</td>\n"; $output .= "<th>" . wfMsgDA("daApprovalDate") . "</td>\n"; $output .= "<th>" . wfMsgDA("daSign") . "</td>\n"; $output .= "<th>" . wfMsgDA("daFunction") . "</td>\n"; $output .= "</tr>\n"; foreach($requests as $request) { $request=split(";",trim($request)); $login = $request[0]; $function = $request[1]; if ($login != "") { $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; // 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 user_id, description FROM ". $dbr->tableName('approval_request'); $sql .= " WHERE page_id = " . $pageid; $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) { $row = $dbr->fetchRow($res); $req_userid = $row[0]; $req_description = $row[1]; } $dbr->freeResult($res); // If not, insert it if ($req_userid == 0) { $sql = "INSERT INTO ". $dbr->tableName('approval_request'); $sql .= " (page_id, user_id, description) VALUES"; $sql .= " ($pageid, $userid, '" . $function . "')"; $res = $dbr->query( $sql, __METHOD__ ); $req_userid = $userid; $req_description = $function; } // 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; } // 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 = "<strong>" . wfMsgDA("daPending") . "</strong>"; $res = $dbr->query( $sql, __METHOD__ ); if ($dbr->numRows($res)) { $row = $dbr->fetchRow($res); $signDate = $row[0]; } $dbr->freeResult($res); $output .= "<tr>\n"; $output .= "<td>$counter</td>\n"; $output .= "<td align=center>$signDate</td>\n"; $output .= "<td>$fullname</td>\n"; $output .= "<td>$function</td>\n"; $output .= "</tr>\n"; } else // If the user was not found { $output .= "<tr>\n"; $output .= "<td>$counter</td>\n"; $output .= "<td bgcolor=#ffc0c0 align=center><strong>" . wfMsgDA("daUserNotFound"). "</strong></td>\n"; $output .= "<td>$login</td>\n"; $output .= "<td>$function</td>\n"; $output .= "</tr>\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 .= "</table>\n"; $output .= "\n"; return $output; } function fnSign($action, $article) { global $wgOut; 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 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 ($reqUserID != $userid) { $wgOut->addWikiText(wfMsgDA("daNotNecessary")); 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 == "") // 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__ ); // 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__ ); } // Clear document cache $article->purge(); } else { $wgOut->addWikiText(wfMsgDA("daPreviouslySigned") . "$signDate."); } return false; } else return false; }
[edit] DocumentApproval.i18n.php
<?php $allMessages = array( 'pt-br' => array( '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' , 'daNotNecessary' => 'Sua assinatura não é necessária para esse documento.' , 'daPreviouslySigned' => 'Documento assinado previamente em' ) , 'en' => array( '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 ' ) );

