diff --git a/airtime_mvc/application/Bootstrap.php b/airtime_mvc/application/Bootstrap.php index 57ff42b0d..91736f51a 100644 --- a/airtime_mvc/application/Bootstrap.php +++ b/airtime_mvc/application/Bootstrap.php @@ -24,12 +24,14 @@ require_once "FileIO.php"; require_once "OsPath.php"; require_once "Database.php"; require_once "ProvisioningHelper.php"; +require_once "GoogleAnalytics.php"; require_once "Timezone.php"; require_once "Auth.php"; require_once __DIR__.'/forms/helpers/ValidationTypes.php'; require_once __DIR__.'/forms/helpers/CustomDecorators.php'; require_once __DIR__.'/controllers/plugins/RabbitMqPlugin.php'; require_once __DIR__.'/controllers/plugins/Maintenance.php'; +require_once __DIR__.'/controllers/plugins/ConversionTracking.php'; require_once __DIR__.'/modules/rest/controllers/ShowImageController.php'; require_once __DIR__.'/modules/rest/controllers/MediaController.php'; @@ -52,6 +54,7 @@ Application_Model_Auth::pinSessionToClient(Zend_Auth::getInstance()); $front = Zend_Controller_Front::getInstance(); $front->registerPlugin(new RabbitMqPlugin()); +$front->registerPlugin(new Zend_Controller_Plugin_ConversionTracking()); $front->throwExceptions(false); //localization configuration diff --git a/airtime_mvc/application/common/FileIO.php b/airtime_mvc/application/common/FileIO.php index 2c7724757..4d1ffd68c 100644 --- a/airtime_mvc/application/common/FileIO.php +++ b/airtime_mvc/application/common/FileIO.php @@ -65,7 +65,9 @@ class Application_Common_FileIO //We can have multiple levels of output buffering. Need to //keep looping until all have been disabled!!! //http://www.php.net/manual/en/function.ob-end-flush.php - while (@ob_end_flush()); + while (ob_get_level() > 0) { + ob_end_flush(); + } // NOTE: We can't use fseek here because it does not work with streams // (a.k.a. Files stored in the cloud) diff --git a/airtime_mvc/application/common/GoogleAnalytics.php b/airtime_mvc/application/common/GoogleAnalytics.php new file mode 100644 index 000000000..00a95a51e --- /dev/null +++ b/airtime_mvc/application/common/GoogleAnalytics.php @@ -0,0 +1,92 @@ +sub($trialDuration); + $interval = $today->diff($accountCreationDate); + $accountDuration = $interval->days; + } + + $code = "$( document ).ready(function() { + dataLayer.push({ + 'UserID': '" . $clientId . "', + 'Customer': 'Customer', + 'PlanType': '" . $plan . "', + 'Trial': '" . $isTrial . "', + 'AccountDuration': '" . strval($accountDuration) . "' + }); + });"; + //No longer sending these variables because we used to make a query to WHMCS + //to fetch them, which was slow. + // 'ZipCode': '" . $postcode . "', + // 'Country': '" . $country . "', + + } catch (Exception $e) { + Logging::error($e); + return ""; + } + return $code; + } + + /** Generate the JavaScript snippet that logs a trial to paid conversion */ + public static function generateConversionTrackingJavaScript() + { + $newPlan = Application_Model_Preference::GetPlanLevel(); + $oldPlan = Application_Model_Preference::GetOldPlanLevel(); + + $code = "dataLayer.push({'event': 'Conversion', + 'Conversion': 'Trial to Paid', + 'Old Plan' : '$oldPlan', + 'New Plan' : '$newPlan'});"; + return $code; + } + + /** Return true if the user used to be on a trial plan and was just converted to a paid plan. */ + public static function didPaidConversionOccur($request) + { + $userInfo = Zend_Auth::getInstance()->getStorage()->read(); + if ($userInfo) { + $user = new Application_Model_User($userInfo->id); + } else { + return; + } + + $oldPlan = Application_Model_Preference::GetOldPlanLevel(); + + if ($user->isSuperAdmin() && + !$user->isSourcefabricAdmin() && + $request->getControllerKey() !== "thank-you") + { + //Only tracking trial->paid conversions for now. + if ($oldPlan == "trial") + { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/airtime_mvc/application/common/HTTPHelper.php b/airtime_mvc/application/common/HTTPHelper.php index 177892e1f..d6f1d6820 100644 --- a/airtime_mvc/application/common/HTTPHelper.php +++ b/airtime_mvc/application/common/HTTPHelper.php @@ -27,7 +27,7 @@ class Application_Common_HTTPHelper if (empty($baseDir)) { $baseDir = "/"; } - if ($baseDir[0] != "") { + if ($baseDir[0] != "/") { $baseDir = "/" . $baseDir; } diff --git a/airtime_mvc/application/configs/ACL.php b/airtime_mvc/application/configs/ACL.php index 5105b812f..fe6e4d3d6 100644 --- a/airtime_mvc/application/configs/ACL.php +++ b/airtime_mvc/application/configs/ACL.php @@ -36,6 +36,7 @@ $ccAcl->add(new Zend_Acl_Resource('library')) ->add(new Zend_Acl_Resource('rest:media')) ->add(new Zend_Acl_Resource('rest:show-image')) ->add(new Zend_Acl_Resource('billing')) + ->add(new Zend_Acl_Resource('thank-you')) ->add(new Zend_Acl_Resource('provisioning')) ->add(new Zend_Acl_Resource('embeddableplayer')); @@ -70,7 +71,11 @@ $ccAcl->allow('G', 'index') ->allow('A', 'user') ->allow('A', 'systemstatus') ->allow('A', 'preference') +<<<<<<< HEAD ->allow('A', 'embeddableplayer') +======= + ->allow('S', 'thank-you') +>>>>>>> saas ->allow('S', 'billing'); diff --git a/airtime_mvc/application/configs/conf.php b/airtime_mvc/application/configs/conf.php index eae99d778..f89a5472e 100644 --- a/airtime_mvc/application/configs/conf.php +++ b/airtime_mvc/application/configs/conf.php @@ -44,6 +44,13 @@ class Config { $CC_CONFIG['dev_env'] = 'production'; } + //Backported static_base_dir default value into saas for now. + if (array_key_exists('static_base_dir', $values['general'])) { + $CC_CONFIG['staticBaseDir'] = $values['general']['static_base_dir']; + } else { + $CC_CONFIG['staticBaseDir'] = '/'; + } + // Parse separate conf file for cloud storage values $cloudStorageConfig = "/etc/airtime-saas/".$CC_CONFIG['dev_env']."/cloud_storage.conf"; if (!file_exists($cloudStorageConfig)) { diff --git a/airtime_mvc/application/controllers/ShowbuilderController.php b/airtime_mvc/application/controllers/ShowbuilderController.php index 5638cf719..3bb30abf4 100644 --- a/airtime_mvc/application/controllers/ShowbuilderController.php +++ b/airtime_mvc/application/controllers/ShowbuilderController.php @@ -35,7 +35,7 @@ class ShowbuilderController extends Zend_Controller_Action $user = Application_Model_User::GetCurrentUser(); $userType = $user->getType(); $this->view->headScript()->appendScript("localStorage.setItem( 'user-type', '$userType' );"); - $this->view->headScript()->appendScript($this->generateGoogleTagManagerDataLayerJavaScript()); + $this->view->headScript()->appendScript(Application_Common_GoogleAnalytics::generateGoogleTagManagerDataLayerJavaScript()); $this->view->headScript()->appendFile($baseUrl.'js/contextmenu/jquery.contextMenu.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'js/datatables/js/jquery.dataTables.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); @@ -367,104 +367,5 @@ class ShowbuilderController extends Zend_Controller_Action throw new Exception("this controller is/was a no-op please fix your code"); } - - /** Returns a string containing the JavaScript code to pass some billing account info - * into Google Tag Manager / Google Analytics, so we can track things like the plan type. - */ - private static function generateGoogleTagManagerDataLayerJavaScript() - { - $code = ""; - - try - { - $accessKey = $_SERVER["WHMCS_ACCESS_KEY"]; - $username = $_SERVER["WHMCS_USERNAME"]; - $password = $_SERVER["WHMCS_PASSWORD"]; - $url = "https://account.sourcefabric.com/includes/api.php?accesskey=" . $accessKey; # URL to WHMCS API file goes here - - $postfields = array(); - $postfields["username"] = $username; - $postfields["password"] = md5($password); - $postfields["action"] = "getclientsdetails"; - $postfields["stats"] = true; - $postfields["clientid"] = Application_Model_Preference::GetClientId(); - $postfields["responsetype"] = "json"; - - $query_string = ""; - foreach ($postfields AS $k=>$v) $query_string .= "$k=".urlencode($v)."&"; - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 ); // WHMCS IP whitelist doesn't support IPv6 - curl_setopt($ch, CURLOPT_TIMEOUT, 5); //Aggressive 5 second timeout - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, $query_string); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); - $jsondata = curl_exec($ch); - if (curl_error($ch)) { - //die("Connection Error: ".curl_errno($ch).' - '.curl_error($ch)); - throw new Exception("WHMCS server down or invalid request."); - } - curl_close($ch); - - $arr = json_decode($jsondata); # Decode JSON String - - if ($arr->result !== "success") { - Logging::warn("WHMCS API call failed in " . __FUNCTION__); - return; - } - - $client = $arr->client; - $stats = $arr->stats; - $currencyCode = $client->currency_code; - //$incomeCents = NumberFormatter::parseCurrency($stats->income, $currencyCode); - - $isTrial = true; - if (strpos($stats->income, "0.00") === FALSE) { - $isTrial = false; - } - /* - if ($incomeCents > 0) { - $isTrial = false; - }*/ - $plan = Application_Model_Preference::GetPlanLevel(); - $country = $client->country; - $postcode = $client->postcode; - - //Figure out how long the customer has been around using a mega hack. - //(I'm avoiding another round trip to WHMCS for now...) - //We calculate it based on the trial end date... - $trialEndDateStr = Application_Model_Preference::GetTrialEndingDate(); - if ($trialEndDateStr == '') { - $accountDuration = 0; - } else { - $today = new DateTime(); - $trialEndDate = new DateTime($trialEndDateStr); - $trialDuration = new DateInterval("P30D"); //30 day trial duration - $accountCreationDate = $trialEndDate->sub($trialDuration); - $interval = $today->diff($accountCreationDate); - $accountDuration = $interval->days; - } - - $code = "$( document ).ready(function() { - dataLayer.push({ - 'ZipCode': '" . $postcode . "', - 'UserID': '" . $client->id . "', - 'Customer': 'Customer', - 'PlanType': '" . $plan . "', - 'Trial': '" . $isTrial . "', - 'Country': '" . $country . "', - 'AccountDuration': '" . strval($accountDuration) . "' - }); - });"; - - } - catch (Exception $e) - { - return ""; - } - return $code; - } + } diff --git a/airtime_mvc/application/controllers/ThankYouController.php b/airtime_mvc/application/controllers/ThankYouController.php new file mode 100644 index 000000000..86a57a54c --- /dev/null +++ b/airtime_mvc/application/controllers/ThankYouController.php @@ -0,0 +1,48 @@ +view->stationUrl = Application_Common_HTTPHelper::getStationUrl(); + $this->view->conversionUrl = Application_Common_HTTPHelper::getStationUrl() . 'thank-you/confirm-conversion'; + $this->view->gaEventTrackingJsCode = ""; //Google Analytics event tracking code that logs an event. + + // Embed the Google Analytics conversion tracking code if the + // user is a super admin and old plan level is set to trial. + if (Application_Common_GoogleAnalytics::didPaidConversionOccur($this->getRequest())) { + $this->view->gaEventTrackingJsCode = Application_Common_GoogleAnalytics::generateConversionTrackingJavaScript(); + } + + $csrf_namespace = new Zend_Session_Namespace('csrf_namespace'); + $csrf_element = new Zend_Form_Element_Hidden('csrf'); + $csrf_element->setValue($csrf_namespace->authtoken)->setRequired('true')->removeDecorator('HtmlTag')->removeDecorator('Label'); + $csrf_form = new Zend_Form(); + $csrf_form->addElement($csrf_element); + $this->view->form = $csrf_form; + } + + /** Confirm that a conversion was tracked. */ + public function confirmConversionAction() + { + $this->view->layout()->disableLayout(); + $this->_helper->viewRenderer->setNoRender(true); + + $current_namespace = new Zend_Session_Namespace('csrf_namespace'); + $observed_csrf_token = $this->_getParam('csrf_token'); + $expected_csrf_token = $current_namespace->authtoken; + + if($observed_csrf_token != $expected_csrf_token) { + Logging::info("Invalid CSRF token"); + return; + } + + if ($this->getRequest()->isPost()) { + Logging::info("Goal conversion from trial to paid."); + // Clear old plan level so we prevent duplicate events. + // This should only be called from AJAX. See thank-you/index.phtml + Application_Model_Preference::ClearOldPlanLevel(); + } + } +} \ No newline at end of file diff --git a/airtime_mvc/application/controllers/UpgradeController.php b/airtime_mvc/application/controllers/UpgradeController.php index 9af3dc1e9..518e173ac 100644 --- a/airtime_mvc/application/controllers/UpgradeController.php +++ b/airtime_mvc/application/controllers/UpgradeController.php @@ -20,7 +20,8 @@ class UpgradeController extends Zend_Controller_Action array_push($upgraders, new AirtimeUpgrader259()); array_push($upgraders, new AirtimeUpgrader2510()); array_push($upgraders, new AirtimeUpgrader2511()); - + array_push($upgraders, new AirtimeUpgrader2512()); + $didWePerformAnUpgrade = false; try { diff --git a/airtime_mvc/application/controllers/plugins/ConversionTracking.php b/airtime_mvc/application/controllers/plugins/ConversionTracking.php new file mode 100644 index 000000000..09904828d --- /dev/null +++ b/airtime_mvc/application/controllers/plugins/ConversionTracking.php @@ -0,0 +1,21 @@ +getControllerName() != 'thank-you') + { + $request->setModuleName('default') + ->setControllerName('thank-you') + ->setActionName('index') + ->setDispatched(true); + } + } + } + +} \ No newline at end of file diff --git a/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.12/upgrade.sql b/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.12/upgrade.sql new file mode 100644 index 000000000..92ca30ade --- /dev/null +++ b/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.12/upgrade.sql @@ -0,0 +1,2 @@ +ALTER TABLE cc_show ALTER COLUMN description TYPE varchar(8192); +ALTER TABLE cc_show_instances ALTER COLUMN description TYPE varchar(8192); diff --git a/airtime_mvc/application/layouts/scripts/layout.phtml b/airtime_mvc/application/layouts/scripts/layout.phtml index df5d0281b..bf97086c5 100644 --- a/airtime_mvc/application/layouts/scripts/layout.phtml +++ b/airtime_mvc/application/layouts/scripts/layout.phtml @@ -21,7 +21,6 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= partial('partialviews/trialBox.phtml', array("is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?>
- versionNotify(); $sss = $this->SourceSwitchStatus(); $scs = $this->SourceConnectionStatus(); @@ -30,17 +29,21 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= "scheduled_play_switch"=>$sss['scheduled_play'])) ?> navigation()->menu()->setPartial($partial); ?> -
- -
+
layout()->content ?>
diff --git a/airtime_mvc/application/logging/Logging.php b/airtime_mvc/application/logging/Logging.php index 5aef4baba..d6d30e932 100644 --- a/airtime_mvc/application/logging/Logging.php +++ b/airtime_mvc/application/logging/Logging.php @@ -138,7 +138,9 @@ class Logging { switch($err['type']) { case E_ERROR: + case E_WARNING: case E_PARSE: + case E_NOTICE: case E_CORE_ERROR: case E_CORE_WARNING: case E_COMPILE_ERROR: diff --git a/airtime_mvc/application/models/Preference.php b/airtime_mvc/application/models/Preference.php index a25679826..bc0b2006e 100644 --- a/airtime_mvc/application/models/Preference.php +++ b/airtime_mvc/application/models/Preference.php @@ -824,7 +824,10 @@ class Application_Model_Preference public static function SetPlanLevel($plan) { + $oldPlanLevel = self::GetPlanLevel(); self::setValue("plan_level", $plan); + //We save the old plan level temporarily to facilitate conversion tracking + self::setValue("old_plan_level", $oldPlanLevel); } public static function GetPlanLevel() @@ -837,6 +840,19 @@ class Application_Model_Preference return $plan; } + public static function GetOldPlanLevel() + { + $oldPlan = self::getValue("old_plan_level"); + return $oldPlan; + } + + /** Clearing the old plan level indicates a change in your plan has been tracked (Google Analytics) */ + public static function ClearOldPlanLevel() + { + self::setValue("old_plan_level", ''); + } + + public static function SetTrialEndingDate($date) { self::setValue("trial_end_date", $date); diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index 5e6e53161..1049d449d 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -984,15 +984,19 @@ SQL; } else { Logging::info("Moving file $audio_file to $audio_stor"); + //Ensure we have permissions to overwrite the file in stor, in case it already exists. + if (file_exists($audio_stor)) { + chmod($audio_stor, 0644); + } + // Martin K.: changed to rename: Much less load + quicker since this is // an atomic operation - if (@rename($audio_file, $audio_stor) === false) { + if (rename($audio_file, $audio_stor) === false) { //something went wrong likely there wasn't enough space in . //the audio_stor to move the file too warn the user that . //the file wasn't uploaded and they should check if there . //is enough disk space . unlink($audio_file); //remove the file after failed rename - //unlink($id_file); // Also remove the identifier file throw new Exception("The file was not uploaded, this error can occur if the computer " . "hard drive does not have enough disk space or the stor " diff --git a/airtime_mvc/application/models/User.php b/airtime_mvc/application/models/User.php index 2001a97f8..ac428fefc 100644 --- a/airtime_mvc/application/models/User.php +++ b/airtime_mvc/application/models/User.php @@ -69,6 +69,15 @@ class Application_Model_User return $result; } + public function isSourcefabricAdmin() + { + $username = $this->getLogin(); + if ($username == "sourcefabric_admin") { + return true; + } + return false; + } + // TODO : refactor code to only accept arrays for isUserType and // simplify code even further public function isUserType($type) diff --git a/airtime_mvc/application/models/airtime/CcFiles.php b/airtime_mvc/application/models/airtime/CcFiles.php index 029d21a15..ff9d3d7fc 100644 --- a/airtime_mvc/application/models/airtime/CcFiles.php +++ b/airtime_mvc/application/models/airtime/CcFiles.php @@ -95,9 +95,10 @@ class CcFiles extends BaseCcFiles { try { self::createAndImport($fileArray, $tempFilePath, $originalFilename); - } catch (Exception $e) - { - @unlink($tempFilePath); + } catch (Exception $e) { + if (file_exists($tempFilePath)) { + unlink($tempFilePath); + } throw $e; } } diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 6a2cccd63..b43bac3c0 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -124,6 +124,7 @@ class Rest_MediaController extends Zend_Rest_Controller catch (Exception $e) { $this->unknownErrorResponse(); Logging::error($e->getMessage()); + throw $e; } } diff --git a/airtime_mvc/application/upgrade/Upgrades.php b/airtime_mvc/application/upgrade/Upgrades.php index 4535fe475..9468753d6 100644 --- a/airtime_mvc/application/upgrade/Upgrades.php +++ b/airtime_mvc/application/upgrade/Upgrades.php @@ -38,14 +38,17 @@ abstract class AirtimeUpgrader //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 + /* DISABLED because this does not work correctly $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 + /* DISABLED because this does not work correctly if ($this->maintenanceFile) { unlink($this->maintenanceFile); - } + }*/ } } @@ -385,3 +388,52 @@ class AirtimeUpgrader2511 extends AirtimeUpgrader } } + +class AirtimeUpgrader2512 extends AirtimeUpgrader +{ + protected function getSupportedVersions() { + return array ( + '2.5.10', + '2.5.11' + ); + } + + public function getNewVersion() { + return '2.5.12'; + } + + 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 -E \"will create implicit sequence|will create implicit index\""); + + Application_Model_Preference::SetAirtimeVersion($newVersion); + Cache::clear(); + + $this->toggleMaintenanceScreen(false); + } catch(Exception $e) { + $this->toggleMaintenanceScreen(false); + throw $e; + } + } + public function downgrade() { + + } +} diff --git a/airtime_mvc/application/views/scripts/menu.phtml b/airtime_mvc/application/views/scripts/menu.phtml index 64af78861..1cd0d7e04 100644 --- a/airtime_mvc/application/views/scripts/menu.phtml +++ b/airtime_mvc/application/views/scripts/menu.phtml @@ -1,4 +1,4 @@ - + diff --git a/airtime_mvc/application/views/scripts/thank-you/index.phtml b/airtime_mvc/application/views/scripts/thank-you/index.phtml new file mode 100644 index 000000000..436b9b378 --- /dev/null +++ b/airtime_mvc/application/views/scripts/thank-you/index.phtml @@ -0,0 +1,20 @@ + +form->getElement('csrf') ?> + +
+
+
+

+

+

+
+
diff --git a/airtime_mvc/build/schema.xml b/airtime_mvc/build/schema.xml index ef382454c..ece788ea7 100644 --- a/airtime_mvc/build/schema.xml +++ b/airtime_mvc/build/schema.xml @@ -139,7 +139,7 @@ - + @@ -156,7 +156,7 @@ - + diff --git a/airtime_mvc/build/sql/schema.sql b/airtime_mvc/build/sql/schema.sql index a617ebda8..392539496 100644 --- a/airtime_mvc/build/sql/schema.sql +++ b/airtime_mvc/build/sql/schema.sql @@ -149,7 +149,7 @@ CREATE TABLE "cc_show" "name" VARCHAR(255) DEFAULT '' NOT NULL, "url" VARCHAR(255) DEFAULT '', "genre" VARCHAR(255) DEFAULT '', - "description" VARCHAR(512), + "description" VARCHAR(8192), "color" VARCHAR(6), "background_color" VARCHAR(6), "live_stream_using_airtime_auth" BOOLEAN DEFAULT 'f', @@ -171,7 +171,7 @@ DROP TABLE IF EXISTS "cc_show_instances" CASCADE; CREATE TABLE "cc_show_instances" ( "id" serial NOT NULL, - "description" VARCHAR(512) DEFAULT '', + "description" VARCHAR(8192) DEFAULT '', "starts" TIMESTAMP NOT NULL, "ends" TIMESTAMP NOT NULL, "show_id" INTEGER NOT NULL, diff --git a/airtime_mvc/library/php-amqplib/amqp.inc b/airtime_mvc/library/php-amqplib/amqp.inc index 1bf03b3c4..57c642abd 100644 --- a/airtime_mvc/library/php-amqplib/amqp.inc +++ b/airtime_mvc/library/php-amqplib/amqp.inc @@ -463,8 +463,10 @@ class AMQPConnection extends AbstractChannel { debug_msg("closing socket"); } - - @fclose($this->sock); + + if (is_resource($this->sock)) { + @fclose($this->sock); + } $this->sock = NULL; } } diff --git a/airtime_mvc/public/css/masterpanel.css b/airtime_mvc/public/css/masterpanel.css index 39c95044f..d641bbb01 100644 --- a/airtime_mvc/public/css/masterpanel.css +++ b/airtime_mvc/public/css/masterpanel.css @@ -300,13 +300,12 @@ .personal-block.solo { - position: absolute; - right: 145px; - top: 104px; - width: auto; - z-index: 1000; - height:auto; - margin:0; + width: auto; + height:auto; + margin: 0 10px 0 0; +} +.personal-block.solo ol { + margin-top: 6px; } .time-info-block.pull-right { margin-right:0; diff --git a/airtime_mvc/public/css/styles.css b/airtime_mvc/public/css/styles.css index d709bf038..ca50bebd7 100644 --- a/airtime_mvc/public/css/styles.css +++ b/airtime_mvc/public/css/styles.css @@ -48,14 +48,12 @@ select { } .logo { - position:absolute; - right:20px; - top:104px; - background:transparent url(images/airtime_logo.png) no-repeat 0 0; - height:35px; - width:66px; - z-index:1000; - display:block; + background: transparent url(images/airtime_logo.png) no-repeat 0 0; + height: 35px; + width: 66px; + float: right; + padding: 0 5px 0 10px; + margin-top: -5px; } /* Version Notification Starts*/ @@ -286,8 +284,74 @@ select { background:url(images/masterpanel_spacer.png) no-repeat right 0; } .time-info-block { - padding:0 14px 0 2px; - min-width:105px; + position: absolute; + top: 0; + right: 0; +} +#navlist { + padding: 0; + margin: 0; +} +#nav li.top { + /*float: none;*/ +} +@media screen and (max-width: 1200px) { + .now-playing-block { + width: 30%; + } + .show-block { + width: 25%; + } +} +@media screen and (max-width: 920px) { + .now-playing-block { + width: 50%; + } + .show-block { + display: none; + } + .personal-block.solo { + right: 10px !important; + } +} +@media screen and (max-width: 810px) { + .now-playing-block { + width: 40%; + } +} +@media screen and (max-width: 863px) { + #nav { + height: inherit; + overflow-y: visible; + } +} +@media screen and (max-width: 680px) { + .now-playing-block { + display: none; + } + #nav li.top { + display: -webkit-flex; + width: 110px; + } + .personal-block.solo { + float: none; + text-align: left; + } + .personal-block.solo ol { + padding-left: 12px; + } + .logo { + float: none; + margin-left: 12px; + } +} +@media screen and (max-width: 380px) { + .time-info-block { + display: none; + } + .on-air-block { + margin: 0; + } } .time-info-block ul { margin:0; @@ -3141,3 +3205,15 @@ dd .stream-status { .quota-reached { font-size: 14px !important; } + +.thankyou-panel +{ + width: 400px; + margin: 0 auto; + margin-bottom: 30px; +} + +.thankyou-panel h3 +{ + color: #222; +} diff --git a/airtime_mvc/public/js/airtime/schedule/add-show.js b/airtime_mvc/public/js/airtime/schedule/add-show.js index a8c9f76e7..df862e971 100644 --- a/airtime_mvc/public/js/airtime/schedule/add-show.js +++ b/airtime_mvc/public/js/airtime/schedule/add-show.js @@ -82,7 +82,7 @@ function closeAddShowForm(event) { redrawAddShowForm($el, json.form); }); - + makeAddShowButton(); } @@ -742,7 +742,7 @@ function setAddShowEvents(form) { image = new FormData(); image.append('file', $('#add_show_logo')[0].files[0]); } - + $.ajax({ url: action, data: {format: "json", data: data, hosts: hosts, days: days}, @@ -784,6 +784,7 @@ function setAddShowEvents(form) { } else { redrawAddShowForm($addShowForm, json.newForm); scheduleRefetchEvents(json); + $addShowForm.hide(); } } }); diff --git a/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py b/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py index 9c2d52a31..23c6175c3 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py @@ -129,6 +129,7 @@ def send_http_request(picklable_request, retry_queue): retry_queue.append(picklable_request) # Retry it later except Exception as e: logging.error("HTTP request failed with unhandled exception. %s" % str(e)) + logging.error(traceback.format_exc()) # Don't put the request into the retry queue, just give up on this one. # I'm doing this to protect against us getting some pathological request # that breaks our code. I don't want us pickling data that potentially diff --git a/python_apps/airtime_analyzer/tools/ftp-upload-hook.sh b/python_apps/airtime_analyzer/tools/ftp-upload-hook.sh index aa543f853..4304f7594 100755 --- a/python_apps/airtime_analyzer/tools/ftp-upload-hook.sh +++ b/python_apps/airtime_analyzer/tools/ftp-upload-hook.sh @@ -2,10 +2,14 @@ post_file() { #kill process after 30 minutes (360*5=30 minutes) - max_retry=360 + max_retry=5 retry_count=0 file_path="${1}" + # Give us write permissions on the file to prevent problems if the user + # uploads a read-only file. + chmod +w "${file_path}" + #We must remove commas because CURL can't upload files with commas in the name # http://curl.haxx.se/mail/archive-2009-07/0029.html stripped_file_path=${file_path//','/''}