diff options
Diffstat (limited to 'site/app/controllers')
-rw-r--r-- | site/app/controllers/addons_controller.php | 104 | ||||
-rw-r--r-- | site/app/controllers/admin_controller.php | 1 | ||||
-rw-r--r-- | site/app/controllers/compatibility_controller.php | 4 | ||||
-rw-r--r-- | site/app/controllers/components/amo.php | 2 | ||||
-rw-r--r-- | site/app/controllers/components/developers.php | 4 | ||||
-rw-r--r-- | site/app/controllers/components/editors.php | 103 | ||||
-rw-r--r-- | site/app/controllers/developers_controller.php | 127 | ||||
-rw-r--r-- | site/app/controllers/editors_controller.php | 31 | ||||
-rw-r--r-- | site/app/controllers/files_controller.php | 81 | ||||
-rw-r--r-- | site/app/controllers/pages_controller.php | 4 | ||||
-rw-r--r-- | site/app/controllers/reviews_controller.php | 5 | ||||
-rw-r--r-- | site/app/controllers/statistics_controller.php | 1 | ||||
-rw-r--r-- | site/app/controllers/tests_controller.php | 3 | ||||
-rw-r--r-- | site/app/controllers/users_controller.php | 2 |
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}¬es={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(); |