diff options
Diffstat (limited to 'site/app/controllers/editors_controller.php')
-rw-r--r-- | site/app/controllers/editors_controller.php | 1054 |
1 files changed, 197 insertions, 857 deletions
diff --git a/site/app/controllers/editors_controller.php b/site/app/controllers/editors_controller.php index 3a97e51..314f2ef 100644 --- a/site/app/controllers/editors_controller.php +++ b/site/app/controllers/editors_controller.php @@ -23,8 +23,6 @@ * Wil Clouser <clouserw@gmail.com> * Frederic Wenzel <fwenzel@mozilla.com> * Les Orchard <lorchard@mozilla.com> - * Cesar Oliveira <a.sacred.line@gmail.com> - * Scott McCammon <smccammon@mozilla.com> * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -56,7 +54,6 @@ class EditorsController extends AppController function beforeFilter() { //beforeFilter() is apparently called before components are initialized. Cake++ $this->Amo->startup($this); - $this->Editors->startup($this); $this->Amo->checkLoggedIn(); @@ -67,10 +64,7 @@ class EditorsController extends AppController $this->publish('cssAdd', $this->cssAdd); $this->publish('jsAdd', array('jquery-compressed.js', - 'jquery.autocomplete.pack.js', - 'jquery.tablesorter.min.js', - 'jquery.flot.js', - 'jquery.sparkline.min.js', + 'jquery.autocomplete.js', 'editors')); $this->breadcrumbs = array(_('editors_pagetitle') => '/editors/index'); @@ -85,10 +79,16 @@ class EditorsController extends AppController } //Get counts - $count['pending'] = $this->_getCount('pending'); - $count['nominated'] = $this->_getCount('nominated'); - $count['reviews'] = $this->_getCount('reviews'); + $pending = $this->File->query("SELECT COUNT(*) FROM `files` WHERE `status`=".STATUS_PENDING." GROUP BY `status`"); + $nominated = $this->Addon->query("SELECT COUNT(*) FROM `addons` WHERE `status`=".STATUS_NOMINATED." GROUP BY `status`"); + $reviews = $this->Review->query("SELECT COUNT(*) FROM `reviews` WHERE `editorreview`=1 GROUP BY `editorreview`"); + + $count['pending'] = !empty($pending) ? $pending[0][0]['COUNT(*)'] : 0; + $count['nominated'] = !empty($nominated) ? $nominated[0][0]['COUNT(*)'] : 0; + $count['reviews'] = !empty($reviews) ? $reviews[0][0]['COUNT(*)'] : 0; $this->publish('count', $count); + + $this->count = $count; } /** @@ -143,6 +143,8 @@ class EditorsController extends AppController $this->publish('collapse_categories', true); + $count = $this->count; + $this->Amo->clean($mode); $this->breadcrumbs[_('editors_review_queue_pagetitle')] = '/editors/queue'; $this->publish('breadcrumbs', $this->breadcrumbs); @@ -150,38 +152,72 @@ class EditorsController extends AppController $this->publish('mode', $mode); - // Setup queue filter - if (array_key_exists('filter', $this->params['form'])) { - // set a new filter on this queue - $filter = $this->Editors->setQueueFilter($mode, $this->data['Filter']); - - } elseif (array_key_exists('clear', $this->params['form'])) { - // clear existing filter on this queue - $filter = $this->Editors->setQueueFilter($mode, null); - - // clear sorting - $this->Editors->setQueueSort($mode, 'default'); - - } else { - // fetch existing filter - $filter = $this->Editors->getQueueFilter($mode); - } + if ($mode == 'pending') { + // Setup our pagination + $this->Pagination->total = $count['pending']; + $_pagination_options = array('sortByClass' => 'Version', 'sortBy' => 'created'); - // Handle changes to sorting - if (isset($this->params['url']['sort'])) { - if (isset($this->params['url']['dir'])) { - $this->Editors->setQueueSort($mode, $this->params['url']['sort'], $this->params['url']['dir']); + if (!array_key_exists('show', $_GET) && $this->Session->read('editor_queue_pending_show')) { + $_pagination_options['show'] = $this->Session->read('editor_queue_pending_show'); + } else { + // If $_GET['show'] exists it overrides this in the pagination component + $_pagination_options['show'] = 50; + } + list($_order,$_limit,$_page) = $this->Pagination->init(null, null, $_pagination_options); + $this->Session->write('editor_queue_pending_show', $_limit); + + //Pull any files that have STATUS_PENDING + $pending = $this->File->findAllByStatus(STATUS_PENDING, + array('File.id', 'File.platform_id', 'Version.id', + 'Version.addon_id', 'Version.version', + 'Version.created' + ), $_order, $_limit, $_page, 0); + + if (!empty($pending)) { + foreach ($pending as $k => $file) { + $addon = $this->Addon->findById($file['Version']['addon_id'], + array('Addon.id', 'Addon.name', 'Addon.defaultlocale', + 'Addon.addontype_id', 'Addon.prerelease', + 'Addon.sitespecific', 'Addon.externalsoftware', + )); + $pending[$k] = array_merge_recursive($pending[$k], $addon); + } + } + $addons = $pending; + } + elseif ($mode == 'nominated') { + // Setup our pagination + $this->Pagination->total = $count['nominated']; + $_pagination_options = array('sortByClass' => 'Addon', 'sortBy' => 'created'); + if (!array_key_exists('show', $_GET) && $this->Session->read('editor_queue_nominated_show')) { + $_pagination_options['show'] = $this->Session->read('editor_queue_nominated_show'); } else { - $this->Editors->setQueueSort($mode, $this->params['url']['sort']); + // If $_GET['show'] exists it overrides this in the pagination component + $_pagination_options['show'] = 50; } - } + list($_order,$_limit,$_page) = $this->Pagination->init(null,null,$_pagination_options); + $this->Session->write('editor_queue_nominated_show', $_limit); - // Build the queue - if ($mode == 'pending' || $mode == 'nominated') { - $addons = $this->_buildQueue($mode); + //Pull any add-ons that have STATUS_NOMINATED + $nominated = $this->Addon->findAllByStatus(STATUS_NOMINATED, + array('Addon.id', 'Addon.name', 'Addon.defaultlocale', + 'Addon.addontype_id', 'Addon.prerelease', + 'Addon.sitespecific', 'Addon.externalsoftware', + 'Addon.created' + ), $_order, $_limit, $_page, 0); + if (!empty($nominated)) { + foreach ($nominated as $k => $addon) { + $version = $this->Version->findByAddon_id($addon['Addon']['id'], + array('Version.id', 'Version.addon_id', + 'Version.version', 'Version.modified' + ), 'Version.created DESC'); + $nominated[$k] = array_merge_recursive($nominated[$k], $version); + } + } + $addons = $nominated; } elseif ($mode == 'reviews') { - $this->_reviews($this->_getCount('reviews')); + $this->_reviews($count['reviews']); return; } else { @@ -189,56 +225,141 @@ class EditorsController extends AppController return; } - //Setup filter form fields - $selected = array('Application'=>'', 'MaxVersion'=>'', - 'SubmissionAge'=>'', 'Addontype'=>'', 'Platform'=>'',); - if (is_array($filter)) { - foreach ($filter as $k => $val) { - if (array_key_exists($k, $selected)) { - $selected[$k] = $val; + $platforms = $this->Amo->getPlatformName(); + $applications = $this->Amo->getApplicationName(); + + $submissionTypes = array( 'new' => _('editors_submissiontype_new'), + 'updated' => _('editors_submissiontype_updated') + ); + + //make modifications to the queue array + if (!empty($addons)) { + foreach ($addons as $k => $addon) { + //get min/max versions + if ($targetApps = $this->Amo->getMinMaxVersions($addon['Version']['id'])) { + foreach ($targetApps as $targetApp) { + $appName = $targetApp['translations']['localized_string']; + $addons[$k]['targetApps'][$appName]['min'] = $targetApp['min']['version']; + $addons[$k]['targetApps'][$appName]['max'] = $targetApp['max']['version']; + } + } + + //Age + if ($mode == 'pending') { + $age = time() - strtotime($addon['Version']['created']); + } + elseif ($mode == 'nominated') { + $age = time() - strtotime($addon['Addon']['created']); + } + + //days + if ($age >= (60*60*24*2)) { + $addons[$k]['age'] = sprintf(_('editors_x_days'), floor($age/(60*60*24))); + } + //1 day + elseif ($age >= (60*60*24)) { + $addons[$k]['age'] = _('editors_one_day'); + } + //hours + elseif ($age >= (60*60*2)) { + $addons[$k]['age'] = sprintf(_('editors_x_hours'), floor($age/(60*60))); + } + //hour + elseif ($age >= (60*60)) { + $addons[$k]['age'] = _('editors_one_hour'); + } + //minutes + elseif ($age > 60) { + $addons[$k]['age'] = sprintf(_('editors_x_minutes'), floor($age/60)); + } + //minute + else { + $addons[$k]['age'] = _('editors_one_minute'); + } + + //Generate any additional notes + $addons[$k]['notes'] = array(); + + //Platform-specific? + if (!empty($addon['Version'][0]['File'][0]['platform_id']) && $addon['Version'][0]['File'][0]['platform_id'] != 1) { + $os = array(); + foreach ($addon['Version'][0]['File'] as $file) { + $os[] = $platforms[$file['platform_id']]; + } + $addons[$k]['notes'][] = sprintf(_('editors_platform_x_only'), implode(', ', $os)); + } + elseif (!empty($addon['File']['platform_id']) && $addon['File']['platform_id'] != 1) { + $addons[$k]['notes'][] = sprintf(_('editors_platform_x_only'), $platforms[$addon['File']['platform_id']]); + } + + //Featured? + //@TODO + + //Site specific? + if ($addon['Addon']['sitespecific'] == 1) { + $addons[$k]['notes'][] = _('editors_site_specific'); + } + //Pre-release? + if ($addon['Addon']['prerelease'] == 1) { + $addons[$k]['notes'][] = _('editors_pre-release'); + } + //External software? + if ($addon['Addon']['externalsoftware'] == 1) { + $addons[$k]['notes'][] = _('editors_external_software'); } } } - - $addonOrAuthor = isset($filter['AddonOrAuthor']) ? $filter['AddonOrAuthor'] : ''; - - $maxVersions = array(); - if (!empty($filter['Application'])) { - $app_versions = $this->Appversion->findAllByApplicationId($filter['Application'], - array('Appversion.id', 'Appversion.version'), 'Appversion.version DESC'); - foreach ($app_versions as $av) { - $maxVersions[$av['Appversion']['id']] = $av['Appversion']['version']; + //pr($addons); + //Filters + $selected = array( 'Addontype' => array(), + 'Application' => array(), + 'Platform' => array(), + 'SubmissionType' => array() + ); + $filtered = false; + + if (!empty($this->data['Approval']['Addontype'])) { + foreach ($this->data['Approval']['Addontype'] as $option) { + $selected['Addontype'][$option] = true; } + $filtered = true; } - $submissionAges = array('1' => '1', '2' => '2', '3' => '3', '4' => '4', '5' => '5', - '6' => '6', '7' => '7', '8' => '8', '9' => '9', '10+' => '10+'); - $platforms = $this->Amo->getPlatformName(); - $applications = $this->Amo->getApplicationName(); - - $filtered = !empty($filter); - $filterChanged = $filtered && array_key_exists('filter', $this->params['form']); - $filteredCount = $this->_getCount($mode, true); - - $sortOpts = $this->Editors->getQueueSort($mode); + if (!empty($this->data['Approval']['Application'])) { + foreach ($this->data['Approval']['Application'] as $option) { + $selected['Application'][$option] = true; + } + $filtered = true; + } - // raw values for selectTags - $this->set('selected', $selected); + if (!empty($this->data['Approval']['Platform'])) { + foreach ($this->data['Approval']['Platform'] as $option) { + $selected['Platform'][$option] = true; + } + $filtered = true; + } + + if (!empty($this->data['Approval']['SubmissionType'])) { + foreach ($this->data['Approval']['SubmissionType'] as $option) { + $selected['SubmissionType'][$option] = true; + } + $filtered = true; + } + + if (isset($this->data['filter'])) { + $filtered = true; + } + elseif (isset($this->data['clear'])) { + $filtered = false; + } + + $this->publish('addons', $addons); $this->set('platforms', $platforms); $this->set('addontypes', $this->Addontype->getNames()); $this->set('applications', $applications); - $this->set('maxVersions', $maxVersions); - $this->set('submissionAges', $submissionAges); - - $this->publish('addonOrAuthor', $addonOrAuthor); + $this->set('submissionTypes', $submissionTypes); + $this->publish('selected', $selected); $this->publish('filtered', $filtered); - $this->publish('filterChanged', $filterChanged); - $this->publish('filteredCount', $filteredCount); - $this->publish('sortBy', $sortOpts['sortby']); - $this->publish('sortDir', $sortOpts['direction']); - - $this->publish('mode', $mode); - $this->publish('addons', $addons); $this->render('queue'); } @@ -303,8 +424,6 @@ class EditorsController extends AppController } } - $this->pageTitle = $addon['Translation']['name']['string'] . ' :: ' . $this->pageTitle; - if (!empty($addon['Tag'])) { foreach ($addon['Tag'] as $tag) { $tags[] = $tag['id']; @@ -375,10 +494,6 @@ class EditorsController extends AppController } else { $reviewType = 'pending'; } - - // count of filtered queue - $filtered = (true && $this->Editors->getQueueFilter($reviewType)); - $filteredCount = $this->_getCount($reviewType, true); // rank in nomination/update queue if (isset($this->params['url']['num']) && is_numeric($this->params['url']['num'])) @@ -397,8 +512,6 @@ class EditorsController extends AppController $this->publish('history', $history); $this->publish('errors', $this->Error->errors); $this->publish('reviewType', $reviewType, false); - $this->publish('filtered', $filtered); - $this->publish('filteredCount', $filteredCount); $this->render('review'); } @@ -408,7 +521,7 @@ class EditorsController extends AppController * @param int $id The file id */ function file($id) { - $this->Amo->clean($id); + $this->Amo->clean($id); $this->File->id = $id; if (!$file = $this->File->read()) { @@ -434,698 +547,6 @@ class EditorsController extends AppController } exit; } - - - /** - * Performance reports jump off point - * Handles report selection, and user parameter - */ - function performance($mode = '') { - $session = $this->Session->read('User'); - if (!$this->SimpleAcl->actionAllowed('Editor', '*', $session)) { - $this->Amo->accessDenied(); - } - - //Senior Editors can generate reports on anyone - $isSenior = $this->SimpleAcl->actionAllowed('Admin', 'EditAnyAddon', $session); - if ($isSenior && !empty($this->params['url']['user'])) { - $user = $this->User->findByEmail($this->params['url']['user']); - if (empty($user)) { - header('HTTP/1.1 404 Not Found'); - $this->flash(___('editors_performance_user_not_found', 'User not found'), "/editors/performance/{$mode}"); - return; - } - } else { - $user = $this->User->findById($session['id']); - } - - //Chart AJAX - // @TODO: enable this and make charts use ajax to load new data - if (false && $mode == 'chartData') { - $summary = !empty($this->params['url']['sum']) ? $this->params['url']['sum'] : ''; - - if ($summary == 'month') { - $data = $this->_performanceSummaryByMonth($user['User']['id'], 12); - } - elseif ($summary == 'cat') { - $year = null; - $month = null; - if (!empty($this->params['url']['year'])) { - $year = intval($this->params['url']['year']); - } - if (!empty($this->params['url']['month'])) { - $month = intval($this->params['url']['month']); - } - $data = $this->_performanceSummaryByCategory($user['User']['id'], $year, $month); - } - - $this->set('json', $data); - $this->render('ajax/json', 'ajax'); - return; - } - - // display name (or email if not set) - $userName = trim("{$user['User']['firstname']} {$user['User']['lastname']}"); - if ($userName == '') { - $userName = $user['User']['email']; - } - - $this->publish('mode', $mode); - $this->publish('user', $user); - $this->publish('userName', $userName); - $this->publish('showUserLookup', $isSenior); - $this->publish('editors', $isSenior ? $this->_recentEditors() : array()); - $this->publish('collapse_categories', false); - $this->publish('subpagetitle', ___('editors_performance_pagetitle', 'Performance Reports')); - $this->set('page', 'performance'); - - //Standard text report - if ($mode == '') { - $this->_performanceTable($user['User']['id']); - - //Charts - } elseif ($mode == 'charts') { - $this->_performanceCharts($user['User']['id']); - - } else { - $this->redirect('/editors/performance'); - } - return; - } - - - /** - * Generate a detailed performance report with weekly totals and team averages - * @param int $userId user to generate report for - */ - function _performanceTable($userId) { - // Initialize report data - $myApprovals = array(); - $myTotal = 0; - $teamTotal = 0; - $teamSize = 0; - $teamAverage = 0; - $weeklyTotals = array(); - $myMtdTotal = 0; - $teamMtdTotal = 0; - $teamMtdAverage = 0; - $myYtdTotal = 0; - $teamYtdTotal = 0; - $teamYtdSize = 0; - $teamYtdAverage = 0; - - //Default conditions are the current month - $ytdEndTime = strtotime('tomorrow'); - $startDate = date('Y-m-01'); - $startTime = strtotime($startDate); - $endDate = ___('editors_date_filter_placeholder', 'YYYY-MM-DD'); - $endTime = $ytdEndTime; - - //If user has specified own conditions, use those - if (!empty($this->params['url']['start'])) { - $ts = strtotime($this->params['url']['start']); - if ($ts !== false && $ts != -1) { - $startTime = $ts; - $startDate = $this->params['url']['start']; - } - } - if (!empty($this->params['url']['end'])) { - $ts = strtotime($this->params['url']['end']); - if ($ts !== false && $ts != -1) { - $endTime = strtotime('+1 day', $ts); - $endDate = $this->params['url']['end']; - } - } - - //Initialize weekly data - $week = array('from' => $startTime, - 'to' => min(strtotime('next Monday', $startTime), $endTime)-1, - 'myTotal' => 0, 'teamTotal' => 0, 'teamAverage' => 0); - while ($week['from'] < $endTime) { - $weeklyKey = $this->_makeYearWeekKey($week['from']); - $weeklyTotals[$weeklyKey] = $week; - - $week = array('from' => $week['to']+1, - 'to' => min(strtotime('+7 day', $week['to']), $endTime-1), - 'myTotal' => 0, 'teamTotal' => 0, 'teamAverage' => 0); - } - - //Fetch approvals over specified date range - $conditions = array("Approval.created >= FROM_UNIXTIME('{$startTime}')", - "Approval.created < FROM_UNIXTIME('{$endTime}')"); - - $order = '`Approval`.`created` ASC'; - if ($approvals = $this->Approval->findAll($conditions, null, $order)) { - foreach ($approvals as $k => $approval) { - $weeklyKey = $this->_makeYearWeekKey(strtotime($approval['Approval']['created'])); - if (!array_key_exists($weeklyKey, $weeklyTotals)) { - // this should never happen, but better to let there be obvious gaps in - // weekly totals than seemingly legit (but probably bogus) counts - continue; - } - - //Fetch addon details for approvals by the report user - if ($approval['User']['id'] == $userId) { - $approval['Addon'] = $this->Addon->getAddon($approval['Approval']['addon_id'], - array('list_details')); - $myApprovals[] = $approval; - $myTotal++; - $weeklyTotals[$weeklyKey]['myTotal']++; - } - $teamTotal++; - $weeklyTotals[$weeklyKey]['teamTotal']++; - } - } - - /* add formatting to aid in debugging - foreach ($weeklyTotals as $k => $w) { - $weeklyTotals[$k]['formatted'] = - date('Y-m-d H:i:s', $w['from']).' - '.date('Y-m-d H:i:s', $w['to']); - } - pr($weeklyTotals); /**/ - - // YTD and MTD calculations - $sql = "SELECT MONTH(`Approval`.`created`) AS `month`, `User`.`id`, COUNT(*) AS `total` - FROM `approvals` AS `Approval` - LEFT JOIN `users` AS `User` ON (`User`.`id`=`Approval`.`user_id`) - WHERE `Approval`.`created` >= '".date('Y')."-01-01 00:00:00' - AND `Approval`.`created` < FROM_UNIXTIME('{$ytdEndTime}') - GROUP BY `month`, `Approval`.`user_id`"; - if ($results = $this->Approval->query($sql)) { - $thisMonth = date('m'); - foreach ($results as $row) { - $teamYtdTotal += $row[0]['total']; - $teamMtdTotal += ($row[0]['month'] == $thisMonth) ? $row[0]['total'] : 0; - if ($row['User']['id'] == $userId) { - $myYtdTotal += $row[0]['total']; - $myMtdTotal += ($row[0]['month'] == $thisMonth) ? $row[0]['total'] : 0; - } - } - } - - //Calculate averages - $teamSize = $this->_teamSize($endTime); - if ($teamSize) { - $teamAverage = $teamTotal / $teamSize; - foreach ($weeklyTotals as $k => $week) { - $weeklyTotals[$k]['teamAverage'] = $week['teamTotal'] / $teamSize; - } - } - $teamYtdSize = $this->_teamSize($ytdEndTime); - if ($teamYtdSize) { - $teamYtdAverage = $teamYtdTotal / $teamYtdSize; - $teamMtdAverage = $teamMtdTotal / $teamYtdSize; - } - - // Publish and render - $this->publish('startDate', $startDate); - $this->publish('endDate', $endDate); - - $this->publish('addonTypes', $this->Addontype->getNames()); - $this->publish('myApprovals', $myApprovals); - $this->publish('myTotal', $myTotal); - $this->publish('teamAverage', $teamAverage); - $this->publish('weeklyTotals', $weeklyTotals); - $this->publish('myMtdTotal', $myMtdTotal); - $this->publish('teamMtdAverage', $teamMtdAverage); - $this->publish('myYtdTotal', $myYtdTotal); - $this->publish('teamYtdAverage', $teamYtdAverage); - - $this->render('performance_table'); - } - - - /** - * Generate charts showing yearly activity and category breakdowns - * @param int $userId user to generate report for - */ - function _performanceCharts($userId) { - $byMonthData = $this->_performanceSummaryByMonth($userId, 12); - $teamSize = $this->_teamSize(time()); - - // category breakdown can be for an entire year, or a specific - // month and year - $year = date('Y'); - $month = null; - if (!empty($this->params['url']['year'])) { - $year = intval($this->params['url']['year']); - } - if (!empty($this->params['url']['month'])) { - $month = intval($this->params['url']['month']); - } - $byCatData = $this->_performanceSummaryByCategory($userId, $year, $month); - - // points for x-axis labels (javascript) - $monthlyTicks = array(); - foreach ($byMonthData['labels'] as $i => $label) { - $this->_sanitizeArray($label); - $monthlyTicks[] = "[{$i},'{$label}']"; - } - - // points for user activity (javascript) - $userPoints = array(); - foreach ($byMonthData['usercount'] as $i => $n) { - $userPoints[] = "[{$i},{$n}]"; - } - - // points for team activity (javascript) - $teamPoints = array(); - foreach ($byMonthData['teamcount'] as $i => $n) { - $n = $n / $teamSize; - $teamPoints[] = "[{$i},{$n}]"; - } - - // pie chart color-scheme (javascript) - $sliceColors = array("'#6d746a'","'#205f9a'","'#3d8128'","'#63522b'", - "'#dc5313'","'#f3c01c'","'#bc1c39'"); - - // pie chart labels (javascript) - $sliceLabels = array(); - foreach ($byCatData['labels'] as $i => $label) { - $this->_sanitizeArray($label); - $sliceLabels[] = "'{$label}'"; - } - - // pie chart date title - if ($month) { - $pieTitleDate = strftime('%B %Y', mktime(12,0,0,$month,1,$year)); - } else { - $pieTitleDate = $year; - } - - // months for filter select - $monthSelect = array(''=>''); - for ($n = 1; $n<=12; $n++) { - $monthSelect[$n] = strftime('%B', mktime(12,0,0,$n,1)); - } - - $this->set('monthlyTicksJS', implode(',', $monthlyTicks)); - $this->set('monthlyUserPointsJS', implode(',', $userPoints)); - $this->set('monthlyTeamPointsJS', implode(',', $teamPoints)); - $this->set('sliceColorsJS', implode(',', $sliceColors)); - $this->set('sliceLabelsJS', implode(',', $sliceLabels)); - $this->set('userPieDataJS', implode(',', $byCatData['usercount'])); - $this->set('teamPieDataJS', implode(',', $byCatData['teamcount'])); - $this->publish('year', $year); - $this->publish('month', $month); - $this->publish('monthSelect', $monthSelect); - $this->publish('pieTitleDate', $pieTitleDate); - $this->render('performance_charts'); - } - - - /** - * Generate data for monthly summary of user and team activity - * @param int $userId user to generate report for - * @param int $months number of months - * @param int $endMonth last month of report (default current month) - * @param int $endYear year of last month of report (default current year) - * @return array - */ - function _performanceSummaryByMonth($userId, $months=12, $endMonth=null, $endYear=null) { - $user = $this->User->findById($userId); - $data = array( - 'email' => $user['User']['email'], - 'firstname' => $user['User']['firstname'], - 'lastname' => $user['User']['lastname'], - 'labels' => array(), - 'usercount' => array(), - 'teamcount' => array()); - - if (is_null($endMonth)) { - $endMonth = date('n'); - } - if (is_null($endYear)) { - $endYear = date('Y'); - } - - $endTime = strtotime(sprintf('%04d-%02d-01 00:00:00 +1 month', $endYear, $endMonth)); - $startTime = strtotime(sprintf('-%d month', $months), $endTime); - - $sql = "SELECT DATE_FORMAT(`Approval`.`created`, '%Y-%m') AS yearmonth, - `Approval`.`created`, `User`.`id`, COUNT(*) AS `total` - FROM `approvals` AS `Approval` - LEFT JOIN `users` AS `User` ON (`User`.`id`=`Approval`.`user_id`) - WHERE `Approval`.`created` >= FROM_UNIXTIME('{$startTime}') - AND `Approval`.`created` < FROM_UNIXTIME('{$endTime}') - GROUP BY yearmonth, `Approval`.`user_id`"; - - $results = $this->Approval->query($sql); - foreach ($results as $row) { - $label = strftime('%b %Y', strtotime($row['Approval']['created'])); - if (!in_array($label, $data['labels'])) { - $data['labels'][] = $label; - $data['teamcount'][] = 0; - $data['usercount'][] = 0; - } - $i = count($data['labels']) - 1; - $data['teamcount'][$i] += $row[0]['total']; - if ($row['User']['id'] == $userId) { - $data['usercount'][$i] += $row[0]['total']; - } - } - - return $data; - } - - - /** - * Generate data for category breakdown summary for user and team - * @param int $userId user to generate report for - * @param int $year year (default: current year) - * @param int $month month to summarize (default: generate data for entire year) - * @return array - */ - function _performanceSummaryByCategory($userId, $year=null, $month=null) { - $user = $this->User->findById($userId); - $data = array( - 'email' => $user['User']['email'], - 'firstname' => $user['User']['firstname'], - 'lastname' => $user['User']['lastname'], - 'labels' => array(), - 'usercount' => array(), - 'teamcount' => array()); - - $addonTypes = $this->Addontype->getNames(); - asort($addonTypes); - - $addonTypeKeys = array(); - foreach ($addonTypes as $key => $val) { - $addonTypeKeys[] = $key; - $data['labels'][] = $val; - $data['usercount'][] = 0; - $data['teamcount'][] = 0; - } - - // single month or year summary breakdown by category - // default date range is current year - if (is_null($year)) { - $year = date('Y'); - } - - if ($month > 0) { - $startTime = strtotime(sprintf('%d-%02d-01 00:00:00', $year, $month)); - $endTime = strtotime('+1 month', $startTime); - } else { - $startTime = strtotime(sprintf('%d-01-01 00:00:00', $year)); - $endTime = strtotime('+1 year', $startTime); - } - - $sql = "SELECT `Addon`.`addontype_id`, `User`.`id`, COUNT(*) AS `total` - FROM `approvals` AS `Approval` - LEFT JOIN `users` AS `User` ON (`User`.`id`=`Approval`.`user_id`) - LEFT JOIN `addons` AS `Addon` ON (`Addon`.`id`=`Approval`.`addon_id`) - WHERE `Approval`.`created` >= FROM_UNIXTIME('{$startTime}') - AND `Approval`.`created` < FROM_UNIXTIME('{$endTime}') - GROUP BY `Approval`.`user_id`, `Addon`.`addontype_id`"; - - $results = $this->Approval->query($sql); - foreach ($results as $row) { - $i = array_search($row['Addon']['addontype_id'], $addonTypeKeys); - if ($i === false) { - continue; // approvals should always have a known addontype ? - } - $data['teamcount'][$i] += $row[0]['total']; - if ($row['User']['id'] == $userId) { - $data['usercount'][$i] += $row[0]['total']; - } - } - - return $data; - } - - - /** - * AJAX Add-on and Author email lookup - */ - function addonAndAuthorLookup($queue='pending') { - if (!$this->SimpleAcl->actionAllowed('Admin', '%', $this->Session->read('User')) || - !$this->SimpleAcl->actionAllowed('Editor', '*', $this->Session->read('User')) ) { - $this->Amo->accessDenied(); - } - - $text = $_REQUEST['q']; - $this->Amo->clean($text, false); - $addonsAndEmails = array(); - - if (strlen($text) > 0 && in_array($queue, array('pending', 'nominated'))) { - // Use the base filter components to limit results to those in the queue - $sql_base = $this->Editors->baseQueueFilterQuery($queue); - - // search localized addon names - $sql = "SELECT DISTINCT IFNULL(`tr_l`.`localized_string`, `tr_en`.`localized_string`) AS `lname` - {$sql_base['FROM']} - {$sql_base['JOIN']} - LEFT JOIN `translations` AS `tr_l` ON - (`tr_l`.`id`=`Addon`.`name` AND `tr_l`.`locale`='".LANG."') - LEFT JOIN `translations` AS `tr_en` ON - (`tr_en`.`id`=`Addon`.`name` AND `tr_en`.`locale`=`Addon`.`defaultlocale`) - {$sql_base['WHERE']} - AND IFNULL(`tr_l`.`localized_string`, `tr_en`.`localized_string`) LIKE '%{$text}%' - ORDER BY `lname` ASC"; - - $results = $this->Version->query($sql); - if (!empty($results)) { - foreach ($results as $row) { - $addonsAndEmails[] = $row[0]['lname']; - } - } - - // search localized addon support emails - $emails = array(); - $sql = "SELECT IFNULL(`tr_l`.`localized_string`, `tr_en`.`localized_string`) AS `lemail` - {$sql_base['FROM']} - {$sql_base['JOIN']} - LEFT JOIN `translations` AS `tr_l` ON - (`tr_l`.`id`=`Addon`.`supportemail` AND `tr_l`.`locale`='".LANG."') - LEFT JOIN `translations` AS `tr_en` ON - (`tr_en`.`id`=`Addon`.`supportemail` AND `tr_en`.`locale`=`Addon`.`defaultlocale`) - {$sql_base['WHERE']} - AND IFNULL(`tr_l`.`localized_string`, `tr_en`.`localized_string`) LIKE '%{$text}%'"; - - $results = $this->Version->query($sql); - if (!empty($results)) { - foreach ($results as $row) { - $emails[] = $row[0]['lemail']; - } - } - - // search author emails - $sql = "SELECT `User`.`email` - {$sql_base['FROM']} - {$sql_base['JOIN']} - LEFT JOIN `addons_users` AS `au` ON (`Addon`.`id`=`au`.`addon_id`) - LEFT JOIN `users` AS `User` ON (`au`.`user_id`=`User`.`id`) - {$sql_base['WHERE']} - AND `au`.`role` IN(".AUTHOR_ROLE_ADMINOWNER."," - .AUTHOR_ROLE_ADMIN."," - .AUTHOR_ROLE_OWNER."," - .AUTHOR_ROLE_DEV.") - AND `User`.`email` LIKE '%{$text}%'"; - - $results = $this->Version->query($sql); - if (!empty($results)) { - foreach ($results as $row) { - $emails[] = $row['User']['email']; - } - } - - // sort, dedup, and merge - sort($emails); - $emails = array_unique($emails); - $addonsAndEmails = array_merge($addonsAndEmails, $emails); - } - - $this->set('addonsAndEmails', $addonsAndEmails); - $this->render('ajax/addon_and_author_lookup', 'ajax'); - } - - /** - * AJAX action for looking up appversions for the specified app - * @param int $app_id The application id - */ - function appversionLookup($app_id) { - $this->Amo->clean($app_id); - $results = $this->Appversion->findAllByApplicationId($app_id, - array('Appversion.id', 'Appversion.version'), 'Appversion.version DESC'); - $appversions = array(); - foreach ($results as $av) { - $appversions[] = $av['Appversion']; - } - - $this->publish('appversions', $appversions); - $this->render('ajax/appversion_lookup', 'ajax'); - } - - /** - * Count the number of (possibly filtered) items in the specified queue - * @param string $queue - * @param bool $useFilter (default=false) - * @return int - * @todo possibly cache results - */ - function _getCount($queue, $useFilter=false) { - $result = null; - - if ($useFilter && $this->Editors->buildQueueFilterQuery($queue)) { - $sql = $this->Editors->buildQueueFilterQuery($queue); - $result = $this->Addon->query( - "SELECT COUNT(*) {$sql['FROM']} {$sql['JOIN']} {$sql['WHERE']}"); - - } elseif ($queue == 'pending') { - $result = $this->File->query( - "SELECT COUNT(*) FROM `files` WHERE `status`=".STATUS_PENDING." GROUP BY `status`"); - - } elseif ($queue == 'nominated') { - $result = $this->Addon->query( - "SELECT COUNT(*) FROM `addons` WHERE `status`=".STATUS_NOMINATED." GROUP BY `status`"); - - } elseif ($queue == 'reviews') { - $result = $this->Review->query( - "SELECT COUNT(*) FROM `reviews` WHERE `editorreview`=1 GROUP BY `editorreview`"); - } - - $count = !empty($result) ? $result[0][0]['COUNT(*)'] : 0; - - return $count; - } - - /** - * Fetch an array of (possibly filtered) addons for the specified queue - * @param string $queue - * @return array - */ - function _buildQueue($queue) { - if (!in_array($queue, array('pending', 'nominated'))) { - return array(); - } - - $sql = $this->Editors->buildQueueFilterQuery($queue); - - // Setup pagination - $this->Pagination->total = $this->_getCount($queue, true); - - $_pagination_options = array(); - if ($queue == 'pending') { - if (!array_key_exists('show', $_GET) && $this->Session->read('editor_queue_pending_show')) { - $_pagination_options['show'] = $this->Session->read('editor_queue_pending_show'); - } else { - // If $_GET['show'] exists it overrides this in the pagination component - $_pagination_options['show'] = 50; - } - list($not_used,$_limit,$_page) = $this->Pagination->init(null, null, $_pagination_options); - $this->Session->write('editor_queue_pending_show', $_limit); - - } else { - if (!array_key_exists('show', $_GET) && $this->Session->read('editor_queue_nominated_show')) { - $_pagination_options['show'] = $this->Session->read('editor_queue_nominated_show'); - } else { - // If $_GET['show'] exists it overrides this in the pagination component - $_pagination_options['show'] = 50; - } - list($not_used,$_limit,$_page) = $this->Pagination->init(null,null,$_pagination_options); - $this->Session->write('editor_queue_nominated_show', $_limit); - } - - $_offset = ($_page > 0) ? $_limit * ($_page-1) : 0; // no negative offsets, thank you - - $extra_fields = ''; - if ($queue == 'pending') { - $extra_fields .= ", `File`.`id`, `File`.`platform_id`"; - } - - // Fetch the queue - $queue_sql = "SELECT - `Version`.`id`, - `Version`.`addon_id`, - `Version`.`version`, - `Version`.`created`, - `Version`.`modified` - {$extra_fields} - {$sql['FROM']} - {$sql['JOIN']} - {$sql['WHERE']} - {$sql['ORDER']} - LIMIT {$_limit} OFFSET {$_offset}"; - - $addons = $this->Version->query($queue_sql); - - //Merge in Addon details - if (!empty($addons)) { - foreach ($addons as $k => $addon) { - $addon = $this->Addon->findById($addon['Version']['addon_id'], - array('Addon.id', - 'Addon.name', 'Addon.defaultlocale', - 'Addon.addontype_id', 'Addon.prerelease', - 'Addon.sitespecific', 'Addon.externalsoftware', - 'Addon.created', 'Addon.nominationdate'), '', 0); - $addons[$k] = array_merge_recursive($addons[$k], $addon); - } - } - - $platforms = $this->Amo->getPlatformName(); - $applications = $this->Amo->getApplicationName(); - - //make modifications to the queue array - if (!empty($addons)) { - foreach ($addons as $k => $addon) { - //get min/max versions - if ($targetApps = $this->Amo->getMinMaxVersions($addon['Version']['id'])) { - foreach ($targetApps as $targetApp) { - $appName = $targetApp['translations']['localized_string']; - $addons[$k]['targetApps'][$appName]['min'] = $targetApp['min']['version']; - $addons[$k]['targetApps'][$appName]['max'] = $targetApp['max']['version']; - } - } - - //Age - if ($queue == 'pending') { - $age = time() - strtotime($addon['Version']['created']); - } - elseif ($queue == 'nominated') { - $age = time() - strtotime($addon['Addon']['created']); - $nominationage = time() - strtotime($addon['Addon']['nominationdate']); - $addons[$k]['nominationage'] = $this->_humanizeAge($nominationage); - } - - $addons[$k]['age'] = $this->_humanizeAge($age); - - //Generate any additional notes - $addons[$k]['notes'] = array(); - - //Platform-specific? - if (!empty($addon['Version'][0]['File'][0]['platform_id']) && $addon['Version'][0]['File'][0]['platform_id'] != 1) { - $os = array(); - foreach ($addon['Version'][0]['File'] as $file) { - $os[] = $platforms[$file['platform_id']]; - } - $addons[$k]['notes'][] = sprintf(_('editors_platform_x_only'), implode(', ', $os)); - } - elseif (!empty($addon['File']['platform_id']) && $addon['File']['platform_id'] != 1) { - $addons[$k]['notes'][] = sprintf(_('editors_platform_x_only'), $platforms[$addon['File']['platform_id']]); - } - - //Featured? - //@TODO - - //Site specific? - if ($addon['Addon']['sitespecific'] == 1) { - $addons[$k]['notes'][] = _('editors_site_specific'); - } - //Pre-release? - if ($addon['Addon']['prerelease'] == 1) { - $addons[$k]['notes'][] = _('editors_pre-release'); - } - //External software? - if ($addon['Addon']['externalsoftware'] == 1) { - $addons[$k]['notes'][] = _('editors_external_software'); - } - } - } - //pr($addons); - - return $addons; - } /** * Moderated Reviews Queue @@ -1448,87 +869,6 @@ class EditorsController extends AppController $this->set('page', 'reviewlog'); $this->render('reviewlog'); } - - /* Humanizes a Unix Timestamp */ - function _humanizeAge($age) { - $humanized = ''; - - //days - if ($age >= (60*60*24*2)) { - $humanized = sprintf(_('editors_x_days'), floor($age/(60*60*24))); - } - //1 day - elseif ($age >= (60*60*24)) { - $humanized = _('editors_one_day'); - } - //hours - elseif ($age >= (60*60*2)) { - $humanized = sprintf(_('editors_x_hours'), floor($age/(60*60))); - } - //hour - elseif ($age >= (60*60)) { - $humanized = _('editors_one_hour'); - } - //minutes - elseif ($age > 60) { - $humanized = sprintf(_('editors_x_minutes'), floor($age/60)); - } - //minute - else { - $humanized = _('editors_one_minute'); - } - - return $humanized; - } - - /* Generate a sortable key from the given timestamp in the form of 'YYYY-WW' */ - function _makeYearWeekKey($timestamp) { - $year = date('Y', $timestamp); - $week = date('W', $timestamp); - - // the end of December is often part of the first week for the following year - if ($week == '01' && date('m', $timestamp) == '12') { - $year++; - } - return "{$year}-{$week}"; - } - - /* Approximate team size at a point in time */ - function _teamSize($timestamp) { - $this->Amo->clean($timestamp); - - // Count the number of unique users that submitted a review during - // the 60 days leading up to the time specified. - $teamSize = 0; - $sql = "SELECT COUNT(DISTINCT `Approval`.`user_id`) AS `teamSize` - FROM `approvals` AS `Approval` - WHERE `Approval`.`created` < FROM_UNIXTIME('{$timestamp}') - AND `Approval`.`created` >= FROM_UNIXTIME('".strtotime('-60 day', $timestamp)."')"; - if ($results = $this->Approval->query($sql)) { - $teamSize = $results[0][0]['teamSize']; - } - return $teamSize; - } - - /* Fetch emails of all editors active in the last reviewDays days */ - function _recentEditors($reviewDays=90) { - $this->Amo->clean($reviewDays); - - $sql = "SELECT DISTINCT `User`.`email` - FROM `approvals` AS `Approval` - INNER JOIN `users` AS `User` ON (`User`.`id`=`Approval`.`user_id`) - WHERE `Approval`.`created` >= FROM_UNIXTIME('".strtotime("-{$reviewDays} day")."') - ORDER BY `User`.`email` ASC"; - - $editors = array(); - if ($results = $this->Approval->query($sql)) { - foreach ($results as $user) { - $editors[] = $user['User']['email']; - } - } - - return $editors; - } } ?> |