Merge branch 'saas-dev' into soundcloud

This commit is contained in:
Duncan Sommerville 2015-06-09 14:03:03 -04:00
commit f031d13867
13 changed files with 119 additions and 56 deletions

View file

@ -42,3 +42,33 @@ class Application_Common_HTTPHelper
return $stationUrl; return $stationUrl;
} }
} }
class ZendActionHttpException extends Exception {
private $_action;
/**
* @param Zend_Controller_Action $action
* @param int $statusCode
* @param string $message
* @param int $code
* @param Exception $previous
*
* @throws Zend_Controller_Response_Exception
*/
public function __construct(Zend_Controller_Action $action, $statusCode, $message,
$code = 0, Exception $previous = null) {
$this->_action = $action;
Logging::info("Error in action " . $action->getRequest()->getActionName()
. " with status code $statusCode: $message");
$action->getResponse()
->setHttpResponseCode($statusCode)
->appendBody($message);
parent::__construct($message, $code, $previous);
}
public function getAction() {
return $this->_action;
}
}

View file

@ -73,6 +73,7 @@ class ApiController extends Zend_Controller_Action
print _('You are not allowed to access this resource.'); print _('You are not allowed to access this resource.');
exit; exit;
} }
return true;
} }
public function versionAction() public function versionAction()
@ -157,7 +158,7 @@ class ApiController extends Zend_Controller_Action
*/ */
public function liveInfoAction() public function liveInfoAction()
{ {
if (Application_Model_Preference::GetAllow3rdPartyApi()) { if (Application_Model_Preference::GetAllow3rdPartyApi() || $this->checkAuth()) {
// disable the view and the layout // disable the view and the layout
$this->view->layout()->disableLayout(); $this->view->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true); $this->_helper->viewRenderer->setNoRender(true);
@ -252,7 +253,7 @@ class ApiController extends Zend_Controller_Action
*/ */
public function liveInfoV2Action() public function liveInfoV2Action()
{ {
if (Application_Model_Preference::GetAllow3rdPartyApi()) { if (Application_Model_Preference::GetAllow3rdPartyApi() || $this->checkAuth()) {
// disable the view and the layout // disable the view and the layout
$this->view->layout()->disableLayout(); $this->view->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true); $this->_helper->viewRenderer->setNoRender(true);
@ -360,7 +361,7 @@ class ApiController extends Zend_Controller_Action
public function weekInfoAction() public function weekInfoAction()
{ {
if (Application_Model_Preference::GetAllow3rdPartyApi()) { if (Application_Model_Preference::GetAllow3rdPartyApi() || $this->checkAuth()) {
// disable the view and the layout // disable the view and the layout
$this->view->layout()->disableLayout(); $this->view->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true); $this->_helper->viewRenderer->setNoRender(true);
@ -434,8 +435,8 @@ class ApiController extends Zend_Controller_Action
* Go through a given array and sanitize any potentially exploitable fields * Go through a given array and sanitize any potentially exploitable fields
* by passing them through htmlspecialchars * by passing them through htmlspecialchars
* *
* @param unknown $arr the array to sanitize * @param array $arr the array to sanitize
* @param unknown $keys indexes of values to be sanitized * @param array $keys indexes of values to be sanitized
*/ */
private function convertSpecialChars(&$arr, $keys) private function convertSpecialChars(&$arr, $keys)
{ {
@ -455,7 +456,7 @@ class ApiController extends Zend_Controller_Action
* Recursively find image_path keys in the various $result subarrays, * Recursively find image_path keys in the various $result subarrays,
* and convert them to point to the show-logo endpoint * and convert them to point to the show-logo endpoint
* *
* @param unknown $arr the array to search * @param array $arr the array to search
*/ */
private function findAndConvertPaths(&$arr) private function findAndConvertPaths(&$arr)
{ {
@ -479,25 +480,37 @@ class ApiController extends Zend_Controller_Action
*/ */
public function showLogoAction() public function showLogoAction()
{ {
if (Application_Model_Preference::GetAllow3rdPartyApi()) { // Disable the view and the layout
$request = $this->getRequest();
$showId = $request->getParam('id');
// if no id is passed, just die - redirects to a 404
if (!$showId || $showId === '') {
return;
}
$show = CcShowQuery::create()->findPk($showId);
// disable the view and the layout
$this->view->layout()->disableLayout(); $this->view->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true); $this->_helper->viewRenderer->setNoRender(true);
if (Application_Model_Preference::GetAllow3rdPartyApi() || $this->checkAuth()) {
$request = $this->getRequest();
$showId = $request->getParam('id');
if (empty($showId)) {
throw new ZendActionHttpException($this, 400, "ERROR: No ID was given.");
}
$show = CcShowQuery::create()->findPk($showId);
if (empty($show)) {
throw new ZendActionHttpException($this, 400, "ERROR: No show with ID $showId exists.");
}
$path = $show->getDbImagePath(); $path = $show->getDbImagePath();
$mime_type = mime_content_type($path); $mime_type = mime_content_type($path);
if (empty($path)) {
throw new ZendActionHttpException($this, 400, "ERROR: Show does not have an associated image.");
}
try {
// Sometimes end users may be looking at stale data - if an image is removed
// but has been cached in a client's browser this will throw an exception
Application_Common_FileIO::smartReadFile($path, filesize($path), $mime_type); Application_Common_FileIO::smartReadFile($path, filesize($path), $mime_type);
} catch(FileNotFoundException $e) {
throw new ZendActionHttpException($this, 404, "ERROR: No image found at $path");
} catch(Exception $e) {
throw new ZendActionHttpException($this, 500, "ERROR: " . $e->getMessage());
}
} else { } else {
header('HTTP/1.0 401 Unauthorized'); header('HTTP/1.0 401 Unauthorized');
print _('You are not allowed to access this resource. '); print _('You are not allowed to access this resource. ');
@ -510,7 +523,7 @@ class ApiController extends Zend_Controller_Action
*/ */
public function stationMetadataAction() public function stationMetadataAction()
{ {
if (Application_Model_Preference::GetAllow3rdPartyApi()) { if (Application_Model_Preference::GetAllow3rdPartyApi() || $this->checkAuth()) {
// disable the view and the layout // disable the view and the layout
$this->view->layout()->disableLayout(); $this->view->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true); $this->_helper->viewRenderer->setNoRender(true);
@ -549,7 +562,7 @@ class ApiController extends Zend_Controller_Action
*/ */
public function stationLogoAction() public function stationLogoAction()
{ {
if (Application_Model_Preference::GetAllow3rdPartyApi()) { if (Application_Model_Preference::GetAllow3rdPartyApi() || $this->checkAuth()) {
// disable the view and the layout // disable the view and the layout
$this->view->layout()->disableLayout(); $this->view->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true); $this->_helper->viewRenderer->setNoRender(true);

View file

@ -10,7 +10,7 @@ class IndexController extends Zend_Controller_Action
public function indexAction() public function indexAction()
{ {
$this->_forward('index', 'showbuilder'); $this->_redirect('Showbuilder');
} }
public function mainAction() public function mainAction()

View file

@ -67,6 +67,7 @@ class PreferenceController extends Zend_Controller_Action
Application_Model_Preference::setDefaultSoundCloudSharingType($values["SoundCloudSharing"]); Application_Model_Preference::setDefaultSoundCloudSharingType($values["SoundCloudSharing"]);
$this->view->statusMsg = "<div class='success'>". _("Preferences updated.")."</div>"; $this->view->statusMsg = "<div class='success'>". _("Preferences updated.")."</div>";
$form = new Application_Form_Preferences();
$this->view->form = $form; $this->view->form = $form;
//$this->_helper->json->sendJson(array("valid"=>"true", "html"=>$this->view->render('preference/index.phtml'))); //$this->_helper->json->sendJson(array("valid"=>"true", "html"=>$this->view->render('preference/index.phtml')));
} else { } else {

View file

@ -144,14 +144,27 @@ class UserController extends Zend_Controller_Action
// We don't allow 6 x's as a password. // We don't allow 6 x's as a password.
// The reason is because we use that as a password placeholder // The reason is because we use that as a password placeholder
// on the client side. // on the client side.
if (($formData['cu_password'] != "xxxxxx") && if (array_key_exists('cu_password', $formData) && ($formData['cu_password'] != "xxxxxx") &&
(!empty($formData['cu_password']))) { (!empty($formData['cu_password']))) {
$user->setPassword($formData['cu_password']); $user->setPassword($formData['cu_password']);
} }
if (array_key_exists('cu_email', $formData)) {
$user->setEmail($formData['cu_email']); $user->setEmail($formData['cu_email']);
}
if (array_key_exists('cu_cell_phone', $formData)) {
$user->setCellPhone($formData['cu_cell_phone']); $user->setCellPhone($formData['cu_cell_phone']);
}
if (array_key_exists('cu_skype', $formData)) {
$user->setSkype($formData['cu_skype']); $user->setSkype($formData['cu_skype']);
}
if (array_key_exists('cu_jabber', $formData)) {
$user->setJabber($formData['cu_jabber']); $user->setJabber($formData['cu_jabber']);
}
$user->save(); $user->save();
Application_Model_Preference::SetUserLocale($formData['cu_locale']); Application_Model_Preference::SetUserLocale($formData['cu_locale']);

View file

@ -239,7 +239,7 @@ class WHMCS_Auth_Adapter implements Zend_Auth_Adapter_Interface {
} }
else else
{ {
if ($product["status"] === "Active") { if (($product["status"] === "Active") || ($product["status"] === "Suspended")) {
$airtimeProduct = $product; $airtimeProduct = $product;
$subdomain = ''; $subdomain = '';

View file

@ -18,7 +18,6 @@ class Application_Form_TuneInPreferences extends Zend_Form_SubForm
$enableTunein->addDecorator('Label', array('class' => 'enable-tunein')); $enableTunein->addDecorator('Label', array('class' => 'enable-tunein'));
$enableTunein->setLabel(_("Push metadata to your station on TuneIn?")); $enableTunein->setLabel(_("Push metadata to your station on TuneIn?"));
$enableTunein->setValue(Application_Model_Preference::getTuneinEnabled()); $enableTunein->setValue(Application_Model_Preference::getTuneinEnabled());
$enableTunein->setAttrib("class", "block-display");
$this->addElement($enableTunein); $this->addElement($enableTunein);
$tuneinStationId = new Zend_Form_Element_Text("tunein_station_id"); $tuneinStationId = new Zend_Form_Element_Text("tunein_station_id");
@ -76,7 +75,6 @@ class Application_Form_TuneInPreferences extends Zend_Form_SubForm
Logging::error("Failed to reach TuneIn: ". curl_errno($ch)." - ". curl_error($ch) . " - " . curl_getinfo($ch, CURLINFO_EFFECTIVE_URL)); Logging::error("Failed to reach TuneIn: ". curl_errno($ch)." - ". curl_error($ch) . " - " . curl_getinfo($ch, CURLINFO_EFFECTIVE_URL));
if (curl_error($ch) == "The requested URL returned error: 403 Forbidden") { if (curl_error($ch) == "The requested URL returned error: 403 Forbidden") {
$this->getElement("enable_tunein")->setErrors(array(_("Invalid TuneIn Settings. Please ensure your TuneIn settings are correct and try again."))); $this->getElement("enable_tunein")->setErrors(array(_("Invalid TuneIn Settings. Please ensure your TuneIn settings are correct and try again.")));
$valid = false; $valid = false;
} }
} }
@ -85,6 +83,7 @@ class Application_Form_TuneInPreferences extends Zend_Form_SubForm
if ($valid) { if ($valid) {
$xmlObj = new SimpleXMLElement($xmlData); $xmlObj = new SimpleXMLElement($xmlData);
if (!$xmlObj || $xmlObj->head->status != "200") { if (!$xmlObj || $xmlObj->head->status != "200") {
$this->getElement("enable_tunein")->setErrors(array(_("Invalid TuneIn Settings. Please ensure your TuneIn settings are correct and try again.")));
$valid = false; $valid = false;
} else if ($xmlObj->head->status == "200") { } else if ($xmlObj->head->status == "200") {
Application_Model_Preference::setLastTuneinMetadataUpdate(time()); Application_Model_Preference::setLastTuneinMetadataUpdate(time());

View file

@ -199,7 +199,6 @@ SQL;
$currentMedia["ends"] = $currentMedia["show_ends"]; $currentMedia["ends"] = $currentMedia["show_ends"];
} }
$currentMediaScheduleId = $currentMedia["id"];
$currentMediaFileId = $currentMedia["file_id"]; $currentMediaFileId = $currentMedia["file_id"];
$currentMediaStreamId = $currentMedia["stream_id"]; $currentMediaStreamId = $currentMedia["stream_id"];
if (isset($currentMediaFileId)) { if (isset($currentMediaFileId)) {
@ -234,9 +233,10 @@ SQL;
); );
$previousMedia = CcScheduleQuery::create() $previousMedia = CcScheduleQuery::create()
->filterByDbId($currentMediaScheduleId-1) ->filterByDbStarts($currentMedia["starts"], Criteria::LESS_THAN)
->filterByDbId($currentMedia["id"], Criteria::NOT_EQUAL)
->filterByDbPlayoutStatus(0, Criteria::GREATER_THAN) ->filterByDbPlayoutStatus(0, Criteria::GREATER_THAN)
->orderByDbStarts() ->orderByDbStarts(Criteria::DESC)
->findOne(); ->findOne();
if (isset($previousMedia)) { if (isset($previousMedia)) {
$previousMediaFileId = $previousMedia->getDbFileId(); $previousMediaFileId = $previousMedia->getDbFileId();
@ -253,10 +253,6 @@ SQL;
$previousWebstream = CcWebstreamQuery::create() $previousWebstream = CcWebstreamQuery::create()
->filterByDbId($previousMediaStreamId) ->filterByDbId($previousMediaStreamId)
->findOne(); ->findOne();
/*$previousWebstreamMetadata = CcWebstreamMetadataQuery::create()
->filterByDbInstanceId($previousMedia->getDbInstanceId())
->orderByDbStartTime(Criteria::DESC)
->findOne();*/
$previousMediaName = $previousWebstream->getDbName(); $previousMediaName = $previousWebstream->getDbName();
} else { } else {
$previousMediaType = null; $previousMediaType = null;
@ -270,8 +266,9 @@ SQL;
} }
$nextMedia = CcScheduleQuery::create() $nextMedia = CcScheduleQuery::create()
->filterByDbId($currentMediaScheduleId+1) ->filterByDbStarts($currentMedia["starts"], Criteria::GREATER_THAN)
->orderByDbStarts() ->filterByDbId($currentMedia["id"], Criteria::NOT_EQUAL)
->orderByDbStarts(Criteria::ASC)
->findOne(); ->findOne();
if (isset($nextMedia)) { if (isset($nextMedia)) {
$nextMediaFileId = $nextMedia->getDbFileId(); $nextMediaFileId = $nextMedia->getDbFileId();
@ -287,10 +284,6 @@ SQL;
$nextWebstream = CcWebstreamQuery::create() $nextWebstream = CcWebstreamQuery::create()
->filterByDbId($nextMediaStreamId) ->filterByDbId($nextMediaStreamId)
->findOne(); ->findOne();
/*$nextWebstreamMetadata = CcWebstreamMetadataQuery::create()
->filterByDbInstanceId($nextMedia->getDbInstanceId())
->orderByDbStartTime(Criteria::DESC)
->findOne();*/
$nextMediaName = $nextWebstream->getDbName(); $nextMediaName = $nextWebstream->getDbName();
} else { } else {
$nextMediaType = null; $nextMediaType = null;

View file

@ -1163,7 +1163,7 @@ ORDER BY
AND si.starts < :timeNow::timestamp THEN 1 AND si.starts < :timeNow::timestamp THEN 1
WHEN si.starts > :timeNow::timestamp THEN 2 WHEN si.starts > :timeNow::timestamp THEN 2
ELSE 3 ELSE 3
END END, si.starts
LIMIT :lim LIMIT :lim
SQL; SQL;

View file

@ -56,12 +56,13 @@ class Rest_ShowImageController extends Zend_Rest_Controller {
$this->getResponse() $this->getResponse()
->setHttpResponseCode(500) ->setHttpResponseCode(500)
->appendBody("Error processing image: " . $e->getMessage()); ->appendBody("Error processing image: " . $e->getMessage());
return;
} }
$show = CcShowQuery::create()->findPk($showId); $show = CcShowQuery::create()->findPk($showId);
try {
$con = Propel::getConnection(); $con = Propel::getConnection();
try {
$con->beginTransaction(); $con->beginTransaction();
$show->setDbImagePath($path); $show->setDbImagePath($path);
@ -103,8 +104,8 @@ class Rest_ShowImageController extends Zend_Rest_Controller {
$show = CcShowQuery::create()->findPk($showId); $show = CcShowQuery::create()->findPk($showId);
try {
$con = Propel::getConnection(); $con = Propel::getConnection();
try {
$con->beginTransaction(); $con->beginTransaction();
$show->setDbImagePath(null); $show->setDbImagePath(null);
@ -268,7 +269,7 @@ class Rest_ShowImageController extends Zend_Rest_Controller {
private static function delTree($dir) { private static function delTree($dir) {
$files = array_diff(scandir($dir), array('.', '..')); $files = array_diff(scandir($dir), array('.', '..'));
foreach ($files as $file) { foreach ($files as $file) {
(is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file"); (is_dir("$dir/$file")) ? self::delTree("$dir/$file") : unlink("$dir/$file");
} }
return rmdir($dir); return rmdir($dir);
} }
@ -279,7 +280,7 @@ class Rest_ShowImageController extends Zend_Rest_Controller {
* provided, otherwise returns the id * provided, otherwise returns the id
*/ */
private function getShowId() { private function getShowId() {
if (!$id = $this->_getParam('id', false)) { if (!($id = $this->_getParam('id', false))) {
$resp = $this->getResponse(); $resp = $this->getResponse();
$resp->setHttpResponseCode(400); $resp->setHttpResponseCode(400);
$resp->appendBody("ERROR: No show ID specified."); $resp->appendBody("ERROR: No show ID specified.");

View file

@ -14,6 +14,8 @@ def generate_liquidsoap_config(ss):
for key, value in data.iteritems(): for key, value in data.iteritems():
try: try:
if not "port" in key and not "bitrate" in key: # Stupid hack
raise ValueError()
str_buffer = "%s = %s\n" % (key, int(value)) str_buffer = "%s = %s\n" % (key, int(value))
except ValueError: except ValueError:
try: # Is it a boolean? try: # Is it a boolean?

View file

@ -477,6 +477,7 @@ class PypoFetch(Thread):
loops = 1 loops = 1
while True: while True:
self.logger.info("Loop #%s", loops) self.logger.info("Loop #%s", loops)
manual_fetch_needed = False
try: try:
""" """
our simple_queue.get() requires a timeout, in which case we our simple_queue.get() requires a timeout, in which case we
@ -492,17 +493,26 @@ class PypoFetch(Thread):
Currently we are checking every POLL_INTERVAL seconds Currently we are checking every POLL_INTERVAL seconds
""" """
message = self.fetch_queue.get(block=True, timeout=self.listener_timeout) message = self.fetch_queue.get(block=True, timeout=self.listener_timeout)
manual_fetch_needed = False
self.handle_message(message) self.handle_message(message)
except Empty, e: except Empty as e:
self.logger.info("Queue timeout. Fetching schedule manually") self.logger.info("Queue timeout. Fetching schedule manually")
self.persistent_manual_schedule_fetch(max_attempts=5) manual_fetch_needed = True
except Exception, e: except Exception as e:
top = traceback.format_exc() top = traceback.format_exc()
self.logger.error('Exception: %s', e) self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", top) self.logger.error("traceback: %s", top)
try:
if manual_fetch_needed:
self.persistent_manual_schedule_fetch(max_attempts=5)
except Exception as e:
top = traceback.format_exc()
self.logger.error('Failed to manually fetch the schedule.')
self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", top)
loops += 1 loops += 1
def run(self): def run(self):
@ -510,3 +520,4 @@ class PypoFetch(Thread):
Entry point of the thread Entry point of the thread
""" """
self.main() self.main()
self.logger.info('PypoFetch thread exiting')

View file

@ -35,6 +35,7 @@ class PypoFile(Thread):
self.media_queue = schedule_queue self.media_queue = schedule_queue
self.media = None self.media = None
self.cache_dir = os.path.join(config["cache_dir"], "scheduler") self.cache_dir = os.path.join(config["cache_dir"], "scheduler")
self._config = self.read_config_file(CONFIG_PATH)
def copy_file(self, media_item): def copy_file(self, media_item):
""" """
@ -65,11 +66,9 @@ class PypoFile(Thread):
if do_copy: if do_copy:
self.logger.debug("copying from %s to local cache %s" % (src, dst)) self.logger.debug("copying from %s to local cache %s" % (src, dst))
try: try:
config = self.read_config_file(CONFIG_PATH)
CONFIG_SECTION = "general" CONFIG_SECTION = "general"
username = config.get(CONFIG_SECTION, 'api_key') username = self._config.get(CONFIG_SECTION, 'api_key')
host = self._config.get(CONFIG_SECTION, 'base_url')
host = config.get(CONFIG_SECTION, 'base_url')
url = "http://%s/rest/media/%s/download" % (host, media_item["id"]) url = "http://%s/rest/media/%s/download" % (host, media_item["id"])
with open(dst, "wb") as handle: with open(dst, "wb") as handle:
response = requests.get(url, auth=requests.auth.HTTPBasicAuth(username, ''), stream=True, verify=False) response = requests.get(url, auth=requests.auth.HTTPBasicAuth(username, ''), stream=True, verify=False)
@ -210,3 +209,4 @@ class PypoFile(Thread):
Entry point of the thread Entry point of the thread
""" """
self.main() self.main()