Upgrades.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. <?php
  2. class UpgradeManager
  3. {
  4. /** Used to determine if the database schema needs an upgrade in order for this version of the Airtime codebase to work correctly.
  5. * @return array A list of schema versions that this version of the codebase supports.
  6. */
  7. public static function getSupportedSchemaVersions()
  8. {
  9. //What versions of the schema does the code support today:
  10. return array('2.5.2');
  11. }
  12. public static function checkIfUpgradeIsNeeded()
  13. {
  14. $schemaVersion = Application_Model_Preference::GetSchemaVersion();
  15. $supportedSchemaVersions = self::getSupportedSchemaVersions();
  16. $upgradeNeeded = !in_array($schemaVersion, $supportedSchemaVersions);
  17. if ($upgradeNeeded) {
  18. self::doUpgrade();
  19. }
  20. }
  21. public static function doUpgrade()
  22. {
  23. $upgradeManager = new UpgradeManager();
  24. $upgraders = array();
  25. array_push($upgraders, new AirtimeUpgrader252());
  26. /* These upgrades do not apply to open source Airtime yet.
  27. array_push($upgraders, new AirtimeUpgrader253());
  28. array_push($upgraders, new AirtimeUpgrader254());
  29. */
  30. return $upgradeManager->runUpgrades(array(new AirtimeUpgrader252()), (dirname(__DIR__) . "/controllers"));
  31. }
  32. /**
  33. * Run a given set of upgrades
  34. *
  35. * @param array $upgraders the upgrades to perform
  36. * @param string $dir the directory containing the upgrade sql
  37. * @return boolean whether or not an upgrade was performed
  38. */
  39. public function runUpgrades($upgraders, $dir) {
  40. $upgradePerformed = false;
  41. for($i = 0; $i < count($upgraders); $i++) {
  42. $upgrader = $upgraders[$i];
  43. if ($upgrader->checkIfUpgradeSupported()) {
  44. // pass the given directory to the upgrades, since __DIR__ returns parent dir of file, not executor
  45. $upgrader->upgrade($dir); // This will throw an exception if the upgrade fails.
  46. $upgradePerformed = true;
  47. $i = 0; // Start over, in case the upgrade handlers are not in ascending order.
  48. }
  49. }
  50. return $upgradePerformed;
  51. }
  52. }
  53. abstract class AirtimeUpgrader
  54. {
  55. /** Schema versions that this upgrader class can upgrade from (an array of version strings). */
  56. abstract protected function getSupportedSchemaVersions();
  57. /** The schema version that this upgrader class will upgrade to. (returns a version string) */
  58. abstract public function getNewVersion();
  59. public static function getCurrentSchemaVersion()
  60. {
  61. CcPrefPeer::clearInstancePool(); //Ensure we don't get a cached Propel object (cached DB results)
  62. //because we're updating this version number within this HTTP request as well.
  63. //Old versions use system_version
  64. $pref = CcPrefQuery::create()
  65. ->filterByKeystr('system_version')
  66. ->findOne();
  67. if (empty($pref)) {
  68. //New versions use schema_version
  69. $pref = CcPrefQuery::create()
  70. ->filterByKeystr('schema_version')
  71. ->findOne();
  72. }
  73. $schema_version = $pref->getValStr();
  74. return $schema_version;
  75. }
  76. /**
  77. * This function checks to see if this class can perform an upgrade of your version of Airtime
  78. * @return boolean True if we can upgrade your version of Airtime.
  79. */
  80. public function checkIfUpgradeSupported()
  81. {
  82. if (!in_array(AirtimeUpgrader::getCurrentSchemaVersion(), $this->getSupportedSchemaVersions())) {
  83. return false;
  84. }
  85. return true;
  86. }
  87. protected function toggleMaintenanceScreen($toggle)
  88. {
  89. if ($toggle)
  90. {
  91. //Disable Airtime UI
  92. //create a temporary maintenance notification file
  93. //when this file is on the server, zend framework redirects all
  94. //requests to the maintenance page and sets a 503 response code
  95. $this->maintenanceFile = isset($_SERVER['AIRTIME_BASE']) ? $_SERVER['AIRTIME_BASE']."maintenance.txt" : "/tmp/maintenance.txt";
  96. $file = fopen($this->maintenanceFile, 'w');
  97. fclose($file);
  98. } else {
  99. //delete maintenance.txt to give users access back to Airtime
  100. if ($this->maintenanceFile) {
  101. unlink($this->maintenanceFile);
  102. }
  103. }
  104. }
  105. /** Implement this for each new version of Airtime */
  106. abstract public function upgrade();
  107. }
  108. /** This upgrade adds schema changes to accommodate show artwork and show instance descriptions */
  109. class AirtimeUpgrader252 extends AirtimeUpgrader {
  110. protected function getSupportedSchemaVersions() {
  111. return array (
  112. '2.5.1'
  113. );
  114. }
  115. public function getNewVersion() {
  116. return '2.5.2';
  117. }
  118. public function upgrade($dir = __DIR__) {
  119. Cache::clear();
  120. assert($this->checkIfUpgradeSupported());
  121. $newVersion = $this->getNewVersion();
  122. try {
  123. $this->toggleMaintenanceScreen(true);
  124. Cache::clear();
  125. // Begin upgrade
  126. $airtimeConf = isset($_SERVER['AIRTIME_CONF']) ? $_SERVER['AIRTIME_CONF'] : "/etc/airtime/airtime.conf";
  127. $values = parse_ini_file($airtimeConf, true);
  128. $username = $values['database']['dbuser'];
  129. $password = $values['database']['dbpass'];
  130. $host = $values['database']['host'];
  131. $database = $values['database']['dbname'];
  132. passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/upgrade_sql/airtime_"
  133. .$this->getNewVersion()."/upgrade.sql $database 2>&1 | grep -v \"will create implicit index\"");
  134. Application_Model_Preference::SetSchemaVersion($newVersion);
  135. Cache::clear();
  136. $this->toggleMaintenanceScreen(false);
  137. return true;
  138. } catch(Exception $e) {
  139. $this->toggleMaintenanceScreen(false);
  140. throw $e;
  141. }
  142. }
  143. }
  144. class AirtimeUpgrader253 extends AirtimeUpgrader
  145. {
  146. protected function getSupportedSchemaVersions()
  147. {
  148. return array('2.5.2');
  149. }
  150. public function getNewVersion()
  151. {
  152. return '2.5.3';
  153. }
  154. public function upgrade($dir = __DIR__)
  155. {
  156. Cache::clear();
  157. assert($this->checkIfUpgradeSupported());
  158. $con = Propel::getConnection();
  159. $con->beginTransaction();
  160. try {
  161. $this->toggleMaintenanceScreen(true);
  162. Cache::clear();
  163. //Begin upgrade
  164. //Update disk_usage value in cc_pref
  165. $musicDir = CcMusicDirsQuery::create()
  166. ->filterByType('stor')
  167. ->filterByExists(true)
  168. ->findOne();
  169. $storPath = $musicDir->getDirectory();
  170. //Update disk_usage value in cc_pref
  171. $storDir = isset($_SERVER['AIRTIME_BASE']) ? $_SERVER['AIRTIME_BASE']."srv/airtime/stor" : "/srv/airtime/stor";
  172. $diskUsage = shell_exec("du -sb $storDir | awk '{print $1}'");
  173. Application_Model_Preference::setDiskUsage($diskUsage);
  174. //clear out the cache
  175. Cache::clear();
  176. $con->commit();
  177. //update system_version in cc_pref and change some columns in cc_files
  178. $airtimeConf = isset($_SERVER['AIRTIME_CONF']) ? $_SERVER['AIRTIME_CONF'] : "/etc/airtime/airtime.conf";
  179. $values = parse_ini_file($airtimeConf, true);
  180. $username = $values['database']['dbuser'];
  181. $password = $values['database']['dbpass'];
  182. $host = $values['database']['host'];
  183. $database = $values['database']['dbname'];
  184. 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\"");
  185. Application_Model_Preference::SetSchemaVersion($this->getNewVersion());
  186. //clear out the cache
  187. Cache::clear();
  188. $this->toggleMaintenanceScreen(false);
  189. } catch (Exception $e) {
  190. $con->rollback();
  191. $this->toggleMaintenanceScreen(false);
  192. }
  193. }
  194. }
  195. class AirtimeUpgrader254 extends AirtimeUpgrader
  196. {
  197. protected function getSupportedSchemaVersions()
  198. {
  199. return array('2.5.3');
  200. }
  201. public function getNewVersion()
  202. {
  203. return '2.5.4';
  204. }
  205. public function upgrade()
  206. {
  207. Cache::clear();
  208. assert($this->checkIfUpgradeSupported());
  209. $newVersion = $this->getNewVersion();
  210. $con = Propel::getConnection();
  211. //$con->beginTransaction();
  212. try {
  213. $this->toggleMaintenanceScreen(true);
  214. Cache::clear();
  215. //Begin upgrade
  216. //First, ensure there are no superadmins already.
  217. $numberOfSuperAdmins = CcSubjsQuery::create()
  218. ->filterByDbType(UTYPE_SUPERADMIN)
  219. ->filterByDbLogin("sourcefabric_admin", Criteria::NOT_EQUAL) //Ignore sourcefabric_admin users
  220. ->count();
  221. //Only create a super admin if there isn't one already.
  222. if ($numberOfSuperAdmins == 0)
  223. {
  224. //Find the "admin" user and promote them to superadmin.
  225. $adminUser = CcSubjsQuery::create()
  226. ->filterByDbLogin('admin')
  227. ->findOne();
  228. if (!$adminUser)
  229. {
  230. //TODO: Otherwise get the user with the lowest ID that is of type administrator:
  231. //
  232. $adminUser = CcSubjsQuery::create()
  233. ->filterByDbType(UTYPE_ADMIN)
  234. ->orderByDbId(Criteria::ASC)
  235. ->findOne();
  236. if (!$adminUser) {
  237. throw new Exception("Failed to find any users of type 'admin' ('A').");
  238. }
  239. }
  240. $adminUser = new Application_Model_User($adminUser->getDbId());
  241. $adminUser->setType(UTYPE_SUPERADMIN);
  242. $adminUser->save();
  243. Logging::info($_SERVER['HTTP_HOST'] . ': ' . $newVersion . " Upgrade: Promoted user " . $adminUser->getLogin() . " to be a Super Admin.");
  244. //Also try to promote the sourcefabric_admin user
  245. $sofabAdminUser = CcSubjsQuery::create()
  246. ->filterByDbLogin('sourcefabric_admin')
  247. ->findOne();
  248. if ($sofabAdminUser) {
  249. $sofabAdminUser = new Application_Model_User($sofabAdminUser->getDbId());
  250. $sofabAdminUser->setType(UTYPE_SUPERADMIN);
  251. $sofabAdminUser->save();
  252. Logging::info($_SERVER['HTTP_HOST'] . ': ' . $newVersion . " Upgrade: Promoted user " . $sofabAdminUser->getLogin() . " to be a Super Admin.");
  253. }
  254. }
  255. //$con->commit();
  256. Application_Model_Preference::SetSchemaVersion($newVersion);
  257. Cache::clear();
  258. $this->toggleMaintenanceScreen(false);
  259. return true;
  260. } catch(Exception $e) {
  261. //$con->rollback();
  262. $this->toggleMaintenanceScreen(false);
  263. throw $e;
  264. }
  265. }
  266. }
  267. /* We are skipping 2.5.5 because it used to be the Show Artwork.
  268. *
  269. * DO NOT USE schema version 2.5.5!
  270. */
  271. /** This is a stub. Please implement this 2.5.6 upgrader for the next schema change that we need.
  272. * (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...
  273. *
  274. */
  275. class AirtimeUpgrader256 extends AirtimeUpgrader {
  276. protected function getSupportedSchemaVersions() {
  277. return array (
  278. '2.5.4', '2.5.5'
  279. );
  280. }
  281. public function getNewVersion() {
  282. return '2.5.6';
  283. }
  284. public function upgrade($dir = __DIR__) {
  285. Cache::clear();
  286. assert($this->checkIfUpgradeSupported());
  287. $newVersion = $this->getNewVersion();
  288. try {
  289. //TODO: Implement this
  290. return true;
  291. } catch(Exception $e) {
  292. $this->toggleMaintenanceScreen(false);
  293. throw $e;
  294. }
  295. }
  296. }