+++ /dev/null
-<?php # vim:ts=2:sw=2:et:
-/* For licensing and copyright terms, see the file named LICENSE */
-
-require_once 'MTrack/Wiki.php';
- require_once 'MTrack/Watch.php';
-
-
-class MTrack_Milestone {
- public $mid = null;
- public $pmid = null;
- public $name = null;
- public $description = null;
- public $duedate = null;
- public $startdate = null;
- public $deleted = null;
- public $completed = null;
- public $created = null;
-
- static function loadByName($name)
- {
- foreach (MTrackDB::q('select mid from milestones where lower(name) = lower(?)', $name)
- ->fetchAll() as $row) {
- return new self($row[0]);
- }
- return null;
- }
-
- static function loadByID($id)
- {
- foreach (MTrackDB::q('select mid from milestones where mid = ?', $id)
- ->fetchAll() as $row) {
- return new self($row[0]);
- }
- return null;
- }
-
- static function enumMilestones($all = false)
- {
- if ($all) {
- $q = MTrackDB::q('select mid, name from milestones where deleted != 1');
- } else {
- $q = MTrackDB::q('select mid, name from milestones where completed is null and deleted != 1');
- }
- $res = array();
- foreach ($q->fetchAll(PDO::FETCH_NUM) as $row) {
- $res[$row[0]] = $row[1];
- }
- return $res;
- }
-
- function __construct($id = null)
- {
- if ($id !== null) {
- $this->mid = $id;
-
- list($row) = MTrackDB::q('select * from milestones where mid = ?', $id)
- ->fetchAll(PDO::FETCH_ASSOC);
- foreach ($row as $k => $v) {
- $this->$k = $v;
- }
- }
- $this->deleted = false;
- }
-
- function save(MTrackChangeset $CS)
- {
- $this->updated = $CS->cid;
-
- if ($this->mid === null) {
- $this->created = $CS->cid;
-
- MTrackDB::q('insert into milestones
- (name, description, startdate, duedate, completed, created,
- pmid, updated, deleted)
- values (?, ?, ?, ?, ?, ?, ?, ?, ?)',
- $this->name,
- $this->description,
- $this->startdate,
- $this->duedate,
- $this->completed,
- $this->created,
- $this->pmid,
- $this->updated,
- (int)$this->deleted);
-
- $this->mid = MTrackDB::lastInsertId('milestones', 'mid');
- } else {
- list($old) = MTrackDB::q(
- 'select * from milestones where mid = ?', $this->mid)->fetchAll();
- foreach ($old as $k => $v) {
- if ($k == 'mid' || $k == 'created' || $k == 'updated') {
- continue;
- }
- $CS->add("milestone:$this->mid:$k", $v, $this->$k);
- }
- MTrackDB::q('update milestones set name = ?,
- description = ?, startdate = ?, duedate = ?, completed = ?,
- updated = ?, deleted = ?, pmid = ?
- WHERE mid = ?',
- $this->name,
- $this->description,
- $this->startdate,
- $this->duedate,
- $this->completed,
- $this->updated,
- (int)$this->deleted,
- $this->pmid,
- $this->mid);
- }
- }
-
- static function macro_BurnDown() {
- global $ABSWEB;
-
- $args = func_get_args();
-
- if (!count($args) || (count($args) == 1 && $args[0] == '')) {
- # Special case for allowing burndown to NOP in the milestone summary
- return '';
- }
-
- $params = array(
- 'width' => '75%',
- 'height' => '250px',
- );
-
- foreach ($args as $arg) {
- list($name, $value) = explode('=', $arg, 2);
- $params[$name] = $value;
- }
-
- $m = MTrack_Milestone::loadByName($params['milestone']);
- if (!$m) {
- return "BurnDown: milestone $params[milestone] is invalid<br>\n";
- }
- if (!MTrackACL::hasAllRights("milestone:" . $m->mid, 'read')) {
- return "Not authorized to view milestone $name<br>\n";
- }
-
- /* step 1: find all changes on this milestone and its children */
- $effort = MTrackDB::q("
- select expended, remaining, changedate
- from
- ticket_milestones tm
- left join
- effort e on (tm.tid = e.tid)
- left join
- changes c on (e.cid = c.cid)
- where (mid = ?
- or (mid in (select mid from milestones where pmid = ?))
- )
- and c.changedate is not null
- order by c.changedate",
- $m->mid, $m->mid)->fetchAll(PDO::FETCH_NUM);
-
- /* estimated hours by day */
- $estimate_by_day = array();
- /* accumulated work spent by day */
- $accum_spent_by_day = array();
- /* accumulated remaining hours by day */
- $accum_remain_by_day = array();
-
- $current_estimate = null;
- $min_day = null;
- $max_value = 0;
- $total_exp = 0;
-
- foreach ($effort as $info) {
- list($exp, $rem, $date) = $info;
- list($day, $rest) = explode('T', $date, 2);
-
- /* previous day estimate carries over to today */
- if (!isset($estimate_by_day[$day])) {
- $estimate_by_day[$day] = $current_estimate;
- }
-
- /* previous accumulation carries over */
- if (!isset($accum_spent_by_day[$day])) {
- $accum_spent_by_day[$day] = $total_exp;
- }
-
- /* revise the estimate for today; also applies
- * to the number we carry over to tomorrow */
- if ($rem !== null) {
- $estimate_by_day[$day] += $rem;
- $current_estimate = $estimate_by_day[$day];
- }
-
- if ($exp !== null) {
- if ($exp != 0 && $min_day === null) {
- $min_day = strtotime($date);
- }
- $accum_spent_by_day[$day] += $exp;
- $total_exp += $exp;
- }
- $accum_remain_by_day[$day] = $current_estimate - $total_exp;
- $max_value = max($max_value, $current_estimate);
- }
-
- $init_estimate = 0;
- foreach ($estimate_by_day as $v) {
- if ($v) {
- $init_estimate = $v;
- break;
- }
- }
-
- /* limit the view to the past 3 weeks */
- $earliest = strtotime('-3 week');
- if ($min_day < $earliest) {
-// $min_day = $earliest;
- }
- $min_day *= 1000;
-
- if ($m->duedate) {
- $maxday = strtotime($m->duedate);
- } else {
- $maxday = time();
- }
- $maxday = strtotime('1 week', $maxday) * 1000;
-
- /* step 3: compute the day by day remaining value,
- * and produce data series for remaining and expended time */
-
- $js_remain = array();
- $js_estimate = array();
- $trend = array();
- foreach ($accum_remain_by_day as $day => $remaining) {
-
- /* compute javascript timestamp */
- list($year, $month, $dayno) = explode('-', $day);
- $ts = gmmktime(0, 0, 0, $month, $dayno, $year) * 1000;
-
- $js_remain[] = "[$ts, $remaining]";
- $est = (int)$estimate_by_day[$day];
- $js_estimate[] = "[$ts, $est]";
- $trend[$ts] = $remaining;
- }
-
- $js_remain = join(',', $js_remain);
- $js_estimate = join(',', $js_estimate);
-
- $flot = "bd_graph_" . sha1(join(':', $args) . time());
-
- $max_value *= 1.2;
-
- $height = (int)$params['height'];
-
- $html = "
-<div id='$flot' class='flotgraph'
- style='width: $params[width]; height: $params[height];'></div>
-<script id='source_$flot' language='javascript' type='text/javascript'>
-\$(function () {
- var p = \$('#$flot');
- // Not sure what's up here, but somehow the height for the element
- // shows up as 0 in safari, despite the style setting above... so let's
- // just force the height here.
- if (p.height() == 0) {
- p.height($height);
- }
- \$.plot(p, [
- { label: \"estimated\", data: [$js_estimate], yaxis: 1 },
- { label: \"remaining\", data: [$js_remain] }
- ], {
- xaxis: {
- mode: \"time\",
- timeformat: '%b %d',
- min: $min_day,
- max: $maxday
- },
- yaxis: {
- max: $max_value
- },
- legend: {
- position: 'sw'
- },
- grid: {
- hoverable: true
- }
- }
- );
-});
-</script>
-";
-
- $delta = $init_estimate - $total_exp;
-
- return
- "<div class='burndown'>Initial estimate: $init_estimate, Work expended: $total_exp<br>\n"
- . $html . "</div>";
- }
-
- static function macro_MilestoneSummary($name) {
- global $ABSWEB;
-
- $m = self::loadByName($name);
- if (!$m) {
- return "milestone: " . htmlentities($name) . " not found<br>\n";
- }
-
- if (!MTrackACL::hasAllRights("milestone:" . $m->mid, 'read')) {
- return "Not authorized to view milestone $name<br>\n";
- }
-
- $completed = mtrack_date($m->completed);
- $description = $m->description;
- if (strpos($description, "[[BurnDown(") === false) {
- $description = "[[BurnDown(milestone=$name,width=50%,height=150)]]\n" .
- $description;
- }
- $desc = MTrack_Wiki::format_to_html($description);
- $pname = $name;
- if ($m->completed !== NULL) {
- $pname = "<del>$name</del>";
- $due = "Completed";
- } elseif ($m->duedate) {
- $due = "Due " . mtrack_date($m->duedate);
- } else {
- $due = null;
- }
-
- $watch = MTrackWatch::getWatchUI('milestone', $m->mid);
-
- $html = <<<HTML
-<div class="milestone">
-<h2><a href="{$ABSWEB}milestone.php/$name">$pname</a></h2>
-$watch
-<div class="due">$due</div>
-$desc<br/>
-HTML;
-
- $estimated = 0;
- $remaining = 0;
- $open = 0;
- $total = 0;
-
- foreach (MTrackDB::q('select status, estimated, estimated - spent as remaining from ticket_milestones tm left join tickets t on (tm.tid = t.tid) where mid = ?',
- $m->mid)->fetchAll(PDO::FETCH_ASSOC) as $row) {
- $total++;
- if ($row['status'] != 'closed') {
- $open++;
- }
- $estimated += $row['estimated'];
- $remaining += $row['remaining'];
- }
-
- $closed = $total - $open;
- if ($total) {
- $apct = (int)($open / $total * 100);
- } else {
- $apct = 0;
- }
- $cpct = 100 - $apct;
- $html .= <<<HTML
-<table class='progress'>
-<tr>
- <td class='closed' style='width:$cpct%;'><a href='#'></a></td>
-HTML;
-
- if ($open) {
- $html .= <<<HTML
- <td class='open' style='width:$apct%;'><a href='#'> </a></td>
-HTML;
- }
-
- $ms = urlencode($name);
-
- $html .= <<<HTML
-</tr>
-</table>
-<a href='{$ABSWEB}query.php?milestone=$ms&status!=closed'>$open open</a>,
-<a href='{$ABSWEB}query.php?milestone=$ms&status=closed'>$closed closed</a>,
-<a href='{$ABSWEB}query.php?milestone=$ms'>$total total</a> ($cpct % complete)
-</div>
-HTML;
- return $html;
- }
-}
-
+++ /dev/null
-<?php
-
-require_once 'MTrackWeb.php';
-
-
-class MTrackWeb_Login extends MTrackWeb
-{
- var $template = 'login.html';
-
- function getAuth()
- {
- return true;
- }
-
- function get($u='', $ar=array())
- {
-
- if (!empty($_REQUEST['logout'])) {
- if ($this->getAuthUser()) {
- $this->getAuthUser()->logout();
- }
- header('location: ' . $this->baseURL);
- exit;
-
-
- }
- if (!isset($_REQUEST['ajax_body'])) {
- $this->title = "Login";
- return;
- }
- $this->masterTemplate = 'login.html';
-
- if (!empty($u)) {
- /** ---------- reset passwords ----- */
- $uu = explode('/', $u);
- if ($uu[0] != 'Reset') {
- $this->err('404', 'Invalid URL');
- }
- $u = DB_DataObject::factory('Person');
- if (!$u->get($uu[1])) {
- $this->err('404', 'Invalid URL');
- }
- $uu[2] = (int) $uu[2];
-
- if ($uu[2] < (time() - (60 * 60 * 24 * 2))) { // older than 2 days.
- HTML_FlexyFramework::run('ForgotPassword', array('errors' => array('reset_expired' => 1)));
- exit;
- }
- // print_R($u->genPassKey($uu[2]));
- if ($uu[3] != $u->genPassKey($uu[2])) {
- HTML_FlexyFramework::run('ForgotPassword', array('errors' => array('reset_invalid' => 1)));
- exit;
- }
- // do reset!!!.
-
- $pp = clone($u);
- $u->generatePassword();
- $u->update($pp);
- $u->sendTemplate('reset_password', $this);
-
- $this->warnings = array('password_sent' => true);
-
- }
-
- if (!empty($ar)) {
- foreach($ar as $k=>$v) {
- $this->$k = $v;
- }
- }
-
-
-
- if (!empty($_POST)) {
- require_once 'HTML/Template/Flexy/Factory.php';
- $this->elements = HTML_Template_Flexy_Factory::fromArray( $_POST ,$this->elements);
-
- }
-
- return;
- }
- function errmsg($str) {
-
- return $this->jerr($str);
-
- }
- /**
- * AJAX ONLY?
- */
- function post()
- {
-
- $u = DB_DataObject::factory('Person');
- //$u->active = 1;
- $u->whereAdd('LENGTH(passwd) > 1');
- //$u->company_id = $this->company->id;
-
- if (empty($_REQUEST['username'])) { //|| (strpos($_REQUEST['username'], '@') < 1)) {
- return $this->errmsg('bad_1');
-
- }
-
- $u->email = $_REQUEST['username'];
- if ($u->count() > 1 || !$u->find(true)) {
- return $this->errmsg('bad_2');
-
- }
-
- //if (!$u->active) {
- // return $this->errmsg('disabled');
- //}
-
- if ($u->checkPassword($_REQUEST['password'])) {
- $u->login();
- $this->addEvent("LOGIN");
- //if (!empty($_REQUEST['lang']) && $_REQUEST['lang'] != $u->lang) {
- // $uu = clone($u);
- //// $uu->lang = $_REQUEST['lang'];
- // $uu->update();
- //}
- // log it..
- $this->jok('OK');
- HTML_FlexyFramework::run(''); //
-
- //$this->sendAuthUserDetails();
- exit;
-
- //exit;
- }
-
-
- return $this->errmsg('bad_3'); // - " . htmlspecialchars(print_r($_POST,true))."'");
-
- }
-
-
-
-
-}
\ No newline at end of file