Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/site/app/controllers/developers_controller.php
diff options
context:
space:
mode:
Diffstat (limited to 'site/app/controllers/developers_controller.php')
-rw-r--r--site/app/controllers/developers_controller.php1643
1 files changed, 1486 insertions, 157 deletions
diff --git a/site/app/controllers/developers_controller.php b/site/app/controllers/developers_controller.php
index f089e63..a77946e 100644
--- a/site/app/controllers/developers_controller.php
+++ b/site/app/controllers/developers_controller.php
@@ -37,31 +37,11 @@
* ***** END LICENSE BLOCK ***** */
require_once('Archive/Zip.php');
-/**
- * Returns $object[$name], or $default if that's not set.
- *
- * If $name is a string of dot-separated names like 'foo.bar.baz',
- * $object['foo']['bar']['baz'] will be returned. If any name
- * along the way is not set, $default will be returned.
- *
- * If you want to fetch a name with embedded dots, look elsewhere.
- */
-function getitem($object, $name, $default=null) {
- $split = explode('.', $name, 2);
- if (count($split) == 2) {
- list($a, $b) = $split;
- return isset($object[$a]) ? getitem($object[$a], $b, $default)
- : $default;
- } else {
- return isset($object[$name]) ? $object[$name] : $default;
- }
-}
-
class DevelopersController extends AppController
{
var $name = 'Developers';
var $uses = array('Addon', 'Addontype', 'Application', 'Approval', 'Appversion',
- 'EditorSubscription', 'Eventlog', 'File', 'License', 'Platform', 'Preview', 'Review',
+ 'EditorSubscription', 'Eventlog', 'File', 'Platform', 'Preview', 'Review',
'Tag', 'Translation', 'User', 'Version');
var $components = array('Amo', 'Developers', 'Editors', 'Email', 'Error',
'Image', 'Opensearch', 'Rdf', 'Src', 'Versioncompare');
@@ -110,9 +90,6 @@ class DevelopersController extends AppController
// Default "My Add-ons" sidebar data
$session = $this->Session->read('User');
$this->publish('all_addons', $this->Addon->getAddonsByUser($session['id']));
-
- // Include the dev_agreement column on developer pages.
- array_push($this->Addon->default_fields, 'dev_agreement');
}
/**
@@ -235,7 +212,6 @@ class DevelopersController extends AppController
*/
function _submitAddon() {
$this->publish('type', 'new');
- $this->publish('hasAgreement', false);
$this->render('uploader');
}
@@ -266,17 +242,9 @@ class DevelopersController extends AppController
$session = $this->Session->read('User');
$this->Addon->saveAuthor($data['Addon']['id'], $session['id']);
- // Save License
- $license_id = $this->Developers->saveLicense(
- $this->data['License'],
- getitem($this->data, 'License.text'),
- getitem($this->params, 'form.data.License'));
- $this->Addon->saveField('dev_agreement', 1);
-
// Add Version
$this->Version->id = 0;
$data['Version']['addon_id'] = $data['Addon']['id'];
- $data['Version']['license_id'] = $license_id;
$this->Version->save($data['Version']);
$data['Version']['id'] = $this->Version->getLastInsertId();
@@ -351,30 +319,13 @@ class DevelopersController extends AppController
return $this->Error->getJSONforError(sprintf(___('devcp_update_addon_version_exists_error'), $data['Version']['version'], $this->url('/developers/versions/addfile/'.$vcheck['Version']['id'])));
}
- // Save License
- if ($addon['Addon']['dev_agreement'] == true) {
- // If we already have an agreement, we didn't show the license
- // picker, so use the previously selected license.
- global $valid_status;
- $old_id = $this->Version->getVersionByAddonId($addon_id, $valid_status);
- $oldVersion = $this->Version->findById($old_id);
- $license_id = $oldVersion['Version']['license_id'];
- } else {
- $license_id = $this->Developers->saveLicense(
- $this->data['License'],
- getitem($this->data, 'License.text'),
- getitem($this->params, 'form.data.License'));
- }
- $this->Addon->save(array('Addon' => array('id' => $addon_id,
- 'dev_agreement' => 1)));
-
+
// Add Version
$this->Version->id = 0;
$data['Version']['addon_id'] = $addon_id;
- $data['Version']['license_id'] = $license_id;
$this->Version->save($data['Version']);
$version_id = $this->Version->getLastInsertId();
-
+
// If add-on is public, cancel any pending files
if ($addon['Addon']['status'] == STATUS_PUBLIC) {
$this->Addon->execute("UPDATE files SET status = ".STATUS_SANDBOX." WHERE files.version_id IN (SELECT id FROM versions WHERE versions.addon_id={$addon_id}) AND files.status = ".STATUS_PENDING);
@@ -456,6 +407,7 @@ class DevelopersController extends AppController
);
}
+
function _rmtree($dir) {
$dir = "$dir";
@@ -543,71 +495,65 @@ class DevelopersController extends AppController
);
}
- // we are sugar
- if (true) {
- $bundle = $addon['File']['details']['path'];
- $pathinfo = pathinfo($bundle);
-
- if ($pathinfo['extension'] == '.xo') {
- $ini = $this->_unbundle($bundle, 'activity/activity.info');
- if (isset($ini['error']))
- return $this->Error->getJSONforError($ini['error']);
- $ini_file = $ini['manifest'];
-
- if (!is_array($ini_file))
- return $this->Error->getJSONforError(_('devcp_error_activity_info_not_found'));
- if (!isset($ini_file['name']))
- return $this->Error->getJSONforError(_('devcp_error_activity_info_missing_name'));
- if (!isset($ini_file['activity_version']))
- return $this->Error->getJSONforError(_('devcp_error_activity_info_missing_activity_version'));
-
- if (isset($ini_file['bundle_id']))
- $addon['Addon']['guid'] = $ini_file['bundle_id'];
- else if (isset($ini_file['service_name']))
- $addon['Addon']['guid'] = $ini_file['service_name'];
- else
- return $this->Error->getJSONforError(_('devcp_error_activity_info_missing_bundle_id'));
+ if ($addon['Addon']['addontype_id'] == ADDON_ACTIVITY) {
+ $ini = $this->_unbundle($addon['File']['details']['path'], 'activity/activity.info');
+ if (isset($ini['error']))
+ return $this->Error->getJSONforError($ini['error']);
+ $ini_file = $ini['manifest'];
- $addon['Addon']['name'] = $ini_file['name'];
- $addon['Addon']['summary'] = $ini_file['name'];
- $addon['Version']['version'] = $ini_file['activity_version'];
+ if (!is_array($ini_file))
+ return $this->Error->getJSONforError(_('devcp_error_activity_info_not_found'));
+ if (!isset($ini_file['name']))
+ return $this->Error->getJSONforError(_('devcp_error_activity_info_missing_name'));
+ if (!isset($ini_file['activity_version']))
+ return $this->Error->getJSONforError(_('devcp_error_activity_info_missing_activity_version'));
+ if (isset($ini_file['bundle_id']))
+ $addon['Addon']['guid'] = $ini_file['bundle_id'];
+ else if (isset($ini_file['service_name']))
+ $addon['Addon']['guid'] = $ini_file['service_name'];
+ else
+ return $this->Error->getJSONforError(_('devcp_error_activity_info_missing_bundle_id'));
+
+ $addon['Addon']['name'] = $ini_file['name'];
+ $addon['Addon']['summary'] = $ini_file['name'];
+ $addon['Version']['version'] = $ini_file['activity_version'];
+
+ } else if ($addon['Addon']['addontype_id'] == ADDON_CONTENT) {
+ $ini = $this->_unbundle($addon['File']['details']['path'], 'library/library.info');
+ if (isset($ini['error']))
+ return $this->Error->getJSONforError($ini['error']);
+ $ini_file = $ini['manifest'];
+
+ if (!is_array($ini_file))
+ return $this->Error->getJSONforError(_('devcp_error_activity_info_not_found'));
+ if (!isset($ini_file['name']))
+ return $this->Error->getJSONforError(_('devcp_error_activity_info_missing_name'));
+ if (!isset($ini_file['long_name']))
+ return $this->Error->getJSONforError(_('devcp_error_activity_info_missing_summary'));
+ if (!isset($ini_file['global_name']))
+ return $this->Error->getJSONforError(_('devcp_error_activity_info_missing_bundle_id'));
+
+ $addon['Addon']['name'] = $ini_file['name'];
+ $addon['Addon']['summary'] = $ini_file['long_name'];
+ $addon['Addon']['guid'] = $ini_file['global_name'];
+
+ if (!isset($this->data['Addon']['id'])) {
+ $addon['Version']['version'] = 1;
} else {
- $ini = $this->_unbundle($bundle, 'library/library.info');
- if (isset($ini['error']))
- return $this->Error->getJSONforError($ini['error']);
- $ini_file = $ini['manifest'];
-
- if (!is_array($ini_file))
- return $this->Error->getJSONforError(_('devcp_error_activity_info_not_found'));
- if (!isset($ini_file['name']))
- return $this->Error->getJSONforError(_('devcp_error_activity_info_missing_name'));
- if (!isset($ini_file['long_name']))
- return $this->Error->getJSONforError(_('devcp_error_activity_info_missing_summary'));
- if (!isset($ini_file['global_name']))
- return $this->Error->getJSONforError(_('devcp_error_activity_info_missing_bundle_id'));
-
- $addon['Addon']['name'] = $ini_file['name'];
- $addon['Addon']['summary'] = $ini_file['long_name'];
- $addon['Addon']['guid'] = $ini_file['global_name'];
-
- if (!isset($this->data['Addon']['id'])) {
- $addon['Version']['version'] = 1;
- } else {
- $addon_id = $this->data['Addon']['id'];
- $_addon = $this->Addon->findById($addon_id);
- $version = 0;
-
- if (!empty($_addon)) {
- foreach ($_addon['Version'] as $i) {
- if ($i['version'] > $version) {
- $version = $i['version'];
- }
+ $addon_id = $this->data['Addon']['id'];
+ $_addon = $this->Addon->findById($addon_id);
+ $version = 0;
+
+ if (!empty($_addon)) {
+ foreach ($_addon['Version'] as $i) {
+ if ($i['version'] > $version) {
+ $version = $i['version'];
}
}
-
- $addon['Version']['version'] = $version + 1;
}
+
+ $addon['Version']['version'] = $version + 1;
}
} else
// Parse install.rdf file if not a search plugin
@@ -665,11 +611,6 @@ class DevelopersController extends AppController
elseif ($addon['Addon']['addontype_id'] == ADDON_SEARCH) {
// Get search engine properties
$search = $this->Opensearch->parse($addon['File']['details']['path']);
-
- // There was a parse error, the name was empty, etc. Bad things.
- if ($search == null) {
- return $this->Error->getJSONforError(___('devcp_verify_search_engine_error','Either the XML is invalid or required fields are missing. Please <a href="https://developer.mozilla.org/en/Creating_OpenSearch_plugins_for_Firefox">read the documentation</a>, verify your add-on, and try again.'));
- }
$addon['Addon']['name'] = $search->name;
$addon['Addon']['summary'] = $search->description;
@@ -863,7 +804,7 @@ class DevelopersController extends AppController
$supportedApps = array(
0 => array(
'Application' => array(
- 'id' => APP_FIREFOX
+ 'id' => APP_SUGAR
)
)
);
@@ -1030,6 +971,7 @@ class DevelopersController extends AppController
$criteria['description'] = !empty($addon['Translation']['description']['string']);
$criteria['category'] = !empty($addon['Tag']);
$criteria['previews'] = !empty($previews);
+ $criteria['reviews'] = (!empty($reviews) && count($reviews) >= 3) ? true : false;
$criteria['prerelease'] = !empty($addon['Addon']['prerelease']) ? false : true;
$criteria['application'] = !empty($versions) ? true : false;
@@ -1068,7 +1010,6 @@ class DevelopersController extends AppController
$addonData = array('status' => STATUS_SANDBOX, 'higheststatus' => STATUS_SANDBOX);
$this->Addon->save($addonData);
$this->publish('success', true);
- if (QUERY_CACHE) $this->Addon->Cache->markListForFlush("addon:{$addon['Addon']['id']}");
return true;
}
@@ -1111,7 +1052,7 @@ class DevelopersController extends AppController
$this->render('addon_status_nominate');
return false;
}
- $addonData = array('status' => STATUS_NOMINATED, 'nominationmessage' => $this->params['form']['data']['Addon']['nominationmessage'], 'nominationdate' => date('Y-m-d H:i:s'));
+ $addonData = array('status' => STATUS_NOMINATED, 'nominationmessage' => $this->params['form']['data']['Addon']['nominationmessage']);
$this->Addon->save($addonData);
$this->publish('success', true);
@@ -1226,9 +1167,6 @@ class DevelopersController extends AppController
$this->publish('version', $version['Version']['version']);
}
- $addon = $this->Addon->findById($addon_id, array('Addon.dev_agreement'));
- $this->publish('hasAgreement', $addon['Addon']['dev_agreement']);
-
$this->render('uploader');
}
@@ -1351,13 +1289,6 @@ class DevelopersController extends AppController
}
}
- // Save license.
- $license_id = $this->Developers->saveLicense(
- $this->data['License'],
- getitem($this->data, 'Version.License.text'),
- getitem($this->params, 'form.data.Version.License'));
- $this->Version->saveField('license_id', $license_id);
-
// flush cached add-on objects
if (QUERY_CACHE) $this->Addon->Cache->markListForFlush("addon:{$addon_id}");
@@ -1385,13 +1316,6 @@ class DevelopersController extends AppController
// Get all translations
$translations = $this->Version->getAllTranslations($version_id);
- if (isset($version['Version']['license_id'])) {
- $trans = $this->License->getAllTranslations($version['Version']['license_id']);
- $translations['license_text'] = $trans['text'];
- } else {
- $translations['license_text'] = array();
- }
-
$this->set('translations', $translations);
// Other info
@@ -1486,9 +1410,7 @@ class DevelopersController extends AppController
// flush cached add-on objects
if (QUERY_CACHE) $this->Addon->Cache->markListForFlush("addon:{$addon_id}");
- // inform about cache lag, if any of the changes were successful
- if (!empty($messages['success'])) $messages['success'][] = ___('devcp_several_hours');
-
+ $messages['success'][] = ___('devcp_several_hours');
$this->publish('messages', $messages);
}
@@ -1607,10 +1529,8 @@ class DevelopersController extends AppController
return;
}
// Make sure user has some permissions to view this add-on
- $session = $this->Session->read('User');
- $isEditor = $this->SimpleAcl->actionAllowed('Editors', '*', $session);
$role = $this->Amo->getAuthorRole($inforequest['Approval']['addon_id']);
- if (!$isEditor && empty($role)) $this->Amo->accessDenied();
+ if (empty($role)) $this->Amo->accessDenied();
$this->publish('inforequest', $inforequest);
@@ -1628,21 +1548,6 @@ class DevelopersController extends AppController
if (!empty($this->data)) {
$session = $this->Session->read('User');
- //Auto-detect addontype if necessary
- if ($this->data['Addon']['addontype_id'] == 0) {
- $this->data['Addon']['addontype_id'] = $this->Developers->detectAddontype($this->data['File']['file1']);
- $this->publish('autoDetected', $this->Addontype->getName($this->data['Addon']['addontype_id']));
- }
-
- //Make sure addontype is allowed
- $allowedAddonTypes = $this->Developers->getAllowedAddonTypes(false, $this->SimpleAcl->actionAllowed('*', '*', $this->Session->read('User')));
- if (!array_key_exists($this->data['Addon']['addontype_id'], $allowedAddonTypes)) {
- $this->Error->addError(_('devcp_error_invalid_addontype'));
- }
-
- //Validate files
- $this->Developers->validateFiles();
-
// reply submitted
$approvalData = array(
'user_id' => $session['id'],
@@ -1684,5 +1589,1429 @@ class DevelopersController extends AppController
}
$this->render();
}
+
+ /**
+ * Index
+ */
+ function index($addon_id = '') {
+ $this->Amo->clean($addon_id);
+ $session = $this->Session->read('User');
+ $this->User->id = $session['id'];
+
+ // If requesting a specific add-on, show details for it
+ if (!empty($addon_id)) {
+ $this->details($addon_id);
+ return;
+ }
+
+ $addon_ids = $this->Addon->getAddonsByUser($session['id']);
+ $data = array();
+
+ if (!empty($addon_ids)) {
+ foreach ($addon_ids as $addon_id => $addon_name) {
+ $addon = $this->Addon->find("Addon.id={$addon_id}");
+
+ if (!empty($addon['Version'][0])) {
+ $files = $this->File->findAll("File.version_id={$addon['Version'][0]['id']}");
+
+ if (!empty($files)) {
+ foreach ($files as $file) {
+ $addon['Version'][0]['File'][] = $file;
+ }
+ }
+ }
+
+ $data['Addon'][$addon_id] = array_merge($addon['Addon'], $addon);
+ $data['Addon'][$addon_id]['updatepings'] = $this->Addon->getMostRecentUpdatePingCount($addon_id);
+
+ }
+ }
+
+ $this->publish('data', $data);
+ $this->publish('approval', $this->Amo->getApprovalStatus());
+ $this->publish('platforms', $this->Amo->getPlatformName());
+ $this->publish('addontypes', $this->Addontype->getNames());
+ }
+
+ /**
+ * Shows the details of a specific add-on
+ * @param int $id The add-on id
+ */
+ function details($id) {
+ $this->Amo->clean($id);
+
+ if (!$this->Amo->checkOwnership($id)) {
+ $this->flash(_('devcp_error_addon_access_denied'), '/developers/index');
+ return;
+ }
+
+ //Bind necessary models
+ $this->User->bindFully();
+ $this->Addontype->bindFully();
+ $this->Version->bindFully();
+ $this->Addon->bindFully();
+
+ $this->Addon->id = intval($id);
+
+ if (!empty($this->data)) {
+ //Save translated fields (releasenotes)
+ $this->Developers->saveTranslations($this->data);
+ $this->flash(_('devcp_comments_updated'), '/developers/details/'.$id);
+ return;
+ }
+
+ if(!$addon = $this->Addon->read()) {
+ $this->flash(_('error_addon_notfound'), '/developers/index');
+ return;
+ }
+
+ if (!empty($addon)) {
+ if (!empty($addon['Version'])) {
+ foreach ($addon['Version'] as $v => $version) {
+ $addon['Version'][$v]['File'] = $this->File->findAll("File.version_id='{$version['id']}'");
+ }
+ }
+
+ if (!empty($addon['Preview'])) {
+ foreach ($addon['Preview'] as $p => $preview) {
+ $this->Preview->id = $preview['id'];
+ $addon['Preview'][$p] = $this->Preview->read();
+ }
+ }
+
+ if (!empty($addon['Tag'])) {
+ foreach ($addon['Tag'] as $tag) {
+ $tags[] = $tag['id'];
+ }
+ $tags = $this->Tag->findAll("Tag.id IN (".implode(', ', $tags).")");
+ if (!empty($tags)) {
+ foreach ($tags as $tag) {
+ $addon['Tags'][] = $tag['Translation']['name']['string'];
+ }
+ }
+ }
+ }
+
+ $this->publish('addon', $addon);
+ $this->publish('approval', $this->Amo->getApprovalStatus());
+ $this->publish('platforms', $this->Amo->getPlatformName());
+ $this->publish('addontypes', $this->Addontype->getNames());
+
+ //Retrieve language arrays from bootstrap.
+ global $valid_languages, $native_languages;
+ foreach (array_keys($valid_languages) as $key) {
+ $languages[$key] = $native_languages[$key]['native'];
+
+ $this->Addon->setLang($key, $this);
+ $addonL = $this->Addon->read();
+
+ foreach ($addonL['Translation'] as $field => $translation) {
+ if ($translation['locale'] == $key) {
+ $info[$key][$field] = $translation['string'];
+ }
+ else {
+ $info[$key][$field] = '';
+ }
+ }
+ }
+ $this->Addon->setLang(LANG, $this);
+
+ //Set up localebox info
+ $this->set('localebox', array('info' => $info,
+ 'defaultLocale' => $addon['Addon']['defaultlocale'],
+ 'languages' => $languages));
+ $this->render('details', 'mozilla');
+ }
+
+ /**
+ * Add new version to a new or existing add-on
+ * @param int $id
+ */
+ function add($id = '') {
+ $this->Amo->clean($id);
+ $this->publish('subpagetitle', _('devcp_addon_submit_pagetitle'));
+ $this->breadcrumbs[_('devcp_addon_submit_pagetitle')] = '/developers/add/'.$id;
+ $this->publish('breadcrumbs', $this->breadcrumbs);
+
+ //If submissions are disabled, show appropriate error
+ if ($this->Config->getValue('submissions_disabled') == 1 && !$this->SimpleAcl->actionAllowed('*', '*', $this->Session->read('User'))) {
+ $this->flash(_('devcp_submissions_disabled'), '/', 3);
+ return;
+ }
+
+ //Bind necessary models
+ $this->User->bindFully();
+ $this->Addontype->bindFully();
+ $this->Version->bindFully();
+ $this->Addon->bindFully();
+
+ //Get a list of add-on types
+ $this->publish('addonTypes', $this->Addontype->getNames());
+
+ //Determine if adding a new addon or new version
+ if (!empty($this->data['Addon']['newAddon'])) {
+ if ($this->data['Addon']['newAddon'] == 'false') {
+ $this->addVars['newAddon'] = false;
+ }
+ else {
+ $this->addVars['newAddon'] = true;
+ }
+ $this->Addon->id = $id;
+ $this->addVars['existing'] = $this->Addon->read();
+ }
+ else {
+ //This is step 1, so check if the id was passed
+ if (!empty($id) && $this->Amo->checkOwnership($id)) {
+ $this->Addon->id = $id;
+ $this->addVars['existing'] = $this->Addon->read();
+ $this->addVars['newAddon'] = false;
+ }
+ else {
+ $this->addVars['newAddon'] = true;
+ $this->addVars['existing'] = array();
+ $id = '';
+ }
+ }
+ $this->publish('existing', $this->addVars['existing']);
+
+ //Set some view data used in all steps
+ $this->publish('id', $id);
+ $this->publish('newAddon', $this->addVars['newAddon']);
+ if (!empty($this->data['Version']['id'])) {
+ $this->publish('version', $this->data['Version']['id']);
+ $this->Version->id = $this->data['Version']['id'];
+ }
+
+ //Set default locale
+ if (!empty($this->data['Addon']['defaultlocale'])) {
+ $this->addVars['defaultLocale'] = $this->data['Addon']['defaultlocale'];
+ }
+ elseif (!empty($this->addVars['existing']['Addon']['defaultlocale'])) {
+ $this->addVars['defaultLocale'] = $this->addVars['existing']['Addon']['defaultlocale'];
+ }
+ else {
+ $this->addVars['defaultLocale'] = LANG;
+ }
+
+ //Set models to read and save using default locale, which may not be the current locale
+ $this->Addon->setLang($this->addVars['defaultLocale'], $this);
+ $this->Version->setLang($this->addVars['defaultLocale'], $this);
+
+ $this->set('defaultLocale', $this->addVars['defaultLocale']);
+
+ //Go to appropriate step
+ if (isset($_POST['cancel'])) {
+ $this->_cancelAdd();
+ }
+ elseif (isset($this->data['Addon']['add_step1'])) {
+ $this->_addStep1();
+ }
+ elseif (isset($this->data['Addon']['add_step2'])) {
+ $this->_addStep2();
+ }
+ elseif (isset($this->data['Addon']['add_step3'])) {
+ $this->_addStep3();
+ }
+ elseif (isset($this->data['Addon']['add_step4'])) {
+ $this->_addStep4();
+ }
+ else {
+ if ($this->addVars['newAddon'] == true) {
+ $this->_addStep0();
+ }
+ else {
+ $this->_addStep1();
+ }
+ }
+ }
+
+ /**
+ * Step 0: Agreement
+ */
+ function _addStep0() {
+ if (isset($this->data['Addon']['add_step0'])) {
+ if (!empty($_POST['accept'])) {
+ $this->data = '';
+ $this->_addStep1();
+ return;
+ }
+ }
+ $this->publish('step', 0);
+ $this->render('add_step0');
+ }
+
+ /**
+ * Step 1: Upload files/select add-on type
+ */
+ function _addStep1() {
+ //Check if we are processing Step 1 or just displaying it
+ if (isset($this->data['Addon']['add_step1'])) {
+ //Check for model validation first
+ if (!$this->Addon->validates($this->data)) {
+ $this->Error->addError(_('error_formerrors'));
+ $this->validateErrors();
+ }
+
+ //Auto-detect addontype if necessary
+ if ($this->data['Addon']['addontype_id'] == 0) {
+ $this->data['Addon']['addontype_id'] = $this->Developers->detectAddontype($this->data['File']['file1']);
+ $this->publish('autoDetected', $this->Addontype->getName($this->data['Addon']['addontype_id']));
+ }
+
+ //Make sure addontype is allowed
+ $allowedAddonTypes = $this->Developers->getAllowedAddonTypes(false, $this->SimpleAcl->actionAllowed('*', '*', $this->Session->read('User')));
+ if (!array_key_exists($this->data['Addon']['addontype_id'], $allowedAddonTypes)) {
+ $this->Error->addError(_('devcp_error_invalid_addontype'));
+ }
+
+ //Validate files
+ $this->Developers->validateFiles();
+
+ //Only proceed if no errors
+ if ($this->Error->noErrors()) {
+ //Search plugins do not have install.rdf to parse
+ if ($this->data['Addon']['addontype_id'] != ADDON_SEARCH) {
+
+ //Iterate through files to make sure they're all valid
+ //Reverse order so that file 1's info will be used after
+ for ($f = 3; $f >= 1; $f--) {
+ if (!empty($this->addVars['file'.$f])) {
+ //Extract install.rdf
+ $zip = new Archive_Zip($this->addVars['file'.$f]['path']);
+ $extraction = $zip->extract(array('extract_as_string' => true, 'by_name' => array('install.rdf')));
+
+ //Make sure install.rdf is present
+ if (!empty($extraction)) {
+ $fileContents = $extraction[0]['content'];
+
+ //Use Rdf Component to parse install.rdf
+ $manifestData = $this->Rdf->parseInstallManifest($fileContents);
+
+ //Clean manifest data - take THAT, evil-doers!
+ $this->Amo->clean($manifestData);
+
+ //Validate manifest data
+ $validate = $this->Developers->validateManifestData($manifestData);
+ // Anything other than boolean true is an error
+ if ($validate === true) {
+
+ //Validate target applications
+ $this->addVars['appversions'] = $this->Developers->validateTargetApplications($manifestData['targetApplication']);
+
+ // If result is a string, it's an error
+ if (is_string($this->addVars['appversions'])) {
+ $this->Error->addError($this->addVars['appversions']);
+ }
+
+ //Make sure GUIDs match in all manifests
+ if (empty($guid)) {
+ $guid = $manifestData['id'];
+ }
+ elseif ($manifestData['id'] != $guid) {
+ $this->Error->addError(_('devcp_error_file_guids_dont_match'));
+ }
+ }
+ else {
+ // There was an error validating manifest data
+ $this->Error->addError($validate);
+ }
+ }
+ else {
+ $validAppReference = sprintf(_('devcp_valid_app_reference'), '<a href="'.$this->url('/pages/appversions').'">'._('devcp_valid_app_reference_linktext').'</a>');
+ $this->Error->addError(_('devcp_error_index_rdf_notfound').'<br>'.$validAppReference);
+ }
+ }
+ }
+
+ if ($this->Error->noErrors()) {
+
+ //These are arrays by locale
+ $addonNames = $manifestData['name'];
+ $addonDesc = $manifestData['description'];
+
+ //In case user said it was a new add-on when it is actually an update
+ if ($existing = $this->Addon->findAll("Addon.guid='{$manifestData['id']}'")) {
+ if ($existing[0]['Addon']['status'] != STATUS_NULL && $this->addVars['newAddon'] == true) {
+ $this->addVars['newAddon'] = false;
+ $this->publish('newAddon', $this->addVars['newAddon']);
+ }
+
+ /**
+ * If user went back to step 1, we know because newAddon is true
+ * and status is NULL. If that's the case, we make a note so that
+ * we don't insert things that are already inserted.
+ */
+ if ($existing[0]['Addon']['status'] == STATUS_NULL) {
+ $this->addVars['skipInserts'] = true;
+ }
+
+ $this->addVars['existing'] = $existing[0];
+ $this->publish('existing', $this->addVars['existing']);
+ $this->publish('id', $this->addVars['existing']['Addon']['id']);
+ $this->Addon->id = $this->addVars['existing']['Addon']['id'];
+ if (!$this->Amo->checkOwnership($this->addVars['existing']['Addon']['id'])) {
+ $this->flash(_('devcp_error_update_access_denied'));
+ return;
+ }
+ }
+ elseif ($this->addVars['newAddon'] == false) {
+ $this->addVars['newAddon'] = true;
+ $this->publish('newAddon', $this->addVars['newAddon']);
+ $this->publish('existing', '');
+ $this->publish('id', '');
+ $this->Addon->id = 0;
+ }
+
+ //Check for identical versions
+ if (!empty($this->Addon->id)) {
+
+ for ($f = 1; $f <= 4; $f++) {
+ if (!empty($this->data['File']['platform_id'.$f])) {
+ $platformIds[] = $this->data['File']['platform_id'.$f];
+ }
+ }
+
+ //If updating the addon, get any identical version numbers
+ //Must have WHERE statement this way, otherwise cake doesn't quote properly
+ if ($versions = $this->Version->findAll("addon_id={$this->Addon->id} AND version='{$manifestData['version']}'")) {
+ foreach ($versions as $version) {
+ foreach($version['File'] as $file) {
+ if (in_array($file['platform_id'], $platformIds) && $file['status'] != STATUS_NULL) {
+ $this->Error->addError(sprintf(_('devcp_error_identical_version_exists'), $manifestData['version']));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ //If it is a search plugin, read the .src file
+ else {
+ //Parse the .src file
+ $src = $this->Src->parse(REPO_PATH.'/temp/'.$this->addVars['file1']['filename']);
+ if ($src !== false) {
+ $manifestData['name']['en-US'] = $src;
+ }
+ else {
+ $manifestData = array();
+ }
+
+ $this->data['Addon']['platform_id'] = 1;
+ }
+
+ //If no errors, save
+ if ($this->Error->noErrors()) {
+
+ //Create the addon entry if new
+ if ($this->addVars['newAddon'] == true) {
+ if ($this->data['Addon']['addontype_id'] != ADDON_SEARCH) {
+ $this->data['Addon']['guid'] = $manifestData['id'];
+ }
+
+ //If creating new, blacklist status and id.
+ $addonData = array_merge($this->data['Addon'], (array)$this->addVars['file4']);
+ $addonData = $this->Amo->filterFields($addonData, array(),
+ array('status', 'id', 'trusted', 'averagerating', 'weeklydownloads', 'totaldownloads'));
+ $this->Addon->save($addonData);
+
+ if (empty($this->addVars['skipInserts'])) {
+ $this->Addon->id = $this->Addon->getLastInsertId();
+
+ //Insert current user as author so no permissions issues occur
+ $session = $this->Session->read('User');
+ $this->Addon->execute("INSERT INTO addons_users (addon_id, user_id) VALUES({$this->Addon->id}, {$session['id']})");
+ }
+
+ $this->addVars['existing'] = $this->data;
+ $this->publish('id', $this->Addon->id);
+ }
+ else {
+ //If updating, whitelist defaultlocale and icon fields
+ if (!empty($this->addVars['file4'])) {
+ $addonData = array_merge($this->data['Addon'], $this->addVars['file4']);
+ }
+ else {
+ $addonData = $this->data['Addon'];
+ }
+ $addonData = $this->Amo->filterFields($addonData,
+ array('addontype_id', 'defaultlocale', 'icondata', 'icontype'));
+ $this->Addon->save($addonData);
+ }
+
+ //Create the version entry
+ $this->data['Version']['addon_id'] = $this->Addon->id;
+ $this->data['Version']['version'] = (!empty($manifestData['version'])) ? $manifestData['version'] : date('Ymd');
+
+ //Blacklist id. addon_id should be watched too, but it's already overwritten above
+ $versionData = $this->Amo->filterFields($this->data['Version'], array(),
+ array('id'));
+ $this->Version->save($versionData);
+ $this->Version->id = $this->Version->getLastInsertId();
+ $this->publish('version', $this->Version->id);
+
+ if(!empty($this->addVars['appversions'])) {
+ //Insert target apps
+ foreach ($this->addVars['appversions'] as $appversion) {
+ //Cake doesn't deal with extra fields in HABTM tables, so have to insert manually
+ $this->Version->execute("INSERT INTO applications_versions (version_id, application_id, min, max) VALUES('{$this->Version->id}', '{$appversion['application_id']}', '{$appversion['min']}', '{$appversion['max']}')");
+ }
+ }
+
+ //Insert files
+ for ($f = 1; $f <= 3; $f++) {
+ if (!empty($this->addVars['file'.$f]['filename'])) {
+ $this->File->id = 0;
+ $this->addVars['file'.$f]['version_id'] = $this->Version->id;
+
+ //These fields are parsed through the code and shouldn't need filtering
+ $this->File->save($this->addVars['file'.$f]);
+ $this->addVars['files'][] = $this->File->getLastInsertId();
+ }
+ }
+ $this->publish('files', $this->addVars['files']);
+
+ //Show next step
+ $this->addVars['manifestData'] = $manifestData;
+
+ //If user opted to not review add-on info and all required info is present,
+ //skip to step 3
+ if (!empty($this->data['Addon']['Review']) && $this->Developers->noReviewRequired()) {
+ $this->_addStep3();
+ }
+ else {
+ $this->_addStep2();
+ }
+
+ return;
+ }
+ }
+ }
+
+ //Prep for view
+ //Get Platforms list
+ $this->set('platforms', $this->Amo->getPlatformName());
+
+ //Default to reviewing add-on information
+ $this->publish('ReviewInfo', ((isset($this->data['Addon']['Review']) && $this->data['Addon']['Review'] == 1) ? array('value' => '1', 'checked' => 'checked') : array()));
+
+ //Set allowed addontypes.
+ $allowedAddonTypes = $this->Developers->getAllowedAddonTypes(true, $this->SimpleAcl->actionAllowed('*', '*', $this->Session->read('User')));
+ $this->set('allowedAddonTypes', $allowedAddonTypes);
+
+ //Retrieve language arrays from bootstrap.
+ global $valid_languages, $native_languages;
+ foreach (array_keys($valid_languages) as $key) {
+ $languages[$key] = $native_languages[$key]['native'];
+ }
+
+ if (empty($this->data))
+ $this->data = array();
+ $this->publish('data', $this->data);
+ $this->set('errors', $this->Error->errors);
+ $this->publish('step', 1);
+ $this->set('languages', $languages);
+ $this->render('add_step1');
+ }
+
+ /**
+ * Step 2: Add-on wide information
+ */
+ function _addStep2() {
+
+ //Check if we are processing step 2 or just displaying the view for it
+ if (isset($this->data['Addon']['add_step2'])) {
+
+ //Check for model validation first
+ if (!$this->Addon->validates($this->data)) {
+ $this->Error->addError(_('error_formerrors'));
+ $this->validateErrors();
+ }
+
+ //Validate tags/categories if not correcting addontype id
+ if (!empty($this->data['Addon']['addontype_id']) && $this->data['Addon']['addontype_id'] != $this->addVars['existing']['Addon']['addontype_id']) {
+ unset($this->data['Tag']);
+ $this->addVars['showTagsStep3'] = $this->data['Addon']['addontype_id'];
+ }
+ elseif ($this->addVars['existing']['Addon']['addontype_id'] != ADDON_SEARCH && empty($this->data['Tag']['noTags'])) {
+ //Search engines don't have tags
+ @$this->Developers->validateTags($this->data['Tag']['Tag']);
+ }
+
+ //Validate users
+ @$this->Developers->validateUsers($this->data['User']['User']);
+
+ if ($this->Error->noErrors()) {
+ //Updated Addon
+ if ($this->addVars['newAddon'] == false) {
+ $tagData = $this->data['Tag']['Tag'];
+ unset($this->data['Tag']);
+ unset($this->Addon->data['Tag']); // Cake--
+ $this->Tag->LEGACY_saveCategories($this->Addon->id, $tagData);
+
+ //Update addon - usual addon blacklist
+ $addonData = $this->Amo->filterFields($this->data, array(),
+ array('id', 'guid', 'status', 'trusted', 'averagerating', 'weeklydownloads', 'totaldownloads'));
+
+ if (!$this->Addon->save($addonData, false)) {
+ $this->Error->addError(_('devcp_error_saving'));
+ }
+ }
+ //New Addon
+ else {
+ //Check for duplicate names
+ //@TODO this doesn't really do well with the new translation stuff.
+ if ($this->Addon->findAllByName($this->data['Addon']['name'])) {
+ $this->Error->addError(_('devcp_error_addonname_not_unique'));
+ }
+ else {
+ //Insert addon
+ $addonData = $this->Amo->filterFields($this->data, array(),
+ array('id', 'guid', 'status', 'trusted', 'averagerating', 'weeklydownloads', 'totaldownloads'));
+ if (!$this->Addon->save($addonData, false)) {
+ $this->Error->addError(_('devcp_error_saving'));
+ }
+ }
+ }
+ }
+
+ if ($this->Error->noErrors()) {
+ //Getting to this point means there were no errors, so show next step
+ $this->_addStep3();
+ return;
+ }
+
+ //Prepare for view - use post data (unclean data before publishing to avoid escaped quotes in html)
+ $info = $this->Amo->unclean($this->data);
+
+ //Checkboxes
+ $checked = array('value' => '1', 'checked' => 'checked');
+ $notChecked = array();
+ $info['Addon']['viewsource'] = (!empty($this->data['Addon']['viewsource'])) ? $checked : $notChecked;
+ $info['Addon']['prerelease'] = (!empty($this->data['Addon']['prerelease'])) ? $checked : $notChecked;
+ $info['Addon']['sitespecific'] = (!empty($this->data['Addon']['sitespecific'])) ? $checked : $notChecked;
+ $info['Addon']['externalsoftware'] = (!empty($this->data['Addon']['externalsoftware'])) ? $checked : $notChecked;
+ }
+ else {
+ //Prepare for view - use existing data if !empty, else use parsed manifest
+ $manifestData = $this->Amo->unclean($this->addVars['manifestData']);
+ $info = $this->Amo->unclean($this->data);
+
+ $info['Addon']['name'] = (!empty($this->addVars['existing']['Translation']['name']['string']) ? $this->addVars['existing']['Translation']['name']['string'] : (!empty($manifestData['name']['en-US']) ? $manifestData['name']['en-US'] : ''));
+ $info['Addon']['description'] = (!empty($this->addVars['existing']['Translation']['description']['string']) ? $this->addVars['existing']['Translation']['description']['string'] : (!empty($manifestData['description']['en-US']) ? $manifestData['description']['en-US'] : ''));
+ $info['Addon']['homepage'] = (!empty($this->addVars['existing']['Translation']['homepage']['string']) ? $this->addVars['existing']['Translation']['homepage']['string'] : (!empty($manifestData['homepageURL']) ? $manifestData['homepageURL'] : ''));
+
+ $info['Addon']['addontype_id'] = !empty($this->addVars['existing']['Addon']['addontype_id']) ? $this->addVars['existing']['Addon']['addontype_id'] : $this->data['Addon']['addontype_id'];
+ $info['Version']['version'] = !empty($manifestData['version']) ? $manifestData['version'] : '';
+ $info['Addon']['summary'] = !empty($this->addVars['existing']['Translation']['summary']['string']) ? $this->addVars['existing']['Translation']['summary']['string'] : '';
+
+ $info['Addon']['supportemail'] = (!empty($this->addVars['existing']['Translation']['supportemail']['string']) ? $this->addVars['existing']['Translation']['supportemail']['string'] : '');
+ $info['Addon']['supporturl'] = (!empty($this->addVars['existing']['Translation']['supporturl']['string']) ? $this->addVars['existing']['Translation']['supporturl']['string'] : (!empty($manifestData['homepageURL']) ? $manifestData['homepageURL'] : ''));
+
+ $info['Addon']['eula'] = !empty($this->addVars['existing']['Translation']['eula']['string']) ? $this->addVars['existing']['Translation']['eula']['string'] : '';
+ $info['Addon']['privacypolicy'] = !empty($this->addVars['existing']['Translation']['privacypolicy']['string']) ? $this->addVars['existing']['Translation']['privacypolicy']['string'] : '';
+ $info['Addon']['guid'] = (!empty($this->addVars['existing']['Addon']['guid']) ? $this->addVars['existing']['Addon']['guid'] : (!empty($manifestData['id']) ? $manifestData['id'] : ''));
+ $info['File']['id'] = $this->addVars['files'];
+
+ //Checkboxes
+ $checked = array('value' => '1', 'checked' => 'checked');
+ $notChecked = array();
+ $info['Addon']['viewsource'] = (!empty($this->addVars['existing']['Addon']['viewsource'])) ? $checked : $notChecked;
+ $info['Addon']['prerelease'] = (!empty($this->addVars['existing']['Addon']['prerelease'])) ? $checked : $notChecked;
+ $info['Addon']['sitespecific'] = (!empty($this->addVars['existing']['Addon']['sitespecific'])) ? $checked : $notChecked;
+ $info['Addon']['externalsoftware'] = (!empty($this->addVars['existing']['Addon']['externalsoftware'])) ? $checked : $notChecked;
+ }
+
+ //Get authors in order of post data, existing data, default data
+ $info['authors'] = @$this->Developers->getAuthors($this->addVars['existing']['User']);
+
+ //Get application_ids
+ $applicationIds = array();
+ if (!empty($this->addVars['appversions'])) {
+ foreach ($this->addVars['appversions'] as $appversion) {
+ $applicationIds[] = $appversion['application_id'];
+ }
+ }
+ else {
+ $version = $this->Version->read();
+ foreach ($version['Application'] as $appversion) {
+ $applicationIds[] = $appversion['id'];
+ }
+ }
+
+ $tags = $this->Developers->getTags($this->addVars['existing']['Addon']['addontype_id'], $applicationIds);
+ $this->set('tags', $tags);
+
+ //Get selected tags in order of post data, existing data, default data
+ $info['selectedTags'] = @$this->Developers->getSelectedTags($this->addVars['existing']['Tag']);
+
+ //Set allowed addontypes.
+ $allowedAddonTypes = $this->Developers->getAllowedAddonTypes(false, $this->SimpleAcl->actionAllowed('*', '*', $this->Session->read('User')));
+ $this->set('allowedAddonTypes', $allowedAddonTypes);
+
+ $this->publish('info', $info);
+ $this->set('errors', $this->Error->errors);
+ $this->publish('step', 2);
+ $this->render('add_step2');
+ }
+
+ /**
+ * Step 3: Version Information
+ */
+ function _addStep3() {
+ //Check whether we are processing Step 3 or just displaying it
+ if (isset($this->data['Addon']['add_step3'])) {
+ //Check for model validation first
+ if (!$this->Version->validates($this->data)) {
+ $this->Error->addError(_('error_formerrors'));
+ $this->validateErrors();
+ }
+
+ if ($this->addVars['newAddon'] == false && empty($this->data['Version']['releasenotes'])) {
+ $this->Error->addError(_('devcp_error_describe_changes'), 'Version/releasenotes');
+ //For some reason, using Version model to invalidate doesn't work...
+ $this->Addon->invalidate('releasenotes');
+ $this->Error->addError(_('error_formerrors'));
+ }
+
+ if ($this->Error->noErrors()) {
+ $version = $this->Version->read();
+
+ $fileUpdates = $this->Developers->moveFiles($version, $this->addVars['existing']['Addon']['addontype_id']);
+
+ if ($this->Error->noErrors()) {
+
+ //Update version
+ $versionData = $this->Amo->filterFields($this->data['Version'], array(),
+ array('id', 'addon_id'));
+ $this->Version->data = '';
+ $this->Version->save($versionData);
+
+ //Determine file status
+ $fileStatus = $this->Developers->determineFileStatus($this->addVars['existing']['Addon']);
+
+ //Update file locations
+ if (!empty($fileUpdates)) {
+ foreach ($fileUpdates as $file => $filename) {
+ $this->File->id = $file;
+ $filename['status'] = $fileStatus;
+ $this->File->save($filename);
+
+ // Copy file to rsync area if public
+ if ($fileStatus == STATUS_PUBLIC) {
+ $fileInfo = $this->File->read();
+ $this->Amo->copyFileToPublic($this->Addon->id, $fileInfo['File']['filename']);
+ $this->File->save(array('datestatuschanged' => $this->Amo->getNOW()));
+ }
+ }
+ }
+
+ //If add-on is public, cancel any pending files
+ if ($this->addVars['existing']['Addon']['status'] == STATUS_PUBLIC) {
+ if (!empty($this->addVars['existing']['Version'])) {
+ foreach($this->addVars['existing']['Version'] as $version) {
+ $version = $this->Version->find("Version.id='{$version['id']}'");
+ if (!empty($version['File'])) {
+ foreach ($version['File'] as $file) {
+ if ($file['status'] == STATUS_PENDING) {
+ $this->File->id = $file['id'];
+ $this->File->save(array('status' => STATUS_SANDBOX));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //Update addon status if new or incomplete
+ if ($this->addVars['newAddon'] == true || $this->addVars['existing']['Addon']['status'] == 0) {
+ $addonData = array('Addon' => array('status' => STATUS_SANDBOX));
+ if (!empty($this->data['Tag'])) {
+ $addonData['Tag'] = $this->data['Tag'];
+ }
+ $this->Addon->save($addonData);
+ }
+
+ //Getting this far means there were no errors, display step 5
+ $this->_addStep4();
+ return;
+ }
+ }
+ }
+
+ //Prep view
+ //Pull version info
+ $info = $this->Version->read();
+
+ if (!empty($this->addVars['showTagsStep3'])) {
+ foreach ($info['Application'] as $appversion) {
+ $applicationIds[] = $appversion['id'];
+ }
+ $tags = $this->Developers->getTags($this->addVars['showTagsStep3'], $applicationIds);
+ $this->publish('tags', $tags);
+ }
+
+ $info['files'] = $this->File->findAllByVersion_id($this->Version->id);
+ $info['targetapps'] = $this->Amo->getMinMaxVersions($this->Version->id);
+
+ // Determine compatibility with latest Firefox
+ $noticeVersion = $this->Config->getValue('firefox_notice_version');
+ if (!empty($noticeVersion)) {
+ if (!empty($info['targetapps'])) {
+ foreach ($info['targetapps'] as $targetApp) {
+ if ($targetApp['max']['application_id'] == APP_FIREFOX &&
+ $this->Versioncompare->compareVersions($targetApp['max']['version'], $noticeVersion) == -1) {
+ $this->publish('showFirefoxVersionNotice', true);
+ }
+ }
+ }
+ }
+
+ //Get Platforms list
+ $this->publish('platforms', $this->Amo->getPlatformName());
+
+ $this->publish('info', $info);
+ $this->set('errors', $this->Error->errors);
+ $this->publish('step', 3);
+ $this->render('add_step3');
+ }
+
+ /**
+ * Step 4: Localization
+ */
+ function _addStep4() {
+ //Check whether we are processing Step 4 or just displaying it
+ if (isset($this->data['Addon']['add_step4'])) {
+
+ $this->Developers->saveTranslations($this->data);
+
+ $this->_addStep5();
+ return;
+ }
+
+ //Prep view
+
+ //Retrieve language arrays from bootstrap.
+ global $valid_languages, $native_languages;
+ foreach (array_keys($valid_languages) as $key) {
+ $languages[$key] = $native_languages[$key]['native'];
+
+ $this->Addon->setLang($key, $this);
+ $addon = $this->Addon->read();
+
+ foreach ($addon['Translation'] as $field => $translation) {
+ if ($translation['locale'] == $key) {
+ $info[$key][$field] = $translation['string'];
+ }
+ else {
+ $info[$key][$field] = '';
+ }
+ }
+
+ $this->Version->useLang = $key;
+ $version = $this->Version->read();
+
+ foreach ($version['Translation'] as $field => $translation) {
+ if ($translation['locale'] == $key) {
+ $info[$key][$field] = $translation['string'];
+ }
+ else {
+ $info[$key][$field] = '';
+ }
+ }
+ }
+
+ $localizedFields = array(
+ 'name' => array(
+ 'type' => 'input',
+ 'display' => _('devcp_addon_field_name_displaytitle'),
+ 'model' => 'Addon',
+ 'field' => 'name',
+ 'attributes' => array()
+ ),
+ 'homepage' => array(
+ 'type' => 'input',
+ 'display' => _('devcp_addon_field_homepage_displaytitle'),
+ 'model' => 'Addon',
+ 'field' => 'homepage',
+ 'attributes' => array(
+ 'size' => 40
+ )
+ ),
+ 'summary' => array(
+ 'type' => 'textarea',
+ 'display' => _('devcp_addon_field_summary_displaytitle'),
+ 'model' => 'Addon',
+ 'field' => 'summary',
+ 'attributes' => array(
+ 'rows' => 3,
+ 'cols' => 55,
+ 'onBlur' => 'checkSummary(this, \''._('devcp_error_addon_field_summary_toolong').'\');'
+ )
+ ),
+ 'description' => array(
+ 'type' => 'textarea',
+ 'display' => _('devcp_addon_field_description_displaytitle'),
+ 'model' => 'Addon',
+ 'field' => 'description',
+ 'attributes' => array(
+ 'rows' => 4,
+ 'cols' => 55
+ )
+ ),
+ 'eula' => array(
+ 'type' => 'textarea',
+ 'display' => _('devcp_addon_field_eula_displaytitle'),
+ 'model' => 'Addon',
+ 'field' => 'eula',
+ 'attributes' => array(
+ 'rows' => 6,
+ 'cols' => 55
+ )
+ ),
+ 'privacypolicy' => array(
+ 'type' => 'textarea',
+ 'display' => _('devcp_addon_field_privacy_displaytitle'),
+ 'model' => 'Addon',
+ 'field' => 'privacypolicy',
+ 'attributes' => array(
+ 'rows' => 6,
+ 'cols' => 55
+ )
+ ),
+ 'releasenotes' => array(
+ 'type' => 'textarea',
+ 'display' => _('devcp_addon_field_versionnotes_displaytitle'),
+ 'model' => 'Version',
+ 'field' => 'releasenotes',
+ 'attributes' => array(
+ 'rows' => 3,
+ 'cols' => 55
+ )
+ )
+ );
+
+ //Set up localebox info
+ $this->set('localebox', array('info' => $info,
+ 'defaultLocale' => $this->addVars['defaultLocale'],
+ 'languages' => $languages,
+ 'localizedFields' => $localizedFields));
+ $this->publish('step', 4);
+ $this->render('add_step4');
+ }
+
+ /**
+ * Step 5: Success
+ */
+ function _addStep5() {
+ //Determine file status
+ $fileStatus = $this->Developers->determineFileStatus($this->addVars['existing']['Addon']);
+
+ $this->publish('fileStatus', $fileStatus);
+ $this->publish('step', 5);
+ $this->render('add_step5');
+ }
+
+ /**
+ * Cancel additem process
+ */
+ function _cancelAdd() {
+ if (!$this->Amo->checkOwnership($this->Addon->id)) {
+ $this->flash(_('devcp_error_addon_access_denied'), '/developers/index');
+ return;
+ }
+
+ //Delete version, files, and translations
+ $this->Developers->deleteVersion($this->Version->id);
+
+ //If this was a new add-on, delete it and translations
+ if ($this->addVars['newAddon'] == true) {
+ $this->Developers->deleteAddon($this->Addon->id);
+ }
+
+ $this->redirect('/developers');
+ }
+
+ /**
+ * Edit add-on
+ * @param int $id
+ */
+ function edit($id) {
+ $this->Amo->clean($id);
+ $this->publish('subpagetitle', _('devcp_addon_edit_pagetitle'));
+ $this->breadcrumbs[_('devcp_addon_edit_pagetitle')] = '/developers/edit/'.$id;
+ $this->publish('breadcrumbs', $this->breadcrumbs);
+
+ if (!$this->Amo->checkOwnership($id)) {
+ $this->flash(_('devcp_error_addon_access_denied'), '/developers/index');
+ return;
+ }
+
+ //Bind necessary models
+ $this->User->bindFully();
+ $this->Addontype->bindFully();
+ $this->Version->bindFully();
+ $this->Addon->bindFully();
+
+ $this->Addon->id = $id;
+
+ $this->Amo->detailedLog('Editing add-on');
+
+ if (!empty($this->data)) {
+ $this->Amo->detailedLog('Non-empty data');
+ $this->Amo->detailedLog('Editing add-on details');
+ //Check for model validation first
+ if (!$this->Addon->validates($this->data)) {
+ $this->Error->addError(_('error_formerrors'));
+ $this->validateErrors();
+ $this->Amo->detailedLog('Validation errors');
+ }
+
+ $addon = $this->Addon->read();
+
+ //Validate tags/categories
+ if ($addon['Addon']['addontype_id'] != ADDON_SEARCH && empty($this->data['Tag']['noTags'])) {
+ @$this->Developers->validateTags($this->data['Tag']['Tag']);
+ }
+
+ //Validate users
+ @$this->Developers->validateUsers($this->data['User']['User']);
+
+ $this->Amo->detailedLog('Validated tags and users');
+
+ //Delete icon if requested
+ if (!empty($this->data['Addon']['DeleteIcon'])) {
+ $this->data['Addon']['icontype'] = '';
+ $this->data['Addon']['icondata'] = '';
+ }
+
+ //Update/insert icon
+ if (!empty($this->data['Addon']['icon']['name'])) {
+ $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');
+
+ $iconData = $this->Developers->validateIcon($this->data['Addon']['icon'], $fileErrors, $allowedImage);
+
+ if (is_string($iconData)) {
+ $this->Error->addError($iconData, 'Addon/icon');
+ }
+ else {
+ $this->data['Addon'] = array_merge($this->data['Addon'], $iconData);
+ }
+ }
+
+ if ($this->Error->noErrors()) {
+ $this->Amo->detailedLog('No errors - performing update');
+ //Update addon
+ $this->Developers->saveUsers($this->data['User']['User']);
+ $this->Amo->detailedLog('Saved users');
+
+ //Strip localized fields
+ $addonData = $this->Developers->stripLocalized($this->data);
+ $this->Amo->detailedLog('Stripped localized fields: '.print_r($addonData, true), false);
+
+ //usual addon blacklist
+ if ($this->SimpleAcl->actionAllowed('*', '*', $this->Session->read('User'))) {
+ $blacklist = array('id', 'guid', 'status');
+ }
+ else {
+ $blacklist = array('id', 'guid', 'status', 'trusted', 'averagerating', 'weeklydownloads', 'totaldownloads');
+ }
+ $addonData = $this->Amo->filterFields($addonData, array(), $blacklist);
+ $this->Amo->detailedLog('Fields filtered: '.print_r($addonData, true), false);
+ $this->Addon->data = array();
+ $tagData = $addonData['Tag']['Tag'];
+ unset($addonData['Tag']['Tag']);
+
+ if ($this->Addon->save($addonData) && $this->Developers->saveTranslations($this->data)) {
+ $this->Tag->LEGACY_saveCategories($this->Addon->id, $tagData);
+ $this->Amo->detailedLog('Add-on and translations saved: '.print_r($addonData, true));
+ $this->flash(_('devcp_addon_updated_successfully'), '/developers/edit/'.$this->Addon->id);
+ return;
+ }
+ else {
+ $this->Error->addError(_('devcp_error_saving'));
+ }
+ }
+ }
+
+ if (!$addon = $this->Addon->read()) {
+ $this->flash(_('error_addon_notfound'), '/developers/index');
+ return;
+ }
+
+ //Get tags based on addontype
+ $this->Version->id = $addon['Version'][0]['id'];
+ $applicationIds = array();
+ $version = $this->Version->read();
+ if (!empty($version)) {
+ foreach ($version['Application'] as $appversion) {
+ $applicationIds[] = $appversion['id'];
+ }
+ }
+ $this->set('tags', $this->Developers->getTags($addon['Addon']['addontype_id'], $applicationIds));
+
+ //Get selected tags
+ $this->set('selectedTags', $this->Developers->getSelectedTags($addon['Tag']));
+
+ //Get author info
+ $addon['authors'] = $this->Developers->getAuthors($addon['User'], false);
+
+ //Retrieve language arrays from bootstrap.
+ global $valid_languages, $native_languages;
+ foreach (array_keys($valid_languages) as $key) {
+ $languages[$key] = $native_languages[$key]['native'];
+
+ $this->Addon->setLang($key, $this);
+ $addonL = $this->Addon->read();
+
+ foreach ($addonL['Translation'] as $field => $translation) {
+ if ($translation['locale'] == $key) {
+ $info[$key][$field] = $translation['string'];
+ }
+ else {
+ $info[$key][$field] = '';
+ }
+ }
+ }
+ $this->Addon->setLang(LANG, $this);
+
+ //Checkboxes
+ $checked = array('value' => '1', 'checked' => 'checked');
+ $notChecked = array();
+ $addon['Addon']['viewsource'] = (!empty($addon['Addon']['viewsource'])) ? $checked : $notChecked;
+ $addon['Addon']['prerelease'] = (!empty($addon['Addon']['prerelease'])) ? $checked : $notChecked;
+ $addon['Addon']['sitespecific'] = (!empty($addon['Addon']['sitespecific'])) ? $checked : $notChecked;
+ $addon['Addon']['externalsoftware'] = (!empty($addon['Addon']['externalsoftware'])) ? $checked : $notChecked;
+ $addon['Addon']['trusted'] = (!empty($addon['Addon']['trusted'])) ? $checked : $notChecked;
+
+ $this->publish('addon', $addon);
+ $this->set('errors', $this->Error->errors);
+ $localizedFields = array(
+ 'name' => array(
+ 'type' => 'input',
+ 'display' => _('devcp_addon_field_name_displaytitle'),
+ 'model' => 'Addon',
+ 'field' => 'name',
+ 'attributes' => array()
+ ),
+ 'homepage' => array(
+ 'type' => 'input',
+ 'display' => _('devcp_addon_field_homepage_displaytitle'),
+ 'model' => 'Addon',
+ 'field' => 'homepage',
+ 'attributes' => array(
+ 'size' => 40
+ )
+ ),
+ 'supportemail' => array(
+ 'type' => 'input',
+ 'display' => _('devcp_addon_field_supportemail_displaytitle'),
+ 'model' => 'Addon',
+ 'field' => 'supportemail',
+ 'attributes' => array(
+ 'size' => 40
+ )
+ ),
+ 'supporturl' => array(
+ 'type' => 'input',
+ 'display' => _('devcp_addon_field_supporturl_displaytitle'),
+ 'model' => 'Addon',
+ 'field' => 'supporturl',
+ 'attributes' => array(
+ 'size' => 40
+ )
+ ),
+ 'summary' => array(
+ 'type' => 'textarea',
+ 'display' => _('devcp_addon_field_summary_displaytitle'),
+ 'model' => 'Addon',
+ 'field' => 'summary',
+ 'attributes' => array(
+ 'rows' => 3,
+ 'cols' => 55,
+ 'onBlur' => 'checkSummary(this, \''._('devcp_error_addon_field_summary_toolong').'\');'
+ )
+ ),
+ 'description' => array(
+ 'type' => 'textarea',
+ 'display' => _('devcp_addon_field_description_displaytitle'),
+ 'model' => 'Addon',
+ 'field' => 'description',
+ 'attributes' => array(
+ 'rows' => 4,
+ 'cols' => 55
+ )
+ ),
+ 'eula' => array(
+ 'type' => 'textarea',
+ 'display' => _('devcp_addon_field_eula_displaytitle'),
+ 'model' => 'Addon',
+ 'field' => 'eula',
+ 'attributes' => array(
+ 'rows' => 6,
+ 'cols' => 55
+ )
+ ),
+ 'privacypolicy' => array(
+ 'type' => 'textarea',
+ 'display' => _('devcp_addon_field_privacy_displaytitle'),
+ 'model' => 'Addon',
+ 'field' => 'privacypolicy',
+ 'attributes' => array(
+ 'rows' => 6,
+ 'cols' => 55
+ )
+ )
+ );
+
+ //Set up localebox info
+ $this->set('localebox', array('info' => $info,
+ 'defaultLocale' => $addon['Addon']['defaultlocale'],
+ 'languages' => $languages,
+ 'localizedFields' => $localizedFields));
+ }
+
+ /**
+ * Edit a version
+ * @param int $id
+ */
+ function editversion($id) {
+ $this->Amo->clean($id);
+ $this->set ('subpagetitle', _('devcp_version_edit_pagetitle'));
+ $this->breadcrumbs[_('devcp_version_edit_pagetitle')] = '/developers/editversion/'.$id;
+ $this->publish('breadcrumbs', $this->breadcrumbs);
+
+ //Bind necessary models
+ $this->User->bindFully();
+ $this->Addontype->bindFully();
+ $this->Version->bindFully();
+ $this->Addon->bindFully();
+
+ $this->Version->id = $id;
+ if (!$version = $this->Version->read()) {
+ $this->flash(_('error_version_notfound'), '/developers/index');
+ return;
+ }
+
+ if (!$this->Amo->checkOwnership($version['Version']['addon_id'])) {
+ $this->flash(_('devcp_error_addon_access_denied'), '/developers/index');
+ return;
+ }
+
+ if (!empty($this->data)) {
+ foreach ($this->data['File']['id'] as $id => $file_id) {
+ $this->File->id = $file_id;
+
+ //Update or delete file
+ if ($this->data['File']['Delete'][$id] != 1) {
+ $fileData = array('platform_id' => $this->data['File']['platform_id'][$id]);
+ $this->File->save($fileData);
+ }
+ else {
+ $this->Developers->deleteFile($this->File->id, $version['Version']['addon_id']);
+ }
+ }
+
+ //Save translated fields (releasenotes)
+ $this->Developers->saveTranslations($this->data);
+
+ //Save min/max versions
+ $this->Amo->saveMinMaxVersions($this->Version->id, $this->data['targetApps']);
+
+ //Save other version fields by whitelist
+ $versionData = $this->Amo->filterFields($this->data['Version'], array('approvalnotes'));
+ $this->Version->save($versionData);
+
+ $this->flash(_('devcp_version_updated_successfully'), '/developers/editversion/'.$this->Version->id);
+ return;
+ }
+
+ $version['targetapps'] = $this->Amo->getMinMaxVersions($this->Version->id);
+
+ // Get all versions
+ foreach ($version['targetapps'] as $k => $app) {
+ $_versionlist = $this->Appversion->findAllByApplication_id($app['applications']['id'], '', '', '', '', -1);
+ $this->Versioncompare->sortAppversionArray($_versionlist);
+ $version['targetapps'][$k]['appversions'] = $_versionlist;
+ }
+
+ //Retrieve language arrays from bootstrap.
+ global $valid_languages, $native_languages;
+ foreach (array_keys($valid_languages) as $key) {
+ $languages[$key] = $native_languages[$key]['native'];
+
+ $this->Version->setLang($key, $this);
+ $versionL = $this->Version->read();
+
+ foreach ($versionL['Translation'] as $field => $translation) {
+ if ($translation['locale'] == $key) {
+ $info[$key][$field] = $translation['string'];
+ }
+ else {
+ $info[$key][$field] = '';
+ }
+ }
+ }
+ $this->Version->setLang(LANG, $this);
+
+ //Pull add-on info for translations
+ $this->Addon->id = $version['Version']['addon_id'];
+ $addon = $this->Addon->read();
+
+ $localizedFields = array(
+ 'releasenotes' => array(
+ 'type' => 'textarea',
+ 'display' => _('devcp_addon_field_versionnotes_displaytitle'),
+ 'model' => 'Version',
+ 'field' => 'releasenotes',
+ 'attributes' => array(
+ 'rows' => 3,
+ 'cols' => 55
+ )
+ )
+ );
+
+ $this->publish('version', $version);
+ $this->publish('addon', $addon);
+ $this->publish('platforms', $this->Amo->getPlatformName());
+
+ //Set up localebox info
+ $this->set('localebox', array('info' => $info,
+ 'defaultLocale' => $addon['Addon']['defaultlocale'],
+ 'languages' => $languages,
+ 'localizedFields' => $localizedFields));
+ //Javascript localization
+ $this->publish('jsLocalization', array(
+ 'deleteMessage' => _('devcp_question_delete_file')
+ ));
+ }
+
+ /**
+ * Disable or enable add-on
+ */
+ function disable($addon_id) {
+ $this->Amo->clean($addon_id);
+ $session = $this->Session->read('User');
+ $this->User->id = $session['id'];
+
+ $this->Addon->id = $addon_id;
+
+ // Make sure user has permission
+ if (!$this->Amo->checkOwnership($addon_id)) {
+ $this->flash(_('devcp_error_addon_access_denied'), '/developers/index');
+ return;
+ }
+
+ if (!empty($_POST)) {
+ if (!empty($_POST['enable'])) {
+ $addonData = array('inactive' => 0);
+ $this->Addon->save($addonData);
+ $this->flash(_('devcp_addon_enabled_successfully'), '/developers/details/'.$this->Addon->id);
+ }
+ else {
+ $addonData = array('inactive' => 1);
+ $this->Addon->save($addonData);
+ $this->flash(_('devcp_addon_disabled_successfully'), '/developers/details/'.$this->Addon->id);
+ }
+
+ return;
+ }
+
+ $addon = $this->Addon->read();
+
+ $this->publish('addon', $addon);
+
+ $this->render('disable');
+ }
+
+ /**
+ * Nominate an add-on to be public
+ * @param int $id the add-on id
+ */
+ function nominate($id) {
+ $this->Amo->clean($id);
+ $session = $this->Session->read('User');
+ $this->User->id = $session['id'];
+
+ $this->publish('subpagetitle', _('devcp_addon_nominate_pagetitle'));
+ $this->breadcrumbs[_('devcp_addon_nominate_pagetitle')] = '/developers/nominate/'.$id;
+ $this->publish('breadcrumbs', $this->breadcrumbs);
+
+ $this->User->bindFully();
+ $data = $this->User->read();
+
+ $this->Addon->id = $id;
+ if (!$addon = $this->Addon->read()) {
+ $this->flash(_('error_addon_notfound'), '/developers/index');
+ return;
+ }
+
+ //Make sure has ownership or is an editor to nominate
+ if (!$this->Amo->checkOwnership($id) && !$this->SimpleAcl->actionAllowed('Editors', '*', $this->Session->read('User'))) {
+ $this->flash(_('devcp_error_addon_access_denied'), '/developers/index');
+ return;
+ }
+
+ //Make sure add-on is in sandbox
+ if ($addon['Addon']['status'] != STATUS_SANDBOX) {
+ $this->flash(_('devcp_error_nominate_sandbox_only'), '/developers/details/'.$id, 3);
+ return;
+ }
+
+ //Nominate
+ if (!empty($_POST['nominate'])) {
+ //Make sure not a pre-release
+ if ($addon['Addon']['prerelease'] == 1) {
+ $this->flash(_('devcp_error_nominate_no_prerelease'), '/developers/details/'.$id, 3);
+ return;
+ }
+
+ //Make sure nomination message not empty
+ if (empty($this->data['Addon']['nominationmessage'])) {
+ $this->flash(_('devcp_error_nominate_message'), '/developers/nominate/'.$id, 3);
+ return;
+ }
+
+ //Amo->clean is being stupid. Yes, that's right. I said STUPID
+ $nominationMessage = str_replace('\n', "\n", $this->data['Addon']['nominationmessage']);
+ $nominationMessage = str_replace('\r', "\r", $nominationMessage);
+
+ $addonData = array('status' => STATUS_NOMINATED, 'nominationmessage' => $nominationMessage);
+
+ $this->Addon->save($addonData);
+ $this->flash(_('devcp_addon_nominated_successfully'), '/developers/details/'.$id, 3);
+ return;
+ }
+
+ $this->publish('addon', $addon);
+ }
+
+ /**
+ * AJAX action for looking up an author by email
+ * @param string $email
+ */
+ function authorLookup() {
+ // Rather than change our cake parameter regex, use a normal get var
+ $email = $_GET['q'];
+ $this->Amo->clean($email);
+ if ($authors = $this->User->findAllByEmail($email)) {
+ $author = $authors[0]['User']['firstname'].' '.$authors[0]['User']['lastname'];
+ $author .= ' ['.$authors[0]['User']['email'].']';
+ $this->publish('id', $authors[0]['User']['id']);
+ }
+ else {
+ $author = false;
+ }
+
+ $this->publish('author', $author);
+ $this->publish('email', $email);
+ $this->render('author_lookup', 'ajax');
+ }
+
}
+
?>