schedule/scheduleRoot.class.php
2023-10-13 06:43:02 +02:00

466 lines
20 KiB
PHP

<?php
/**
* @license http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.html
* @author Francois Merciol <dokuplugin@merciol.fr>
*
* Plugin Schedule: manage events per wiki @groups
*
* $df_ : 31/12/2000
* $ds_ : 20001231
* $dn_ : 978217200
* $dt_ : array ("Y" => 2000, "m" => 12, "d" => "31)
*/
if (!defined ('DOKU_INC'))
define ('DOKU_INC', realpath (dirname (__FILE__).'/../../../').'/');
if (!defined ('DOKU_PLUGIN'))
define ('DOKU_PLUGIN', DOKU_INC.'lib/plugins/');
function cmpScheduleConfig ($a, $b) {
return ($a['nameSpace'] < $b['nameSpace']) ? -1 : 1;
}
// ============================================================
// admin class
class scheduleRoot {
// ============================================================
// Config attributs
// ============================================================
var $cacheRootDir; // root cache directory
var $dataRootDir; // root data directory
var $scheduleGroup; // group who can display and fill form
var $groupsDir; // pages groups directories
var $scheduleDir; // schedule pages groups directories
var $sharedDir; // schedule directory for shared events
var $scheduleWhat = array (); // set of legal "what"
var $scheduleAudience = array (); // set of legal "audience"
var $iconName; // group icon name
var $iconWidth; // group icon width
// lang
var $scheduleShared = array (); // notshared/shared
var $currentDateFormat;
// ============================================================
// Constant attributs $this->scheduleRoot->
// ============================================================
//var $imagesUrlDir = '/lib/plugins/schedule/images/'; // DOKU_REL
var $wizardIconUrl = '/lib/plugins/schedule/images/wizard.png'; // $this->imagesUrlDir
var $editIconUrl = '/lib/plugins/schedule/images/edit.png';
var $repeatIconUrl = '/lib/plugins/schedule/images/repeat.png';
var $emptyIconUrl = '/lib/plugins/schedule/images/empty.png';
var $oldConfigFile = "config.xml"; // old file config name
var $configFile = "cfg.xml"; // file config name
var $mbrPrefix = "mbr-"; // member prefix file name
var $propFile = "prop.xml"; // member prefix file name
var $configAttributsName = array ("nameSpace", "lastNotification", "lastNotificationReset");
// scheduleDir == NS ?
var $dateFormat = array ("dmY" => array ("shortScan" => "(?<d>[0-9]{1,2})[ /-](?<m>[0-9]{1,2})[ /-](?<Y>[0-9]{1,2})",
"longScan" => "(?<d>[0-9]{1,2})[ /-](?<m>[0-9]{1,2})[ /-](?<Y>[0-9]{4})",
"fieldName" => array ("d", "m", "Y"),
"prettyPrint" => "d/m/Y",
"dayMonth" => "d/m"),
"mdY" => array ("shortScan" => "(?<m>[0-9]{1,2})[ /-](?<d>[0-9]{1,2})[ /-](?<Y>[0-9]{1,2})",
"longScan" => "(?<m>[0-9]{1,2})[ /-](?<d>[0-9]{1,2})[ /-](?<Y>[0-9]{4})",
"fieldName" => array ("m", "d", "Y"),
"prettyPrint" => "m/d/Y",
"dayMonth" => "m/d"));
var $oddEvenValues = array ("odd", "even");
var $scheduleRequestAttributsName = array ("id", "audience", "shared",
"what", "title", "lead", "posterURL", "paperURL", "remark", "rate",
"where", "lon", "lat", "addr",
"from", "to", "at",
"repeat", "repeatType", "weekRank", "dayInWeek", "dayRank",
"user");
var $scheduleSaveAttributsName;
var $filterNames = array ("noMember" => "member",
"noWhat" => "what",
"NoAudience" => "audience");
// ============================================================
// Transcient attributs
// ============================================================
var $message = array (); // messages to display : "notify" =>, "info" =>, "success" =>, "error" =>
var $plugin; // link to wiki plugin inforation (conf, lang, ...)
var $isAdmin; // if user member of schedule adminGroup
var $oddEven = 0; // background color for table lines
// ============================================================
// Util
// ============================================================
/* messages container to be display before plugin */
function message ($type, $text) {
if (isset ($this->message[$type]))
$this->message[$type] .= '<br/>'.NL;
$this->message[$type] .= $text;
}
function startMessage ($type, $text) {
if (isset ($this->message[$type]))
$this->message[$type] = '<br/>'.NL.$this->message[$type];
$this->message[$type] = $text.$this->message[$type];
}
/* debug messages for admin only */
function debug ($text) {
global $INFO;
// XXX
if (isset ($INFO['userinfo'] ['grps']) && in_array ('admin', $INFO ['userinfo'] ['grps']))
$this->message ('notify', '<pre>'.$text.'</pre>');
}
/* Change date format from array to number */
function dt2dn ($dt_date) {
$dn_date = mktime (0, 0, 0, $dt_date["m"], $dt_date["d"], $dt_date["Y"]);
if (!$dn_date)
$this->message ('error', $dt_date["Y"]."-".$dt_date["d"]."-".$dt_date["m"]." : ".$this->plugin->getLang ('mktimeError').'<br/>'.NL);
return $dn_date;
}
/* Check date format 31/12/2000 */
function checkDS ($ds_date) {
return
preg_match ("#([0-9]{8})#", $ds_date, $dumy);
}
/* Change date format from MM/DD/AAAA to number */
function df2ds ($df_date) {
$df_date = trim ($df_date);
if (!$df_date)
return;
if ("!" == $df_date)
$ds_date = date ("Ymd");
elseif (preg_match ("#\+(?<delta>[0-9]+)#", $df_date, $matches))
$ds_date = sprintf ("%08d", date ("Ymd", mktime (0, 0, 0, date ("n"), date ("j")+$matches["delta"], date ("Y"))));
elseif (preg_match ("#\-(?<delta>[0-9]+)#", $df_date, $matches))
$ds_date = sprintf ("%08d", date ("Ymd", mktime (0, 0, 0, date ("n"), date ("j")-$matches["delta"], date ("Y"))));
elseif (preg_match ("#".$this->currentDateFormat ["longScan"]."#", $df_date, $dt_date))
$ds_date = sprintf ("%04d%02d%02d", $dt_date["Y"], $dt_date["m"], $dt_date["d"]);
elseif (preg_match ("#".$this->currentDateFormat ["shortScan"]."#", $df_date, $dt_date))
$ds_date = sprintf ("20%02d%02d%02d", $dt_date["Y"], $dt_date["m"], $dt_date["d"]);
else
$ds_date = "{$df_date}";
return $ds_date;
}
/* Change date format from number to MM/DD/AAAA */
function ds2df ($ds_date) {
$ds_date = trim ($ds_date);
if (preg_match ("#(?<Y>[0-9][0-9][0-9][0-9])(?<m>[0-9][0-9])(?<d>[0-9][0-9])#", $ds_date, $dt_date))
return sprintf ("%02d/%02d/%04d",
$dt_date[$this->currentDateFormat["fieldName"][0]],
$dt_date[$this->currentDateFormat["fieldName"][1]],
$dt_date[$this->currentDateFormat["fieldName"][2]]);
else
return "{$ds_date}";
}
function ds2ln ($ds_date, $bold = false) {
$ds_date = trim ($ds_date);
if (preg_match ("#(?<Y>[0-9][0-9][0-9][0-9])(?<m>[0-9][0-9])(?<d>[0-9][0-9])#", $ds_date, $dt_date)) {
// XXX prévoir le format anglais
setlocale (LC_TIME, 'fr_FR.utf8','fra');
return strftime (($bold ? "**%A %e %B** %Y" : "%A %e %B %Y"),
mktime (0, 0, 0,
$dt_date[$this->currentDateFormat["fieldName"][1]],
$dt_date[$this->currentDateFormat["fieldName"][0]],
$dt_date[$this->currentDateFormat["fieldName"][2]]));
} else
return "{$ds_date}";
}
/* Convert array on string (words seperated bay '|') */
static function array2string ($array) {
if (!$array)
return "";
$array = array_unique ($array);
if (in_array ("", $array))
$array = array_diff ("", $array);
if (count ($array) < 1)
return "";
return implode ("|", $array);
}
/* Convert array on string (words seperated bay '|') */
function assocImplode ($array, $vSep = '|', $kSep = ':') {
$result = "";
foreach ($array as $k => $v) {
$result .= $vSepNeeded.$k.$kSep.$v;
$vSepNeeded = $vSep;
}
return $result;
}
/* Convert array on string (words seperated bay '|') */
function assocExplode ($string, $vSep = '|', $kSep = ':') {
$result = array ();
foreach (explode ($vSep, $string) as $kv) {
$data = explode ($kSep, $kv);
$result [$data[0]] = $data[1];
}
return $result;
}
/* Convert array on string (words seperated bay '|') */
// $ find data/[mp]*/membres/*/agenda/*/* data/[mp]*/commun/agenda/*/* -type f -print > dumy
// $ emacs dumy
// C-x ( mv ' ' C-k C-y ' ' C-y C-f C-x )
// M-1000 C-x e
// C-M-%
// ^\([^ ]* [^ ]* [^ ]*agenda/[^/ ]*_\)/ => \1
// C-M-%
// ^\([^ ]* [^ ]* [^ ]*agenda/[^/ ]*_\)/ => \1
// C-M-%
// ^\([^ ]* [^ ]* [^ ]*agenda/[^/ ]*\)/ => \1_
// $ find data/[mp]*/membres/*/agenda/* -type d -exec rmdir {} \; -print
function removeSep ($titleId) {
return strtr ($titleId, ':/;', ' ');
}
function getPageId ($schedule) {
return ":".
$this->scheduleDir.":".
($schedule->shared ? $this->sharedDir : $schedule->member).":".
$this->removeSep ($schedule->title);
}
function resetOddEven () {
$this->oddEven = 0;
}
function switchOddEven () {
$this->oddEven = 1 - $this->oddEven;
}
function getOddEven () {
return $this->oddEvenValues [$this->oddEven];
}
static function createDirIsNeeded ($dir) {
if (is_dir ($dir))
return;
@mkdir ($dir);
@chmod ($dir, 0775);
}
// ============================================================
function __construct ($plugin) {
$this->plugin = $plugin;
$this->scheduleSaveAttributsName = array_merge ($this->scheduleRequestAttributsName, array ("weekDays"));
global $conf;
$savedir = ((!$conf['savedir'] || strpos ($conf['savedir'], '.') === 0) ? DOKU_INC : "").$conf['savedir']."/";
$this->cacheRootDir = $savedir."cache/schedule/";
$this->dataRootDir = $savedir.trim ($this->plugin->getConf ('dataDir').'/');
scheduleRoot::createDirIsNeeded ($this->cacheRootDir);
scheduleRoot::createDirIsNeeded ($this->dataRootDir);
$this->scheduleGroup = trim ($this->plugin->getConf ('scheduleGroup'));
$this->groupsDir = trim ($this->plugin->getConf ('groupsDir'));
$this->scheduleDir = trim ($this->plugin->getConf ('scheduleDir'));
$this->sharedDir = trim ($this->plugin->getConf ('sharedDir'));
foreach (explode ('|', $this->plugin->getConf ('scheduleWhat')) as $tmpCatDef) {
$tmpCatExp = explode (':', trim ($tmpCatDef));
$tmpCat = trim ($tmpCatExp[0]);
foreach (explode (',', $tmpCatExp[1]) as $tmpWhat) {
$tmpWhat = trim ($tmpWhat);
$this->scheduleWhat[$tmpWhat] = $tmpCat;
}
}
$this->scheduleAudience [""] = $this->plugin->getLang ('audienceChoice');
foreach (explode (',', $this->plugin->getConf ('scheduleAudience')) as $tmpAudience)
$this->scheduleAudience[trim ($tmpAudience)] = trim ($tmpAudience);
$this->iconName = $this->plugin->getConf ('iconName');
$this->iconWidth = $this->plugin->getConf ('iconWidth');
foreach (array (false, true) as $sharedVal) {
$tmp = $this->plugin->getLang ('shared');
$this->scheduleShared[] = trim ($tmp[$sharedVal]);
}
$this->currentDateFormat = $this->dateFormat [$this->plugin->getLang ('dateFormat')];
global $INFO;
$this->isAdmin =
isset ($INFO ['userinfo']) &&
isset ($INFO ['userinfo']['grps']) &&
in_array (trim ($this->plugin->getConf ('adminGroup')), $INFO ['userinfo']['grps']);
}
// ============================================================
// Manage XML file
// ============================================================
/* read lodging config */
function readConfig ($dir) {
$oldFileName = $dir.$this->oldConfigFile;
$fileName = $dir.$this->configFile;
// rename old fashion membre file name
if (file_exists ($oldFileName)) {
// XXX migration
rename ($oldFileName, $fileName);
$exclude = ".|..|".$this->scheduleRoot->configFile;
$exclude_array = explode("|", $exclude);
$pathDir = rtrim ($dir, "/") . "/";
if (is_dir($pathDir)) {
$pathDirObj = opendir ($pathDir);
while (false !== ($file = readdir ($pathDirObj))) {
if (in_array (strtolower ($file), $exclude_array))
continue;
$pathFile = $pathDir.$file;
if (is_file ($pathFile) && preg_match ('#.*\.xml$#i', $file, $b))
rename ($pathFile, $pathDir.$this->mbrPrefix.$file);
}
}
}
if (!file_exists ($fileName))
return false;
$result = array ();
// if (! class_exists ('DOMDocument'))
// return $result;
$xml = new DOMDocument ("1.0", "utf8");
$xml->load ($fileName);
$root = $xml->documentElement;
foreach ($this->configAttributsName as $field) {
$element = $root->getElementsByTagName ($field);
if ($element)
$result [$field] = $element->item (0)->nodeValue;
}
return $result;
}
/* write lodging config */
function writeConfig ($schedules) {
$fileName = $schedules->dataDir.$this->configFile;
scheduleRoot::createDirIsNeeded ($schedules->dataDir);
// if (! class_exists ('DOMDocument'))
// return;
$xml = new DOMDocument ("1.0", "utf8");
$root = $xml->createElement ("schedule");
$xml->appendChild ($root);
foreach ($this->configAttributsName as $field)
$root->appendChild ($xml->createElement ($field, htmlspecialchars ($schedules->$field)));
$xml->formatOutput = true;
$xml->save ($fileName);
chmod ($fileName, 0664);
}
// ============================================================
function manageAction ($request) {
if (!$this->isAdmin)
return;
$md5 = $request['md5'];
if (!$md5)
return;
$schedules = new schedules ($this, $request[$md5]['ns']);
switch ($request["action"]) {
case 'moveSchedules':
$md5 = $request['md5'];
$date = $this->df2ds ($request[$md5]['date']);
$md5bis = $request[$md5]['toNs'];
if (!$date)
return;
$src = new schedules ($this, $request[$md5]['ns']);
$src->load ();
$dst = new schedules ($this, $request[$md5bis]['ns']);
$dst->load ();
$filter = array ();
foreach ($src->allSchedules as $id => $schedule)
if (($schedule->to ? $schedule->to : $schedule->from) < $date)
$filter [$id] = $schedule;
foreach ($filter as $id => $schedule) {
$dst->addSchedule ($schedule);
$src->removeSchedule ($id);
}
$dst->writeSchedules ();
$src->writeSchedules ();
unset ($_REQUEST['schd']);
break;
default:
return;
}
}
// ============================================================
function printForm () {
if (!$this->isAdmin)
return;
$list = $this->readAllSchedules ();
echo
'<form method="POST" action="" onSubmit="return false;" >'.NL.
' <table class="admin" >'.NL.
' <thead>'.NL.
// XXX getLang ()
' <tr><th>Description</th><th>Valeurs</th></tr>'.NL.
' </thead>'.NL.
' <tbody>'.NL;
$this->resetOddEven ();
foreach ($list as $md5 => $item) {
$nameSpace = $item ["nameSpace"];
$schedules = $item ["schedules"];
echo
' <tr class="'.$this->getOddEven ().'">'.NL.
' <td class="name">NameSpace</td>'.NL.
' <td class="value"><input type="hidden" name="schd['.$md5.'][ns]" value="'.$nameSpace.'"/>'.$nameSpace.'</td>'.NL.
' </tr>'.NL.
' <tr class="'.$this->getOddEven ().'">'.NL.
' <td class="name">MD5</td>'.NL.
' <td class="value">'.$md5.'</td>'.NL.
' </tr>'.NL.
' <tr class="'.$this->getOddEven ().'">'.NL.
' <td class="name">Members</td>'.NL.
' <td class="value">'.count ($schedules->memberSchedules).'</td>'.NL.
' </tr>'.NL.
' <tr class="'.$this->getOddEven ().'">'.NL.
' <td class="name">Events</td>'.NL.
' <td class="value">'.count ($schedules->datedSchedules).'</td>'.NL.
' </tr>'.NL.
' <tr class="'.$this->getOddEven ().'">'.NL.
' <td class="name">Repeated</td>'.NL.
' <td class="value">'.count ($schedules->repeatedSchedules).'</td>'.NL.
' </tr>'.NL.
' <tr class="'.$this->getOddEven ().'">'.NL.
' <td class="name">Date</td>'.NL.
' <td><input type="text" name="schd['.$md5.'][date]" value="'.'" placeholder="'.$this->plugin->getLang ('rootMoveDatePH').'"/></td>'.NL.
' </tr>'.NL.
' <tr class="'.$this->getOddEven ().'">'.NL.
' <td class="name">Vers</td>'.NL.
' <td><select name="schd['.$md5.'][toNs]"/>'.NL;
foreach ($list as $md5bis => $itemBis)
if ($md5bis != $md5)
echo
' <option value="'.$md5bis.'">'.$itemBis["nameSpace"].'</option>'.NL;
echo
' </select></td>'.NL.
' </tr>'.NL.
' <tr class="'.$this->getOddEven ().'">'.NL.
' <td class="name">Action</td>'.NL.
' <td><input type="submit" name="action" value="moveSchedules" onClick="scheduleAjax(this.form,\'moveSchedules\',\''.$md5.'\')" /></td>'.NL.
' </tr>'.NL;
$this->switchOddEven ();
}
echo
' </tbody>'.NL.
' </table>'.NL.
'</form>'.NL;
}
// ============================================================
function readAllSchedules () {
$exclude_array = explode ("|", ".|..");
if (!is_dir($this->dataRootDir))
return;
$pathDirObj = opendir ($this->dataRootDir);
while (false !== ($file = readdir ($pathDirObj))) {
$subDir = $this->dataRootDir.$file.'/';
if (in_array (strtolower ($file), $exclude_array) || !is_dir ($subDir))
continue;
$list [$file] = $this->readConfig ($subDir);
$list [$file]["schedules"] = new schedules ($this, $list [$file]["nameSpace"]);
$list [$file]["schedules"]->load ();
}
uasort ($list, "cmpScheduleConfig");
return $list;
}
function clearCache () {
$list = $this->readAllSchedules ();
foreach ($list as $md5 => $item) {
$schedules = $item ["schedules"];
$schedules->clearCache ();
}
}
// ============================================================
}