Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/site/app/controllers
diff options
context:
space:
mode:
Diffstat (limited to 'site/app/controllers')
-rw-r--r--site/app/controllers/addons_controller.php104
-rw-r--r--site/app/controllers/admin_controller.php1
-rw-r--r--site/app/controllers/compatibility_controller.php4
-rw-r--r--site/app/controllers/components/amo.php2
-rw-r--r--site/app/controllers/components/developers.php4
-rw-r--r--site/app/controllers/components/editors.php103
-rw-r--r--site/app/controllers/developers_controller.php127
-rw-r--r--site/app/controllers/editors_controller.php31
-rw-r--r--site/app/controllers/files_controller.php81
-rw-r--r--site/app/controllers/pages_controller.php4
-rw-r--r--site/app/controllers/reviews_controller.php5
-rw-r--r--site/app/controllers/statistics_controller.php1
-rw-r--r--site/app/controllers/tests_controller.php3
-rw-r--r--site/app/controllers/users_controller.php2
14 files changed, 397 insertions, 75 deletions
diff --git a/site/app/controllers/addons_controller.php b/site/app/controllers/addons_controller.php
index d4ace7d..28caa85 100644
--- a/site/app/controllers/addons_controller.php
+++ b/site/app/controllers/addons_controller.php
@@ -56,6 +56,8 @@ class AddonsController extends AppController
var $securityLevel = 'low';
+ var $link_sharing_services;
+
function beforeFilter() {
// Disable ACLs because this controller is entirely public.
$this->SimpleAuth->enabled = false;
@@ -64,6 +66,96 @@ class AddonsController extends AppController
if (array_key_exists('addons-author-addons-select', $this->params['url']) && ctype_digit($this->params['url']['addons-author-addons-select'])) {
redirectWithNewLocaleAndExit(array('addon',$this->params['url']['addons-author-addons-select']));
}
+
+ // Set of available link sharing services with associated labels and
+ // submission URL templates.
+ // @TODO: Move this to a model class when share counts are enabled in DB
+ $this->link_sharing_services = array(
+
+ // see: http://digg.com/tools/integrate#3
+ 'digg' => array(
+ 'label' => ___('addons_share_label_digg', 'Digg this!'),
+ 'url' => 'http://digg.com/submit?url={URL}&title={TITLE}&bodytext={DESCRIPTION}&media=news&topic=tech_news'
+ ),
+
+ // see: http://www.facebook.com/share_options.php
+ 'facebook' => array(
+ 'label' => ___('addons_share_label_facebook', 'Post to Facebook'),
+ 'url' => 'http://www.facebook.com/share.php?u={URL}&t={TITLE}'
+ ),
+
+ // see: http://delicious.com/help/savebuttons
+ 'delicious' => array(
+ 'label' => ___('addons_share_label_delicious', 'Add to Delicious'),
+ 'url' => 'http://delicious.com/save?url={URL}&title={TITLE}&notes={DESCRIPTION}'
+ ),
+
+ // see: http://www.myspace.com/posttomyspace
+ 'myspace' => array(
+ 'label' => ___('addons_share_label_myspace', 'Post to MySpace'),
+ 'url' => 'http://www.myspace.com/index.cfm?fuseaction=postto&t={TITLE}&c={DESCRIPTION}&u={URL}&l=1'
+ ),
+
+ // see: http://friendfeed.com/embed/link
+ 'friendfeed' => array(
+ 'label' => ___('addons_share_label_friendfeed', 'Share on FriendFeed'),
+ 'url' => 'http://friendfeed.com/?url={URL}&title={TITLE}'
+ )
+
+ );
+
+ }
+
+ /**
+ * Share an addon with a link sharing service.
+ * @param int $id the id of the addon
+ */
+ function share($id = null) {
+ global $valid_status;
+
+ $_conditions = array(
+ 'Addon.id' => $id,
+ 'Addon.inactive' => 0,
+ 'Addon.addontype_id' => array(
+ ADDON_EXTENSION, ADDON_THEME, ADDON_DICT,
+ ADDON_SEARCH, ADDON_LPAPP, ADDON_PLUGIN
+ ),
+ 'Addon.status' => $valid_status
+ );
+ $addon = $this->Addon->find($_conditions, null , null , 1);
+
+ $service = @$this->link_sharing_services[$_GET['service']];
+
+ // Panic if either the addon or the sharing service is not found.
+ if (empty($addon) || empty($service)) {
+ $this->flash(_('error_addon_notfound'), '/', 3);
+ return;
+ }
+
+ $this->publish('addon_id', $id);
+
+ // Build a suitable link title based on the addon name, version, and
+ // the site title.
+ $title =
+ sprintf(
+ _('addons_display_pagetitle'),
+ $addon['Translation']['name']['string'].' '.
+ $addon['Version'][0]['version']
+ ) .
+ ' :: '.
+ sprintf(
+ _('addons_home_pagetitle'),
+ APP_PRETTYNAME
+ );
+
+ $this->publish('share_title', $title);
+
+ // Come up with description text from the summary
+ $this->publish('description', $addon['Translation']['summary']['string']);
+
+ $this->publish('service_url', $service['url']);
+
+ $this->layout = 'ajax';
}
/**
@@ -101,6 +193,16 @@ class AddonsController extends AppController
return;
}
+ // TODO: Look up the current share totals for this addon.
+ // $share_counts = $this->ShareCount->getTotalCountsForAddon(
+ // $addon_data['Addon']['id']
+ // );
+ // $this->set('link_sharing_counts', $share_counts);
+
+ // Not using publish() here because this will all be app constants,
+ // localized strings with placeholders, or counts from the DB.
+ $this->set('link_sharing_services', $this->link_sharing_services);
+
if($loggedIn) {
$isauthor = $this->Amo->checkOwnership($id, $addon_data['Addon'], true);
$this->publish('isAuthor', $isauthor);
@@ -119,7 +221,7 @@ class AddonsController extends AppController
$_addoncriteria = array(
'Addon.id' => $_addonids,
'Addon.inactive' => 0,
- 'Addon.status' => $this->status
+ 'Addon.status' => $valid_status
);
$authorAddons = $this->Addon->findAll($_addoncriteria, null, 'Translation.name');
} else {
diff --git a/site/app/controllers/admin_controller.php b/site/app/controllers/admin_controller.php
index eb90afb..bea1f6c 100644
--- a/site/app/controllers/admin_controller.php
+++ b/site/app/controllers/admin_controller.php
@@ -1502,6 +1502,7 @@ class AdminController extends AppController
$_constants = $_constants['user'];
ksort($_constants);
+ $_constants['ANON_BIND_PW'] = '--removed--';
$_constants['DB_USER'] = '--removed--';
$_constants['DB_PASS'] = '--removed--';
$_constants['SHADOW_DB_USER'] = '--removed--';
diff --git a/site/app/controllers/compatibility_controller.php b/site/app/controllers/compatibility_controller.php
index 014f2cb..9a9754f 100644
--- a/site/app/controllers/compatibility_controller.php
+++ b/site/app/controllers/compatibility_controller.php
@@ -88,7 +88,7 @@ class CompatibilityController extends AppController
global $compatibility_versions;
if (!in_array($version, $compatibility_versions)) $version = COMPAT_DEFAULT_VERSION;
- $data = unserialize(file_get_contents(NETAPP_STORAGE.'/compatibility.serialized'));
+ $data = unserialize(file_get_contents(NETAPP_STORAGE.'/compatibility-fx-'.$version.'.serialized'));
$this->publish('totals', $data['totals']);
$this->publish('version', $version);
@@ -107,7 +107,7 @@ class CompatibilityController extends AppController
global $compatibility_versions;
if (!in_array($version, $compatibility_versions)) $version = COMPAT_DEFAULT_VERSION;
- $data = unserialize(file_get_contents(NETAPP_STORAGE.'/compatibility.serialized'));
+ $data = unserialize(file_get_contents(NETAPP_STORAGE.'/compatibility-fx-'.$version.'.serialized'));
$this->publish('addons', $data['addons']);
$this->publish('totals', $data['totals']);
diff --git a/site/app/controllers/components/amo.php b/site/app/controllers/components/amo.php
index fa2cad1..a8b61b4 100644
--- a/site/app/controllers/components/amo.php
+++ b/site/app/controllers/components/amo.php
@@ -221,7 +221,7 @@ class AmoComponent extends Object {
*/
function getStatusNames() {
return array(
- STATUS_NULL => ___('Incomplete'),
+ STATUS_NULL => ___('addons_status_incomplete', 'Incomplete'),
STATUS_SANDBOX => ___('addons_status_sandbox', 'In Sandbox'),
STATUS_PENDING => ___('addons_status_pending', 'In Sandbox; Pending Review'),
STATUS_NOMINATED => ___('addons_status_nominated', 'In Sandbox; Public Nomination'),
diff --git a/site/app/controllers/components/developers.php b/site/app/controllers/components/developers.php
index 83b277c..7ccd263 100644
--- a/site/app/controllers/components/developers.php
+++ b/site/app/controllers/components/developers.php
@@ -659,9 +659,9 @@ class DevelopersComponent extends Object {
// Move file
if (file_exists($currentPath)) {
- // Delete file if one already exists
+ // Bail if the file exists. See bug 470652 for a rough explanation
if (file_exists($newPath)) {
- unlink($newPath);
+ return sprintf(___('devcp_error_file_exists'), $filename);
}
// We must copy instead of rename now in case there are other platforms
if (!copy($currentPath, $newPath)) {
diff --git a/site/app/controllers/components/editors.php b/site/app/controllers/components/editors.php
index 0abb343..4b9dd47 100644
--- a/site/app/controllers/components/editors.php
+++ b/site/app/controllers/components/editors.php
@@ -54,7 +54,7 @@ class EditorsComponent extends Object {
function reviewNominatedAddon($addon, $data) {
//Make sure add-on is actually nominated
if ($addon['Addon']['status'] != STATUS_NOMINATED) {
- $this->controller->Errors->addError(_('This add-on has not been nominated'));
+ $this->controller->Error->addError(___('editor_review_error_addon_not_nominated', 'This add-on has not been nominated'));
return false;
}
@@ -76,12 +76,12 @@ class EditorsComponent extends Object {
$addonData['status'] = STATUS_NOMINATED;
}
else {
- $this->controller->Error->addError(_('Please select a review action.'));
+ $this->controller->Error->addError(___('editor_review_error_no_action', 'Please select a review action.'));
return false;
}
if (empty($data['Approval']['comments'])) {
- $this->controller->Error->addError(_('Please enter review comments.'));
+ $this->controller->Error->addError(___('editor_review_error_no_comments', 'Please enter review comments.'));
return false;
}
@@ -158,7 +158,7 @@ class EditorsComponent extends Object {
*/
function reviewPendingFiles($addon, $data) {
if (empty($data['Approval']['File'])) {
- $this->controller->addError(_('Please select at least one file to review.'));
+ $this->controller->addError(___('editor_review_error_no_files', 'Please select at least one file to review.'));
return false;
}
@@ -179,22 +179,22 @@ class EditorsComponent extends Object {
$fileData['status'] = STATUS_PENDING;
}
else {
- $this->controller->Error->addError(_('Please select a review action.'));
+ $this->controller->Error->addError(___('editor_review_error_no_action', 'Please select a review action.'));
return false;
}
if (empty($data['Approval']['comments'])) {
- $this->controller->Error->addError(_('Please enter review comments.'));
+ $this->controller->Error->addError(___('editor_review_error_no_comments', 'Please enter review comments.'));
return false;
}
if (empty($data['Approval']['applications'])) {
- $this->controller->Error->addError(_('Please enter the tested applications.'));
+ $this->controller->Error->addError(___('editor_review_error_no_applications', 'Please enter the tested applications.'));
return false;
}
if (empty($data['Approval']['os'])) {
- $this->controller->Error->addError(_('Please enter the tested operating systems.'));
+ $this->controller->Error->addError(___('editor_review_error_no_operating_system', 'Please enter the tested operating systems.'));
return false;
}
@@ -210,7 +210,7 @@ class EditorsComponent extends Object {
// Make sure file is pending review
if ($file['File']['status'] != STATUS_PENDING) {
- $this->controller->Error->addError(_('File not pending review.'));
+ $this->controller->Error->addError(___('editor_review_error_file_not_pending', 'File not pending review.'));
return false;
}
@@ -262,13 +262,16 @@ class EditorsComponent extends Object {
'version' => !empty($version) ? $version['Version']['version'] : '',
'files' => $files
);
-
$this->controller->set('info', $emailInfo);
if ($data['Approval']['ActionField'] != 'superreview') {
$this->controller->Email->template = 'email/pending/'.$data['Approval']['ActionField'];
$this->controller->Email->to = $emailInfo['email'];
+<<<<<<< HEAD:site/app/controllers/components/editors.php
$this->controller->Email->subject = sprintf(_('Sugar Labs Activities: %s %s'), $emailInfo['name'], $emailInfo['version']);
+=======
+ $this->controller->Email->subject = sprintf('Mozilla Add-ons: %s %s', $emailInfo['name'], $emailInfo['version']);
+>>>>>>> svn:site/app/controllers/components/editors.php
}
else {
$this->controller->Email->template = 'email/superreview';
@@ -282,6 +285,52 @@ class EditorsComponent extends Object {
}
/**
+ * Request more information from an author regarding an update/nomination
+ * request
+ */
+ function requestInformation($addon, $data) {
+ global $valid_status;
+
+ // store information request
+ $session = $this->controller->Session->read('User');
+ foreach($data['Approval']['File'] as $_fid) {
+ if ($_fid > 0) {
+ $file_id = $_fid;
+ break;
+ }
+ }
+ $approvalData = array(
+ 'user_id' => $session['id'],
+ 'reviewtype' => 'info',
+ 'action' => 0,
+ 'addon_id' => $addon['Addon']['id'],
+ 'comments' => $data['Approval']['comments']
+ );
+ $this->controller->Approval->save($approvalData);
+ $infoid = $this->controller->Approval->getLastInsertID();
+
+ // send email to all authors
+ $authors = array();
+ foreach ($addon['User'] as &$user) $authors[] = $user['email'];
+
+ $versionid = $this->controller->Version->getVersionByAddonId($addon['Addon']['id'], $valid_status);
+ $version = $this->controller->Version->findById($versionid, null, null, -1);
+
+ $emailInfo = array(
+ 'name' => $addon['Translation']['name']['string'],
+ 'infoid' => $infoid,
+ 'reviewer' => $session['firstname'].' '.$session['lastname'],
+ 'comments' => $data['Approval']['comments'],
+ 'version' => !empty($version) ? $version['Version']['version'] : ''
+ );
+ $this->controller->publish('info', $emailInfo, false);
+ $this->controller->Email->template = 'email/inforequest';
+ $this->controller->Email->to = implode(', ', $authors);
+ $this->controller->Email->subject = sprintf('Mozilla Add-ons: %s %s', $emailInfo['name'], $emailInfo['version']);
+ $this->controller->Email->send();
+ }
+
+ /**
* Jump to specific item in queue
* redirects to review page if item was found, to queue otherwise
* @param string $listtype 'nominated' or 'pending'
@@ -318,5 +367,39 @@ class EditorsComponent extends Object {
// if we did not find anything, redirect to queue
$this->controller->redirect("/editors/queue/{$listtype}");
}
+
+ /**
+ * Notify subscribed editors of an add-on's update
+ * @param int $addonid ID of add-on that was updated
+ * @param int $versionid ID of the add-on's new version
+ */
+ function updateNotify($addonid, $versionid) {
+ $_ids = $this->controller->EditorSubscription->getSubscribers($addonid);
+ if (empty($_ids)) return;
+ $subscribers = $this->controller->User->findAllById($_ids, null, null, null, null, -1);
+
+ $addon = $this->controller->Addon->getAddon($addonid);
+ $version = $this->controller->Version->findById($versionid, null, null, null, null, -1);
+
+ // send out notification email(s)
+ $emailInfo = array(
+ 'id' => $addonid,
+ 'name' => $addon['Translation']['name']['string'],
+ 'versionid' => $versionid,
+ 'version' => $version['Version']['version']
+ );
+ $this->controller->publish('info', $emailInfo, false);
+
+ $this->controller->Email->template = '../editors/email/notify_update';
+ $this->controller->Email->subject = sprintf('Mozilla Add-ons: %s Updated', $emailInfo['name']);
+
+ foreach ($subscribers as &$subscriber) {
+ $this->controller->Email->to = $subscriber['User']['email'];
+ $result = $this->controller->Email->send();
+ // unsubscribe user from further updates
+ $this->controller->EditorSubscription->cancelUpdates($subscriber['User']['id'], $addonid);
+ }
+
+ }
}
?>
diff --git a/site/app/controllers/developers_controller.php b/site/app/controllers/developers_controller.php
index b46bcd1..8ff0a4f 100644
--- a/site/app/controllers/developers_controller.php
+++ b/site/app/controllers/developers_controller.php
@@ -40,8 +40,11 @@ require_once('Archive/Zip.php');
class DevelopersController extends AppController
{
var $name = 'Developers';
- var $uses = array('Addon', 'Addontype', 'Application', 'Appversion', 'Eventlog', 'File', 'Platform', 'Preview', 'Review', 'Tag', 'Translation', 'User', 'Version');
- var $components = array('Amo', 'Developers', 'Error', 'Image', 'Opensearch', 'Rdf', 'Src', 'Versioncompare');
+ var $uses = array('Addon', 'Addontype', 'Application', 'Approval', 'Appversion',
+ 'EditorSubscription', 'Eventlog', 'File', 'Platform', 'Preview', 'Review',
+ 'Tag', 'Translation', 'User', 'Version');
+ var $components = array('Amo', 'Developers', 'Editors', 'Email', 'Error',
+ 'Image', 'Opensearch', 'Rdf', 'Src', 'Versioncompare');
var $helpers = array('Html', 'Javascript', 'Ajax', 'Link', 'Listing', 'Localization', 'Form');
var $addVars = array(); //variables accessible to all additem steps
@@ -226,7 +229,7 @@ class DevelopersController extends AppController
if (!in_array($data['Addon']['addontype_id'], array(ADDON_SEARCH, ADDON_ACTIVITY))) {
// Make sure GUID doesn't exist already
if ($existing = $this->Addon->findAll("Addon.guid='{$data['Addon']['guid']}'")) {
- return $this->Error->getJSONforError(sprintf('This add-on ID (%1$s) already exists in the database. If this is your add-on, you can <a href="%2$s">upload a new version</a>.', $data['Addon']['guid'], $this->url("/developers/versions/add/{$existing[0]['Addon']['id']}")));
+ return $this->Error->getJSONforError(sprintf(___('devcp_new_addon_error'), $data['Addon']['guid'], $this->url("/developers/versions/add/{$existing[0]['Addon']['id']}")));
}
}
@@ -296,7 +299,7 @@ class DevelopersController extends AppController
// Make sure user has upload permissions
$role = $this->Amo->getAuthorRole($addon_id);
if (empty($role) || $role < AUTHOR_ROLE_DEV) {
- return $this->Error->getJSONforError('You do not have sufficient privileges to update this add-on.');
+ return $this->Error->getJSONforError(___('devcp_update_addon_priv_error'));
}
$addon = $this->Addon->findById($addon_id);
@@ -305,7 +308,7 @@ class DevelopersController extends AppController
if ($data['Addon']['addontype_id'] != ADDON_SEARCH) {
// Make sure GUID matches add-on ID
if ($addon['Addon']['guid'] != $data['Addon']['guid']) {
- return $this->Error->getJSONforError(sprintf('The add-on GUID used in this file (%1$s) does not match the existing GUID for this add-on (%2$s).', $data['Addon']['guid'], $addon['Addon']['guid']));
+ return $this->Error->getJSONforError(sprintf(___('devcp_update_addon_guid_error'), $data['Addon']['guid'], $addon['Addon']['guid']));
}
}
@@ -313,7 +316,7 @@ class DevelopersController extends AppController
// Make sure version doesn't exist already
$vcheck = $this->Version->find("Version.addon_id={$addon_id} AND Version.version='{$data['Version']['version']}'");
if (!empty($vcheck)) {
- return $this->Error->getJSONforError(sprintf('The version number uploaded (%1$s) already exists for this add-on. If you are trying to add another file to this version, <a href="%2$s">click here</a>.', $data['Version']['version'], $this->url('/developers/versions/addfile/'.$vcheck['Version']['id'])));
+ return $this->Error->getJSONforError(sprintf(___('devcp_update_addon_version_exists_error'), $data['Version']['version'], $this->url('/developers/versions/addfile/'.$vcheck['Version']['id'])));
}
@@ -334,6 +337,9 @@ class DevelopersController extends AppController
$this->Version->addCompatibleApp($version_id, $appversion['application_id'], $appversion['min'], $appversion['max']);
}
}
+
+ // notify subscribed editors of update (if any)
+ $this->Editors->updateNotify($addon['Addon']['id'], $version_id);
}
elseif ($type == 'file') {
$version_id = $this->data['Version']['id'];
@@ -341,12 +347,13 @@ class DevelopersController extends AppController
// Make sure version id belongs to this add-on
$vcheck = $this->Version->find("Version.id={$version_id} AND Version.addon_id={$addon_id}");
if (empty($vcheck)) {
+ return $this->Error->getJSONforError(sprintf(___('devcp_update_addon_version_belong_error'), $version_id, $addon_id));
return $this->Error->getJSONforError(sprintf('The specified version (%1$s) does not belong to this add-on (%2$s).', $version_id, $addon_id));
}
// Make sure version number matches
if ($vcheck['Version']['version'] != $data['Version']['version']) {
- return $this->Error->getJSONforError(sprintf('The uploaded version number (%1$s) does not match the existing version number (%2$s).', $data['Version']['version'], $vcheck['Version']['version']));
+ return $this->Error->getJSONforError(sprintf(___('devcp_update_addon_version_match_error'), $data['Version']['version'], $vcheck['Version']['version']));
}
}
$data['Version']['id'] = $version_id;
@@ -560,7 +567,7 @@ class DevelopersController extends AppController
);
}
else {
- return $this->Error->getJSONforError('No account found for that email address.');
+ return $this->Error->getJSONforError(___('devcp_verify_author_error'));
}
}
@@ -900,7 +907,7 @@ class DevelopersController extends AppController
function _addonStatusAction($action) {
$this->publish('subaction', $action);
- $addon = $this->Addon->findById($this->viewVars['addon_id'], array('addontype_id', 'nominationmessage', 'status', 'higheststatus'), null, -1);
+ $addon = $this->Addon->findById($this->viewVars['addon_id'], array('id', 'addontype_id', 'nominationmessage', 'status', 'higheststatus'), null, -1);
$this->publish('addon', $addon);
// Complete an add-on
@@ -960,6 +967,11 @@ class DevelopersController extends AppController
$addonData = array('status' => STATUS_NOMINATED, 'nominationmessage' => $this->params['form']['data']['Addon']['nominationmessage']);
$this->Addon->save($addonData);
$this->publish('success', true);
+
+ // notify subscribed editors of update
+ global $valid_status;
+ $version_id = $this->Version->getVersionByAddonId($addon['Addon']['id'], $valid_status);
+ $this->Editors->updateNotify($addon['Addon']['id'], $version_id);
}
}
@@ -1079,7 +1091,7 @@ class DevelopersController extends AppController
// Make sure user has permission
if ($this->viewVars['author_role'] < AUTHOR_ROLE_DEV) {
- $this->flash('You do not have privileges to delete versions or files.', '/developers/versions/edit/'.$version_id, 6);
+ $this->flash(___('devcp_delete_version_priv_error'), '/developers/versions/edit/'.$version_id, 6);
return;
}
@@ -1290,7 +1302,7 @@ class DevelopersController extends AppController
// flush cached add-on objects
if (QUERY_CACHE) $this->Addon->Cache->markListForFlush("addon:{$addon_id}");
- $messages['success'][] = 'Please note that some changes may take several hours to appear in all areas of the website.';
+ $messages['success'][] = ___('devcp_several_hours');
$this->publish('messages', $messages);
}
@@ -1335,7 +1347,7 @@ class DevelopersController extends AppController
// Check for allowed file extensions
$extension = strtolower(substr($name, strrpos($name, '.')));
if (!in_array($extension, $this->Developers->imageExtensions)) {
- $return['errors'][] = sprintf('File %1$s has an invalid extension (%2$s). Allowed extensions: %3$s', $name, $extension, implode(', ', $this->Developers->imageExtensions));
+ $return['errors'][] = sprintf(___('devcp_add_previews_extension_error'), $name, $extension, implode(', ', $this->Developers->imageExtensions));
continue;
}
@@ -1363,12 +1375,12 @@ class DevelopersController extends AppController
// Save preview to db
if ($this->Preview->save($previewData)) {
if (in_array($id, $existing))
- $return['success'][] = sprintf('Preview %1$s was replaced with file %2$s successfully.', $id, $name);
+ $return['success'][] = sprintf(___('devcp_add_previews_success_replace'), $id, $name);
else
- $return['success'][] = sprintf('File %s was uploaded successfully. You can add a caption below.', $name);
+ $return['success'][] = sprintf(___('devcp_add_previews_success_upload'), $name);
}
else
- $return['errors'][] = sprintf('File %s could not be saved to the database. Please try again.', $name);
+ $return['errors'][] = sprintf(___('devcp_add_previews_save_error'), $name);
}
return $return;
@@ -1387,14 +1399,87 @@ class DevelopersController extends AppController
// Delete the preview
$this->Preview->id = $id;
if ($this->Preview->delete())
- $return['success'][] = sprintf('Preview %s has been deleted successfully.', $id);
+ $return['success'][] = sprintf(___('devcp_delete_previews_success'), $id);
else
- $return['errors'][] = sprintf('Preview %s could not be deleted from the database. Please try again.', $id);
+ $return['errors'][] = sprintf(___('devcp_delete_previews_error'), $id);
}
return $return;
}
+ /**
+ * Discuss a review request with an editor
+ */
+ function discuss($infoid) {
+ global $valid_status;
+
+ $inforequest = $this->Approval->findById($infoid);
+ if (empty($inforequest)) {
+ $this->flash(_('error_addon_notfound'), '/developers/index');
+ return;
+ }
+ // Make sure user has some permissions to view this add-on
+ $role = $this->Amo->getAuthorRole($inforequest['Approval']['addon_id']);
+ if (empty($role)) $this->Amo->accessDenied();
+
+ $this->publish('inforequest', $inforequest);
+
+ $addon = $this->Addon->getAddon($inforequest['Approval']['addon_id'], array('authors'));
+ $this->publish('addonName', $addon['Translation']['name']['string']);
+
+ $versionid = $this->Version->getVersionByAddonId($addon['Addon']['id'], $valid_status);
+ $version = $this->Version->findById($versionid, null, null, -1);
+ $this->publish('versionno', $version['Version']['version']);
+
+ // grab replies
+ $replies = $this->Approval->findAll(array('reply_to' => $infoid), null, 'Approval.created');
+ $this->publish('replies', $replies);
+
+ if (!empty($this->data)) {
+ $session = $this->Session->read('User');
+
+ // reply submitted
+ $approvalData = array(
+ 'user_id' => $session['id'],
+ 'reviewtype' => 'info',
+ 'action' => 0,
+ 'reply_to' => $infoid,
+ 'addon_id' => $addon['Addon']['id'],
+ 'comments' => $this->data['Approval']['comments']
+ );
+ if (true === $this->Approval->save($approvalData)) {
+ $this->set('success', true);
+
+ // add this to the replies set
+ $replies[] = $this->Approval->findById($this->Approval->getLastInsertID());
+ $this->publish('replies', $replies);
+
+ // send email to all authors and the editor, but not the current user
+ $recipients = array();
+ foreach ($addon['User'] as &$user) $recipients[] = $user['email'];
+ $recipients[] = $inforequest['User']['email'];
+ foreach ($replies as &$reply) $recipients[] = $reply['User']['email'];
+ $recipients = array_diff(array_unique($recipients), array($session['email'])); // remove current user
+
+ $emailInfo = array(
+ 'name' => $addon['Translation']['name']['string'],
+ 'infoid' => $infoid,
+ 'sender' => $session['firstname'].' '.$session['lastname'],
+ 'comments' => $this->data['Approval']['comments'],
+ 'version' => !empty($version) ? $version['Version']['version'] : ''
+ );
+ $this->publish('info', $emailInfo, false);
+ $this->Email->template = '../editors/email/inforequest_reply';
+ $this->Email->subject = sprintf('Mozilla Add-ons: %s %s', $emailInfo['name'], $emailInfo['version']);
+ foreach ($recipients as &$recipient) {
+ $this->Email->to = $recipient;
+ $this->Email->send();
+ }
+ }
+ }
+ $this->render();
+ }
+
/**
* Index
*/
@@ -2391,10 +2476,10 @@ class DevelopersController extends AppController
//Update/insert icon
if (!empty($this->data['Addon']['icon']['name'])) {
- $fileErrors = array('1' => _('Exceeds maximum upload size'),
- '2' => _('Exceeds maximum upload size'),
- '3' => _('Incomplete transfer'),
- '4' => _('No file uploaded')
+ $fileErrors = array('1' => ___('devcp_edit_file_error_size'),
+ '2' => ___('devcp_edit_file_error_size'),
+ '3' => ___('devcp_edit_file_error_incomplete'),
+ '4' => ___('devcp_edit_file_error_no')
);
$allowedImage = array('.png', '.jpg', '.gif');
diff --git a/site/app/controllers/editors_controller.php b/site/app/controllers/editors_controller.php
index 3770b91..03957bf 100644
--- a/site/app/controllers/editors_controller.php
+++ b/site/app/controllers/editors_controller.php
@@ -41,7 +41,10 @@
class EditorsController extends AppController
{
var $name = 'Editors';
- var $uses = array('Addon', 'AddonTag', 'Addontype', 'Application', 'Approval', 'Appversion', 'Cannedresponse', 'Eventlog', 'Favorite', 'File', 'Platform', 'Review', 'ReviewsModerationFlag', 'Tag', 'Translation', 'User', 'Version');
+ var $uses = array('Addon', 'AddonTag', 'Addontype', 'Application', 'Approval',
+ 'Appversion', 'Cannedresponse', 'EditorSubscription', 'Eventlog', 'Favorite',
+ 'File', 'Platform', 'Review', 'ReviewsModerationFlag', 'Tag', 'Translation',
+ 'User', 'Version');
var $components = array('Amo', 'Audit', 'Developers', 'Editors', 'Email', 'Error', 'Image', 'Pagination');
var $helpers = array('Html', 'Javascript', 'Ajax', 'Listing', 'Localization', 'Pagination');
@@ -400,7 +403,11 @@ class EditorsController extends AppController
if (!empty($this->data)) {
//pr($this->data);
- if ($this->data['Approval']['Type'] == 'nominated') {
+ if ($this->data['Approval']['ActionField'] == 'info') {
+ // request more information
+ $this->Editors->requestInformation($addon, $this->data);
+ }
+ elseif ($this->data['Approval']['Type'] == 'nominated') {
$this->Editors->reviewNominatedAddon($addon, $this->data);
}
else {
@@ -408,6 +415,10 @@ class EditorsController extends AppController
}
if ($this->Error->noErrors()) {
+ // if editor chose to be reminded of the next upcoming update, save this
+ if ($this->data['Approval']['subscribe'])
+ $this->EditorSubscription->subscribeToUpdates($session['id'], $addon['Addon']['id']);
+
$this->flash(_('editors_reviewed_successfully'), '/editors/queue/'.$this->data['Approval']['Type']);
return;
}
@@ -462,10 +473,17 @@ class EditorsController extends AppController
));
//Review History
- if ($history = $this->Approval->findAllByAddon_id($addon['Addon']['id'])) {
- foreach ($history as $k => $hist) {
- $vLookup = $this->Version->findById($hist['File']['version_id'], array('Version.version'));
- $history[$k] = array_merge_recursive($history[$k], $vLookup);
+ if ($history = $this->Approval->findAll(array('Approval.addon_id' => $addon['Addon']['id'], 'reply_to IS NULL'))) {
+ foreach ($history as $k => &$hist) {
+ if (!empty($hist['File']['id'])) {
+ $vLookup = $this->Version->findById($hist['File']['version_id'], array('Version.version'));
+ $history[$k] = array_merge_recursive($history[$k], $vLookup);
+ }
+
+ // add replies to information requests
+ if ($hist['Approval']['reviewtype'] == 'info') {
+ $hist['replies'] = $this->Approval->findAll(array('Approval.reply_to' => $hist['Approval']['id']), null, 'Approval.created');
+ }
}
}
@@ -489,6 +507,7 @@ class EditorsController extends AppController
$this->publish('version', $version);
$this->publish('platforms', $platforms);
$this->publish('addontypes', $this->Addontype->getNames());
+ $this->publish('addontype', $addon['Addon']['addontype_id']);
$this->publish('approval', $this->Amo->getApprovalStatus());
$this->publish('history', $history);
$this->publish('errors', $this->Error->errors);
diff --git a/site/app/controllers/files_controller.php b/site/app/controllers/files_controller.php
index 837779c..da78b3c 100644
--- a/site/app/controllers/files_controller.php
+++ b/site/app/controllers/files_controller.php
@@ -84,6 +84,8 @@ class FilesController extends AppController
return;
}
+ $addontype = $addon['Addon']['addontype_id'];
+ $startfile = 'install.rdf';
$path = REPO_PATH.'/'.$this->Addon->id.'/'.$file['File']['filename'];
if (!file_exists($path)) {
@@ -98,45 +100,53 @@ class FilesController extends AppController
//If a specific file is requested, show it
if (!empty($_GET['view'])) {
- $this->_view($path, $_GET['view']);
+ $this->_view($path, $_GET['view'], $addontype);
return;
}
-
- $zip = new Archive_Zip($path);
- $contents = $zip->listContent();
$files = array();
- foreach ($contents as $content) {
- $isJar = false;
- if (substr($content['filename'], strrpos($content['filename'], '.')) == '.jar') {
- $content['folder'] = 1;
- $isJar = true;
- }
+ if ($addontype === ADDON_SEARCH) {
+ $startfile = $file['File']['filename'];
+ $this->Filebrowser->buildContentsArray($startfile, false, false, $files);
+ } else {
+ $zip = new Archive_Zip($path);
+ $contents = $zip->listContent();
- $this->Filebrowser->buildContentsArray($content['filename'], $content['folder'], false, $files);
+ foreach ($contents as $content) {
+ $isJar = false;
- if ($isJar == true) {
- $filename = substr($content['filename'], strrpos($content['filename'], '/'));
- $jarfile = $zip->extract(array('extract_as_string' => true, 'by_name' => array($content['filename'])));
+ if (substr($content['filename'], strrpos($content['filename'], '.')) == '.jar') {
+ $content['folder'] = 1;
+ $isJar = true;
+ }
- //write a .jar file with the .jar contents to extract in a new Archive_Zip
- //I spent a long time trying to figure out an easier way, but no such luck
- $jarcontents = $this->Filebrowser->getJarContents(REPO_PATH.'/temp'.$filename, $jarfile[0]['content']);
+ $this->Filebrowser->buildContentsArray($content['filename'], $content['folder'], false, $files);
- foreach ($jarcontents as $jarcontent) {
- $this->Filebrowser->buildContentsArray($content['filename'].'/'.$jarcontent['filename'], $jarcontent['folder'], false, $files);
- }
+ if ($isJar == true) {
+ $filename = substr($content['filename'], strrpos($content['filename'], '/'));
+ $jarfile = $zip->extract(array('extract_as_string' => true, 'by_name' => array($content['filename'])));
+
+ //write a .jar file with the .jar contents to extract in a new Archive_Zip
+ //I spent a long time trying to figure out an easier way, but no such luck
+ $jarcontents = $this->Filebrowser->getJarContents(REPO_PATH.'/temp'.$filename, $jarfile[0]['content']);
+
+ foreach ($jarcontents as $jarcontent) {
+ $this->Filebrowser->buildContentsArray($content['filename'].'/'.$jarcontent['filename'], $jarcontent['folder'], false, $files);
+ }
+ }
}
}
$this->publish('id', $file_id);
- $this->publish('contents', $contents);
$this->publish('files', $files);
$this->publish('version', $file['Version']['id']);
$this->publish('addon', $this->Addon->id);
+ $this->publish('addonname', $addon['Translation']['name']['string']);
$this->publish('review', $review);
+ $this->publish('addontype', $addontype);
+ $this->publish('startfile', $startfile);
$this->render('browse', 'ajax');
}
@@ -145,9 +155,10 @@ class FilesController extends AppController
* @param string $path the package
* @param string $file the file
*/
- function _view($path, $file) {
+ function _view($path, $file, $addontype) {
$file = html_entity_decode(urldecode($file), ENT_QUOTES, 'UTF-8');
- $contents = $this->_get_contents($path, $file);
+ $contents = $this->_get_contents($path, $file, $addontype);
+
if (is_bool($contents) && $contents == false) {
$this->flash(_('error_file_notfound'), '/');
return;
@@ -186,6 +197,7 @@ class FilesController extends AppController
return;
}
+ $addontype = $addon['Addon']['addontype_id'];
$path = REPO_PATH.'/'.$this->Addon->id.'/'.$file['File']['filename'];
if (!file_exists($path)) {
@@ -196,7 +208,7 @@ class FilesController extends AppController
if (!empty($_GET['compare'])) {
$public_path = REPO_PATH.'/'.$this->Addon->id.'/'.$public_file['File'][0]['filename'];
$sandbox_path = REPO_PATH.'/'.$this->Addon->id.'/'.$sandbox_file['File']['filename'];
- $this->_compare($sandbox_path, $public_path, html_entity_decode($_GET['compare'], ENT_QUOTES, 'UTF-8'));
+ $this->_compare($sandbox_path, $public_path, html_entity_decode($_GET['compare'], ENT_QUOTES, 'UTF-8'), $addontype);
return;
}
@@ -269,12 +281,13 @@ class FilesController extends AppController
$this->publish('addon', $this->Addon->id);
$this->publish('review', 1);
$this->publish('is_diff', true);
+ $this->publish('startfile', 'install.rdf');
$this->render('browse', 'ajax');
}
- function _compare($sandbox_path, $public_path, $file) {
- $sandbox_contents = $this->_get_contents($sandbox_path, $file);
- $public_contents = $this->_get_contents($public_path, $file);
+ function _compare($sandbox_path, $public_path, $file, $addontype) {
+ $sandbox_contents = $this->_get_contents($sandbox_path, $file, $addontype);
+ $public_contents = $this->_get_contents($public_path, $file, $addontype);
$diff = "";
if ($sandbox_contents === false) {
@@ -387,9 +400,21 @@ class FilesController extends AppController
$this->render('view', 'ajax');
}
- function _get_contents($path, $file) {
+ /* $path must refer to a file that exists */
+ function _get_contents($path, $file, $addontype) {
$this->Amo->clean($path);
+ // Search engine. Safe to output directly
+ if ($addontype === ADDON_SEARCH) {
+ // We have to make sure that the file in $path and $file match.
+ // Otherwise we reproduce bug 461253
+ if (substr($path, -(strlen($file))) == $file) {
+ return file_get_contents($path);
+ } else {
+ return false;
+ }
+ }
+
if (preg_match("/^(.+\.jar)\/(.+)$/is", $file, $matches)) {
$file = $matches[1];
$jarfile = $matches[2];
diff --git a/site/app/controllers/pages_controller.php b/site/app/controllers/pages_controller.php
index 458c892..c22cd47 100644
--- a/site/app/controllers/pages_controller.php
+++ b/site/app/controllers/pages_controller.php
@@ -67,7 +67,7 @@ class PagesController extends AppController{
$path = func_get_args();
$path_string = join('/', $path);
- if (!count($path)) {
+ if (!count($path) || ($path[0] == 'home')) {
$this->redirect('/');
}
@@ -90,8 +90,6 @@ class PagesController extends AppController{
$title = ___('page_title_appversions', _('pages_appversions_header')); break;
case 'credits':
$title = ___('page_title_credits', 'Credits'); break;
- case 'experimental_addons':
- $title = ___('page_title_experimental_addons', 'Experimental Add-ons'); break;
case 'fashionyourfirefox_faq':
$title = ___('page_title_fashionyourfirefox_faq', 'Fashion your Firefox FAQ');
$this->set('cssAdd', array('collection-style'));
diff --git a/site/app/controllers/reviews_controller.php b/site/app/controllers/reviews_controller.php
index 4515479..f1dad56 100644
--- a/site/app/controllers/reviews_controller.php
+++ b/site/app/controllers/reviews_controller.php
@@ -283,6 +283,7 @@ class ReviewsController extends AppController
}
if ($this->Review->save($this->data)) {
+ $this->Review->updateBayesianRating(array($id));
$this->render('review_added');
return;
} else {
@@ -441,6 +442,10 @@ class ReviewsController extends AppController
$this->Review->delete();
+ // update average ratings
+ debug($review['Addon']['Addon']['id']);
+ $this->Review->updateBayesianRating(array($review['Addon']['Addon']['id']));
+
$this->flash(_('addon_review_deleted_successfully'), "/reviews/display/{$review['Version']['addon_id']}");
return;
}
diff --git a/site/app/controllers/statistics_controller.php b/site/app/controllers/statistics_controller.php
index 6f1b595..7acf45e 100644
--- a/site/app/controllers/statistics_controller.php
+++ b/site/app/controllers/statistics_controller.php
@@ -223,6 +223,7 @@ class StatisticsController extends AppController
'statistics_js_download_csv' => ___('statistics_js_download_csv', 'View this table in CSV format'),
'statistics_js_groupby_selector_date' => ___('statistics_js_groupby_selector_date', 'Group by: Day'),
'statistics_js_groupby_selector_week' => ___('statistics_js_groupby_selector_week', 'Group by: Week'),
+ 'statistics_js_groupby_selector_week_over_week' => ___('statistics_js_groupby_selector_week_over_week', 'Compare by: Week'),
'statistics_js_groupby_selector_month' => ___('statistics_js_groupby_selector_month', 'Group by: Month'),
'statistics_js_plotselection_selector_summary' => _('statistics_js_plotselection_selector_summary'),
'statistics_js_plotselection_selector_downloads' => _('statistics_js_plotselection_selector_downloads'),
diff --git a/site/app/controllers/tests_controller.php b/site/app/controllers/tests_controller.php
index 66cb659..a9a9c89 100644
--- a/site/app/controllers/tests_controller.php
+++ b/site/app/controllers/tests_controller.php
@@ -149,6 +149,9 @@ class TestsController extends AppController {
elseif (!empty($_GET['group'])) {
TestManager::runGroup($_GET['groups'][$_GET['group']], $reporter);
}
+ elseif (!empty($_GET['discover'])) {
+ $this->render('discover', 'ajax');
+ }
exit();
}
diff --git a/site/app/controllers/users_controller.php b/site/app/controllers/users_controller.php
index 91f8fbc..0671eff 100644
--- a/site/app/controllers/users_controller.php
+++ b/site/app/controllers/users_controller.php
@@ -131,7 +131,7 @@ class UsersController extends AppController
$this->User->invalidate('nickname');
}
- // any errors? Get our of here.
+ // any errors? Get out of here.
if (!$this->User->save()) {
$this->publish('errorMessage', true);
$this->render();