glossary/glossary.class.php
2023-10-12 19:53:50 +02:00

939 lines
36 KiB
PHP

<?php
/**
* @license http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.html
* @author Francois Merciol <dokuplugin@merciol.fr>
*
* Plugin Glossary: manage forms for glossary
*/
if(!defined('DOKU_INC'))
define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN'))
define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
/* Sort glossary by definition */
function cmpGlossary ($a, $b) {
if ($a['word'] == $b['word'])
return 0;
return ($a['word'] < $b['word']) ? -1 : 1;
}
class glossary {
// ============================================================
// Config attributs
// ============================================================
var $cacheRootDir; // root cache directory
var $cacheDir; // cache directory for specific namespace
var $dataRootDir; // root data directory
var $dataDir; // data directory for specific namespace for xml file
var $recentDays; // time during the clock is display to indicate a nex definition
var $maxIP; // max proposition per guest user
var $propGroup; // user group without limits of proposition
var $adminGroup; // admin group who validate proposition
var $transSep; // line separator for translate if not empty
// ============================================================
// Constant attributs
// ============================================================
var $configFile = "config.xml"; // file config name
var $prop = "prop-"; // prefix for proposal
var $def = "def-"; // prefix for definition // XXXX
var $poll = "poll-"; // prefix for polling (evaluation per definition)
var $form = "form-"; // subset used in form
var $hide = "hide-"; // subset not used in form
var $statusFields = // fields managed per step (status)
array ("prop-" => array ("date", "ip", "email", "ns", "ticket", "word", "translate", "why"),
"def-" => array ("date", "ip", "email", "ns", "ticket", "useTicket", "word", "translate"),
"poll-" => array ("word", "view", "up", "down"),
"form-" => array ("ticket", "useTicket", "word", "translate", "why"),
"hide-" => array ("date", "ip", "email", "ns"));
var $oddEven = // for row color
array ("odd", "even");
var $imgDir;
// ============================================================
// Transcient attributs
// ============================================================
var $message = array (); // "notify" =>, "info" =>, "success" =>, "error" =>
var $plugin; // link to wiki plugin information (conf, lang, ...)
var $NS; // namespace where definition could be found
var $lastNotification; // time of last proposal notification
var $lastNotificationReset; // time of last administrators acknowledgement
var $md5ns; // the ns directory
var $md5id; // the wiki id
var $sampleFile; // cache for sample
var $listFile; // cache for sample
// ============================================================
function createDirIsNeeded ($dir) {
if (is_dir ($dir))
return;
@mkdir ($dir);
@chmod ($dir, 0775);
}
function __construct ($plugin, $ns) {
$this->plugin = $plugin;
$this->imgDir = DOKU_REL.'lib/plugins/glossary/images/';
global $conf;
$savedir = ((!$conf['savedir'] || strpos ($conf['savedir'], '.') === 0) ? DOKU_INC : "").$conf['savedir']."/";
$this->cacheRootDir = $savedir."cache/glossary/";
$this->dataRootDir = $savedir.trim ($this->plugin->getConf ('dataDir').'/');
glossary::createDirIsNeeded ($this->cacheRootDir);
glossary::createDirIsNeeded ($this->dataRootDir);
$this->NS = cleanId (trim ($ns));
$this->md5ns = md5 ($this->NS);
$this->cacheDir = $this->cacheRootDir.$this->md5ns."/";
glossary::createDirIsNeeded ($this->cacheDir);
$this->dataDir = $this->dataRootDir.$this->md5ns."/";
glossary::createDirIsNeeded ($this->dataDir);
$this->sampleFile = $this->cacheDir."sample.cache";
$this->listFile = $this->cacheDir."list.cache";
$this->recentDays = $this->getConf ('recentDays');
$this->maxIP = $this->getConf ('maxIP');
$this->adminGroup = trim ($this->getConf ('adminGroup'));
$this->propGroup = trim ($this->getConf ('propGroup'));
$this->transSep = trim ($this->getConf ('transSep'));
}
function getConf ($name) {
return $this->plugin->getConf ($name);
}
function getLang ($name) {
return $this->plugin->getLang ($name);
}
// function isAdmin ($name) {
// return $this->plugin->isAdmin ($name);
// }
function localFN ($name) {
return $this->plugin->localFN ($name);
}
/* messages container to be display before plugin */
function message ($type, $text) {
if (isset ($this->message[$type]))
$this->message[$type] .= '<br/>';
$this->message[$type] .= $text;
}
/* debug messages for admin only */
function debug ($text) {
global $INFO;
if (in_array ('admin', $INFO ['userinfo'] ['grps']))
$this->message ('notify', '<pre>'.$text.'</pre>');
}
/* get next parity for row color */
function nextOddEven (&$even) {
$result = $this->oddEven [$even];
$even = 1 - $even;
return $result;
}
// ============================================================
// Control rights
// ============================================================
/* true if the user has the admin rights */
function testAdminGroup () {
global $INFO;
return
isset ($INFO ['userinfo']['grps']) &&
in_array ($this->adminGroup, $INFO ['userinfo']['grps']);
}
/* true if the user has no proposition limits */
function testPropGroup () {
global $INFO;
return
isset ($INFO ['userinfo']['grps']) &&
in_array ($this->propGroup, $INFO ['userinfo']['grps']);
}
/* true if limit occured (i.e. problems => can't continued)*/
function maxIP (&$request) {
$ip = $request['ip'];
$count = 1;
$all = $this->readAllGlossary ($this->prop);
if (isset ($all[$this->md5id])) {
$this->message ('success', $this->getLang ('update'));
return false;
}
if ($this->testPropGroup ())
return false;
foreach ($all as $record)
if ($record['ip'] == $ip)
$count++;
if ($count <= $this->maxIP) {
if ($count == $this->maxIP)
$this->message ('notify', $this->getLang ('lastIP'));
return false;
}
$this->message ('error', $this->getLang ('maxIP'));
return true;
}
// ============================================================
// Control fields
// ============================================================
function testNotEmpty () {
return
$this->wordOk () || $this->translateOk () || $this->translateOk () || $this->ticketOk ();
}
function wordOk () {
return isset ($_REQUEST ['glossary']['word']) && trim ($_REQUEST ['glossary']['word']) != "";
}
function translateOk () {
return isset ($_REQUEST ['glossary']['translate']) && trim ($_REQUEST ['glossary']['translate']) != "";
}
function ticketOk () {
return isset ($_REQUEST ['glossary']['ticket']) && trim ($_REQUEST ['glossary']['ticket']) != "";
}
// ============================================================
// Manage XML file
// ============================================================
/* read lodging config */
function readConfig ($dir) {
$fileName = $dir.$this->configFile;
if (!file_exists ($fileName))
return false;
$xml = new DOMDocument ("1.0", "utf8");
$xml->load ($fileName);
$root = $xml->documentElement;
$this->lastNotification = $root->getElementsByTagName ("lastNotification")->item (0)->nodeValue;
$this->lastNotificationReset = $root->getElementsByTagName ("lastNotificationReset")->item (0)->nodeValue;
return $root->getElementsByTagName ("nameSpace")->item (0)->nodeValue;
}
/* write lodging config */
function writeConfig () {
if ($this->NS == false)
return;
$fileName = $this->dataDir.$this->configFile;
@mkdir ($this->dataDir);
@chmod ($this->dataDir, 0775);
$xml = new DOMDocument ("1.0", "utf8");
$root = $xml->createElement ("glossary");
$xml->appendChild ($root);
$root->appendChild ($xml->createElement ("nameSpace", htmlspecialchars ($this->NS)));
$root->appendChild ($xml->createElement ("lastNotification", htmlspecialchars ($this->lastNotification)));
$root->appendChild ($xml->createElement ("lastNotificationReset", htmlspecialchars ($this->lastNotificationReset)));
$xml->formatOutput = true;
$xml->save ($fileName);
chmod ($fileName, 0664);
}
/* read all propositions, definitions, polls */
function readAllGlossary ($status) {
if (!is_dir ($this->dataDir))
return;
if ($this->NS == false)
return;
$result = array ();
$exclude_array = explode ("|", ".|..|".$this->configFile);
$pathDirObj = opendir ($this->dataDir);
while (false !== ($file = readdir ($pathDirObj))) {
if (in_array (strtolower ($file), $exclude_array) || !preg_match ('#'.$status.'(.*)\.xml$#i', $file, $regs))
continue;
$result[$regs[1]] = $this->readGlossary ($regs[1], $status, LOCK_SH);
}
uasort ($result, "cmpGlossary");
return $result;
}
/* read one proposition, definition, poll */
function readGlossary ($md5id, $status, $lock) {
$fileName = $this->dataDir.$status.$md5id.".xml";
if (!file_exists ($fileName))
return false;
$lock = LOCK_SH;
if ($lock != LOCK_SH) {
$fp = fopen ($fileName, "r+");
if (!flock ($fp, $lock)) {
$this->message ("error", "can't lock file ".$fileName.".");
return;
}
}
$xml = new DOMDocument ("1.0", "utf8");
$xml->load ($fileName);
$root = $xml->documentElement;
$result = array ();
foreach ($this->statusFields [$status] as $field)
$result [$field] = $root->getElementsByTagName ($field)->item (0)->nodeValue;
return $result;
}
/* write one proposition, definition, poll */
function writeGlossary ($md5id, &$values, $status) {
if (! isset ($values['ns']) || $values['ns'] == "")
$values['ns'] = $this->NS; // XXX compatibilité
$xml = new DOMDocument ("1.0", "utf8");
$root = $xml->createElement ("glossary");
$xml->appendChild ($root);
foreach ($this->statusFields [$status] as $field)
$root->appendChild ($xml->createElement ($field, htmlspecialchars ($values [$field])));
$xml->formatOutput = true;
$fileName = $this->dataDir.$status.$md5id.".xml";
$xml->save ($fileName);
chmod ($fileName, 0664);
//flock (fopen ($fileName, "r+"), LOCK_UN);
}
/* remove one proposition, definition, poll */
function removeGlossary ($md5id, $status) {
$fileName = $this->dataDir.$status.$md5id.".xml";
@unlink ($fileName);
}
/* count file propositions, definitions, polls */
function getGlosarySize ($status, $md5ns) {
$subDir = $this->dataRootDir.$md5ns."/";
if (!is_dir ($subDir))
return 0;
$result = 0;
$exclude_array = explode ("|", ".|..|".$this->configFile);
$pathDirObj = opendir ($subDir);
while (false !== ($file = readdir ($pathDirObj))) {
if (in_array (strtolower ($file), $exclude_array) || !eregi ($status.'(.*)\.xml$', $file, $regs))
continue;
$result++;
}
return $result;
}
// ============================================================
// Actions to performed
// ============================================================
/* update proposition, definition */
function updateRequest (&$request, $status) {
$reread = false;
$update = false;
$this->md5id = md5 (trim ($request['ticket']));
$oldValues = $this->readGlossary ($this->md5id, $status, LOCK_SH);
if ($oldValues) {
foreach ($this->statusFields [$this->form] as $field) {
if ((!isset ($request[$field]) || $request[$field] == "") &&
$request[$field] != $oldValues [$field]) {
$request[$field] = $oldValues [$field];
$reread = true;
} elseif (isset ($request[$field]) && $request[$field] != "" &&
$request[$field] != $oldValues [$field]) {
$update = true;
}
}
foreach ($this->statusFields [$this->hide] as $field)
$request[$field] = $oldValues [$field];
if ($reread)
$this->message ('success', $this->getLang ('readData'));
return $update;
}
return true;
}
/* display poll */
function printPoll ($arg) {
echo
'<div class="glossary toolTip">'.NL;
$this->printPollAjax (md5 (trim ($arg)));
echo '</div>';
}
function printPollAjax ($md5id) {
$filename = $this->cacheDir."poll-".md5($md5id).".cache";
if (file_exists ($filename)) {
echo file_get_contents ($filename);
return;
}
$poll = $this->readGlossary ($md5id, $this->poll, LOCK_SH);
list ($scoreVal, $scoreImg) = $this->getScore ($poll);
$text =
'<a onClick="glossaryPoll(this,\''.$md5id.'\',\'down\',\''.$this->NS.'\');">'.NL.
' <img src="'.$this->imgDir.'face-sad.png" /><span>'.$this->getLang ('tipPollDown').'</span>'.NL.
'</a>'.
$scoreImg.NL.
'<a onClick="glossaryPoll(this,\''.$md5id.'\',\'up\',\''.$this->NS.'\');">'.NL.
' <img src="'.$this->imgDir.'face-smile.png" /><span>'.$this->getLang ('tipPollUp').'</span>'.NL.
'</a>';
if (!$poll|| ($poll['up']+$poll['down'] < 1))
$text .=
'<br/><b>'.$this->getLang ('notPolledYet').'</b>';
file_put_contents ($filename, $text);
echo $text;
}
function getScore ($poll) {
$scoreImg = '<img src="'.$this->imgDir.'score';
if ($poll && $poll["up"] + $poll["down"] > 0) {
$scoreVal = (($poll["up"] - $poll["down"]) /
(max (5, $poll["up"] + $poll["down"])));
$scoreImg .= '-'.intval (round (($scoreVal+1)*3));
} else
$scoreVal = 0;
$scoreImg .= '.png"/>';
return array ($scoreVal, $scoreImg);
}
/* update poll */
function poll () {
$request = &$_REQUEST ['glossary'];
$md5id = $request['ticket'];
$opinion = $request['opinion'];
$all = $this->readAllGlossary ($this->def);
if (! isset ($all[$md5id]) || !in_array ($opinion, $this->statusFields [$this->poll])) {
$this->message ('error', $this->getLang ('noDef'));
return;
}
$poll = $this->readGlossary ($md5id, $this->poll, LOCK_EX);
if (!$poll)
$poll = array ("word" => $all[$md5id]['word'], "up" => 0, "down" => 0);
if ($poll [$opinion] != PHP_INT_MAX)
$poll [$opinion]++;
$this->writeGlossary ($md5id, $poll, $this->poll);
$this->message ('success', $this->getLang ('writePoll'));
@unlink ($this->cacheDir."poll-".md5($md5id).".cache");
$this->printPollAjax ($md5id);
}
function incView ($md5id, $word) {
$poll = $this->readGlossary ($md5id, $this->poll, LOCK_EX);
if (!$poll)
$poll = array ("word" => $word, "view" => 0, "up" => 0, "down" => 0);
$poll ["view"]++;
$this->writeGlossary ($md5id, $poll, $this->poll);
return $poll;
}
function clearCache ($nsMd5) {
$exclude = ".|..";
$exclude_array = explode("|", $exclude);
$allNsMd5 = array ();
if ($nsMd5)
$allNsMd5[] = $nsMd5;
else {
$pathDirObj = opendir ($cacheRootDir);
while (false !== ($file = readdir ($pathDirObj))) {
if (in_array (strtolower ($file), $exclude_array))
continue;
$pathFile = $pathDir.$file;
if (!is_dir ($pathFile))
continue;
$allNsMd5[] = $file;
}
}
foreach ($allNsMd5 as $nsMd5) {
$cacheDir = $this->cacheRootDir.$nsMd5."/";
if (!is_dir ($cacheDir))
break;
$pathDirObj = opendir ($cacheDir);
while (false !== ($file = readdir ($pathDirObj))) {
if (in_array (strtolower ($file), $exclude_array))
continue;
$pathFile = $cacheDir.$file;
if (!is_file ($pathFile))
continue;
if (eregi ('.*\.cache$', $file, $b))
unlink ($pathFile);
}
@rmdir ($cacheDir);
}
}
// ============================================================
function manageRecord (&$request, $status, $needCaptcha) {
if (!$this->testNotEmpty ())
return;
if ($this->ticketOk ()) {
if (!$this->updateRequest ($request, $status))
return;
} else {
$request ['ticket'] = substr (md5 (date ('YmdHis')), 0, 12);
$this->md5id = md5 (trim ($request ['ticket']));
}
if ($needCaptcha && (!$captcha =& plugin_load ('helper', 'captcha') || !$captcha->check ())) {
$this->message ('error', $this->getLang ('badCaptcha'));
return;
}
if (!$this->wordOk ()) {
$this->message ('error', $this->getLang ('wordMandatory'));
return;
}
if (!$this->translateOk ()) {
$this->message ('error', $this->getLang ('translateMandatory'));
return;
}
if (! isset ($request['date']) || $request['date'] == "") {
$request['date'] = date ('YmdHis');
$request['ip'] = $_SERVER ['REMOTE_ADDR'];
global $INFO;
if (isset ($INFO['userinfo']['mail']))
$request['email'] = $INFO['userinfo']['mail'];
$request['ns'] = $this->NS;
}
unset ($request['operation']);
sleep (1);
if ($status == $this->prop && $this->maxIP ($request))
return;
$this->writeGlossary ($this->md5id, $request, $status);
$this->message ('success', $this->getLang ('proposalRecorded').'<b>'.$request['ticket']."</b>.");
$this->adminNotification ($request, $status);
}
// ============================================================
// Result for display
// ============================================================
function getDefinitionSize () {
return $this->getGlosarySize ($this->def, $this->md5ns);
}
function getProposalSize () {
return $this->getGlosarySize ($this->prop, $this->md5ns);
}
function getPollSize () {
return $this->getGlosarySize ($this->poll, $this->md5ns);
}
function printProposal () {
global $INFO;
$needCaptcha = !(isset ($INFO ['userinfo']) &&
isset ($INFO ['userinfo']['grps']) &&
$INFO ['userinfo']['grps']);
$request = &$_REQUEST ['glossary'];
if ($request['operation'] == "record")
$this->manageRecord ($request, $this->prop, $needCaptcha);
echo
'<form method="post" action="" onsubmit="return glossaryAjax(this);">'.NL.
' <table>'.NL.
' <tr class="title">'.NL.
' <th><img src="'.$this->imgDir.'stop.png" /> '.$this->getLang ('word').'</th>'.NL.
' <th><img src="'.$this->imgDir.'one-way.png" /> '.$this->getLang ('translate').'</th>'.NL.
' </tr><tr class="odd">'.NL.
' <td>'.NL.
' * <input type="text" name="glossary[word]" value="'.$request['word'].'" class="text" />'.NL.
' </td><td>'.NL.
' * <input type="text" name="glossary[translate]" value="'.$request['translate'].'" class="text" />'.NL.
' </td>'.NL.
' <tr class="title">'.NL.
' <th>'.$this->getLang ('why').'</th>'.NL.
' <th>'.NL.
' <input type="hidden" name="glossary[operation]" value="record">'.NL.
' <input type="hidden" name="glossary[ns]" value="'.$this->NS.'">'.NL.
' <input type="submit" name="glossary[action]" value="'.$this->getLang (empty ($request['ticket']) ? 'proposal' : 'update').'" />'.NL.
' <input type="reset" onClick="glossaryReset(this);glossaryUpdateProposalLabel(this.form)" value="'.$this->getLang ('new').'" />'.NL.
' </th>'.NL.
' </tr><tr class="odd">'.NL.
' <td colspan="2"><textarea name="glossary[why]" class="why" />'.$request['why'].'</textarea></td>'.NL.
' </tr><tr class="even">'.NL.
' <td class="right">'.NL.
' '.$this->getLang ('ticketIfUpdate').NL.
' </td><td>'.NL.
' <input type="text" name="glossary[ticket]" value="'.$request['ticket'].'" class="text" onChange="glossaryUpdateProposalLabel(this.form)" onKeypress="glossaryUpdateProposalLabel(this.form)" />'.NL.
' </td>'.NL.
' </tr>'.NL;
if ($needCaptcha && $captcha =& plugin_load ('helper', 'captcha'))
echo '<tr><td colspan=2>'.$captcha->getHTML ().'</td></tr>'.NL;
echo
' </table>'.NL;
'</form>';
}
// ============================================================
function printSample () {
if (file_exists ($this->sampleFile) &&
(time () - filemtime ($this->sampleFile) < $this->getConf ('sampleDelai'))) {
echo file_get_contents ($this->sampleFile);
return;
}
$all = $this->readAllGlossary ($this->def);
$keys = array_keys ($all);
$rand = array_rand ($keys);
$record = $all [$keys [$rand]];
$imgDir = DOKU_REL.'lib/plugins/glossary/images/';
foreach (explode ($this->transSep, $record['word']) as $word)
foreach (explode ($this->transSep, $record['translate']) as $translate) {
$word = trim ($word);
$translate = trim ($translate);
$pageId = trim ($record['useTicket']);
if (!$pageId)
$pageId = trim ($record['ticket']);
resolve_pageid ($this->NS, $pageId, $exists);
$cleanId = cleanId ($pageId);
$link = '<a class="wikilink1" href="'.DOKU_REL.$cleanId.'">';
$text =
'<div>'.$this->getLang ('word').'<br/><img src="'.$imgDir.'stop.png" align="left"/> <span class="glossaryWord"> '.$link.$word.' </a></span></div>'.NL.
'<div>'.$this->getLang ('translate').'<br/><img src="'.$imgDir.'one-way.png" align="left"/> <span class="glossaryTranslate"> '.$link.$translate.' </a></span></div>'.NL;
file_put_contents ($this->sampleFile, $text);
echo $text;
return;
}
}
// ============================================================
function clearListFile () {
@unlink ($this->listFile);
}
function printList () {
if ($this->testAdminGroup ()) {
echo '<div><form>';
foreach (array ('clear', 'clearAll') as $action)
echo '<input value="'.$this->getLang ($action).'" onclick="javascript:glossarySendClear (\''.$action.'\', \''.$this->NS.'\')" type="button">';
echo '</form></div>';
}
if (file_exists ($this->listFile) &&
(time () - filemtime ($this->listFile) < $this->getConf ('listDelai'))) {
echo file_get_contents ($this->listFile);
return;
}
$all = $this->readAllGlossary ($this->def);
$poll = $this->readAllGlossary ($this->poll);
$text =
'<table>'.NL.
' <tr class="title">'.NL.
' <th></th>'.NL.
' <th class="toolTip">'.NL.
' <a onClick="glossarySort(this,glossaryComparatorWord);"><span>'.$this->getLang ('tipWord').'</span><img src="'.$this->imgDir.'stop.png" /></a>'.NL.
' <a onClick="glossarySort(this,glossaryComparatorTranslate);"><span>'.$this->getLang ('tipTranslate').'</span><img src="'.$this->imgDir.'one-way.png" /></a>'.NL.
' <a onClick="glossarySort(this,glossaryComparatorDate);"><span>'.$this->getLang ('tipDate').'</span><img src="'.$this->imgDir.'clock.png" /></a>'.NL.
' <a onClick="glossarySort(this,glossaryComparatorView);"><span>'.$this->getLang ('tipView').'</span><img src="'.$this->imgDir.'eye.png" /></a>'.NL.
' <a onClick="glossarySort(this,glossaryComparatorScore);"><span>'.$this->getLang ('tipScore').'</span><img src="'.$this->imgDir.'score-all.png" width="32" /></a>'.NL.
' </th>'.NL.
' <th>'.$this->getLang ('why').'</th>'.NL.
' <th><img src="'.$this->imgDir.'stop.png" /> '.$this->getLang ('word').'</th>'.NL.
' <th colspan="2" class="toolTip" style="white-space: nowrap;">'.NL.
' <form onsubmit="javascript:glossarySearch(this.elements[0]);return false;">'.NL.
' <span>'.$this->getLang ('tipSearch').'</span><img src="'.$this->imgDir.'search.png" />'.NL.
' <input type="text" name="glossary[search]" value="" class="search" keyup="glossarySearch(this);" onChange="glossarySearch(this);" />'.NL.
' </form>'.NL.
' </th>'.NL.
' <th><img src="'.$this->imgDir.'one-way.png" /> '.$this->getLang ('translate').'</th>'.NL.
' <th>'.$this->getLang ('poll').'</th>'.NL.
' </tr>';
$even = 0;
$recentTime = mktime (0, 0, 0, date ("n"), date ("j")-$this->recentDays, date ("Y"));
$recent = date ("YmdHis", $recentTime);
global $ID;
// XXX bug si empty ($this->transSep)
$canInc = true;
foreach ($all as $md5id => $record)
foreach (explode ($this->transSep, $record['word']) as $word)
foreach (explode ($this->transSep, $record['translate']) as $translate) {
$word = trim ($word);
$translate = trim ($translate);
$pageId = trim ($record['useTicket']);
if (!$pageId)
$pageId = trim ($record['ticket']);
resolve_pageid ($this->NS, $pageId, $exists);
$style = false;
$imgClock = '';
if ($record['date'] > $recent) {
$opacity = 1;
if (preg_match ("#(?<Y>[0-9]{4})(?<m>[0-9]{1,2})(?<d>[0-9]{1,2})#", $record['date'], $dt_date)) {
$delta = (mktime (0, 0, 0, $dt_date["m"], $dt_date["d"], $dt_date["Y"]) - $recentTime) / 86400;
$opacity = ($delta)/($this->recentDays+1);
}
$imgClock = '<img src="'.$this->imgDir.'clock.png" style="opacity:'.$opacity.';" />';
}
$cleanId = cleanId ($pageId);
if ($canInc && $ID == $cleanId) {
$poll [$md5id] = $this->incView ($md5id, $word);
$canInc = false;
}
$link = '<a href="'.DOKU_REL.$cleanId.'">';
list ($scoreVal, $scoreImg) = $this->getScore ($poll [$md5id]);
$text .=
'<tr class="'.$this->nextOddEven ($even).'"'.NL.
' word="'.$word.'" translate="'.$translate.'"'.NL.
' date="'.$record['date'].'" view="'.$poll [$md5id]['view'].'" score="'.$scoreVal.'">'.NL.
' <td class="count"></td>'.NL.
' <td>'.$imgClock.'</td>'.NL.
' <td class="why toolTip">'.$link.'<img src="'.$this->imgDir.'help.png"/><span>'.$this->getLang ('tipWhy').'</span></a></td>'.NL.
' <td class="word" colspan="2">'.$link.$word.'</a></td>'.NL.
' <td class="translate" colspan="2">'.$link.$translate.'</a></td>'.NL.
' <td class="poll toolTip">'.$link.'<span>'.$this->getLang ('tipPoll').'</span>'.$scoreImg.'</a></td>'.NL.
' </tr>';
}
$text .=
NL.
'</table>';
file_put_contents ($this->listFile, $text);
echo $text;
}
// ============================================================
function manageUpdate (&$request) {
if (!$this->testAdminGroup ())
return;
$this->manageRecord ($request, $this->def, false);
}
function manageRemove (&$request) {
if (!$this->testAdminGroup ())
return;
foreach (array ($this->prop, $this->def) as $status) {
if (empty ($request[$status.'tickets']))
continue;
foreach ($request[$status.'tickets'] as $ticket) {
$this->removeGlossary (md5 (trim ($ticket)), $status);
$this->message ('info', $ticket." ".$this->getLang ('ticketDeleted'));
if ($status == $this->def) {
$pageId = $ticket;
resolve_pageid ($this->NS, $pageId, $exists);
if ($exists) {
saveWikiText ($pageId, "", "wizard remove");
$this->message ('info', $pageId." ".$this->getLang ('pageDeleted'));
}
}
}
}
}
// ============================================================
function printManagedList ($status) {
$all = $this->readAllGlossary ($status);
echo
'<form method="post" action="" onsubmit="return glossaryAjax(this);">'.NL.
' <table>'.NL.
' <tr class="title">'.NL.
' <th></th>'.NL;
foreach (array_diff ($this->statusFields [$status], array ("ns")) as $field)
echo
' <th>'.$this->getLang ($field).'</th>'.NL;
echo
' </tr>';
$even = 0;
foreach ($all as $record) {
echo
'<tr class="'.$this->nextOddEven ($even).'">'.NL.
' <td><input type="checkbox" name="glossary['.$status.'tickets][]" value="'.$record['ticket'].'"/></td>'.NL.
' <td>'.substr ($record['date'],0, 8).'</td>'.NL.
' <td>'.$record['ip'].'</td>'.NL.
' <td>'.$record['email'].'</td>'.NL.
' <td>'.$record['ticket'].'</td>'.NL;
if ($status == $this->def)
echo
' <td>'.$record['useTicket'].'</td>'.NL;
echo
' <td>'.$record['word'].'</td>'.NL.
' <td>'.$record['translate'].'</td>'.NL;
if ($status == $this->prop)
echo
' <td>'.str_replace ("\n", "<br/>\n", $record['why']).'</td>'.NL;
echo
' </tr>';
}
echo
'<tr>'.NL.
' <td colspan="2">'.NL.
' <input type="hidden" name="glossary[operation]" value="'.$status.'remove">'.NL.
' <input type="hidden" name="glossary[ns]" value="'.$this->NS.'">'.NL.
' <input type="submit" name="glossary[action]" value="'.$this->getLang ('remove').'"/></td>'.NL.
' <td colspan="6"></td>'.NL.
' </tr>'.NL.
' </table>'.NL.
' </form>'.NL;
}
// ============================================================
function printManagedForm (&$request) {
echo
'<form method="post" action="" onsubmit="return glossaryAjax(this);">'.NL.
' <table>'.NL.
' <tr class="title">'.NL.
' <th></th>'.NL.
' <th><img src="'.$this->imgDir.'stop.png" /> '.$this->getLang ('word').'</th>'.NL.
' <th><img src="'.$this->imgDir.'one-way.png" /> '.$this->getLang ('translate').'</th>'.NL.
' </tr><tr class="'.$this->oddEven [0].'">'.NL.
' <td><input type="reset" onClick="glossaryReset(this)" value="'.$this->getLang ('new').'" /></td>'.NL.
' <td><input type="text" name="glossary[word]" value="'.$request['word'].'" class="text" /></td>'.NL.
' <td><input type="text" name="glossary[translate]" value="'.$request['translate'].'" class="text" /></td>'.NL.
' </tr><tr class="title">'.NL.
' <th></th>'.NL.
' <th>'.$this->getLang ('ticket').'</th>'.NL.
' <th>'.$this->getLang ('useTicket').'</th>'.NL.
' </tr><tr class="'.$this->oddEven [0].'">'.NL.
' <td>'.NL.
' <input type="hidden" name="glossary[operation]" value="'.$this->def.'update">'.NL.
' <input type="hidden" name="glossary[ns]" value="'.$this->NS.'">'.NL.
' <input type="submit" name="glossary[action]" value="'.$this->getLang ('update').'"/></td>'.NL.
' <td><input type="text" name="glossary[ticket]" value="'.$request['ticket'].'" class="text" /></td>'.NL.
' <td><input type="text" name="glossary[useTicket]" value="'.$request['useTicket'].'" class="text" /></td>'.NL.
' </tr>'.NL.
' </table>'.NL.
'</form>'.NL;
}
// ============================================================
function createPage (&$request) {
if (!$this->ticketOk ())
return;
$pageId = trim ($request['useTicket']);
if (!$pageId)
$pageId = trim ($request['ticket']);
$this->md5id = md5 ($pageId);
$values = $this->readGlossary ($this->md5id, $this->def, LOCK_SH);
if (!$values)
return;
resolve_pageid ($this->NS, $pageId, $exists);
if ($exists)
return;
$pageTpl = io_readfile ($this->localFN ('pageTemplate'));
$wordTpl = io_readfile ($this->localFN ('wordTemplate'));
$translateTpl = io_readfile ($this->localFN ('translateTemplate'));
$wordList = '';
foreach (explode ($this->transSep, $values['word']) as $word)
$wordList .= str_replace ("@@WORD@@", $word, $wordTpl);
$translateList = '';
foreach (explode ($this->transSep, $values['word']) as $word)
$translateList .= str_replace ("@@TRANSLATE@@", $word, $translateTpl);
$replace = array ('@@WORD@@' => $wordList,
'@@TRANSLATE@@' => $translateList,
'@@POL@@' => $values['ticket'],
'@@PROPOSITIONPAGE@@' => $this->getConf ('propositionPage'));
$content = str_replace (array_keys ($replace), array_values ($replace), $pageTpl);
saveWikiText ($pageId, $content, "wizard creation");
$this->message ('success', $this->getLang ('createPage'));
}
// ============================================================
function glossariesRemove (&$request) {
if (!$this->testAdminGroup ())
return;
if (empty ($request['dir']))
return;
foreach ($request['dir'] as $md5ns) {
$subDir = $this->dataRootDir.$md5ns.'/';
$ns = $this->readConfig ($subDir);
if ($this->getGlosarySize ($this->def, $md5ns)+$this->getGlosarySize ($this->prop, $md5ns) > 0)
$this->message ('error', $this->getLang ('glossaryNotEmpty').$ns." (".$md5ns.").");
else {
if (!is_dir ($subDir))
continue;
$pathDirObj = opendir ($subDir);
while (false !== ($file = readdir ($pathDirObj))) {
if (!eregi ($this->poll.'(.*)\.xml$', $file, $regs))
continue;
@unlink ($subDir.$file);
}
@unlink ($subDir.$this->configFile);
@rmdir ($subDir);
$this->message ('success', $this->getLang ('glossaryRemoved').$ns." (".$md5ns.").");
}
}
}
function printGlossariesList () {
if (!is_dir ($this->dataRootDir))
return;
$list = array ();
$exclude_array = explode ("|", ".|..");
$pathDirObj = opendir ($this->dataRootDir);
while (false !== ($file = readdir ($pathDirObj))) {
$subDir = $this->dataRootDir.$file.'/';
if (in_array (strtolower ($file), $exclude_array) || !is_dir ($subDir))
continue;
$ns = $this->readConfig ($subDir);
$list [$file] =
array ($ns,
$this->getGlosarySize ($this->def, $file),
$this->getGlosarySize ($this->prop, $file),
$this->getGlosarySize ($this->poll, $file));
}
$even = 0;
echo
'<form method="post" action="" onsubmit="return glossaryAjax(this);">'.NL.
' <table>'.NL.
' <tr class="title">'.NL.
' <th></th><th>directory</th><th>nameSpace</th><th>definition</th><th>proposal</th><th>poll</th>'.NL.
' </tr>';
foreach ($list as $md5ns => $data) {
list ($ns, $def, $prop, $poll) = $data;
echo
'<tr class="'.$this->nextOddEven ($even).'">'.NL.
' <td><input type="checkbox" name="glossary[dir][]" value="'.$md5ns.'"/></td> '.NL.
' <td>'.$md5ns.'</td>'.NL.
' <td>'.$ns.'</td>'.NL.
' <td>'.$def.'</td>'.NL.
' <td>'.$prop.'</td>'.NL.
' <td>'.$poll.'</td>'.NL.
' </tr>';
}
echo
'<tr class="'.$this->nextOddEven ($even).'">'.NL.
' <td colspan="2">'.NL.
' <input type="hidden" name="glossary[operation]" value="glos-remove">'.NL.
' <input type="submit" name="glossary[action]" value="'.$this->getLang ('remove').'"/></td>'.NL.
' <td colspan="4"></td>'.NL.
' </tr>'.NL.
' </table>'.NL.
'</form>';
}
// ============================================================
function adminProposal () {
if (!$this->testAdminGroup ())
return;
$request = &$_REQUEST ['glossary'];
if ($request['operation'] == $this->prop."remove")
$this->manageRemove ($request);
$this->printManagedList ($this->prop);
$this->resetAdminNotification ();
}
function adminDefinition () {
if (!$this->testAdminGroup ())
return;
$request = &$_REQUEST ['glossary'];
if ($request['operation'] == $this->def."remove")
$this->manageRemove ($request);
if ($request['operation'] == $this->def."update") {
$this->manageUpdate ($request);
$this->createPage ($request);
}
$this->clearListFile ();
$this->printManagedForm ($request);
$this->printManagedList ($this->def);
}
function adminGlossaries () {
if (!$this->testAdminGroup ())
return;
$request = &$_REQUEST ['glossary'];
if ($request['operation'] == "glos-remove")
$this->glossariesRemove ($request);
$this->printGlossariesList ();
}
// ============================================================
function resetAdminNotification () {
$subDir = $this->dataRootDir.$this->md5ns.'/';
$this->readConfig ($subDir);
$this->lastNotificationReset = date ('YmdHis');
$this->writeConfig ();
}
function adminNotification ($request, $status) {
$this->readConfig ($this->dataRootDir.$this->md5ns.'/');
if ($this->lastNotification <= $this->lastNotificationReset) {
$this->lastNotification = date ('YmdHis');
global $auth;
$users = $auth->retrieveUsers ();
foreach ($users as $user => $userinfo) {
$mailSubject = $this->getLang ('notifySubject');
$mailContent = $this->getLang ('notifyContent');
$mailContent = str_replace ('@WORD@', $request['word'], $mailContent);
$mailContent = str_replace ('@TRANSLATE@', $request['translate'], $mailContent);
if (in_array ($this->adminGroup, $userinfo ['grps'])) {
$mailTo = $userinfo['mail'];
mail_send ($mailTo, $mailSubject, $mailContent);
// XXX $this->debug (print_r (array ($mailTo, $mailSubject, $mailContent), 1));
}
}
$this->writeConfig ();
}
}
// ============================================================
}