Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/site/app/controllers/editors_controller.php
diff options
context:
space:
mode:
Diffstat (limited to 'site/app/controllers/editors_controller.php')
-rw-r--r--site/app/controllers/editors_controller.php1054
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;
- }
}
?>