/** * @return TimeTrack[] */ public function getTimeTracks() { if (NULL == $this->timeTracks) { $accessLevel_dev = Team::accessLevel_dev; $accessLevel_manager = Team::accessLevel_manager; // select tasks within timestamp, where user is in the team // WARN: users having left the team will be included, this is a pre-filter. $query = "SELECT timetracking.* " . "FROM `codev_timetracking_table` as timetracking " . "JOIN `codev_team_user_table` as team_user ON timetracking.userid = team_user.user_id " . "WHERE team_user.team_id = {$this->team_id} " . "AND team_user.access_level IN ({$accessLevel_dev}, {$accessLevel_manager}) " . "AND timetracking.date >= {$this->startTimestamp} AND timetracking.date <= {$this->endTimestamp};"; $result = SqlWrapper::getInstance()->sql_query($query); if (!$result) { echo "<span style='color:red'>ERROR: Query FAILED</span>"; exit; } $this->timeTracks = array(); while ($row = SqlWrapper::getInstance()->sql_fetch_object($result)) { $tt = TimeTrackCache::getInstance()->getTimeTrack($row->id, $row); $user = UserCache::getInstance()->getUser($tt->getUserId()); $timestamp = $tt->getDate(); // check that the user was in the team at the timetrack's date. if ($user->isTeamMember($this->team_id, NULL, $timestamp, $timestamp)) { $this->timeTracks[] = $tt; } } } return $this->timeTracks; }
/** * get timetracks for each Issue * * @param array $useridList * @param type $startTimestamp * @param type $endTimestamp * @return array of TimeTrack */ public function getTimetracks($useridList = NULL, $startTimestamp = NULL, $endTimestamp = NULL) { if (empty($this->issueList)) { return array(); } $formatedBugidString = implode(', ', array_keys($this->issueList)); // TODO cache results ! $query = "SELECT * FROM `codev_timetracking_table` " . "WHERE bugid IN (" . $formatedBugidString . ") "; if (NULL != $useridList) { $formatedUseridString = implode(', ', $useridList); $query .= 'AND userid IN (' . $formatedUseridString . ') '; } if (NULL != $startTimestamp) { $query .= "AND date >= {$startTimestamp} "; } if (NULL != $endTimestamp) { $query .= "AND date <= {$endTimestamp} "; } $query .= ' ORDER BY bugid'; $result = SqlWrapper::getInstance()->sql_query($query); if (!$result) { echo '<span style="color:red">ERROR: Query FAILED</span>'; exit; } $timeTracks = array(); while ($row = SqlWrapper::getInstance()->sql_fetch_object($result)) { $timeTracks[$row->id] = TimeTrackCache::getInstance()->getTimeTrack($row->id, $row); } return $timeTracks; }
/** * @param int $startTimestamp * @param int $endTimestamp * @return TimeTrack[] */ public function getTimeTracks($startTimestamp, $endTimestamp) { if (NULL == $this->timeTracksCache) { $this->timeTracksCache = array(); } $key = $startTimestamp . '-' . $endTimestamp; if (!array_key_exists($key, $this->timeTracksCache)) { $query = "SELECT * FROM `codev_timetracking_table` " . "WHERE date >= {$startTimestamp} AND date <= {$endTimestamp} " . "AND userid = {$this->id};"; $result = SqlWrapper::getInstance()->sql_query($query); if (!$result) { echo "<span style='color:red'>ERROR: Query FAILED</span>"; exit; } $timeTracks = array(); while ($row = SqlWrapper::getInstance()->sql_fetch_object($result)) { $timeTracks[] = TimeTrackCache::getInstance()->getTimeTrack($row->id, $row); } $this->timeTracksCache[$key] = $timeTracks; } return $this->timeTracksCache[$key]; }
/** * * returns an array of [user][activity] * activity in (elapsed, sidetask, other, external, leave) * */ public function execute() { $team = TeamCache::getInstance()->getTeam($this->teamid); $members = $team->getActiveMembers($this->startTimestamp, $this->endTimestamp); $formatedUseridString = implode(', ', array_keys($members)); $extProjId = Config::getInstance()->getValue(Config::id_externalTasksProject); $extTasksCatLeave = Config::getInstance()->getValue(Config::id_externalTasksCat_leave); // get timetracks for each Issue, $issueList = $this->inputIssueSel->getIssueList(); $bugidList = array_keys($issueList); $query = "SELECT * FROM `codev_timetracking_table` " . "WHERE userid IN (" . $formatedUseridString . ") "; if (isset($this->startTimestamp)) { $query .= "AND date >= {$this->startTimestamp} "; } if (isset($this->endTimestamp)) { $query .= "AND date <= {$this->endTimestamp} "; } $query .= " ORDER BY bugid"; $result = SqlWrapper::getInstance()->sql_query($query); if (!$result) { echo "<span style='color:red'>ERROR: Query FAILED</span>"; exit; } $timeTracks = array(); while ($row = SqlWrapper::getInstance()->sql_fetch_object($result)) { $timeTracks[$row->id] = TimeTrackCache::getInstance()->getTimeTrack($row->id, $row); } // --- // un tablean de users avec repartition temps en categories: regular,external,sidetask $teams = array($this->teamid); $usersActivity = array(); foreach ($timeTracks as $tt) { $issueId = $tt->getIssueId(); try { $issue = IssueCache::getInstance()->getIssue($issueId); } catch (Exception $e) { self::$logger->error("execute() skip issue {$issueId} : " . $e->getMessage()); continue; } $userid = $tt->getUserId(); if (!array_key_exists($userid, $usersActivity)) { $usersActivity[$userid] = array(); } //$activityList = $usersActivity[$userid]; $duration = $tt->getDuration(); try { if ($extProjId == $tt->getProjectId()) { #self::$logger->error("external ".$tt->getIssueId()); if ($extTasksCatLeave == $issue->getCategoryId()) { if (array_key_exists('leave', $usersActivity[$userid])) { $usersActivity[$userid]['leave'] += $duration; } else { $usersActivity[$userid]['leave'] = $duration; } } else { if (array_key_exists('external', $usersActivity[$userid])) { $usersActivity[$userid]['external'] += $duration; } else { $usersActivity[$userid]['external'] = $duration; } } } else { if ($issue->isSideTaskNonProductionIssue($teams)) { #self::$logger->error("execute showSidetasks = ".$this->showSidetasks.' cat='.$cat); // if sideTask is in the IssueSelection, then it is considered as 'normal', // else it should not be included if (in_array($issueId, $bugidList)) { $cat = $this->showSidetasks ? 'sidetask' : 'elapsed'; if (array_key_exists($cat, $usersActivity[$userid])) { $usersActivity[$userid][$cat] += $duration; } else { $usersActivity[$userid][$cat] = $duration; } } else { // all sideTasks are in 'other' except inactivity tasks. $project = ProjectCache::getInstance()->getProject($issue->getProjectId()); if ($project->getCategory(Project::cat_st_inactivity) == $issue->getCategoryId()) { if (array_key_exists('leave', $usersActivity[$userid])) { $usersActivity[$userid]['leave'] += $duration; } else { $usersActivity[$userid]['leave'] = $duration; } } else { if (array_key_exists('other', $usersActivity[$userid])) { $usersActivity[$userid]['other'] += $duration; } else { $usersActivity[$userid]['other'] = $duration; } } } } else { if (in_array($issueId, $bugidList)) { #self::$logger->error("selection ".$tt->getIssueId()); if (array_key_exists('elapsed', $usersActivity[$userid])) { $usersActivity[$userid]['elapsed'] += $duration; } else { $usersActivity[$userid]['elapsed'] = $duration; } } else { #echo "other ".$tt->getIssueId()."<br>"; if (array_key_exists('other', $usersActivity[$userid])) { $usersActivity[$userid]['other'] += $duration; } else { $usersActivity[$userid]['other'] = $duration; } } } } } catch (Exception $e) { // Issue::isSideTaskIssue() throws an Ex if project not found in mantis self::$logger->error("Unknown activity for issue {$issueId}, duration ({$duration}) added to 'elapsed'\n" . $e->getMessage()); $usersActivity[$userid]['elapsed'] += $duration; // should it be added in userActivity[$userid]['unknown'] ? } } #var_dump($usersActivity); $this->execData = $usersActivity; }
/** * update Backlog and delete TimeTrack * @param int $trackid */ public static function delete($trackid) { // increase backlog (only if 'backlog' already has a value) $timetrack = TimeTrackCache::getInstance()->getTimeTrack($trackid); $bugid = $timetrack->bugId; $duration = $timetrack->duration; $issue = IssueCache::getInstance()->getIssue($bugid); if (!is_null($issue->getBacklog())) { $backlog = $issue->getBacklog() + $duration; $issue->setBacklog($backlog); } // delete track if (!$timetrack->remove()) { echo "<span style='color:red'>ERROR: Query FAILED</span>"; exit; } }
/** * */ public function execute() { $my_endTimestamp = mktime(23, 59, 59, date('m', $this->endTimestamp), date('d', $this->endTimestamp), date('Y', $this->endTimestamp)); // candidate teams $teamList = Team::getTeams(true); if (!array_key_exists($this->displayedTeam, $teamList)) { $teamIds = array_keys($teamList); if (count($teamIds) > 0) { $this->displayedTeam = $teamIds[0]; } else { $this->displayedTeam = 0; } } // get timetracks $timetracks = array(); if (0 != $this->displayedTeam) { $members = TeamCache::getInstance()->getTeam($this->displayedTeam)->getActiveMembers(); if (!empty($members)) { $memberIdList = array_keys($members); $formatedMembers = implode(', ', $memberIdList); $query = "SELECT * FROM `codev_timetracking_table` " . "WHERE date >= {$this->startTimestamp} AND date <= {$my_endTimestamp} " . "AND userid IN ({$formatedMembers})" . "ORDER BY date;"; $result = SqlWrapper::getInstance()->sql_query($query); if (!$result) { echo "<span style='color:red'>ERROR: Query FAILED</span>"; exit; } $jobs = new Jobs(); while ($row = SqlWrapper::getInstance()->sql_fetch_object($result)) { $tt = TimeTrackCache::getInstance()->getTimeTrack($row->id, $row); $user = UserCache::getInstance()->getUser($tt->getUserId()); $issue = IssueCache::getInstance()->getIssue($tt->getIssueId()); if (!is_null($tt->getCommitterId())) { $committer = UserCache::getInstance()->getUser($tt->getCommitterId()); $committer_name = $committer->getName(); $commit_date = date('Y-m-d H:i:s', $tt->getCommitDate()); } else { $committer_name = ''; // this info does not exist before v1.0.4 $commit_date = ''; } $timetracks[$row->id] = array('user' => $user->getName(), 'date' => date('Y-m-d', $tt->getDate()), 'job' => $jobs->getJobName($tt->getJobId()), 'duration' => $tt->getDuration(), 'committer' => $committer_name, 'commit_date' => $commit_date, 'task_id' => $issue->getId(), 'task_extRef' => $issue->getTcId(), 'task_summary' => $issue->getSummary()); } } } $this->execData = array('teamList' => $teamList, 'startTimestamp' => $this->startTimestamp, 'endTimestamp' => $this->endTimestamp, 'timetracks' => $timetracks); return $this->execData; }
/** * @return TimeTrack */ public function getLatestTimetrack() { $query = "SELECT * from `codev_timetracking_table` " . "WHERE bugid = {$this->bugId} " . "ORDER BY date DESC LIMIT 1"; $result = SqlWrapper::getInstance()->sql_query($query); if (!$result) { echo "<span style='color:red'>ERROR: Query FAILED</span>"; exit; } $timeTrack = NULL; if (0 != SqlWrapper::getInstance()->sql_num_rows($result)) { $row = SqlWrapper::getInstance()->sql_fetch_object($result); $timeTrack = TimeTrackCache::getInstance()->getTimeTrack($row->id, $row); } return $timeTrack; }
protected function display() { if (Tools::isConnectedUser()) { // only teamMembers can access this page if (0 == $this->teamid || $this->session_user->isTeamCustomer($this->teamid) || $this->session_user->isTeamObserver($this->teamid) || !$this->session_user->isTeamMember($this->teamid)) { $this->smartyHelper->assign('accessDenied', TRUE); } else { $team = TeamCache::getInstance()->getTeam($this->teamid); $teamMembers = $team->getActiveMembers(NULL, NULL, TRUE); $managed_userid = Tools::getSecurePOSTIntValue('userid', $this->session_userid); if ($this->session_user->isTeamManager($this->teamid)) { // session_user is Manager, let him choose the teamMember he wants to manage $this->smartyHelper->assign('users', $teamMembers); $this->smartyHelper->assign('selectedUser', $managed_userid); $this->smartyHelper->assign("isManager", true); } // display AddTrack Page $year = Tools::getSecurePOSTIntValue('year', date('Y')); $managed_user = UserCache::getInstance()->getUser($managed_userid); // Need to be Manager to handle other users if ($managed_userid != $this->session_userid) { if (!$this->session_user->isTeamManager($this->teamid) || !array_key_exists($managed_userid, $teamMembers)) { self::$logger->error(' SECURITY ALERT changeManagedUser: session_user ' . $this->session_userid . " is not allowed to manage user {$managed_userid}"); Tools::sendForbiddenAccess(); } } // developper & manager can add timeTracks $mTeamList = $managed_user->getDevTeamList(); $managedTeamList = $managed_user->getManagedTeamList(); $teamList = $mTeamList + $managedTeamList; $action = Tools::getSecurePOSTStringValue('action', ''); $weekid = Tools::getSecurePOSTIntValue('weekid', date('W')); $defaultDate = Tools::getSecurePOSTStringValue('date', date("Y-m-d", time())); $defaultBugid = Tools::getSecurePOSTIntValue('bugid', 0); $defaultProjectid = Tools::getSecurePOSTIntValue('projectid', 0); $job = Tools::getSecurePOSTIntValue('job', 0); $duration = Tools::getSecurePOSTNumberValue('duree', 0); if ("addTrack" == $action) { self::$logger->debug("addTrack: called from form1"); // TODO merge addTrack & addTimetrack actions ! // called by form1 when no backlog has to be set. // updateBacklogDialogBox must not raise up, // track must be added, backlog & status must NOT be updated $timestamp = Tools::date2timestamp($defaultDate); $defaultBugid = Tools::getSecurePOSTIntValue('bugid'); $job = Tools::getSecurePOSTStringValue('job'); $duration = Tools::getSecurePOSTNumberValue('duree'); // dialogBox is not called, then track must be saved to DB $trackid = TimeTrack::create($managed_userid, $defaultBugid, $job, $timestamp, $duration, $this->session_userid); if (self::$logger->isDebugEnabled()) { self::$logger->debug("Track {$trackid} added : userid={$managed_userid} bugid={$defaultBugid} job={$job} duration={$duration} timestamp={$timestamp}"); } // Don't show job and duration after add track $job = 0; $duration = 0; $defaultProjectid = Tools::getSecurePOSTIntValue('projectid'); } elseif ("addTimetrack" == $action) { // updateBacklogDialogbox with 'addTimetrack' action // add track AND update backlog & status & handlerId // TODO merge addTrack & addTimetrack actions ! self::$logger->debug("addTimetrack: called from the updateBacklogDialogBox"); // add timetrack (all values mandatory) $defaultDate = Tools::getSecurePOSTStringValue('trackDate'); $defaultBugid = Tools::getSecurePOSTIntValue('bugid'); $job = Tools::getSecurePOSTIntValue('trackJobid'); $duration = Tools::getSecurePOSTNumberValue('timeToAdd'); $handlerId = Tools::getSecurePOSTNumberValue('handlerid'); // check jobid (bug happens sometime... if (0 == $job) { $this->smartyHelper->assign('error', T_("Timetrack not added: Job has not specified.")); self::$logger->error("Add track : FAILED. issue={$defaultBugid}, jobid={$job}, duration={$duration} date={$defaultDate}"); } // check bug_id (this happens when user uses the 'back' button of the browser ?) if (0 == $defaultBugid) { self::$logger->error("Add track : FAILED. issue=0, jobid={$job}, duration={$duration} date={$defaultDate}"); } else { $timestamp = 0 !== $defaultDate ? Tools::date2timestamp($defaultDate) : 0; $trackid = TimeTrack::create($managed_userid, $defaultBugid, $job, $timestamp, $duration, $this->session_userid); if (self::$logger->isDebugEnabled()) { self::$logger->debug("Track {$trackid} added : userid={$managed_userid} bugid={$defaultBugid} job={$job} duration={$duration} timestamp={$timestamp}"); } $issue = IssueCache::getInstance()->getIssue($defaultBugid); // setBacklog $formattedBacklog = Tools::getSecurePOSTNumberValue('backlog'); $issue->setBacklog($formattedBacklog); // setStatus $newStatus = Tools::getSecurePOSTIntValue('statusid'); $issue->setStatus($newStatus); // set handlerId if ($handlerId != $issue->getHandlerId()) { // TODO security check (userid exists/valid ?) $issue->setHandler($handlerId); } $defaultProjectid = $issue->getProjectId(); } // Don't show job and duration after add track $job = 0; $duration = 0; } elseif ("deleteTrack" == $action) { $trackid = Tools::getSecurePOSTIntValue('trackid'); $timeTrack = TimeTrackCache::getInstance()->getTimeTrack($trackid); $defaultBugid = $timeTrack->getIssueId(); $duration = $timeTrack->getDuration(); $job = $timeTrack->getJobId(); $defaultDate = date("Y-m-d", $timeTrack->getDate()); // delete track if (!$timeTrack->remove()) { $this->smartyHelper->assign('error', T_("Failed to delete the timetrack !")); self::$logger->error("Delete track {$trackid} : FAILED."); } if (0 == $defaultBugid) { self::$logger->error("Delete track : bug_id=0"); $defaultProjectid = 0; } else { try { // pre-set form fields $issue = IssueCache::getInstance()->getIssue($defaultBugid); $defaultProjectid = $issue->getProjectId(); // if project not defined for current team, do not pre-set form fields. if (!in_array($defaultProjectid, array_keys($team->getProjects()))) { $defaultProjectid = 0; $defaultBugid = 0; } } catch (Exception $e) { $defaultProjectid = 0; $defaultBugid = 0; } } } elseif ("setBugId" == $action) { // pre-set form fields // find ProjectId to update categories $defaultBugid = Tools::getSecurePOSTIntValue('bugid'); $issue = IssueCache::getInstance()->getIssue($defaultBugid); $defaultProjectid = $issue->getProjectId(); } elseif ("setFiltersAction" == $action) { $isFilter_onlyAssignedTo = isset($_POST["cb_onlyAssignedTo"]) ? '1' : '0'; $isFilter_hideResolved = isset($_POST["cb_hideResolved"]) ? '1' : '0'; $managed_user->setTimetrackingFilter('onlyAssignedTo', $isFilter_onlyAssignedTo); $managed_user->setTimetrackingFilter('hideResolved', $isFilter_hideResolved); if ($defaultBugid != 0) { $issue = IssueCache::getInstance()->getIssue($defaultBugid); $defaultProjectid = $issue->getProjectId(); } } // Display user name $this->smartyHelper->assign('managedUser_realname', $managed_user->getRealname()); $this->smartyHelper->assign('userid', $managed_userid); // display Track Form $this->smartyHelper->assign('date', $defaultDate); // All projects except disabled $projList = $team->getProjects(true, false); $this->smartyHelper->assign('projects', SmartyTools::getSmartyArray($projList, $defaultProjectid)); $this->smartyHelper->assign('defaultProjectid', $defaultProjectid); $this->smartyHelper->assign('defaultBugid', $defaultBugid); $this->smartyHelper->assign('weekid', $weekid); $this->smartyHelper->assign('year', $year); $isOnlyAssignedTo = '0' == $managed_user->getTimetrackingFilter('onlyAssignedTo') ? false : true; $this->smartyHelper->assign('isOnlyAssignedTo', $isOnlyAssignedTo); $isHideResolved = '0' == $managed_user->getTimetrackingFilter('hideResolved') ? false : true; $this->smartyHelper->assign('isHideResolved', $isHideResolved); $availableIssues = TimeTrackingTools::getIssues($this->teamid, $defaultProjectid, $isOnlyAssignedTo, $managed_user->getId(), $projList, $isHideResolved, $defaultBugid); $this->smartyHelper->assign('issues', $availableIssues); $this->smartyHelper->assign('jobs', SmartyTools::getSmartyArray(TimeTrackingTools::getJobs($defaultProjectid, $this->teamid), $job)); $this->smartyHelper->assign('duration', SmartyTools::getSmartyArray(TimeTrackingTools::getDurationList($this->teamid), $duration)); $this->smartyHelper->assign('weeks', SmartyTools::getWeeks($weekid, $year)); $this->smartyHelper->assign('years', SmartyTools::getYears($year, 1)); $weekDates = Tools::week_dates($weekid, $year); $startTimestamp = $weekDates[1]; $endTimestamp = mktime(23, 59, 59, date("m", $weekDates[7]), date("d", $weekDates[7]), date("Y", $weekDates[7])); $timeTracking = new TimeTracking($startTimestamp, $endTimestamp, $this->teamid); $incompleteDays = array_keys($timeTracking->checkCompleteDays($managed_userid, TRUE)); $missingDays = $timeTracking->checkMissingDays($managed_userid); $errorDays = array_merge($incompleteDays, $missingDays); $smartyWeekDates = TimeTrackingTools::getSmartyWeekDates($weekDates, $errorDays); // UTF8 problems in smarty, date encoding needs to be done in PHP $this->smartyHelper->assign('weekDates', array($smartyWeekDates[1], $smartyWeekDates[2], $smartyWeekDates[3], $smartyWeekDates[4], $smartyWeekDates[5])); $this->smartyHelper->assign('weekEndDates', array($smartyWeekDates[6], $smartyWeekDates[7])); $weekTasks = TimeTrackingTools::getWeekTask($weekDates, $this->teamid, $managed_userid, $timeTracking, $errorDays); $this->smartyHelper->assign('weekTasks', $weekTasks["weekTasks"]); $this->smartyHelper->assign('dayTotalElapsed', $weekTasks["totalElapsed"]); $timeTrackingTuples = $this->getTimetrackingTuples($managed_userid, $timeTracking); $this->smartyHelper->assign('weekTimetrackingTuples', $timeTrackingTuples['current']); $this->smartyHelper->assign('timetrackingTuples', $timeTrackingTuples['future']); // ConsistencyCheck $consistencyErrors = $this->getConsistencyErrors($managed_userid, $this->teamid); if (count($consistencyErrors) > 0) { $this->smartyHelper->assign('ccheckErrList', $consistencyErrors); $this->smartyHelper->assign('ccheckButtonTitle', count($consistencyErrors) . ' ' . T_("Errors")); $this->smartyHelper->assign('ccheckBoxTitle', count($consistencyErrors) . ' ' . T_("days are incomplete or undefined")); } $this->smartyHelper->assign('isForbidAddTimetracksOnClosed', 1 == $team->getGeneralPreference('forbidAddTimetracksOnClosed') ? true : false); } } }