define('RELATED_SVN', 2); // Do modes define('MENU_GLOBAL', 1); define('MENU_PROJECT', 2); define('ERROR_INTERNAL', 7); define('ERROR_INPUT', 6); define('ERROR_PERMS', 4); define('ERROR_RECOVER', 3); define('SUBMIT_OK', 2); define('NO_SUBMIT', 1); // Function parameters define('REINDEX', true); define('GET_CONTENTS', true); define('LOCK_FIELD', true); define('USE_DEFAULT', true); define('PLAINTEXT', true); // Others define('MIN_PW_LENGTH', 5); define('LOGIN_ATTEMPTS', 5); define('FS_CACHE_DIR', Flyspray::get_tmp_dir() . DIRECTORY_SEPARATOR . md5($_SERVER['SERVER_NAME'] . BASEDIR)); define('FLYSPRAY_WEBDOT', 'http://webdot.flyspray.org/'); is_dir(FS_CACHE_DIR) || mkdir(FS_CACHE_DIR, 0700); // local installation constants, this file must not exist in the svn repository. if (is_readable(BASEDIR . '/includes/constants.' . $_SERVER['SERVER_NAME'] . '.php')) { include BASEDIR . '/includes/constants.' . $_SERVER['SERVER_NAME'] . '.php'; } defined('FS_ATTACHMENTS_DIR') || define('FS_ATTACHMENTS_DIR', BASEDIR . DIRECTORY_SEPARATOR . 'attachments'); // developers or advanced users only //define('DEBUG_SQL', true); //define('FS_MAIL_DEBUG', true); //define('FS_NO_EMAIL', true);
require dirname(__DIR__) . '/vendor/autoload.php'; // Initialise DB require_once dirname(__DIR__) . '/vendor/adodb/adodb-php/adodb.inc.php'; require_once dirname(__DIR__) . '/vendor/adodb/adodb-php/adodb-xmlschema03.inc.php'; $db = new Database(); $db->dbOpenFast($conf['database']); $webdir = dirname(htmlspecialchars($_SERVER['PHP_SELF'], ENT_QUOTES, 'utf-8')); $baseurl = rtrim(Flyspray::absoluteURI($webdir), '/\\') . '/'; // --------------------------------------------------------------------- // Application Web locations // --------------------------------------------------------------------- $fs = new Flyspray(); define('APPLICATION_SETUP_INDEX', Flyspray::absoluteURI()); define('UPGRADE_VERSION', Flyspray::base_version($fs->version)); define('DOMAIN_HASH', md5($_SERVER['SERVER_NAME'] . (int) $_SERVER['SERVER_PORT'])); define('CACHE_DIR', Flyspray::get_tmp_dir() . DIRECTORY_SEPARATOR . DOMAIN_HASH); // Get installed version $sql = $db->Query('SELECT pref_value FROM {prefs} WHERE pref_name = ?', array('fs_ver')); $installed_version = $db->FetchOne($sql); $page = new Tpl(); $page->assign('title', 'Upgrade '); $page->assign('short_version', UPGRADE_VERSION); if (!isset($conf['general']['syntax_plugin']) || !$conf['general']['syntax_plugin'] || $conf['general']['syntax_plugin'] == 'none') { $page->assign('ask_for_conversion', true); } else { $page->assign('ask_for_conversion', false); } //cleanup //the cache dir @rmdirr(sprintf('%s/cache/dokuwiki', APPLICATION_PATH)); // ---------------------------------------------------------------------
} foreach (array('opened', 'closed', 'reopened', 'assigned') as $type) { if (count(${$type})) { $message .= L($type . 'tasks') . ':' . "\n" . implode("\n", ${$type}) . "\n\n"; } } if (Notifications::send_now($pms, ADDRESS_USER, NOTIFY_DIGEST, array('message' => $message))) { $db->x->execParam('UPDATE {projects} SET last_digest = ? WHERE project_id = ?', array(time(), $project['project_id'])); } } ############ Task four: Close tasks ############ $tasks = $db->query('SELECT t.*, c.date_added, max(c.date_added) FROM {tasks} t LEFT JOIN {comments} c ON t.task_id = c.task_id WHERE is_closed = 0 AND close_after > 0 GROUP BY t.task_id'); while ($row = $tasks->FetchRow()) { if (max($row['date_added'], $row['last_edited_time']) + $row['close_after'] < time()) { Backend::close_task($row['task_id'], $row['resolution_reason'], $row['closure_comment'], false); $db->x->execParam('UPDATE {tasks} SET close_after = 0 WHERE task_id = ?', $row['task_id']); } } //wait 10 minutes for the next loop. if (php_sapi_name() !== 'cli') { sleep(600); } } while (php_sapi_name() !== 'cli'); //forever ¡¡¡ ( oh well. a least will not stop unless killed or the server restarted) @register_shutdown_function('unlink', Flyspray::get_tmp_dir() . '/flysprayreminders.run'); } else { die('You are not authorized to start the remider daemon.'); }
/** * Starts the reminder daemon * @access public static * @return void * @version 1.0 */ function startReminderDaemon() { global $baseurl; $runfile = Flyspray::get_tmp_dir() . '/flysprayreminders.run'; $timeout = 600; if (!is_file($runfile) or filemtime($runfile) < time() - $timeout * 2) { $include = 'schedule.php'; /* "localhost" is on **purpose** not a mistake ¡¡ * almost any server accepts requests to itself in localhost ;) * firewalls will not block it. * the "Host" http header will tell the webserver where flyspray is running. */ Flyspray::remote_request($baseurl . $include, !GET_CONTENTS, $_SERVER['SERVER_PORT'], 'localhost', $_SERVER['HTTP_HOST']); } }
/** * show * * @access public * @return void */ function show() { global $user, $page, $fs, $conf, $db, $proj, $baseurl; $path_to_dot = array_get($conf['general'], 'dot_path', ''); //php 4 on windows does not have is_executable.. $func = function_exists('is_executable') ? 'is_executable' : 'is_file'; $path_to_dot = $func($path_to_dot) ? $path_to_dot : ''; $useLocal = !Flyspray::function_disabled('shell_exec') && $path_to_dot; $fmt = Filters::enum(array_get($conf['general'], 'dot_format', 'png'), array('png', 'svg')); $id = $this->task['task_id']; $page->assign('task_id', $id); $prunemode = Get::num('prune', 0); $selfurl = CreateURL(array('depends', 'task' . $id)); $pmodes = array(L('none'), L('pruneclosedlinks'), L('pruneclosedtasks')); foreach ($pmodes as $mode => $desc) { if ($mode == $prunemode) { $strlist[] = $desc; } else { $strlist[] = "<a href='" . Filters::noXSS($selfurl) . ($mode != 0 ? "&prune={$mode}" : "") . "'>{$desc}</a>\n"; } } $page->assign('strlist', $strlist); $starttime = microtime(); $sql = 'SELECT t1.task_id AS id1, t1.prefix_id AS pxid1, p1.project_prefix AS ppx1, t1.item_summary AS sum1, t1.percent_complete AS pct1, t1.is_closed AS clsd1, t1.closure_comment AS com1, u1c.real_name AS clsdby1, r1.item_name as res1, t2.task_id AS id2, t2.prefix_id AS pxid2, p2.project_prefix AS ppx2, t2.item_summary AS sum2, t2.percent_complete AS pct2, t2.is_closed AS clsd2, t2.closure_comment AS com2, u2c.real_name AS clsdby2, r2.item_name as res2 FROM {dependencies} AS d JOIN {tasks} AS t1 ON d.task_id=t1.task_id LEFT JOIN {users} AS u1c ON t1.closed_by=u1c.user_id LEFT JOIN {projects} AS p1 ON t1.project_id = p1.project_id LEFT JOIN {list_items} AS r1 ON t1.resolution_reason=r1.list_item_id JOIN {tasks} AS t2 ON d.dep_task_id=t2.task_id LEFT JOIN {users} AS u2c ON t2.closed_by=u2c.user_id LEFT JOIN {projects} AS p2 ON t2.project_id = p2.project_id LEFT JOIN {list_items} AS r2 ON t2.resolution_reason=r2.list_item_id WHERE t1.project_id= ? ORDER BY d.task_id, d.dep_task_id'; $edges = $db->x->getAll($sql, null, $proj->id); $edge_list = array(); $rvrs_list = array(); $node_list = array(); foreach ($edges as $row) { extract($row, EXTR_REFS); $edge_list[$id1][] = $id2; $rvrs_list[$id2][] = $id1; if (!isset($node_list[$id1])) { $node_list[$id1] = array('id' => $id1, 'sum' => $sum1, 'pct' => $pct1, 'clsd' => $clsd1, 'ppx' => $ppx1, 'pxid' => $pxid1, 'com' => $com1, 'clsdby' => $clsdby1, 'res' => $res1); } if (!isset($node_list[$id2])) { $node_list[$id2] = array('id' => $id2, 'sum' => $sum2, 'pct' => $pct2, 'clsd' => $clsd2, 'ppx' => $ppx2, 'pxid' => $pxid2, 'com' => $com2, 'clsdby' => $clsdby2, 'res' => $res2); } } // Now we have our lists of nodes and edges, along with a helper // list of reverse edges. Time to do the graph coloring, so we know // which ones are in our particular connected graph. We'll set up a // list and fill it up as we visit nodes that are connected to our // main task. $connected = array(); $levelsdown = 0; $levelsup = 0; function ConnectsTo($id, $down, $up, &$connected, &$edge_list, &$rvrs_list, &$levelsdown, &$levelsup, &$prunemode, &$node_list) { if (!isset($connected[$id])) { $connected[$id] = 1; } if ($down > $levelsdown) { $levelsdown = $down; } if ($up > $levelsup) { $levelsup = $up; } $selfclosed = $node_list[$id]['clsd']; if (isset($edge_list[$id])) { foreach ($edge_list[$id] as $neighbor) { $neighborclosed = $node_list[$neighbor]['clsd']; if (!isset($connected[$neighbor]) && !($prunemode == 1 && $selfclosed && $neighborclosed) && !($prunemode == 2 && $neighborclosed)) { ConnectsTo($neighbor, $down, $up + 1, $connected, $edge_list, $rvrs_list, $levelsdown, $levelsup, $prunemode, $node_list); } } } if (isset($rvrs_list[$id])) { foreach ($rvrs_list[$id] as $neighbor) { $neighborclosed = $node_list[$neighbor]['clsd']; if (!isset($connected[$neighbor]) && !($prunemode == 1 && $selfclosed && $neighborclosed) && !($prunemode == 2 && $neighborclosed)) { ConnectsTo($neighbor, $down + 1, $up, $connected, $edge_list, $rvrs_list, $levelsdown, $levelsup, $prunemode, $node_list); } } } } ConnectsTo($id, 0, 0, $connected, $edge_list, $rvrs_list, $levelsdown, $levelsup, $prunemode, $node_list); $connected_nodes = array_keys($connected); sort($connected_nodes); // Now lets get rid of the extra junk in our arrays. // In prunemode 0, we know we're only going to have to get rid of // whole lists, and not elements in the lists, because if they were // in the list, they'd be connected, so we wouldn't be removing them. // In prunemode 1 or 2, we may have to remove stuff from the list, because // you can have an edge to a node that didn't end up connected. foreach (array("edge_list", "rvrs_list", "node_list") as $l) { foreach (${$l} as $n => $list) { if (!isset($connected[$n])) { unset(${$l}[$n]); } if ($prunemode != 0 && $l != "node_list" && isset(${$l}[$n])) { // Only keep entries that appear in the $connected_nodes list ${$l}[$n] = array_intersect(${$l}[$n], $connected_nodes); } } } // Now we've got everything we need... let's draw the pretty pictures //Open the graph, and print global options $lj = 'n'; // label justification - l, r, or n (for center) $graphname = "task_{$id}_dependencies"; $dotgraph = "digraph {$graphname} {\n" . "node [width=1.1, shape=ellipse, border=10, color=\"#00E11E\", style=\"filled\", " . "fontsize=10.0, pencolor=black, margin=\"0.1, 0.0\"];\n"; // define the nodes foreach ($node_list as $n => $r) { $col = ""; if ($r['clsd'] && $n != $id) { $r['pct'] = 120; } // color code: shades of gray for % done $x = dechex(255 - ($r['pct'] + 10)); $col = "#{$x}{$x}{$x}"; // Make sure label terminates in \n! $label = $r['ppx'] . '#' . $r['pxid'] . " \n" . ($useLocal ? addslashes(utf8_substr($r['sum'], 0, 15)) . "\n" : '') . ($r['clsd'] ? L('closed') : "{$r['pct']}% " . L('complete')); $tooltip = $r['clsd'] ? L('closed') . ": {$r['res']}" . (!empty($r['clsdby']) ? " ({$r['clsdby']})" : '') . ($r['com'] != '' ? ' - ' . str_replace(array("\r", "\n"), '', $r['com']) : '') : $r['pct']; $dotgraph .= "FS{$n} [label=\"" . str_replace("\n", "\\{$lj}", $label) . "\", " . ($r['clsd'] ? 'color=black,' : '') . ($r['clsd'] ? 'fillcolor=white,' : "fillcolor=\"{$col}\",") . ($n == $id ? 'shape=box,' : '') . "href=\"javascript:top.window.location.href='" . CreateURL(array("details", 'task' . $n)) . "'\", target=\"_top\" " . "tooltip=\"{$tooltip}\"];\n"; } // Add edges foreach ($edge_list as $src => $dstlist) { foreach ($dstlist as $dst) { $dotgraph .= "FS{$src} -> FS{$dst};\n"; } } // all done $dotgraph .= "}\n"; // All done with the graph. Save it to a temp file (new name if the data has changed) $dotfilename = sprintf('cache/fs_depends_dot_%d_%s.dot', $id, md5($dotgraph)); $imgfilename = sprintf('%s/%s.%s', BASEDIR, $dotfilename, $fmt); $mapfilename = sprintf('%s/%s.%s', BASEDIR, $dotfilename, 'map'); //cannot use tempnam( ) as file has to end with $ftm extension if (!$useLocal) { //cannot use tempnam() as file has to end with $ftm extension $tname = $dotfilename; } else { // we are operating on the command line, avoid races. $tname = tempnam(Flyspray::get_tmp_dir(), md5(uniqid(mt_rand(), true))); } //get our dot done.. file_put_contents($tname, $dotgraph, LOCK_EX); // Now run dot on it, if target file does not already exist if (!is_file($imgfilename)) { if (!$useLocal) { require_once 'Zend/Rest/Client.php'; $client = new Zend_Rest_Client('http://webdot.flyspray.org/'); $data = base64_decode($client->getGraph(base64_encode($dotgraph), $fmt)->post()); file_put_contents($imgfilename, $data, LOCK_EX); $data = base64_decode($client->getGraph(base64_encode($dotgraph), 'cmapx')->post()); file_put_contents($mapfilename, $data, LOCK_EX); } else { $tfn = escapeshellarg($tname); shell_exec(sprintf('%s -T %s -o %s %s', $path_to_dot, escapeshellarg($fmt), escapeshellarg($imgfilename), $tfn)); $data['map'] = shell_exec(sprintf('%s -T cmapx %s', $path_to_dot, $tfn)); file_put_contents($mapfilename, $data['map'], LOCK_EX); // Remove files so that they are not exposed to the public unlink($tname); } } $page->assign('map', file_get_contents($mapfilename)); $page->assign('image', sprintf('%s%s.%s', $baseurl, $dotfilename, $fmt)); // we have to find out the image size if it is SVG if ($fmt == 'svg') { if (!$remote) { $data = file_get_contents(BASEDIR . '/' . $file_name . '.' . $fmt); } preg_match('/<svg width="([0-9.]+)([a-zA-Z]+)" height="([0-9.]+)([a-zA-Z]+)"/', $data, $matches); $page->assign('width', round($matches[1] * ($matches[2] == 'pt' ? 1.4 : ($matches[2] == 'in' ? 1.33 * 72.27 : 1)), 0)); $page->assign('height', round($matches[3] * ($matches[4] == 'pt' ? 1.4 : ($matches[4] == 'in' ? 1.35 * 72.27 : 1)), 0)); } /* [TC] We cannot have this stuff outputting here, so I put it in a quick template */ $page->assign('taskid', $id); $page->assign('fmt', $fmt); $page->assign('graphname', $graphname); $endtime = microtime(); list($startusec, $startsec) = explode(' ', $starttime); list($endusec, $endsec) = explode(' ', $endtime); $diff = $endsec - $startsec + ($endusec - $startusec); $page->assign('time', round($diff, 2)); $page->setTitle($this->task['project_prefix'] . '#' . $this->task['prefix_id'] . ': ' . L('dependencygraph')); $page->pushTpl('depends.tpl'); }