From fb4aef405cf46364cbfd7785ce4fcc3fee6e1e89 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Mon, 19 Oct 2015 15:23:50 -0400 Subject: [PATCH 1/9] Increase transaction isolation level to avoid duplicate shows, SAAS-1111 --- airtime_mvc/application/models/Show.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/airtime_mvc/application/models/Show.php b/airtime_mvc/application/models/Show.php index 2653fe848..504a53418 100644 --- a/airtime_mvc/application/models/Show.php +++ b/airtime_mvc/application/models/Show.php @@ -850,6 +850,9 @@ SQL; $con = Propel::getConnection(CcPrefPeer::DATABASE_NAME); try { $con->beginTransaction(); + //It is extremely important that we increase the transaction isolation level, so that if two + //requests cause the show schedule to be generated at the same time, one will be rolled back. + $con->exec("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE"); //UTC DateTime object $showsPopUntil = Application_Model_Preference::GetShowsPopulatedUntil(); @@ -862,7 +865,9 @@ SQL; $con->commit(); } catch (Exception $e) { $con->rollBack(); - throw $e; + //throw $e; + Logging::warn("Did not create show instances due to transaction error. This is usually safe + and caused by two concurrent transactions. " . $e->getMessage()); } } From bd3a16ae7bdbdcd637398d3d795cf066044f47e1 Mon Sep 17 00:00:00 2001 From: Duncan Sommerville Date: Mon, 19 Oct 2015 16:10:20 -0400 Subject: [PATCH 2/9] SAAS-1110 - Fix header sizing at most screen resolutions --- airtime_mvc/public/css/styles.css | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/airtime_mvc/public/css/styles.css b/airtime_mvc/public/css/styles.css index 8929a33f0..3f9381aed 100644 --- a/airtime_mvc/public/css/styles.css +++ b/airtime_mvc/public/css/styles.css @@ -288,15 +288,13 @@ select { color:#ff5d1a; } .now-playing-block { - /*width:35%;*/ - flex: 1 auto; + flex: 1 0; background: url(images/masterpanel_spacer.png) no-repeat 0 0; margin-left: 152px; padding-left: 14px; } .show-block { - /*width:30%;*/ - flex: 1 auto; + flex: 1 0; } .text-row { height:30px; @@ -3962,4 +3960,4 @@ li .ui-state-hover { } /* jQuery dialog */ -.no-close .ui-dialog-titlebar-close {display: none } \ No newline at end of file +.no-close .ui-dialog-titlebar-close {display: none } From f8a6721703bad8881a993e490a8987891290ec5e Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Mon, 19 Oct 2015 17:31:26 -0400 Subject: [PATCH 3/9] Increase transaction isolation level for track scheduling and moving --- airtime_mvc/application/models/Scheduler.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/airtime_mvc/application/models/Scheduler.php b/airtime_mvc/application/models/Scheduler.php index 51b964589..e5ecd707c 100644 --- a/airtime_mvc/application/models/Scheduler.php +++ b/airtime_mvc/application/models/Scheduler.php @@ -955,6 +955,10 @@ class Application_Model_Scheduler $this->con->beginTransaction(); try { + //Increase the transaction isolation level to prevent two concurrent requests from potentially resulting + //in tracks scheduled at the same time. + $this->con->exec("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE"); + $this->validateMediaItems($mediaItems); //Check for missing files, etc. $this->validateRequest($scheduleItems, true); @@ -1005,6 +1009,9 @@ class Application_Model_Scheduler //$this->con->useDebug(true); try { + //Increase the transaction isolation level to prevent two concurrent requests from potentially resulting + //in tracks scheduled at the same time. + $this->con->exec("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE"); $this->validateItemMove($selectedItems, $afterItems[0]); $this->validateRequest($selectedItems); From c8e1408dbe74a80c2b9d0954a013484abe1dc31e Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Tue, 20 Oct 2015 11:45:26 -0400 Subject: [PATCH 4/9] Handle error case with bad user timezone strings break advanced search --- airtime_mvc/application/models/Datatables.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/airtime_mvc/application/models/Datatables.php b/airtime_mvc/application/models/Datatables.php index 8002f45f0..b966269ae 100644 --- a/airtime_mvc/application/models/Datatables.php +++ b/airtime_mvc/application/models/Datatables.php @@ -12,10 +12,15 @@ class Application_Model_Datatables if (strstr($term, '~')) { $info = explode('~', $term); if ($dbname == 'utime' || $dbname == 'mtime' || $dbname == 'lptime') { - - $input1 = ($info[0] != "") ? Application_Common_DateHelper::UserTimezoneStringToUTCString($info[0]) : null; - $input2 = ($info[1] != "") ? Application_Common_DateHelper::UserTimezoneStringToUTCString($info[1]) : null; - + + try { + $input1 = ($info[0] != "") ? Application_Common_DateHelper::UserTimezoneStringToUTCString($info[0]) : null; + $input2 = ($info[1] != "") ? Application_Common_DateHelper::UserTimezoneStringToUTCString($info[1]) : null; + } catch (Exception $e) { + $input1 = null; + $input2 = null; + } + } else if($dbname == 'bit_rate' || $dbname == 'sample_rate') { $input1 = isset($info[0])?doubleval($info[0]) * 1000:null; $input2 = isset($info[1])?doubleval($info[1]) * 1000:null; From 9d4cc6c205155195e5ecb495460d42880dbd15b9 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Tue, 20 Oct 2015 12:28:18 -0400 Subject: [PATCH 5/9] Temporary workaround for upgrade problems --- airtime_mvc/application/forms/BillingClient.php | 8 ++++++++ airtime_mvc/application/forms/BillingUpgradeDowngrade.php | 2 ++ 2 files changed, 10 insertions(+) diff --git a/airtime_mvc/application/forms/BillingClient.php b/airtime_mvc/application/forms/BillingClient.php index 098c004a4..6057775ba 100644 --- a/airtime_mvc/application/forms/BillingClient.php +++ b/airtime_mvc/application/forms/BillingClient.php @@ -188,9 +188,17 @@ class Application_Form_BillingClient extends Zend_Form $passwordVerify->addValidator($notEmptyValidator); $this->addElement($passwordVerify); + /* + $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'); + $this->addElement($csrf_element); + + $this->addElement('hash', 'csrf', array( 'salt' => 'unique' )); + */ $submit = new Zend_Form_Element_Submit("submit"); $submit->setIgnore(true) diff --git a/airtime_mvc/application/forms/BillingUpgradeDowngrade.php b/airtime_mvc/application/forms/BillingUpgradeDowngrade.php index 5ff4ff4de..7947ab60b 100644 --- a/airtime_mvc/application/forms/BillingUpgradeDowngrade.php +++ b/airtime_mvc/application/forms/BillingUpgradeDowngrade.php @@ -3,6 +3,7 @@ class Application_Form_BillingUpgradeDowngrade extends Zend_Form { public function init() { + /* $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'); @@ -11,6 +12,7 @@ class Application_Form_BillingUpgradeDowngrade extends Zend_Form $this->addElement('hash', 'csrf', array( 'salt' => 'unique' )); + */ $productPrices = array(); $productTypes = array(); From 885f47c20e0f761d8ddb93848b64d0b6f9a5ffb9 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Tue, 20 Oct 2015 14:52:17 -0400 Subject: [PATCH 6/9] Better solution for upgrade problems (SAAS-1133) --- airtime_mvc/application/forms/BillingClient.php | 12 ++---------- .../application/forms/BillingUpgradeDowngrade.php | 9 +-------- .../application/views/scripts/billing/upgrade.phtml | 9 +++++---- 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/airtime_mvc/application/forms/BillingClient.php b/airtime_mvc/application/forms/BillingClient.php index 6057775ba..70def8c33 100644 --- a/airtime_mvc/application/forms/BillingClient.php +++ b/airtime_mvc/application/forms/BillingClient.php @@ -187,18 +187,10 @@ class Application_Form_BillingClient extends Zend_Form $passwordVerify->addValidator('Identical', false, array('token' => 'password2')); $passwordVerify->addValidator($notEmptyValidator); $this->addElement($passwordVerify); - - /* - $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'); - $this->addElement($csrf_element); - - - $this->addElement('hash', 'csrf', array( + + $this->addElement('hash', 'csrf_client', array( 'salt' => 'unique' )); - */ $submit = new Zend_Form_Element_Submit("submit"); $submit->setIgnore(true) diff --git a/airtime_mvc/application/forms/BillingUpgradeDowngrade.php b/airtime_mvc/application/forms/BillingUpgradeDowngrade.php index 7947ab60b..858f74ddd 100644 --- a/airtime_mvc/application/forms/BillingUpgradeDowngrade.php +++ b/airtime_mvc/application/forms/BillingUpgradeDowngrade.php @@ -3,16 +3,9 @@ class Application_Form_BillingUpgradeDowngrade extends Zend_Form { public function init() { - /* - $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'); - $this->addElement($csrf_element); - - $this->addElement('hash', 'csrf', array( + $this->addElement('hash', 'csrf_upgrade', array( //Needs a unique ID (csrf_upgrade) so it doesn't conflict with other tokens in subforms 'salt' => 'unique' )); - */ $productPrices = array(); $productTypes = array(); diff --git a/airtime_mvc/application/views/scripts/billing/upgrade.phtml b/airtime_mvc/application/views/scripts/billing/upgrade.phtml index 835b50d1f..fc1799140 100644 --- a/airtime_mvc/application/views/scripts/billing/upgrade.phtml +++ b/airtime_mvc/application/views/scripts/billing/upgrade.phtml @@ -274,7 +274,7 @@ echo($currentProduct["name"]);
- csrf ?> + csrf_upgrade ?>
newproductid ?> @@ -353,8 +353,9 @@ echo($currentProduct["name"]);
- -
+ csrf_client ?> + +
getElement("71")->renderViewHelper(); ?>
@@ -379,7 +380,7 @@ echo($currentProduct["name"]); Total:
- +
\ No newline at end of file From f79ca8650f8c7dac81598f1f7a6f223e63307b24 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Tue, 20 Oct 2015 15:44:24 -0400 Subject: [PATCH 7/9] Unpaid invoice usability hint and invoice page style fix - SAAS-1134 --- airtime_mvc/application/common/Billing.php | 45 +++++++++++++++++++ .../application/common/UsabilityHints.php | 21 ++++++++- .../controllers/BillingController.php | 23 +--------- .../application/forms/BillingClient.php | 2 +- .../views/scripts/billing/invoices.phtml | 2 +- airtime_mvc/public/css/billing.css | 8 ++++ 6 files changed, 75 insertions(+), 26 deletions(-) diff --git a/airtime_mvc/application/common/Billing.php b/airtime_mvc/application/common/Billing.php index 137451172..2dbfafa9a 100644 --- a/airtime_mvc/application/common/Billing.php +++ b/airtime_mvc/application/common/Billing.php @@ -329,4 +329,49 @@ class Billing $result = Billing::makeRequest($credentials["url"], $query_string); } + public static function getInvoices() + { + Billing::ensureClientIdIsValid(); + $credentials = Billing::getAPICredentials(); + + $postfields = array(); + $postfields["username"] = $credentials["username"]; + $postfields["password"] = md5($credentials["password"]); + $postfields["action"] = "getinvoices"; + $postfields["responsetype"] = "json"; + $postfields["userid"] = Application_Model_Preference::GetClientId(); + + $query_string = ""; + foreach ($postfields AS $k=>$v) $query_string .= "$k=".urlencode($v)."&"; + + $result = Billing::makeRequest($credentials["url"], $query_string); + + $invoices = array(); + if ($result["invoices"]) { + $invoices = $result["invoices"]["invoice"]; + } + return $invoices; + } + + /** + * Checks if the customer has any unpaid invoices and if so, returns + * the ID of one of them. Returns 0 otherwise. + */ + public static function checkForUnpaidInvoice() { + $invoices = self::getInvoices(); + $unpaidInvoice = 0; + $unpaidInvoices = 0; + foreach ($invoices as $invoice) + { + if ($invoice['status'] == 'Unpaid') { + $unpaidInvoices += 1; + $unpaidInvoice = $invoice; + } + } + if ($unpaidInvoices > 0) { + return $unpaidInvoice; + } else { + return 0; + } + } } diff --git a/airtime_mvc/application/common/UsabilityHints.php b/airtime_mvc/application/common/UsabilityHints.php index fb52de7b6..04022a1a7 100644 --- a/airtime_mvc/application/common/UsabilityHints.php +++ b/airtime_mvc/application/common/UsabilityHints.php @@ -21,6 +21,8 @@ class Application_Common_UsabilityHints $userIsOnCalendarPage = false; $userIsOnAddMediaPage = false; + $userIsOnShowbuilderPage = false; + $userIsSuperAdmin = Application_Model_User::getCurrentUser()->isSuperAdmin(); // If $userPath is set the request came from AJAX so the user's // current location inside Airtime gets passed in to this function. @@ -36,6 +38,11 @@ class Application_Common_UsabilityHints if (strpos(strtolower($userPath), 'schedule') !== false) { $userIsOnCalendarPage = true; } + + if (strpos(strtolower($userPath), 'showbuilder') !== false) { + $userIsOnShowbuilderPage = true; + } + } else { // If $userPath is not set the request came from inside Airtime so // we can use Zend's Front Controller to get the user's current location. @@ -48,6 +55,10 @@ class Application_Common_UsabilityHints if ($currentController == "plupload") { $userIsOnAddMediaPage = true; } + + if ($currentController == 'showbuilder') { + $userIsOnShowbuilderPage = true; + } } if (self::zeroFilesUploaded()) { @@ -92,9 +103,15 @@ class Application_Common_UsabilityHints "", ""); } - } else { - return ""; + } else if ($userIsOnShowbuilderPage && $userIsSuperAdmin) { + $unpaidInvoice = Billing::checkForUnpaidInvoice(); + if ($unpaidInvoice != null) { + $invoiceUrl = "/billing/invoice?invoiceid=" . $unpaidInvoice['id']; + $amount = $unpaidInvoice['currencyprefix'] . $unpaidInvoice['total']; + return _pro(sprintf("You have an unpaid invoice for %s due soon. Please pay it to keep your station on the air.", $amount, $invoiceUrl));; + } } + return ""; } /** diff --git a/airtime_mvc/application/controllers/BillingController.php b/airtime_mvc/application/controllers/BillingController.php index 4cfbd4f77..bf508036b 100644 --- a/airtime_mvc/application/controllers/BillingController.php +++ b/airtime_mvc/application/controllers/BillingController.php @@ -283,26 +283,7 @@ class BillingController extends Zend_Controller_Action { $baseUrl = Application_Common_OsPath::getBaseDir(); $this->view->headLink()->appendStylesheet($baseUrl.'css/billing.css?'.$CC_CONFIG['airtime_version']); - Billing::ensureClientIdIsValid(); - $credentials = Billing::getAPICredentials(); - - $postfields = array(); - $postfields["username"] = $credentials["username"]; - $postfields["password"] = md5($credentials["password"]); - $postfields["action"] = "getinvoices"; - $postfields["responsetype"] = "json"; - $postfields["userid"] = Application_Model_Preference::GetClientId(); - - $query_string = ""; - foreach ($postfields AS $k=>$v) $query_string .= "$k=".urlencode($v)."&"; - - $result = Billing::makeRequest($credentials["url"], $query_string); - - if ($result["invoices"]) { - $this->view->invoices = $result["invoices"]["invoice"];; - } else { - $this->view->invoices = array(); - } + $this->view->invoices = Billing::getInvoices(); } public function invoiceAction() @@ -312,6 +293,4 @@ class BillingController extends Zend_Controller_Action { $invoice_id = $request->getParam('invoiceid'); self::viewInvoice($invoice_id); } - - } diff --git a/airtime_mvc/application/forms/BillingClient.php b/airtime_mvc/application/forms/BillingClient.php index 70def8c33..60561b114 100644 --- a/airtime_mvc/application/forms/BillingClient.php +++ b/airtime_mvc/application/forms/BillingClient.php @@ -187,7 +187,7 @@ class Application_Form_BillingClient extends Zend_Form $passwordVerify->addValidator('Identical', false, array('token' => 'password2')); $passwordVerify->addValidator($notEmptyValidator); $this->addElement($passwordVerify); - + $this->addElement('hash', 'csrf_client', array( 'salt' => 'unique' )); diff --git a/airtime_mvc/application/views/scripts/billing/invoices.phtml b/airtime_mvc/application/views/scripts/billing/invoices.phtml index ea4cb3401..7fc3f4e01 100644 --- a/airtime_mvc/application/views/scripts/billing/invoices.phtml +++ b/airtime_mvc/application/views/scripts/billing/invoices.phtml @@ -5,7 +5,7 @@ $topTextClass = ""; if (array_key_exists("planupdated", $_GET)) { $topText = _pro("Thank you! Your plan has been updated and you will be invoiced during your next billing cycle."); - $topTextClass = "status-good"; + $topTextClass = "invoice-status-good"; } else { $topText = _pro("Tip: To pay an invoice, click \"View Invoice\" and look for the \"Checkout\" button."); diff --git a/airtime_mvc/public/css/billing.css b/airtime_mvc/public/css/billing.css index 7a0e53980..d749b324b 100644 --- a/airtime_mvc/public/css/billing.css +++ b/airtime_mvc/public/css/billing.css @@ -225,6 +225,14 @@ color: #ff0000; } +.invoice-status-good { + background: #e3ffc9 url(images/stream_status.png) no-repeat 10px 10px; + border-color: #54b300; + padding: 2px 12px 4px 32px; + margin: 2px 1px 10px 0px; + color: #330; +} + /** This form is the separate one on the Billing Account Details page (BillingClient.php) */ #clientdetails_form { width: 500px; From f441f2d385a9a22d2d08727739c5c69549499733 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Tue, 20 Oct 2015 16:57:31 -0400 Subject: [PATCH 8/9] SAAS-1136: Disk usage div overflows if your disk usage is over 100% --- airtime_mvc/application/layouts/scripts/layout.phtml | 2 +- airtime_mvc/application/views/scripts/plupload/index.phtml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/airtime_mvc/application/layouts/scripts/layout.phtml b/airtime_mvc/application/layouts/scripts/layout.phtml index bc9b14951..ec2c64088 100644 --- a/airtime_mvc/application/layouts/scripts/layout.phtml +++ b/airtime_mvc/application/layouts/scripts/layout.phtml @@ -99,7 +99,7 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
-
;">
+
;">