From 67155b136afc35ff9a162072c1f34b4205687e3e Mon Sep 17 00:00:00 2001 From: Duncan Sommerville Date: Wed, 24 Jun 2015 18:38:04 -0400 Subject: [PATCH] Add downgrade action to UpgradeController, fix SoundCloud schema and bugs --- .../controllers/UpgradeController.php | 31 ++++ .../airtime_2.5.13/downgrade.sql | 11 ++ .../upgrade_sql/airtime_2.5.13/upgrade.sql | 3 +- .../airtime/map/CeleryTasksTableMap.php | 6 +- .../models/airtime/om/BaseCeleryTasks.php | 124 +++++++++++---- .../models/airtime/om/BaseCeleryTasksPeer.php | 41 +++-- .../airtime/om/BaseCeleryTasksQuery.php | 70 +++++++-- .../application/services/CeleryService.php | 8 +- .../services/SoundcloudService.php | 1 - .../services/ThirdPartyCeleryService.php | 8 +- airtime_mvc/application/upgrade/Upgrades.php | 142 +++++++++++++++--- airtime_mvc/build/schema.xml | 3 +- airtime_mvc/build/sql/schema.sql | 3 +- .../public/js/airtime/library/library.js | 3 +- 14 files changed, 361 insertions(+), 93 deletions(-) create mode 100644 airtime_mvc/application/controllers/downgrade_sql/airtime_2.5.13/downgrade.sql diff --git a/airtime_mvc/application/controllers/UpgradeController.php b/airtime_mvc/application/controllers/UpgradeController.php index c2bd2bfae..465ab9f2b 100644 --- a/airtime_mvc/application/controllers/UpgradeController.php +++ b/airtime_mvc/application/controllers/UpgradeController.php @@ -33,4 +33,35 @@ class UpgradeController extends Zend_Controller_Action ->appendBody($e->getMessage()); } } + + public function downgradeAction() { + $this->view->layout()->disableLayout(); + $this->_helper->viewRenderer->setNoRender(true); + + if (!RestAuth::verifyAuth(true, false, $this)) { + return; + } + + $request = $this->getRequest(); + $toVersion = $request->getParam("version"); + + try { + $downgradePerformed = UpgradeManager::doDowngrade($toVersion); + + if (!$downgradePerformed) { + $this->getResponse() + ->setHttpResponseCode(200) + ->appendBody("No downgrade was performed. The current schema version is " . Application_Model_Preference::GetSchemaVersion() . ".
"); + } else { + $this->getResponse() + ->setHttpResponseCode(200) + ->appendBody("Downgrade to Airtime schema version " . Application_Model_Preference::GetSchemaVersion() . " OK
"); + } + } catch (Exception $e) { + $this->getResponse() + ->setHttpResponseCode(400) + ->appendBody($e->getMessage()); + } + } + } diff --git a/airtime_mvc/application/controllers/downgrade_sql/airtime_2.5.13/downgrade.sql b/airtime_mvc/application/controllers/downgrade_sql/airtime_2.5.13/downgrade.sql new file mode 100644 index 000000000..5943649f2 --- /dev/null +++ b/airtime_mvc/application/controllers/downgrade_sql/airtime_2.5.13/downgrade.sql @@ -0,0 +1,11 @@ +----------------------------------------------------------------------- +-- third_party_track_references +----------------------------------------------------------------------- + +DROP TABLE IF EXISTS "third_party_track_references" CASCADE; + +----------------------------------------------------------------------- +-- celery_tasks +----------------------------------------------------------------------- + +DROP TABLE IF EXISTS "celery_tasks" CASCADE; \ No newline at end of file diff --git a/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.13/upgrade.sql b/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.13/upgrade.sql index fbf7235bf..42ba8a8d0 100644 --- a/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.13/upgrade.sql +++ b/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.13/upgrade.sql @@ -20,7 +20,8 @@ CREATE TABLE IF NOT EXISTS "third_party_track_references" CREATE TABLE IF NOT EXISTS "celery_tasks" ( - "id" VARCHAR(256) NOT NULL, + "id" serial NOT NULL, + "task_id" VARCHAR(256) NOT NULL, "track_reference" INTEGER NOT NULL, "name" VARCHAR(256), "dispatch_time" TIMESTAMP, diff --git a/airtime_mvc/application/models/airtime/map/CeleryTasksTableMap.php b/airtime_mvc/application/models/airtime/map/CeleryTasksTableMap.php index f2ed15cb6..042cee8d8 100644 --- a/airtime_mvc/application/models/airtime/map/CeleryTasksTableMap.php +++ b/airtime_mvc/application/models/airtime/map/CeleryTasksTableMap.php @@ -36,9 +36,11 @@ class CeleryTasksTableMap extends TableMap $this->setPhpName('CeleryTasks'); $this->setClassname('CeleryTasks'); $this->setPackage('airtime'); - $this->setUseIdGenerator(false); + $this->setUseIdGenerator(true); + $this->setPrimaryKeyMethodInfo('celery_tasks_id_seq'); // columns - $this->addPrimaryKey('id', 'DbId', 'VARCHAR', true, 256, null); + $this->addPrimaryKey('id', 'DbId', 'INTEGER', true, null, null); + $this->addColumn('task_id', 'DbTaskId', 'VARCHAR', true, 256, null); $this->addForeignKey('track_reference', 'DbTrackReference', 'INTEGER', 'third_party_track_references', 'id', true, null, null); $this->addColumn('name', 'DbName', 'VARCHAR', false, 256, null); $this->addColumn('dispatch_time', 'DbDispatchTime', 'TIMESTAMP', false, null, null); diff --git a/airtime_mvc/application/models/airtime/om/BaseCeleryTasks.php b/airtime_mvc/application/models/airtime/om/BaseCeleryTasks.php index c95a5f649..70879be46 100644 --- a/airtime_mvc/application/models/airtime/om/BaseCeleryTasks.php +++ b/airtime_mvc/application/models/airtime/om/BaseCeleryTasks.php @@ -31,10 +31,16 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent /** * The value for the id field. - * @var string + * @var int */ protected $id; + /** + * The value for the task_id field. + * @var string + */ + protected $task_id; + /** * The value for the track_reference field. * @var int @@ -87,7 +93,7 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent /** * Get the [id] column value. * - * @return string + * @return int */ public function getDbId() { @@ -95,6 +101,17 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent return $this->id; } + /** + * Get the [task_id] column value. + * + * @return string + */ + public function getDbTaskId() + { + + return $this->task_id; + } + /** * Get the [track_reference] column value. * @@ -166,13 +183,13 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent /** * Set the value of [id] column. * - * @param string $v new value + * @param int $v new value * @return CeleryTasks The current object (for fluent API support) */ public function setDbId($v) { if ($v !== null && is_numeric($v)) { - $v = (string) $v; + $v = (int) $v; } if ($this->id !== $v) { @@ -184,6 +201,27 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent return $this; } // setDbId() + /** + * Set the value of [task_id] column. + * + * @param string $v new value + * @return CeleryTasks The current object (for fluent API support) + */ + public function setDbTaskId($v) + { + if ($v !== null && is_numeric($v)) { + $v = (string) $v; + } + + if ($this->task_id !== $v) { + $this->task_id = $v; + $this->modifiedColumns[] = CeleryTasksPeer::TASK_ID; + } + + + return $this; + } // setDbTaskId() + /** * Set the value of [track_reference] column. * @@ -306,11 +344,12 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent { try { - $this->id = ($row[$startcol + 0] !== null) ? (string) $row[$startcol + 0] : null; - $this->track_reference = ($row[$startcol + 1] !== null) ? (int) $row[$startcol + 1] : null; - $this->name = ($row[$startcol + 2] !== null) ? (string) $row[$startcol + 2] : null; - $this->dispatch_time = ($row[$startcol + 3] !== null) ? (string) $row[$startcol + 3] : null; - $this->status = ($row[$startcol + 4] !== null) ? (string) $row[$startcol + 4] : null; + $this->id = ($row[$startcol + 0] !== null) ? (int) $row[$startcol + 0] : null; + $this->task_id = ($row[$startcol + 1] !== null) ? (string) $row[$startcol + 1] : null; + $this->track_reference = ($row[$startcol + 2] !== null) ? (int) $row[$startcol + 2] : null; + $this->name = ($row[$startcol + 3] !== null) ? (string) $row[$startcol + 3] : null; + $this->dispatch_time = ($row[$startcol + 4] !== null) ? (string) $row[$startcol + 4] : null; + $this->status = ($row[$startcol + 5] !== null) ? (string) $row[$startcol + 5] : null; $this->resetModified(); $this->setNew(false); @@ -320,7 +359,7 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent } $this->postHydrate($row, $startcol, $rehydrate); - return $startcol + 5; // 5 = CeleryTasksPeer::NUM_HYDRATE_COLUMNS. + return $startcol + 6; // 6 = CeleryTasksPeer::NUM_HYDRATE_COLUMNS. } catch (Exception $e) { throw new PropelException("Error populating CeleryTasks object", $e); @@ -542,11 +581,28 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent $modifiedColumns = array(); $index = 0; + $this->modifiedColumns[] = CeleryTasksPeer::ID; + if (null !== $this->id) { + throw new PropelException('Cannot insert a value for auto-increment primary key (' . CeleryTasksPeer::ID . ')'); + } + if (null === $this->id) { + try { + $stmt = $con->query("SELECT nextval('celery_tasks_id_seq')"); + $row = $stmt->fetch(PDO::FETCH_NUM); + $this->id = $row[0]; + } catch (Exception $e) { + throw new PropelException('Unable to get sequence id.', $e); + } + } + // check the columns in natural order for more readable SQL queries if ($this->isColumnModified(CeleryTasksPeer::ID)) { $modifiedColumns[':p' . $index++] = '"id"'; } + if ($this->isColumnModified(CeleryTasksPeer::TASK_ID)) { + $modifiedColumns[':p' . $index++] = '"task_id"'; + } if ($this->isColumnModified(CeleryTasksPeer::TRACK_REFERENCE)) { $modifiedColumns[':p' . $index++] = '"track_reference"'; } @@ -571,7 +627,10 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent foreach ($modifiedColumns as $identifier => $columnName) { switch ($columnName) { case '"id"': - $stmt->bindValue($identifier, $this->id, PDO::PARAM_STR); + $stmt->bindValue($identifier, $this->id, PDO::PARAM_INT); + break; + case '"task_id"': + $stmt->bindValue($identifier, $this->task_id, PDO::PARAM_STR); break; case '"track_reference"': $stmt->bindValue($identifier, $this->track_reference, PDO::PARAM_INT); @@ -728,15 +787,18 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent return $this->getDbId(); break; case 1: - return $this->getDbTrackReference(); + return $this->getDbTaskId(); break; case 2: - return $this->getDbName(); + return $this->getDbTrackReference(); break; case 3: - return $this->getDbDispatchTime(); + return $this->getDbName(); break; case 4: + return $this->getDbDispatchTime(); + break; + case 5: return $this->getDbStatus(); break; default: @@ -769,10 +831,11 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent $keys = CeleryTasksPeer::getFieldNames($keyType); $result = array( $keys[0] => $this->getDbId(), - $keys[1] => $this->getDbTrackReference(), - $keys[2] => $this->getDbName(), - $keys[3] => $this->getDbDispatchTime(), - $keys[4] => $this->getDbStatus(), + $keys[1] => $this->getDbTaskId(), + $keys[2] => $this->getDbTrackReference(), + $keys[3] => $this->getDbName(), + $keys[4] => $this->getDbDispatchTime(), + $keys[5] => $this->getDbStatus(), ); $virtualColumns = $this->virtualColumns; foreach ($virtualColumns as $key => $virtualColumn) { @@ -821,15 +884,18 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent $this->setDbId($value); break; case 1: - $this->setDbTrackReference($value); + $this->setDbTaskId($value); break; case 2: - $this->setDbName($value); + $this->setDbTrackReference($value); break; case 3: - $this->setDbDispatchTime($value); + $this->setDbName($value); break; case 4: + $this->setDbDispatchTime($value); + break; + case 5: $this->setDbStatus($value); break; } // switch() @@ -857,10 +923,11 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent $keys = CeleryTasksPeer::getFieldNames($keyType); if (array_key_exists($keys[0], $arr)) $this->setDbId($arr[$keys[0]]); - if (array_key_exists($keys[1], $arr)) $this->setDbTrackReference($arr[$keys[1]]); - if (array_key_exists($keys[2], $arr)) $this->setDbName($arr[$keys[2]]); - if (array_key_exists($keys[3], $arr)) $this->setDbDispatchTime($arr[$keys[3]]); - if (array_key_exists($keys[4], $arr)) $this->setDbStatus($arr[$keys[4]]); + if (array_key_exists($keys[1], $arr)) $this->setDbTaskId($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setDbTrackReference($arr[$keys[2]]); + if (array_key_exists($keys[3], $arr)) $this->setDbName($arr[$keys[3]]); + if (array_key_exists($keys[4], $arr)) $this->setDbDispatchTime($arr[$keys[4]]); + if (array_key_exists($keys[5], $arr)) $this->setDbStatus($arr[$keys[5]]); } /** @@ -873,6 +940,7 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent $criteria = new Criteria(CeleryTasksPeer::DATABASE_NAME); if ($this->isColumnModified(CeleryTasksPeer::ID)) $criteria->add(CeleryTasksPeer::ID, $this->id); + if ($this->isColumnModified(CeleryTasksPeer::TASK_ID)) $criteria->add(CeleryTasksPeer::TASK_ID, $this->task_id); if ($this->isColumnModified(CeleryTasksPeer::TRACK_REFERENCE)) $criteria->add(CeleryTasksPeer::TRACK_REFERENCE, $this->track_reference); if ($this->isColumnModified(CeleryTasksPeer::NAME)) $criteria->add(CeleryTasksPeer::NAME, $this->name); if ($this->isColumnModified(CeleryTasksPeer::DISPATCH_TIME)) $criteria->add(CeleryTasksPeer::DISPATCH_TIME, $this->dispatch_time); @@ -899,7 +967,7 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent /** * Returns the primary key for this object (row). - * @return string + * @return int */ public function getPrimaryKey() { @@ -909,7 +977,7 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent /** * Generic method to set the primary key (id column). * - * @param string $key Primary key. + * @param int $key Primary key. * @return void */ public function setPrimaryKey($key) @@ -940,6 +1008,7 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent */ public function copyInto($copyObj, $deepCopy = false, $makeNew = true) { + $copyObj->setDbTaskId($this->getDbTaskId()); $copyObj->setDbTrackReference($this->getDbTrackReference()); $copyObj->setDbName($this->getDbName()); $copyObj->setDbDispatchTime($this->getDbDispatchTime()); @@ -1060,6 +1129,7 @@ abstract class BaseCeleryTasks extends BaseObject implements Persistent public function clear() { $this->id = null; + $this->task_id = null; $this->track_reference = null; $this->name = null; $this->dispatch_time = null; diff --git a/airtime_mvc/application/models/airtime/om/BaseCeleryTasksPeer.php b/airtime_mvc/application/models/airtime/om/BaseCeleryTasksPeer.php index 2a651fd0e..b6dff77b4 100644 --- a/airtime_mvc/application/models/airtime/om/BaseCeleryTasksPeer.php +++ b/airtime_mvc/application/models/airtime/om/BaseCeleryTasksPeer.php @@ -24,17 +24,20 @@ abstract class BaseCeleryTasksPeer const TM_CLASS = 'CeleryTasksTableMap'; /** The total number of columns. */ - const NUM_COLUMNS = 5; + const NUM_COLUMNS = 6; /** The number of lazy-loaded columns. */ const NUM_LAZY_LOAD_COLUMNS = 0; /** The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS) */ - const NUM_HYDRATE_COLUMNS = 5; + const NUM_HYDRATE_COLUMNS = 6; /** the column name for the id field */ const ID = 'celery_tasks.id'; + /** the column name for the task_id field */ + const TASK_ID = 'celery_tasks.task_id'; + /** the column name for the track_reference field */ const TRACK_REFERENCE = 'celery_tasks.track_reference'; @@ -66,12 +69,12 @@ abstract class BaseCeleryTasksPeer * e.g. CeleryTasksPeer::$fieldNames[CeleryTasksPeer::TYPE_PHPNAME][0] = 'Id' */ protected static $fieldNames = array ( - BasePeer::TYPE_PHPNAME => array ('DbId', 'DbTrackReference', 'DbName', 'DbDispatchTime', 'DbStatus', ), - BasePeer::TYPE_STUDLYPHPNAME => array ('dbId', 'dbTrackReference', 'dbName', 'dbDispatchTime', 'dbStatus', ), - BasePeer::TYPE_COLNAME => array (CeleryTasksPeer::ID, CeleryTasksPeer::TRACK_REFERENCE, CeleryTasksPeer::NAME, CeleryTasksPeer::DISPATCH_TIME, CeleryTasksPeer::STATUS, ), - BasePeer::TYPE_RAW_COLNAME => array ('ID', 'TRACK_REFERENCE', 'NAME', 'DISPATCH_TIME', 'STATUS', ), - BasePeer::TYPE_FIELDNAME => array ('id', 'track_reference', 'name', 'dispatch_time', 'status', ), - BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, ) + BasePeer::TYPE_PHPNAME => array ('DbId', 'DbTaskId', 'DbTrackReference', 'DbName', 'DbDispatchTime', 'DbStatus', ), + BasePeer::TYPE_STUDLYPHPNAME => array ('dbId', 'dbTaskId', 'dbTrackReference', 'dbName', 'dbDispatchTime', 'dbStatus', ), + BasePeer::TYPE_COLNAME => array (CeleryTasksPeer::ID, CeleryTasksPeer::TASK_ID, CeleryTasksPeer::TRACK_REFERENCE, CeleryTasksPeer::NAME, CeleryTasksPeer::DISPATCH_TIME, CeleryTasksPeer::STATUS, ), + BasePeer::TYPE_RAW_COLNAME => array ('ID', 'TASK_ID', 'TRACK_REFERENCE', 'NAME', 'DISPATCH_TIME', 'STATUS', ), + BasePeer::TYPE_FIELDNAME => array ('id', 'task_id', 'track_reference', 'name', 'dispatch_time', 'status', ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, ) ); /** @@ -81,12 +84,12 @@ abstract class BaseCeleryTasksPeer * e.g. CeleryTasksPeer::$fieldNames[BasePeer::TYPE_PHPNAME]['Id'] = 0 */ protected static $fieldKeys = array ( - BasePeer::TYPE_PHPNAME => array ('DbId' => 0, 'DbTrackReference' => 1, 'DbName' => 2, 'DbDispatchTime' => 3, 'DbStatus' => 4, ), - BasePeer::TYPE_STUDLYPHPNAME => array ('dbId' => 0, 'dbTrackReference' => 1, 'dbName' => 2, 'dbDispatchTime' => 3, 'dbStatus' => 4, ), - BasePeer::TYPE_COLNAME => array (CeleryTasksPeer::ID => 0, CeleryTasksPeer::TRACK_REFERENCE => 1, CeleryTasksPeer::NAME => 2, CeleryTasksPeer::DISPATCH_TIME => 3, CeleryTasksPeer::STATUS => 4, ), - BasePeer::TYPE_RAW_COLNAME => array ('ID' => 0, 'TRACK_REFERENCE' => 1, 'NAME' => 2, 'DISPATCH_TIME' => 3, 'STATUS' => 4, ), - BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'track_reference' => 1, 'name' => 2, 'dispatch_time' => 3, 'status' => 4, ), - BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, ) + BasePeer::TYPE_PHPNAME => array ('DbId' => 0, 'DbTaskId' => 1, 'DbTrackReference' => 2, 'DbName' => 3, 'DbDispatchTime' => 4, 'DbStatus' => 5, ), + BasePeer::TYPE_STUDLYPHPNAME => array ('dbId' => 0, 'dbTaskId' => 1, 'dbTrackReference' => 2, 'dbName' => 3, 'dbDispatchTime' => 4, 'dbStatus' => 5, ), + BasePeer::TYPE_COLNAME => array (CeleryTasksPeer::ID => 0, CeleryTasksPeer::TASK_ID => 1, CeleryTasksPeer::TRACK_REFERENCE => 2, CeleryTasksPeer::NAME => 3, CeleryTasksPeer::DISPATCH_TIME => 4, CeleryTasksPeer::STATUS => 5, ), + BasePeer::TYPE_RAW_COLNAME => array ('ID' => 0, 'TASK_ID' => 1, 'TRACK_REFERENCE' => 2, 'NAME' => 3, 'DISPATCH_TIME' => 4, 'STATUS' => 5, ), + BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'task_id' => 1, 'track_reference' => 2, 'name' => 3, 'dispatch_time' => 4, 'status' => 5, ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, ) ); /** @@ -161,12 +164,14 @@ abstract class BaseCeleryTasksPeer { if (null === $alias) { $criteria->addSelectColumn(CeleryTasksPeer::ID); + $criteria->addSelectColumn(CeleryTasksPeer::TASK_ID); $criteria->addSelectColumn(CeleryTasksPeer::TRACK_REFERENCE); $criteria->addSelectColumn(CeleryTasksPeer::NAME); $criteria->addSelectColumn(CeleryTasksPeer::DISPATCH_TIME); $criteria->addSelectColumn(CeleryTasksPeer::STATUS); } else { $criteria->addSelectColumn($alias . '.id'); + $criteria->addSelectColumn($alias . '.task_id'); $criteria->addSelectColumn($alias . '.track_reference'); $criteria->addSelectColumn($alias . '.name'); $criteria->addSelectColumn($alias . '.dispatch_time'); @@ -409,7 +414,7 @@ abstract class BaseCeleryTasksPeer public static function getPrimaryKeyFromRow($row, $startcol = 0) { - return (string) $row[$startcol]; + return (int) $row[$startcol]; } /** @@ -764,6 +769,10 @@ abstract class BaseCeleryTasksPeer $criteria = $values->buildCriteria(); // build Criteria from CeleryTasks object } + if ($criteria->containsKey(CeleryTasksPeer::ID) && $criteria->keyContainsValue(CeleryTasksPeer::ID) ) { + throw new PropelException('Cannot insert a value for auto-increment primary key ('.CeleryTasksPeer::ID.')'); + } + // Set the correct dbName $criteria->setDbName(CeleryTasksPeer::DATABASE_NAME); @@ -952,7 +961,7 @@ abstract class BaseCeleryTasksPeer /** * Retrieve a single object by pkey. * - * @param string $pk the primary key. + * @param int $pk the primary key. * @param PropelPDO $con the connection to use * @return CeleryTasks */ diff --git a/airtime_mvc/application/models/airtime/om/BaseCeleryTasksQuery.php b/airtime_mvc/application/models/airtime/om/BaseCeleryTasksQuery.php index 20e683d70..9d25080d0 100644 --- a/airtime_mvc/application/models/airtime/om/BaseCeleryTasksQuery.php +++ b/airtime_mvc/application/models/airtime/om/BaseCeleryTasksQuery.php @@ -7,12 +7,14 @@ * * * @method CeleryTasksQuery orderByDbId($order = Criteria::ASC) Order by the id column + * @method CeleryTasksQuery orderByDbTaskId($order = Criteria::ASC) Order by the task_id column * @method CeleryTasksQuery orderByDbTrackReference($order = Criteria::ASC) Order by the track_reference column * @method CeleryTasksQuery orderByDbName($order = Criteria::ASC) Order by the name column * @method CeleryTasksQuery orderByDbDispatchTime($order = Criteria::ASC) Order by the dispatch_time column * @method CeleryTasksQuery orderByDbStatus($order = Criteria::ASC) Order by the status column * * @method CeleryTasksQuery groupByDbId() Group by the id column + * @method CeleryTasksQuery groupByDbTaskId() Group by the task_id column * @method CeleryTasksQuery groupByDbTrackReference() Group by the track_reference column * @method CeleryTasksQuery groupByDbName() Group by the name column * @method CeleryTasksQuery groupByDbDispatchTime() Group by the dispatch_time column @@ -29,12 +31,14 @@ * @method CeleryTasks findOne(PropelPDO $con = null) Return the first CeleryTasks matching the query * @method CeleryTasks findOneOrCreate(PropelPDO $con = null) Return the first CeleryTasks matching the query, or a new CeleryTasks object populated from the query conditions when no match is found * + * @method CeleryTasks findOneByDbTaskId(string $task_id) Return the first CeleryTasks filtered by the task_id column * @method CeleryTasks findOneByDbTrackReference(int $track_reference) Return the first CeleryTasks filtered by the track_reference column * @method CeleryTasks findOneByDbName(string $name) Return the first CeleryTasks filtered by the name column * @method CeleryTasks findOneByDbDispatchTime(string $dispatch_time) Return the first CeleryTasks filtered by the dispatch_time column * @method CeleryTasks findOneByDbStatus(string $status) Return the first CeleryTasks filtered by the status column * - * @method array findByDbId(string $id) Return CeleryTasks objects filtered by the id column + * @method array findByDbId(int $id) Return CeleryTasks objects filtered by the id column + * @method array findByDbTaskId(string $task_id) Return CeleryTasks objects filtered by the task_id column * @method array findByDbTrackReference(int $track_reference) Return CeleryTasks objects filtered by the track_reference column * @method array findByDbName(string $name) Return CeleryTasks objects filtered by the name column * @method array findByDbDispatchTime(string $dispatch_time) Return CeleryTasks objects filtered by the dispatch_time column @@ -146,10 +150,10 @@ abstract class BaseCeleryTasksQuery extends ModelCriteria */ protected function findPkSimple($key, $con) { - $sql = 'SELECT "id", "track_reference", "name", "dispatch_time", "status" FROM "celery_tasks" WHERE "id" = :p0'; + $sql = 'SELECT "id", "task_id", "track_reference", "name", "dispatch_time", "status" FROM "celery_tasks" WHERE "id" = :p0'; try { $stmt = $con->prepare($sql); - $stmt->bindValue(':p0', $key, PDO::PARAM_STR); + $stmt->bindValue(':p0', $key, PDO::PARAM_INT); $stmt->execute(); } catch (Exception $e) { Propel::log($e->getMessage(), Propel::LOG_ERR); @@ -240,30 +244,72 @@ abstract class BaseCeleryTasksQuery extends ModelCriteria * * Example usage: * - * $query->filterByDbId('fooValue'); // WHERE id = 'fooValue' - * $query->filterByDbId('%fooValue%'); // WHERE id LIKE '%fooValue%' + * $query->filterByDbId(1234); // WHERE id = 1234 + * $query->filterByDbId(array(12, 34)); // WHERE id IN (12, 34) + * $query->filterByDbId(array('min' => 12)); // WHERE id >= 12 + * $query->filterByDbId(array('max' => 12)); // WHERE id <= 12 * * - * @param string $dbId The value to use as filter. - * Accepts wildcards (* and % trigger a LIKE) + * @param mixed $dbId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL * * @return CeleryTasksQuery The current query, for fluid interface */ public function filterByDbId($dbId = null, $comparison = null) { - if (null === $comparison) { - if (is_array($dbId)) { + if (is_array($dbId)) { + $useMinMax = false; + if (isset($dbId['min'])) { + $this->addUsingAlias(CeleryTasksPeer::ID, $dbId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($dbId['max'])) { + $this->addUsingAlias(CeleryTasksPeer::ID, $dbId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { $comparison = Criteria::IN; - } elseif (preg_match('/[\%\*]/', $dbId)) { - $dbId = str_replace('*', '%', $dbId); - $comparison = Criteria::LIKE; } } return $this->addUsingAlias(CeleryTasksPeer::ID, $dbId, $comparison); } + /** + * Filter the query on the task_id column + * + * Example usage: + * + * $query->filterByDbTaskId('fooValue'); // WHERE task_id = 'fooValue' + * $query->filterByDbTaskId('%fooValue%'); // WHERE task_id LIKE '%fooValue%' + * + * + * @param string $dbTaskId The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return CeleryTasksQuery The current query, for fluid interface + */ + public function filterByDbTaskId($dbTaskId = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($dbTaskId)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $dbTaskId)) { + $dbTaskId = str_replace('*', '%', $dbTaskId); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(CeleryTasksPeer::TASK_ID, $dbTaskId, $comparison); + } + /** * Filter the query on the track_reference column * diff --git a/airtime_mvc/application/services/CeleryService.php b/airtime_mvc/application/services/CeleryService.php index ad18a56b1..8e9091290 100644 --- a/airtime_mvc/application/services/CeleryService.php +++ b/airtime_mvc/application/services/CeleryService.php @@ -75,7 +75,7 @@ class CeleryService { $config = parse_ini_file(Application_Model_RabbitMq::getRmqConfigPath(), true); $queue = self::$_CELERY_RESULTS_EXCHANGE . "." . $task; $c = self::_setupCeleryExchange($config, self::$_CELERY_RESULTS_EXCHANGE, $queue); - $message = $c->getAsyncResultMessage($task->getDbName(), $task->getDbId()); + $message = $c->getAsyncResultMessage($task->getDbName(), $task->getDbTaskId()); // If the message isn't ready yet (Celery hasn't finished the task), // only throw an exception if the message has timed out. @@ -85,12 +85,12 @@ class CeleryService { // track reference here in case it was a deletion that failed, for example. $task->setDbStatus(CELERY_FAILED_STATUS)->save(); throw new CeleryTimeoutException("Celery task " . $task->getDbName() - . " with ID " . $task->getDbId() . " timed out"); + . " with ID " . $task->getDbTaskId() . " timed out"); } else { // The message hasn't timed out, but it's still false, which means it hasn't been // sent back from Celery yet. throw new CeleryException("Waiting on Celery task " . $task->getDbName() - . " with ID " . $task->getDbId()); + . " with ID " . $task->getDbTaskId()); } } return $message; @@ -147,7 +147,7 @@ class CeleryService { protected static function _getPendingTasks($taskName, $serviceName) { $query = CeleryTasksQuery::create() ->filterByDbStatus(CELERY_PENDING_STATUS) - ->filterByDbId('', Criteria::NOT_EQUAL); + ->filterByDbTaskId('', Criteria::NOT_EQUAL); if (!empty($taskName)) { $query->filterByDbName($taskName); } diff --git a/airtime_mvc/application/services/SoundcloudService.php b/airtime_mvc/application/services/SoundcloudService.php index dcb207f9e..494eeaf29 100644 --- a/airtime_mvc/application/services/SoundcloudService.php +++ b/airtime_mvc/application/services/SoundcloudService.php @@ -69,7 +69,6 @@ class SoundcloudService extends ThirdPartyCeleryService implements OAuth2 { */ protected function _getUploadData($file) { $file = $file->getPropelOrm(); - Logging::info($file); // TODO: Move this into a proper serializer $trackArray = $this->_serializeTrack($file); foreach (self::$_SOUNDCLOUD_PREF_FUNCTIONS as $func => $param) { diff --git a/airtime_mvc/application/services/ThirdPartyCeleryService.php b/airtime_mvc/application/services/ThirdPartyCeleryService.php index 33d661e9b..5dbc1ebad 100644 --- a/airtime_mvc/application/services/ThirdPartyCeleryService.php +++ b/airtime_mvc/application/services/ThirdPartyCeleryService.php @@ -82,12 +82,8 @@ abstract class ThirdPartyCeleryService extends ThirdPartyService { */ protected function _createTaskReference($fileId, $brokerTaskId, $taskName) { $trackId = $this->createTrackReference($fileId); - // First, check if the track already has an entry in the database - $task = CeleryTasksQuery::create()->findOneByDbTrackReference($trackId); - if (is_null($task)) { - $task = new CeleryTasks(); - } - $task->setDbId($brokerTaskId); + $task = new CeleryTasks(); + $task->setDbTaskId($brokerTaskId); $task->setDbName($taskName); $utc = new DateTimeZone("UTC"); $task->setDbDispatchTime(new DateTime("now", $utc)); diff --git a/airtime_mvc/application/upgrade/Upgrades.php b/airtime_mvc/application/upgrade/Upgrades.php index 7510e6c52..aa012eca6 100644 --- a/airtime_mvc/application/upgrade/Upgrades.php +++ b/airtime_mvc/application/upgrade/Upgrades.php @@ -22,7 +22,9 @@ function getUpgrades() { class UpgradeManager { - /** Used to determine if the database schema needs an upgrade in order for this version of the Airtime codebase to work correctly. + + /** + * Used to determine if the database schema needs an upgrade in order for this version of the Airtime codebase to work correctly. * @return array A list of schema versions that this version of the codebase supports. */ public static function getSupportedSchemaVersions() @@ -64,10 +66,35 @@ class UpgradeManager return $upgradePerformed; } + /** + * Downgrade the Airtime schema version to match the given version + * + * @param string $toVersion the version we want to downgrade to + * + * @return boolean whether or not an upgrade was performed + */ + public static function doDowngrade($toVersion) + { + $downgraders = array_reverse(getUpgrades()); // Reverse the array because we're downgrading + $dir = (dirname(__DIR__) . "/controllers"); + $downgradePerformed = false; + + foreach ($downgraders as $downgrader) { + /** @var AirtimeUpgrader $downgrader */ + $downgrader = new $downgrader($dir); + if ($downgrader->getNewVersion() == $toVersion) { + break; // We've reached the version we wanted to downgrade to, so break + } + $downgradePerformed = self::_runDowngrade($downgrader) ? true : $downgradePerformed; + } + + return $downgradePerformed; + } + /** * Run the given upgrade * - * @param $upgrader AirtimeUpgrader the upgrade class to be executed + * @param $upgrader AirtimeUpgrader the upgrader class to be executed * * @return bool true if the upgrade was successful, otherwise false */ @@ -75,12 +102,26 @@ class UpgradeManager return $upgrader->checkIfUpgradeSupported() && $upgrader->upgrade(); } + /** + * Run the given downgrade + * + * @param $downgrader AirtimeUpgrader the upgrader class to be executed + * @param $supportedVersions array array of supported versions + * + * @return bool true if the downgrade was successful, otherwise false + */ + private static function _runDowngrade(AirtimeUpgrader $downgrader) { + return $downgrader->checkIfDowngradeSupported() && $downgrader->downgrade(); + } + } abstract class AirtimeUpgrader { protected $_dir; + protected $username, $password, $host, $database; + /** * @param $dir string directory housing upgrade files */ @@ -105,7 +146,17 @@ abstract class AirtimeUpgrader */ public function checkIfUpgradeSupported() { - return in_array(AirtimeUpgrader::getCurrentSchemaVersion(), $this->getSupportedSchemaVersions()); + return in_array(static::getCurrentSchemaVersion(), $this->getSupportedSchemaVersions()); + } + + /** + * This function checks to see if this class can perform a downgrade of your version of Airtime + * + * @return boolean True if we can downgrade your version of Airtime. + */ + public function checkIfDowngradeSupported() + { + return static::getCurrentSchemaVersion() == $this->getNewVersion(); } protected function toggleMaintenanceScreen($toggle) @@ -143,6 +194,7 @@ abstract class AirtimeUpgrader // $this->toggleMaintenanceScreen(true); Cache::clear(); + $this->_getDbValues(); $this->_runUpgrade(); Application_Model_Preference::SetSchemaVersion($this->getNewVersion()); @@ -157,18 +209,57 @@ abstract class AirtimeUpgrader return true; } - protected function _runUpgrade() { + /** + * Implement this for each new version of Airtime + * This function abstracts out the core downgrade functionality, + * allowing child classes to overwrite _runDowngrade to reduce duplication + */ + public function downgrade() { + Cache::clear(); + + try { + $this->_getDbValues(); + $this->_runDowngrade(); + + $highestSupportedVersion = null; + foreach ($this->getSupportedSchemaVersions() as $v) { + // version_compare returns 1 (true) if the second parameter is lower + if (!$highestSupportedVersion || version_compare($v, $highestSupportedVersion)) { + $highestSupportedVersion = $v; + } + } + + // Set the schema version to the highest supported version so we don't skip versions when downgrading + Application_Model_Preference::SetSchemaVersion($highestSupportedVersion); + + Cache::clear(); + } catch(Exception $e) { + return false; + } + + return true; + } + + protected function _getDbValues() { $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 ".$this->_dir."/upgrade_sql/airtime_" - .$this->getNewVersion()."/upgrade.sql $database 2>&1 | grep -v -E \"will create implicit sequence|will create implicit index\""); + $this->username = $values['database']['dbuser']; + $this->password = $values['database']['dbpass']; + $this->host = $values['database']['host']; + $this->database = $values['database']['dbname']; } + + protected function _runUpgrade() { + passthru("export PGPASSWORD=".$this->password." && psql -h ".$this->host." -U ".$this->username." -q -f ".$this->_dir."/upgrade_sql/airtime_" + .$this->getNewVersion()."/upgrade.sql ".$this->database." 2>&1 | grep -v -E \"will create implicit sequence|will create implicit index\""); + } + + protected function _runDowngrade() { + passthru("export PGPASSWORD=".$this->password." && psql -h ".$this->host." -U ".$this->username." -q -f ".$this->_dir."/downgrade_sql/airtime_" + .$this->getNewVersion()."/downgrade.sql ".$this->database." 2>&1 | grep -v -E \"will create implicit sequence|will create implicit index\""); + } + } class AirtimeUpgrader253 extends AirtimeUpgrader @@ -330,18 +421,27 @@ class AirtimeUpgrader2512 extends AirtimeUpgrader /** * Class AirtimeUpgrader2513 - Celery and SoundCloud upgrade * - * Adds third_party_track_references table for third party service + * Adds third_party_track_references and celery_tasks tables for third party service * authentication and task architecture. * - * Schema: - * id -> int PK - * service -> string internal service name - * foreign_id -> int external unique service id - * broker_task_id -> int external unique amqp results identifier - * broker_task_name -> string external Celery task name - * broker_task_dispatch_time -> timestamp internal message dispatch time - * file_id -> int internal FK->cc_files track id - * status -> string external Celery task status - PENDING, SUCCESS, or FAILED + *
third_party_track_references schema: + * + * id -> int PK + * service -> string internal service name + * foreign_id -> int external unique service id + * file_id -> int internal FK->cc_files track id + * upload_time -> timestamp internal upload timestamp + * status -> string external service status + * + *
celery_tasks schema: + * + * id -> int PK + * task_id -> string external unique amqp results identifier + * track_reference -> int internal FK->third_party_track_references id + * name -> string external Celery task name + * dispatch_time -> timestamp internal message dispatch time + * status -> string external Celery task status + * */ class AirtimeUpgrader2513 extends AirtimeUpgrader { diff --git a/airtime_mvc/build/schema.xml b/airtime_mvc/build/schema.xml index a4ce8193b..87f820cb6 100644 --- a/airtime_mvc/build/schema.xml +++ b/airtime_mvc/build/schema.xml @@ -548,7 +548,8 @@ - + + diff --git a/airtime_mvc/build/sql/schema.sql b/airtime_mvc/build/sql/schema.sql index 9868de899..d358b5912 100644 --- a/airtime_mvc/build/sql/schema.sql +++ b/airtime_mvc/build/sql/schema.sql @@ -696,7 +696,8 @@ DROP TABLE IF EXISTS "celery_tasks" CASCADE; CREATE TABLE "celery_tasks" ( - "id" VARCHAR(256) NOT NULL, + "id" serial NOT NULL, + "task_id" VARCHAR(256) NOT NULL, "track_reference" INTEGER NOT NULL, "name" VARCHAR(256), "dispatch_time" TIMESTAMP, diff --git a/airtime_mvc/public/js/airtime/library/library.js b/airtime_mvc/public/js/airtime/library/library.js index 65bbb1111..562a25cbb 100644 --- a/airtime_mvc/public/js/airtime/library/library.js +++ b/airtime_mvc/public/js/airtime/library/library.js @@ -1018,7 +1018,8 @@ var AIRTIME = (function(AIRTIME) { if (soundcloud.upload !== undefined) { callback = function() { - alert($.i18n._("Your track is being uploaded to SoundCloud")); + alert($.i18n._("Your track is being uploaded and will " + + "appear on SoundCloud in a couple of minutes")); $.post(soundcloud.upload.url, function(){}); }; soundcloud.upload.callback = callback;