public function execute() { $action = JobAction::newFromContext($this->getContext()); $action->doAction(); $this->setAction($action); $this->content = $this->initContent(); }
/** * @param string|bool $name */ protected function getActiveClients($name = false) { $context = $this->getContext(); $db = $context->getDB(); $nameQuery = $name ? 'AND name = \'' . $db->strEncode($name) . '\'' : ''; $results = array(); $rows = $db->getRows(str_queryf("SELECT\n\t\t\t\tid,\n\t\t\t\tname,\n\t\t\t\tuseragent,\n\t\t\t\tupdated,\n\t\t\t\tcreated\n\t\t\tFROM\n\t\t\t\tclients\n\t\t\tWHERE updated >= %s\n\t\t\t{$nameQuery}\n\t\t\tORDER BY created DESC;", swarmdb_dateformat(Client::getMaxAge($context)))); if ($rows) { foreach ($rows as $row) { $bi = BrowserInfo::newFromContext($this->getContext(), $row->useragent); $resultRow = $db->getRow(str_queryf('SELECT id, run_id, client_id, status, total, fail, error, updated, created FROM runresults WHERE client_id = %u ORDER BY created DESC LIMIT 1;', $row->id)); $client = array('id' => $row->id, 'name' => $row->name, 'uaID' => $bi->getSwarmUaID(), 'uaRaw' => $bi->getRawUA(), 'uaData' => $bi->getUaData(), 'viewUrl' => swarmpath("client/{$row->id}"), 'lastResult' => !$resultRow ? null : array('id' => intval($resultRow->id), 'viewUrl' => swarmpath("result/{$resultRow->id}"), 'status' => JobAction::getRunresultsStatus($resultRow))); self::addTimestampsTo($client, $row->created, 'connected'); self::addTimestampsTo($client, $row->updated, 'pinged'); $results[$row->id] = $client; } } return $results; }
/** * @actionParam string sort: [optional] What to sort the results by. * Must be one of "title", "id" or "creation". Defaults to "title". * @actionParam string sort_dir: [optional] * Must be one of "asc" (ascending) or "desc" (decending). Defaults to "asc". */ public function doAction() { $db = $this->getContext()->getDB(); $request = $this->getContext()->getRequest(); $sortField = $request->getVal('sort', 'title'); $sortDir = $request->getVal('sort_dir', 'asc'); if (!in_array($sortField, array('title', 'id', 'creation'))) { $this->setError('invalid-input', "Unknown sort `{$sortField}`."); return; } if (!in_array($sortDir, array('asc', 'desc'))) { $this->setError('invalid-input', "Unknown sort direction `{$sortDir}`."); return; } $sortDirQuery = ''; switch ($sortDir) { case 'asc': $sortDirQuery = 'ASC'; break; case 'desc': $sortDirQuery = 'DESC'; break; } $sortFieldQuery = ''; switch ($sortField) { case 'title': $sortFieldQuery = "ORDER BY display_title {$sortDirQuery}"; break; case 'id': $sortFieldQuery = "ORDER BY id {$sortDirQuery}"; break; case 'creation': $sortFieldQuery = "ORDER BY created {$sortDirQuery}"; break; } $projects = array(); $projectRows = $db->getRows("SELECT\n\t\t\t\tid,\n\t\t\t\tdisplay_title,\n\t\t\t\tcreated\n\t\t\tFROM projects\n\t\t\t{$sortFieldQuery};"); if ($projectRows) { foreach ($projectRows as $projectRow) { // Get information about the latest job (if any) $jobRow = $db->getRow(str_queryf('SELECT id FROM jobs WHERE project_id = %s ORDER BY id DESC LIMIT 1;', $projectRow->id)); if (!$jobRow) { $job = false; } else { $jobAction = JobAction::newFromContext($this->getContext()->createDerivedRequestContext(array('item' => $jobRow->id))); $jobAction->doAction(); $job = $jobAction->getData(); } $project = array('id' => $projectRow->id, 'displayTitle' => $projectRow->display_title, 'job' => $job); self::addTimestampsTo($project, $projectRow->created, 'created'); $projects[] = $project; } } $this->setData($projects); }
/** * @actionParam int item: Runresults ID. */ public function doAction() { $context = $this->getContext(); $db = $context->getDB(); $conf = $context->getConf(); $request = $context->getRequest(); $item = $request->getInt('item'); $row = $db->getRow(str_queryf('SELECT id, run_id, client_id, status, updated, created, result_url, build_url FROM runresults WHERE id = %u;', $item)); if (!$row) { $this->setError('invalid-input', 'Runresults ID not found.'); return; } $data = array(); $data['result_url'] = $row->result_url; $data['build_url'] = $row->build_url; // A job can be deleted without nuking the runresults, // this is by design so results stay permanently accessible // under a simple url. // If the job is no longer in existance, properties // 'otherRuns' and 'job' will be set to null. $runRow = $db->getRow(str_queryf('SELECT id, url, name, job_id FROM runs WHERE id = %u;', $row->run_id)); if (!$runRow) { $data['otherRuns'] = null; $data['job'] = null; } else { $data['otherRuns'] = JobAction::getDataFromRunRows($context, array($runRow)); $jobID = intval($runRow->job_id); $data['job'] = array('id' => $jobID, 'url' => swarmpath("job/{$jobID}", "fullurl")); } $clientRow = $db->getRow(str_queryf('SELECT id, name, useragent_id, useragent FROM clients WHERE id = %u;', $row->client_id)); $data['info'] = array('id' => intval($row->id), 'runID' => intval($row->run_id), 'clientID' => intval($row->client_id), 'status' => self::getStatus($row->status)); $data['client'] = array('id' => $clientRow->id, 'name' => $clientRow->name, 'uaID' => $clientRow->useragent_id, 'uaRaw' => $clientRow->useragent, 'viewUrl' => swarmpath('client/' . $clientRow->id)); // If still busy or if the client was lost, then the last update time is irrelevant // Alternatively this could test if $row->updated == $row->created, which would effectively // do the same. if ($row->status == self::$STATE_BUSY || $row->status == self::$STATE_LOST) { $data['info']['runTime'] = null; } else { $data['info']['runTime'] = gmstrtotime($row->updated) - gmstrtotime($row->created); self::addTimestampsTo($data['info'], $row->updated, 'saved'); } self::addTimestampsTo($data['info'], $row->created, 'started'); $this->setData($data); }
public function doAction() { $db = $this->getContext()->getDB(); $request = $this->getContext()->getRequest(); $userName = $request->getVal("item"); if (!$userName) { $this->setError("missing-parameters"); return; } $userID = $db->getOne(str_queryf("SELECT id FROM users WHERE name = %s;", $userName)); $userID = intval($userID); if (!$userID) { $this->setError("invalid-input", "User does not exist"); return; } $uaIndex = BrowserInfo::getSwarmUAIndex(); // Active clients $activeClients = array(); $clientRows = $db->getRows(str_queryf("SELECT\n\t\t\t\tuseragent_id,\n\t\t\t\tuseragent,\n\t\t\t\tcreated\n\t\t\tFROM\n\t\t\t\tclients\n\t\t\tWHERE user_id = %u\n\t\t\tAND updated > %s\n\t\t\tORDER BY created DESC;", $userID, swarmdb_dateformat(strtotime("1 minutes ago")))); if ($clientRows) { foreach ($clientRows as $clientRow) { $bi = BrowserInfo::newFromContext($this->getContext(), $clientRow->useragent); $activeClient = array("uaID" => $clientRow->useragent_id, "uaRaw" => $bi->getRawUA(), "uaData" => $bi->getSwarmUaItem(), "uaBrowscap" => $bi->getBrowscap()); self::addTimestampsTo($activeClient, $clientRow->created, "connected"); $activeClients[] = $activeClient; } } // Recent jobs $recentJobs = array(); // List of all user agents used in recent jobs // This is as helper allow creating proper gaps when iterating // over jobs. $userAgents = array(); $jobRows = $db->getRows(str_queryf("SELECT\n\t\t\t\tid,\n\t\t\t\tname\n\t\t\tFROM\n\t\t\t\tjobs\n\t\t\tWHERE jobs.user_id = %u\n\t\t\tORDER BY jobs.created DESC\n\t\t\tLIMIT 15;", $userID)); if ($jobRows) { $uaRunStatusStrength = array_flip(array("passed", "new", "progress", "failed", "timedout", "error")); foreach ($jobRows as $jobRow) { $jobID = intval($jobRow->id); $jobActionContext = $this->getContext()->createDerivedRequestContext(array("action" => "job", "item" => $jobID), "GET"); $jobAction = JobAction::newFromContext($jobActionContext); $jobAction->doAction(); if ($jobAction->getError()) { $this->setError($jobAction->getError()); return; } $jobActionData = $jobAction->getData(); // Add user agents array of this job to the overal user agents list. // php array+ automatically fixes clashing keys. The values are always the same // so it doesn't matter whether or not it overwrites. $userAgents += $jobActionData["userAgents"]; // The summerized status for each user agent run // of this job. e.g. if all are new except one, // then it will be on "progress", if all are complete // then the worst failure is put in the summary $uaSummary = array(); $uaNotNew = array(); $uaHasIncomplete = array(); $uaStrongestStatus = array(); foreach ($jobActionData["runs"] as $run) { foreach ($run["uaRuns"] as $uaID => $uaRun) { if ($uaRun["runStatus"] !== "new" && !in_array($uaID, $uaNotNew)) { $uaNotNew[] = $uaID; } if ($uaRun["runStatus"] === "new" || $uaRun["runStatus"] === "progress") { if (!in_array($uaID, $uaHasIncomplete)) { $uaHasIncomplete[] = $uaID; } } if (!isset($uaStrongestStatus[$uaID]) || $uaRunStatusStrength[$uaRun["runStatus"]] > $uaRunStatusStrength[$uaStrongestStatus[$uaID]]) { $uaStrongestStatus[$uaID] = $uaRun["runStatus"]; } $uaSummary[$uaID] = !in_array($uaID, $uaNotNew) ? "new" : (in_array($uaID, $uaHasIncomplete) ? "progress" : $uaStrongestStatus[$uaID]); } } $recentJobs[] = array("id" => $jobID, "name" => $jobRow->name, "url" => swarmpath("job/{$jobID}", "fullurl"), "uaSummary" => $uaSummary); } } natcaseksort($userAgents); $this->setData(array("userName" => $userName, "activeClients" => $activeClients, "recentJobs" => $recentJobs, "uasInJobs" => $userAgents)); }
/** * @actionParam int item: Runresults ID. */ public function doAction() { $context = $this->getContext(); $db = $context->getDB(); $conf = $context->getConf(); $request = $context->getRequest(); $resultsID = $request->getInt('item'); $row = $db->getRow(str_queryf('SELECT run_id, client_id, status, error, total, fail, updated, created, report_html_size, LENGTH( report_html ) as \'compressed_size\' FROM runresults WHERE id = %u;', $resultsID)); if (!$row) { $this->setError('invalid-input', 'Runresults ID not found.'); return; } $data = array(); // A job can be deleted without nuking the runresults, // this is by design so results stay permanently accessible // under a simple url. // If the job is no longer in existance, properties // 'otherRuns' and 'job' will be set to null. $runRows = $db->getRows(str_queryf('SELECT id, url, name, job_id FROM runs WHERE id = %u;', $row->run_id)); if (!$runRows || !count($runRows)) { $data['otherRuns'] = null; $data['job'] = null; } else { $data['otherRuns'] = JobAction::getDataFromRunRows($db, $runRows); $jobID = intval($runRows[0]->job_id); $data['job'] = array('id' => $jobID, 'url' => swarmpath("job/{$jobID}", "fullurl")); } $clientRow = $db->getRow(str_queryf('SELECT id, user_id, useragent_id, useragent, device_name FROM clients WHERE id = %u;', $row->client_id)); $userRow = $db->getRow(str_queryf('SELECT id, name FROM users WHERE id = %u;', $clientRow->user_id)); $data['client'] = array('id' => $clientRow->id, 'uaID' => $clientRow->useragent_id, 'userAgent' => $clientRow->useragent, 'deviceName' => $clientRow->device_name, 'userID' => $userRow->id, 'userName' => $userRow->name, 'userUrl' => swarmpath('user/' . $userRow->name)); $data['resultInfo'] = array('id' => $resultsID, 'runID' => $row->run_id, 'fail' => $row->fail, 'total' => $row->total, 'error' => $row->error, 'clientID' => $row->client_id, 'status' => self::getStatus($row->status), 'reportHtmlSize' => $row->report_html_size, 'reportHtmlCompressedSize' => $row->compressed_size, 'reportHtmlCompressionRatio' => $row->report_html_size == 0 ? 0 : round(($row->report_html_size - $row->compressed_size) / $row->report_html_size * 100 / 1, 2)); // If still busy or if the client was lost, then the last update time is irrelevant // Alternatively this could test if $row->updated == $row->created, which would effectively // do the same. if ($row->status == self::$STATE_BUSY || $row->status == self::$STATE_LOST) { $data['resultInfo']['runTime'] = null; } else { $data['resultInfo']['runTime'] = gmstrtotime($row->updated) - gmstrtotime($row->created); self::addTimestampsTo($data['resultInfo'], $row->updated, 'saved'); } self::addTimestampsTo($data['resultInfo'], $row->created, 'started'); $this->setData($data); }
/** * @actionParam string item: Client id. */ public function doAction() { $context = $this->getContext(); $db = $context->getDB(); $request = $context->getRequest(); $item = $request->getInt('item'); if (!$item) { $this->setError('missing-parameters'); return; } // Client information $row = $db->getRow(str_queryf('SELECT id, name, useragent, updated, created FROM clients WHERE id = %u;', $item)); if (!$row) { $this->setError('invalid-input', 'Client not found'); return; } $bi = BrowserInfo::newFromContext($context, $row->useragent); $info = array('id' => intval($row->id), 'name' => $row->name, 'viewUrl' => swarmpath("clients/{$row->name}"), 'uaID' => $bi->getSwarmUaID(), 'uaRaw' => $bi->getRawUA(), 'uaData' => $bi->getUaData(), 'sessionAge' => gmstrtotime($row->updated) - gmstrtotime($row->created)); self::addTimestampsTo($info, $row->created, 'connected'); self::addTimestampsTo($info, $row->updated, 'pinged'); // Run results $results = array(); $rows = $db->getRows(str_queryf('SELECT id, run_id, client_id, status, total, fail, error, updated, created FROM runresults WHERE client_id = %u ORDER BY created DESC;', $item)); if ($rows) { foreach ($rows as $row) { $runRow = $jobRow = false; $result = array('id' => intval($row->id), 'viewUrl' => swarmpath("result/{$row->id}"), 'status' => JobAction::getRunresultsStatus($row)); $runRow = $db->getRow(str_queryf('SELECT name, job_id FROM runs WHERE id = %u;', $row->run_id)); if ($runRow) { $jobRow = $db->getRow(str_queryf('SELECT id, name, project_id FROM jobs WHERE id = %u', $runRow->job_id)); if ($jobRow) { $projectRow = $db->getRow(str_queryf('SELECT display_title FROM projects WHERE id = %s;', $jobRow->project_id)); $result['job'] = array('nameText' => strip_tags($jobRow->name), 'viewUrl' => swarmpath("job/{$jobRow->id}")); $result['run'] = array('name' => $runRow->name); $result['project'] = array('id' => $jobRow->project_id, 'display_title' => $projectRow->display_title, 'viewUrl' => swarmpath("project/{$jobRow->project_id}")); } } // Runs and jobs could be deleted, results are preserved. if (!$jobRow) { $result['job'] = null; $result['run'] = null; $result['project'] = null; } $results[] = $result; } } $this->setData(array('info' => $info, 'results' => $results)); }
/** * @actionParam string item: Project ID. */ public function doAction() { $conf = $this->getContext()->getConf(); $db = $this->getContext()->getDB(); $request = $this->getContext()->getRequest(); $projectID = $request->getVal('item'); if (!$projectID) { $this->setError('missing-parameters'); return; } // Note: The job list is reverse chronologic (descending). // To query the "next" page, you get the jobs with an id // that is lower than the last entry on the current page. // Parameters for navigation of job list in this project $dir = $request->getVal('dir', ''); $offset = $request->getInt('offset'); $limit = $request->getInt('limit', $this->defaultLimit); if (!in_array($dir, array('', 'back')) || $limit < 1 || $limit > 100) { $this->setError('invalid-input'); return; } // Get project info $projectRow = $db->getRow(str_queryf('SELECT id, display_title, site_url, updated, created FROM projects WHERE id = %s;', $projectID)); if (!$projectRow) { $this->setError('invalid-input', 'Project does not exist'); return; } $conds = ''; if ($offset) { if ($dir === 'back') { $conds = 'AND id > ' . intval($offset); } else { $conds = 'AND id < ' . intval($offset); } } // Get list of jobs $jobRows = $db->getRows(str_queryf('SELECT id, name FROM jobs WHERE project_id = %s ' . $conds . ' ORDER BY id ' . ($dir === 'back' ? 'ASC' : 'DESC') . ' LIMIT %u;', $projectID, $limit + 1)); $jobs = array(); // List of all user agents used in recent jobs // This is as helper to allow easy creation of placeholder gaps in a UI // when iterating over jobs, because not all jobs have the same user agents. $userAgents = array(); if (!$jobRows) { $pagination = array(); } else { $pagination = $this->getPaginationData($dir, $offset, $limit, $jobRows, $projectID); if ($dir === 'back') { $jobRows = array_reverse($jobRows); } foreach ($jobRows as $jobRow) { $jobID = intval($jobRow->id); $jobAction = JobAction::newFromContext($this->getContext()->createDerivedRequestContext(array('item' => $jobID))); $jobAction->doAction(); if ($jobAction->getError()) { $this->setError($jobAction->getError()); return; } $jobActionData = $jobAction->getData(); // Add user agents array of this job to the overal user agents list. // php array+ automatically fixes clashing keys. The values are always the same // so it doesn't matter whether or not it overwrites. $userAgents += $jobActionData['userAgents']; $jobs[] = array('info' => $jobActionData['info'], 'name' => $jobRow->name, 'summaries' => $jobActionData['uaSummaries']); } } uasort($userAgents, 'BrowserInfo::sortUaData'); $projectInfo = (array) $projectRow; unset($projectInfo['updated'], $projectInfo['created']); self::addTimestampsTo($projectInfo, $projectRow->updated, 'updated'); self::addTimestampsTo($projectInfo, $projectRow->created, 'created'); $this->setData(array('info' => $projectInfo, 'jobs' => $jobs, 'pagination' => $pagination, 'userAgents' => $userAgents)); }