diff --git a/airtime_mvc/application/configs/constants.php b/airtime_mvc/application/configs/constants.php
index 7b27bc891..45bdbd123 100644
--- a/airtime_mvc/application/configs/constants.php
+++ b/airtime_mvc/application/configs/constants.php
@@ -19,6 +19,7 @@ define('LICENSE_URL' , 'http://www.gnu.org/licenses/agpl-3.0-standalone.h
define('AIRTIME_COPYRIGHT_DATE' , '2010-2012');
define('AIRTIME_REST_VERSION' , '1.1');
define('AIRTIME_API_VERSION' , '1.1');
+define('AIRTIME_CODE_VERSION' , '2.5.2');
// Metadata Keys for files
define('MDATA_KEY_FILEPATH' , 'filepath');
diff --git a/airtime_mvc/application/controllers/UpgradeController.php b/airtime_mvc/application/controllers/UpgradeController.php
new file mode 100644
index 000000000..2691f270f
--- /dev/null
+++ b/airtime_mvc/application/controllers/UpgradeController.php
@@ -0,0 +1,78 @@
+view->layout()->disableLayout();
+ $this->_helper->viewRenderer->setNoRender(true);
+
+ if (!$this->verifyAuth()) {
+ return;
+ }
+
+ $upgraders = array();
+ array_push($upgraders, new AirtimeUpgrader252());
+ /* These upgrades do not apply to open source Airtime yet.
+ array_push($upgraders, new AirtimeUpgrader253());
+ array_push($upgraders, new AirtimeUpgrader254());
+ */
+ $didWePerformAnUpgrade = false;
+ try
+ {
+ for ($i = 0; $i < count($upgraders); $i++)
+ {
+ $upgrader = $upgraders[$i];
+ if ($upgrader->checkIfUpgradeSupported())
+ {
+ // pass __DIR__ to the upgrades, since __DIR__ returns parent dir of file, not executor
+ $upgrader->upgrade(__DIR__); //This will throw an exception if the upgrade fails.
+ $didWePerformAnUpgrade = true;
+ $this->getResponse()
+ ->setHttpResponseCode(200)
+ ->appendBody("Upgrade to Airtime " . $upgrader->getNewVersion() . " OK
");
+ $i = 0; //Start over, in case the upgrade handlers are not in ascending order.
+ }
+ }
+
+ if (!$didWePerformAnUpgrade)
+ {
+ $this->getResponse()
+ ->setHttpResponseCode(200)
+ ->appendBody("No upgrade was performed. The current Airtime version is " . AirtimeUpgrader::getCurrentVersion() . ".
");
+ }
+ }
+ catch (Exception $e)
+ {
+ $this->getResponse()
+ ->setHttpResponseCode(400)
+ ->appendBody($e->getMessage());
+ }
+ }
+
+ private function verifyAuth()
+ {
+ //The API key is passed in via HTTP "basic authentication":
+ //http://en.wikipedia.org/wiki/Basic_access_authentication
+
+ $CC_CONFIG = Config::getConfig();
+
+ //Decode the API key that was passed to us in the HTTP request.
+ $authHeader = $this->getRequest()->getHeader("Authorization");
+
+ $encodedRequestApiKey = substr($authHeader, strlen("Basic "));
+ $encodedStoredApiKey = base64_encode($CC_CONFIG["apiKey"][0] . ":");
+
+ if ($encodedRequestApiKey !== $encodedStoredApiKey)
+ {
+ $this->getResponse()
+ ->setHttpResponseCode(401)
+ ->appendBody("Error: Incorrect API key.
");
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.3/upgrade.sql b/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.3/upgrade.sql
new file mode 100644
index 000000000..6c7980983
--- /dev/null
+++ b/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.3/upgrade.sql
@@ -0,0 +1,6 @@
+DELETE FROM cc_pref WHERE keystr = 'system_version';
+INSERT INTO cc_pref (keystr, valstr) VALUES ('system_version', '2.5.3');
+
+ALTER TABLE cc_files DROP COLUMN state;
+ALTER TABLE cc_files ADD import_status integer default 1; -- Default is "pending"
+UPDATE cc_files SET import_status=0; -- Existing files are already "imported"
diff --git a/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.5/upgrade.sql b/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.5/upgrade.sql
new file mode 100644
index 000000000..191eb2084
--- /dev/null
+++ b/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.5/upgrade.sql
@@ -0,0 +1,5 @@
+DELETE FROM cc_pref WHERE keystr = 'system_version';
+INSERT INTO cc_pref (keystr, valstr) VALUES ('system_version', '2.5.5');
+
+ALTER TABLE cc_show ADD COLUMN image_path varchar(255) DEFAULT '';
+ALTER TABLE cc_show_instances ADD COLUMN description varchar(255) DEFAULT '';
diff --git a/airtime_mvc/application/upgrade/Upgrades.php b/airtime_mvc/application/upgrade/Upgrades.php
new file mode 100644
index 000000000..f95216bd0
--- /dev/null
+++ b/airtime_mvc/application/upgrade/Upgrades.php
@@ -0,0 +1,292 @@
+filterByKeystr('system_version')
+ ->findOne();
+ $airtime_version = $pref->getValStr();
+ return $airtime_version;
+ }
+
+ /**
+ * This function checks to see if this class can perform an upgrade of your version of Airtime
+ * @return boolean True if we can upgrade your version of Airtime.
+ */
+ public function checkIfUpgradeSupported()
+ {
+ if (!in_array(AirtimeUpgrader::getCurrentVersion(), $this->getSupportedVersions())) {
+ return false;
+ }
+ return true;
+ }
+
+ protected function toggleMaintenanceScreen($toggle)
+ {
+ if ($toggle)
+ {
+ //Disable Airtime UI
+ //create a temporary maintenance notification file
+ //when this file is on the server, zend framework redirects all
+ //requests to the maintenance page and sets a 503 response code
+ $this->maintenanceFile = isset($_SERVER['AIRTIME_BASE']) ? $_SERVER['AIRTIME_BASE']."maintenance.txt" : "/tmp/maintenance.txt";
+ $file = fopen($this->maintenanceFile, 'w');
+ fclose($file);
+ } else {
+ //delete maintenance.txt to give users access back to Airtime
+ if ($this->maintenanceFile) {
+ unlink($this->maintenanceFile);
+ }
+ }
+ }
+
+ /** Implement this for each new version of Airtime */
+ abstract public function upgrade();
+}
+
+/** This upgrade adds schema changes to accommodate show artwork and show instance descriptions */
+class AirtimeUpgrader252 extends AirtimeUpgrader {
+ protected function getSupportedVersions() {
+ return array (
+ '2.5.1'
+ );
+ }
+
+ public function getNewVersion() {
+ return '2.5.2';
+ }
+
+ public function upgrade($dir = __DIR__) {
+ Cache::clear();
+ assert($this->checkIfUpgradeSupported());
+
+ $newVersion = $this->getNewVersion();
+
+ try {
+ $this->toggleMaintenanceScreen(true);
+ Cache::clear();
+
+ // Begin upgrade
+ $airtimeConf = isset($_SERVER['AIRTIME_CONF']) ? $_SERVER['AIRTIME_CONF'] : "/etc/airtime/airtime.conf";
+ $values = parse_ini_file($airtimeConf, true);
+
+ $username = $values['database']['dbuser'];
+ $password = $values['database']['dbpass'];
+ $host = $values['database']['host'];
+ $database = $values['database']['dbname'];
+
+ passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/upgrade_sql/airtime_"
+ .$this->getNewVersion()."/upgrade.sql $database 2>&1 | grep -v \"will create implicit index\"");
+
+ Application_Model_Preference::SetAirtimeVersion($newVersion);
+ Cache::clear();
+
+ $this->toggleMaintenanceScreen(false);
+
+ return true;
+ } catch(Exception $e) {
+ $this->toggleMaintenanceScreen(false);
+ throw $e;
+ }
+ }
+}
+
+class AirtimeUpgrader253 extends AirtimeUpgrader
+{
+ protected function getSupportedVersions()
+ {
+ return array('2.5.2');
+ }
+ public function getNewVersion()
+ {
+ return '2.5.3';
+ }
+
+ public function upgrade($dir = __DIR__)
+ {
+ Cache::clear();
+ assert($this->checkIfUpgradeSupported());
+
+ $con = Propel::getConnection();
+ $con->beginTransaction();
+ try {
+
+ $this->toggleMaintenanceScreen(true);
+ Cache::clear();
+
+ //Begin upgrade
+
+ //Update disk_usage value in cc_pref
+ $musicDir = CcMusicDirsQuery::create()
+ ->filterByType('stor')
+ ->filterByExists(true)
+ ->findOne();
+ $storPath = $musicDir->getDirectory();
+
+ //Update disk_usage value in cc_pref
+ $storDir = isset($_SERVER['AIRTIME_BASE']) ? $_SERVER['AIRTIME_BASE']."srv/airtime/stor" : "/srv/airtime/stor";
+ $diskUsage = shell_exec("du -sb $storDir | awk '{print $1}'");
+
+ Application_Model_Preference::setDiskUsage($diskUsage);
+
+ //clear out the cache
+ Cache::clear();
+
+ $con->commit();
+
+ //update system_version in cc_pref and change some columns in cc_files
+ $airtimeConf = isset($_SERVER['AIRTIME_CONF']) ? $_SERVER['AIRTIME_CONF'] : "/etc/airtime/airtime.conf";
+ $values = parse_ini_file($airtimeConf, true);
+
+ $username = $values['database']['dbuser'];
+ $password = $values['database']['dbpass'];
+ $host = $values['database']['host'];
+ $database = $values['database']['dbname'];
+
+ passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/upgrade_sql/airtime_".$this->getNewVersion()."/upgrade.sql $database 2>&1 | grep -v \"will create implicit index\"");
+
+ Application_Model_Preference::SetAirtimeVersion($this->getNewVersion());
+ //clear out the cache
+ Cache::clear();
+
+ $this->toggleMaintenanceScreen(false);
+
+ } catch (Exception $e) {
+ $con->rollback();
+ $this->toggleMaintenanceScreen(false);
+ }
+ }
+}
+
+class AirtimeUpgrader254 extends AirtimeUpgrader
+{
+ protected function getSupportedVersions()
+ {
+ return array('2.5.3');
+ }
+ public function getNewVersion()
+ {
+ return '2.5.4';
+ }
+
+ public function upgrade()
+ {
+ Cache::clear();
+
+ assert($this->checkIfUpgradeSupported());
+
+ $newVersion = $this->getNewVersion();
+
+ $con = Propel::getConnection();
+ //$con->beginTransaction();
+ try {
+ $this->toggleMaintenanceScreen(true);
+ Cache::clear();
+
+ //Begin upgrade
+
+ //First, ensure there are no superadmins already.
+ $numberOfSuperAdmins = CcSubjsQuery::create()
+ ->filterByDbType(UTYPE_SUPERADMIN)
+ ->filterByDbLogin("sourcefabric_admin", Criteria::NOT_EQUAL) //Ignore sourcefabric_admin users
+ ->count();
+
+ //Only create a super admin if there isn't one already.
+ if ($numberOfSuperAdmins == 0)
+ {
+ //Find the "admin" user and promote them to superadmin.
+ $adminUser = CcSubjsQuery::create()
+ ->filterByDbLogin('admin')
+ ->findOne();
+ if (!$adminUser)
+ {
+ //TODO: Otherwise get the user with the lowest ID that is of type administrator:
+ //
+ $adminUser = CcSubjsQuery::create()
+ ->filterByDbType(UTYPE_ADMIN)
+ ->orderByDbId(Criteria::ASC)
+ ->findOne();
+
+ if (!$adminUser) {
+ throw new Exception("Failed to find any users of type 'admin' ('A').");
+ }
+ }
+
+ $adminUser = new Application_Model_User($adminUser->getDbId());
+ $adminUser->setType(UTYPE_SUPERADMIN);
+ $adminUser->save();
+ Logging::info($_SERVER['HTTP_HOST'] . ': ' . $newVersion . " Upgrade: Promoted user " . $adminUser->getLogin() . " to be a Super Admin.");
+
+ //Also try to promote the sourcefabric_admin user
+ $sofabAdminUser = CcSubjsQuery::create()
+ ->filterByDbLogin('sourcefabric_admin')
+ ->findOne();
+ if ($sofabAdminUser) {
+ $sofabAdminUser = new Application_Model_User($sofabAdminUser->getDbId());
+ $sofabAdminUser->setType(UTYPE_SUPERADMIN);
+ $sofabAdminUser->save();
+ Logging::info($_SERVER['HTTP_HOST'] . ': ' . $newVersion . " Upgrade: Promoted user " . $sofabAdminUser->getLogin() . " to be a Super Admin.");
+ }
+ }
+
+ //$con->commit();
+ Application_Model_Preference::SetAirtimeVersion($newVersion);
+ Cache::clear();
+
+ $this->toggleMaintenanceScreen(false);
+
+ return true;
+
+ } catch(Exception $e) {
+ //$con->rollback();
+ $this->toggleMaintenanceScreen(false);
+ throw $e;
+ }
+ }
+}
+
+/* We are skipping 2.5.5 because it used to be the Show Artwork.
+ *
+ * DO NOT USE schema version 2.5.5!
+ */
+
+
+/** This is a stub. Please implement this 2.5.6 upgrader for the next schema change that we need.
+ * (It's setup to upgrade from 2.5.4 and 2.5.5 - this is a must due to the 2.5.5 schema being phase out. Long story...
+ *
+ */
+class AirtimeUpgrader256 extends AirtimeUpgrader {
+ protected function getSupportedVersions() {
+ return array (
+ '2.5.4', '2.5.5'
+ );
+ }
+
+ public function getNewVersion() {
+ return '2.5.6';
+ }
+
+ public function upgrade($dir = __DIR__) {
+ Cache::clear();
+ assert($this->checkIfUpgradeSupported());
+
+ $newVersion = $this->getNewVersion();
+
+ try {
+ //TODO: Implement this
+ return true;
+ } catch(Exception $e) {
+ $this->toggleMaintenanceScreen(false);
+ throw $e;
+ }
+ }
+}
diff --git a/airtime_mvc/build/sql/defaultdata.sql b/airtime_mvc/build/sql/defaultdata.sql
index af82be2b8..94e478fcb 100644
--- a/airtime_mvc/build/sql/defaultdata.sql
+++ b/airtime_mvc/build/sql/defaultdata.sql
@@ -1,3 +1,6 @@
+-- Schema version
+INSERT INTO cc_pref("keystr", "valstr") VALUES('system_version', '2.5.2');
+
INSERT INTO cc_subjs ("login", "type", "pass") VALUES ('admin', 'A', md5('admin'));
-- added in 2.3
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('off_air_meta', 'Airtime - offline', 'string');