@@ -24,7 +33,9 @@
diff --git a/airtime_mvc/application/models/Block.php b/airtime_mvc/application/models/Block.php
index babef06a5..8ea3593b1 100644
--- a/airtime_mvc/application/models/Block.php
+++ b/airtime_mvc/application/models/Block.php
@@ -1038,7 +1038,7 @@ SQL;
{
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
- $isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
+ $isAdminOrPM = $user->isUserType(array(UTYPE_SUPERADMIN, UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
// get only the files from the blocks
// we are about to delete
diff --git a/airtime_mvc/application/models/Cache.php b/airtime_mvc/application/models/Cache.php
index af4e6417b..dbbcb9d58 100644
--- a/airtime_mvc/application/models/Cache.php
+++ b/airtime_mvc/application/models/Cache.php
@@ -2,30 +2,44 @@
class Cache
{
- private function createCacheKey($key, $isUserValue, $userId = null) {
-
- $CC_CONFIG = Config::getConfig();
- $a = $CC_CONFIG["apiKey"][0];
-
- if ($isUserValue) {
- $cacheKey = "{$key}{$userId}{$a}";
- }
- else {
- $cacheKey = "{$key}{$a}";
- }
+
+ private function createCacheKey($key, $isUserValue, $userId = null) {
+
+ $CC_CONFIG = Config::getConfig();
+ $a = $CC_CONFIG["apiKey"][0];
+
+ if ($isUserValue) {
+ $cacheKey = "{$key}{$userId}{$a}";
+ }
+ else {
+ $cacheKey = "{$key}{$a}";
+ }
- return $cacheKey;
- }
-
- public function store($key, $value, $isUserValue, $userId = null) {
-
- //$cacheKey = self::createCacheKey($key, $userId);
- return false; ///apc_store($cacheKey, $value);
- }
-
- public function fetch($key, $isUserValue, $userId = null) {
-
- //$cacheKey = self::createCacheKey($key, $isUserValue, $userId);
- return false; //apc_fetch($cacheKey);
+ return $cacheKey;
+ }
+
+ public function store($key, $value, $isUserValue, $userId = null) {
+
+ $cacheKey = self::createCacheKey($key, $userId);
+ //XXX: Disabling APC on SaaS because it turns out we have multiple webservers
+ // running, which means we have to use a distributed data cache like memcached.
+ //return apc_store($cacheKey, $value);
+ return false;
+ }
+
+ public function fetch($key, $isUserValue, $userId = null) {
+
+ $cacheKey = self::createCacheKey($key, $isUserValue, $userId);
+ //XXX: Disabling APC on SaaS because it turns out we have multiple webservers
+ // running, which means we have to use a distributed data cache like memcached.
+ //return apc_fetch($cacheKey);
+ return false;
+ }
+
+ public static function clear()
+ {
+ // Disabled on SaaS
+ // apc_clear_cache('user');
+ // apc_clear_cache();
}
}
diff --git a/airtime_mvc/application/models/Locale.php b/airtime_mvc/application/models/Locale.php
index 726302a82..2008591a8 100644
--- a/airtime_mvc/application/models/Locale.php
+++ b/airtime_mvc/application/models/Locale.php
@@ -38,10 +38,16 @@ class Application_Model_Locale
} else {
$lang = $locale.'.'.$codeset;
}
- putenv("LC_ALL=$lang");
- putenv("LANG=$lang");
- $res = setlocale(LC_MESSAGES, $lang);
-
+ //putenv("LC_ALL=$lang");
+ //putenv("LANG=$lang");
+ //Setting the LANGUAGE env var supposedly lets gettext search inside our locale dir even if the system
+ //doesn't have the particular locale that we want installed. This doesn't actually seem to work though. -- Albert
+ putenv("LANGUAGE=$locale");
+ if (setlocale(LC_MESSAGES, $lang) === false)
+ {
+ Logging::warn("Your system does not have the " . $lang . " locale installed. Run: sudo locale-gen " . $lang);
+ }
+
$domain = 'airtime';
bindtextdomain($domain, '../locale');
textdomain($domain);
diff --git a/airtime_mvc/application/models/Playlist.php b/airtime_mvc/application/models/Playlist.php
index 7a7573d2a..90baaf621 100644
--- a/airtime_mvc/application/models/Playlist.php
+++ b/airtime_mvc/application/models/Playlist.php
@@ -987,7 +987,7 @@ SQL;
{
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
- $isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
+ $isAdminOrPM = $user->isUserType(array(UTYPE_SUPERADMIN, UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
// get only the files from the playlists
// we are about to delete
diff --git a/airtime_mvc/application/models/Preference.php b/airtime_mvc/application/models/Preference.php
index cfed23b1c..e5d459652 100644
--- a/airtime_mvc/application/models/Preference.php
+++ b/airtime_mvc/application/models/Preference.php
@@ -6,7 +6,7 @@ class Application_Model_Preference
{
private static function getUserId()
- {
+ {
//pass in true so the check is made with the autoloader
//we need this check because saas calls this function from outside Zend
if (!class_exists("Zend_Auth", true) || !Zend_Auth::getInstance()->hasIdentity()) {
@@ -733,11 +733,7 @@ class Application_Model_Preference
$outputArray['NUM_OF_PAST_SHOWS'] = Application_Model_ShowInstance::GetShowInstanceCount(gmdate("Y-m-d H:i:s"));
$outputArray['UNIQUE_ID'] = self::GetUniqueId();
$outputArray['SAAS'] = self::GetPlanLevel();
- if ($outputArray['SAAS'] != 'disabled') {
- $outputArray['TRIAL_END_DATE'] = self::GetTrialEndingDate();
- } else {
- $outputArray['TRIAL_END_DATE'] = NULL;
- }
+ $outputArray['TRIAL_END_DATE'] = self::GetTrialEndingDate();
$outputArray['INSTALL_METHOD'] = self::GetInstallMethod();
$outputArray['NUM_OF_STREAMS'] = self::GetNumOfStreams();
$outputArray['STREAM_INFO'] = Application_Model_StreamSetting::getStreamInfoForDataCollection();
@@ -763,9 +759,7 @@ class Application_Model_Preference
$outputString .= $key." : FALSE\n";
}
} elseif ($key == "SAAS") {
- if (strcmp($out, 'disabled')!=0) {
- $outputString .= $key.' : '.$out."\n";
- }
+ $outputString .= $key.' : '.$out."\n";
} else {
$outputString .= $key.' : '.$out."\n";
}
@@ -1023,6 +1017,24 @@ class Application_Model_Preference
Logging::warn("Attempting to set client_id to invalid value: $id");
}
}
+
+ public static function GetLiveChatEnabled()
+ {
+ $liveChat = self::getValue("live_chat", false);
+ if (is_null($liveChat) || $liveChat == "" || $liveChat == "1") { //Defaults to on
+ return true;
+ }
+ return false;
+ }
+
+ public static function SetLiveChatEnabled($toggle)
+ {
+ if (is_bool($toggle)) {
+ self::setValue("live_chat", $toggle ? "1" : "0");
+ } else {
+ Logging::warn("Attempting to set live_chat to invalid value: $toggle. Must be a bool.");
+ }
+ }
/* User specific preferences start */
diff --git a/airtime_mvc/application/models/RabbitMq.php b/airtime_mvc/application/models/RabbitMq.php
index 15ad912e0..f5e7fb0c3 100644
--- a/airtime_mvc/application/models/RabbitMq.php
+++ b/airtime_mvc/application/models/RabbitMq.php
@@ -82,8 +82,24 @@ class Application_Model_RabbitMq
public static function SendMessageToAnalyzer($tmpFilePath, $importedStorageDirectory, $originalFilename,
$callbackUrl, $apiKey)
{
- $exchange = 'airtime-uploads';
+ //Hack for Airtime Pro. The RabbitMQ settings for communicating with airtime_analyzer are global
+ //and shared between all instances on Airtime Pro.
+ $CC_CONFIG = Config::getConfig();
+ $devEnv = "production"; //Default
+ if (array_key_exists("dev_env", $CC_CONFIG)) {
+ $devEnv = $CC_CONFIG["dev_env"];
+ }
+ $config = parse_ini_file("/etc/airtime-saas/rabbitmq-analyzer-" . $devEnv . ".ini", true);
+ $conn = new AMQPConnection($config["rabbitmq"]["host"],
+ $config["rabbitmq"]["port"],
+ $config["rabbitmq"]["user"],
+ $config["rabbitmq"]["password"],
+ $config["rabbitmq"]["vhost"]);
+ $exchange = 'airtime-uploads';
+ $exchangeType = 'topic';
+ $queue = 'airtime-uploads';
+ $autoDeleteExchange = false;
$data['tmp_file_path'] = $tmpFilePath;
$data['import_directory'] = $importedStorageDirectory;
$data['original_filename'] = $originalFilename;
@@ -91,6 +107,68 @@ class Application_Model_RabbitMq
$data['api_key'] = $apiKey;
$jsonData = json_encode($data);
- self::sendMessage($exchange, 'topic', false, $jsonData, 'airtime-uploads');
+ //self::sendMessage($exchange, 'topic', false, $jsonData, 'airtime-uploads');
+
+ if (!isset($conn)) {
+ throw new Exception("Cannot connect to RabbitMQ server");
+ }
+
+ $channel = $conn->channel();
+ $channel->access_request($config["rabbitmq"]["vhost"], false, false,
+ true, true);
+
+ //I'm pretty sure we DON'T want to autodelete ANY exchanges but I'm keeping the code
+ //the way it is just so I don't accidentally break anything when I add the Analyzer code in. -- Albert, March 13, 2014
+ $channel->exchange_declare($exchange, $exchangeType, false, true, $autoDeleteExchange);
+
+ $msg = new AMQPMessage($jsonData, array('content_type' => 'text/plain'));
+
+ $channel->basic_publish($msg, $exchange);
+ $channel->close();
+ $conn->close();
+
}
+
+
+ public static function SendMessageToHaproxyConfigDaemon($md){
+ $config = parse_ini_file("/etc/airtime-saas/rabbitmq.ini", true);
+ $conn = new AMQPConnection($config["rabbitmq"]["host"],
+ $config["rabbitmq"]["port"],
+ $config["rabbitmq"]["user"],
+ $config["rabbitmq"]["password"],
+ $config["rabbitmq"]["vhost"]);
+
+ $exchange = $config["rabbitmq"]["queue"];
+ $queue = $config["rabbitmq"]["queue"];
+
+ $ch = $conn->channel();
+
+
+ /*
+ name: $queue
+ passive: false
+ durable: true // the queue will survive server restarts
+ exclusive: false // the queue can be accessed in other channels
+ auto_delete: false //the queue won't be deleted once the channel is closed.
+ */
+ $ch->queue_declare($queue, false, true, false, false);
+
+ /*
+ name: $exchange
+ type: direct
+ passive: false
+ durable: true // the exchange will survive server restarts
+ auto_delete: false //the exchange won't be deleted once the channel is closed.
+ */
+
+ $ch->exchange_declare($exchange, 'direct', false, true, false);
+ $ch->queue_bind($queue, $exchange);
+
+ $data = json_encode($md).PHP_EOL;
+ $msg = new AMQPMessage($data, array('content_type' => 'application/json'));
+
+ $ch->basic_publish($msg, $exchange);
+ $ch->close();
+ $conn->close();
+ }
}
diff --git a/airtime_mvc/application/models/Schedule.php b/airtime_mvc/application/models/Schedule.php
index 4a1bcb8b0..ecbbe887d 100644
--- a/airtime_mvc/application/models/Schedule.php
+++ b/airtime_mvc/application/models/Schedule.php
@@ -62,7 +62,14 @@ SQL;
*/
public static function GetPlayOrderRange($utcTimeEnd = null, $showsToRetrieve = 5)
{
- // Everything in this function must be done in UTC. You will get a swift kick in the pants if you mess that up.
+ //Everything in this function must be done in UTC. You will get a swift kick in the pants if you mess that up.
+
+ if (!is_int($p_prev) || !is_int($p_next)) {
+ //must enter integers to specify ranges
+ Logging::info("Invalid range parameters: $p_prev or $p_next");
+
+ return array();
+ }
// when timeEnd is unspecified, return to the default behaviour - set a range of 48 hours from current time
if (!$utcTimeEnd) {
@@ -873,7 +880,7 @@ SQL;
$CC_CONFIG = Config::getConfig();
$utcTimeZone = new DateTimeZone('UTC');
-
+
/* if $p_fromDateTime and $p_toDateTime function parameters are null,
then set range * from "now" to "now + 24 hours". */
if (is_null($p_fromDateTime)) {
@@ -931,6 +938,7 @@ SQL;
//row is from "file"
$media_id = $item['file_id'];
$storedFile = Application_Model_StoredFile::RecallById($media_id);
+
$file = $storedFile->getPropelOrm();
$uri = $file->getAbsoluteFilePath();
@@ -939,13 +947,13 @@ SQL;
$object_name = $storedFile->getResourceId();
}
self::createFileScheduleEvent($data, $item, $media_id, $uri, $object_name);
- }
+ }
elseif (!is_null($item['stream_id'])) {
//row is type "webstream"
$media_id = $item['stream_id'];
$uri = $item['url'];
self::createStreamScheduleEvent($data, $item, $media_id, $uri);
- }
+ }
else {
throw new Exception("Unknown schedule type: ".print_r($item, true));
}
@@ -1021,7 +1029,6 @@ SQL;
$needScheduleUntil->add(new DateInterval("P1D"));
}
Application_Model_Show::createAndFillShowInstancesPastPopulatedUntilDate($needScheduleUntil);
-
list($range_start, $range_end) = self::getRangeStartAndEnd($p_fromDateTime, $p_toDateTime);
$data = array();
diff --git a/airtime_mvc/application/models/Show.php b/airtime_mvc/application/models/Show.php
index b0507dba6..8973fcd6a 100644
--- a/airtime_mvc/application/models/Show.php
+++ b/airtime_mvc/application/models/Show.php
@@ -877,11 +877,14 @@ SELECT si1.starts AS starts,
si1.instance_id AS record_id,
si1.show_id AS show_id,
show.name AS name,
+ show.description AS description,
show.color AS color,
show.background_color AS background_color,
+ show.image_path AS image_path,
show.linked AS linked,
si1.file_id AS file_id,
si1.id AS instance_id,
+ si1.description AS instance_description,
si1.created AS created,
si1.last_scheduled AS last_scheduled,
si1.time_filled AS time_filled,
@@ -1076,10 +1079,13 @@ SQL;
SELECT si.starts AS start_timestamp,
si.ends AS end_timestamp,
s.name,
+ s.description,
s.id,
si.id AS instance_id,
+ si.description AS instance_description,
si.record,
s.url,
+ s.image_path,
starts,
ends
FROM cc_show_instances si
@@ -1211,7 +1217,7 @@ SQL;
$CC_CONFIG = Config::getConfig();
$con = Propel::getConnection();
-
+
//TODO, returning starts + ends twice (once with an alias). Unify this after the 2.0 release. --Martin
$sql = <<
$rows[$i]['id'],
"instance_id" => $rows[$i]['instance_id'],
"instance_description" => $rows[$i]['instance_description'],
- "name" => $rows[$i]['name'],
+ "name" => $rows[$i]['name'],
"description" => $rows[$i]['description'],
- "url" => $rows[$i]['url'],
+ "url" => $rows[$i]['url'],
"start_timestamp" => $rows[$i]['start_timestamp'],
"end_timestamp" => $rows[$i]['end_timestamp'],
"starts" => $rows[$i]['starts'],
"ends" => $rows[$i]['ends'],
"record" => $rows[$i]['record'],
"image_path" => $rows[$i]['image_path'],
- "type" => "show");
+ "type" => "show");
break;
}
}
@@ -1369,11 +1375,14 @@ SQL;
SELECT si.starts AS start_timestamp,
si.ends AS end_timestamp,
s.name,
+ s.description,
s.id,
si.id AS instance_id,
+ si.description AS instance_description,
si.record,
s.url,
- starts,
+ s.image_path,
+ starts,
ends
FROM cc_show_instances si
LEFT JOIN cc_show s
diff --git a/airtime_mvc/application/models/ShowInstance.php b/airtime_mvc/application/models/ShowInstance.php
index f5fbf1aa7..c3b423af6 100644
--- a/airtime_mvc/application/models/ShowInstance.php
+++ b/airtime_mvc/application/models/ShowInstance.php
@@ -69,6 +69,13 @@ SQL;
return $show->getDbName();
}
+
+ public function getImagePath()
+ {
+ $show = CcShowQuery::create()->findPK($this->getShowId());
+
+ return $show->getDbImagePath();
+ }
public function getGenre()
{
diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php
index 60e5bd6fe..85e268ba7 100644
--- a/airtime_mvc/application/models/StoredFile.php
+++ b/airtime_mvc/application/models/StoredFile.php
@@ -375,7 +375,7 @@ SQL;
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
- $isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
+ $isAdminOrPM = $user->isUserType(array(UTYPE_SUPERADMIN, UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
if (!$isAdminOrPM && $this->getFileOwnerId() != $user->getId()) {
throw new FileNoPermissionException();
}
@@ -972,6 +972,8 @@ SQL;
// Did all the checks for real, now trying to copy
$audio_stor = Application_Common_OsPath::join($stor, "organize",
$originalFilename);
+ Logging::info($originalFilename);
+ Logging::info($audio_stor);
$user = Application_Model_User::getCurrentUser();
if (is_null($user)) {
$uid = Application_Model_User::getFirstAdminId();
diff --git a/airtime_mvc/application/models/Systemstatus.php b/airtime_mvc/application/models/Systemstatus.php
index 05e69bc34..1b07099c9 100644
--- a/airtime_mvc/application/models/Systemstatus.php
+++ b/airtime_mvc/application/models/Systemstatus.php
@@ -215,23 +215,25 @@ class Application_Model_Systemstatus
{
$partitions = array();
- /* First lets get all the watched directories. Then we can group them
- * into the same partitions by comparing the partition sizes. */
- $musicDirs = Application_Model_MusicDir::getWatchedDirs();
- $musicDirs[] = Application_Model_MusicDir::getStorDir();
+ //connect to DB and find how much total space user has allocated.
+ $totalSpace = Application_Model_Preference::GetDiskQuota();
- foreach ($musicDirs as $md) {
- $totalSpace = disk_total_space($md->getDirectory());
-
- if (!isset($partitions[$totalSpace])) {
- $partitions[$totalSpace] = new StdClass;
- $partitions[$totalSpace]->totalSpace = $totalSpace;
- $partitions[$totalSpace]->totalFreeSpace = disk_free_space($md->getDirectory());
-
- }
-
- $partitions[$totalSpace]->dirs[] = $md->getDirectory();
+ $usedSpace = Application_Model_Preference::getDiskUsage();
+ if (empty($usedSpace)) {
+ $usedSpace = 0;
}
+ /* $path = $_SERVER['AIRTIME_BASE']."etc/airtime/num_bytes.ini";
+ $arr = parse_ini_file($path);
+
+ $usedSpace = 0;
+ if ($arr !== false) {
+ $usedSpace = $arr['num_bytes'];
+ } */
+
+ $partitions[$totalSpace] = new stdClass();
+ $partitions[$totalSpace]->totalSpace = $totalSpace;
+ $partitions[$totalSpace]->totalFreeSpace = $totalSpace - $usedSpace;
+ //Logging::info($partitions[$totalSpace]->totalFreeSpace);
return array_values($partitions);
}
@@ -241,7 +243,7 @@ class Application_Model_Systemstatus
$diskInfo = self::GetDiskInfo();
$diskInfo = $diskInfo[0];
$diskUsage = $diskInfo->totalSpace - $diskInfo->totalFreeSpace;
- if ($diskUsage >= $diskInfo->totalSpace) {
+ if ($diskUsage > 0 && $diskUsage >= $diskInfo->totalSpace) {
return true;
}
diff --git a/airtime_mvc/application/models/User.php b/airtime_mvc/application/models/User.php
index 8a1008577..2001a97f8 100644
--- a/airtime_mvc/application/models/User.php
+++ b/airtime_mvc/application/models/User.php
@@ -49,14 +49,20 @@ class Application_Model_User
{
return $this->isUserType(UTYPE_ADMIN);
}
-
+
+ public function isSuperAdmin()
+ {
+ return $this->isUserType(UTYPE_SUPERADMIN);
+ }
+
public function canSchedule($p_showId)
{
$type = $this->getType();
$result = false;
- if ($type === UTYPE_ADMIN ||
- $type === UTYPE_PROGRAM_MANAGER ||
+ if ($this->isAdmin() ||
+ $this->isSuperAdmin() ||
+ $this->isPM() ||
self::isHostOfShow($p_showId)) {
$result = true;
}
@@ -239,10 +245,14 @@ class Application_Model_User
}
public static function getFirstAdmin() {
- $admins = Application_Model_User::getUsersOfType('A');
- if (count($admins) > 0) { // found admin => pick first one
- return $admins[0];
+ $superAdmins = Application_Model_User::getUsersOfType('S');
+ if (count($superAdmins) > 0) { // found superadmin => pick first one
+ return $superAdmins[0];
} else {
+ $admins = Application_Model_User::getUsersOfType('A');
+ if (count($admins) > 0) { // found admin => pick first one
+ return $admins[0];
+ }
Logging::warn("Warning. no admins found in database");
return null;
}
@@ -324,16 +334,26 @@ class Application_Model_User
$res = Application_Model_Datatables::findEntries($con, $displayColumns, $fromTable, $datatables);
// mark record which is for the current user
- foreach ($res['aaData'] as &$record) {
+ foreach($res['aaData'] as $key => &$record){
if ($record['login'] == $username) {
$record['delete'] = "self";
} else {
$record['delete'] = "";
}
+
+ if($record['login'] == 'sourcefabric_admin'){
+ //arrays in PHP are basically associative arrays that can be iterated in order.
+ //Deleting an earlier element does not change the keys of elements that come after it. --MK
+ unset($res['aaData'][$key]);
+ $res['iTotalDisplayRecords']--;
+ $res['iTotalRecords']--;
+ }
$record = array_map('htmlspecialchars', $record);
}
+ $res['aaData'] = array_values($res['aaData']);
+
return $res;
}
diff --git a/airtime_mvc/application/models/airtime/CcSubjs.php b/airtime_mvc/application/models/airtime/CcSubjs.php
index 78fd56d9e..7fe6289f1 100644
--- a/airtime_mvc/application/models/airtime/CcSubjs.php
+++ b/airtime_mvc/application/models/airtime/CcSubjs.php
@@ -15,7 +15,7 @@ class CcSubjs extends BaseCcSubjs {
public function isAdminOrPM()
{
- return $this->type === UTYPE_ADMIN || $this->type === UTYPE_PROGRAM_MANAGER;
+ return $this->type === UTYPE_SUPERADMIN || $this->type === UTYPE_ADMIN || $this->type === UTYPE_PROGRAM_MANAGER;
}
public function isHostOfShow($showId)
diff --git a/airtime_mvc/application/modules/rest/Bootstrap.php b/airtime_mvc/application/modules/rest/Bootstrap.php
index f04c61ef3..058ebbdf1 100644
--- a/airtime_mvc/application/modules/rest/Bootstrap.php
+++ b/airtime_mvc/application/modules/rest/Bootstrap.php
@@ -8,9 +8,10 @@ class Rest_Bootstrap extends Zend_Application_Module_Bootstrap
$router = $front->getRouter();
$restRoute = new Zend_Rest_Route($front, array(), array(
- 'rest'=> array('media')));
+ 'rest'=> array('media', 'show')));
assert($router->addRoute('rest', $restRoute));
+ /** MediaController Routes **/
$downloadRoute = new Zend_Controller_Router_Route(
'rest/media/:id/download',
array(
@@ -46,5 +47,32 @@ class Rest_Bootstrap extends Zend_Application_Module_Bootstrap
)
);
$router->addRoute('delete-success', $deleteSuccessRoute);
+
+ /** ShowController Routes **/
+ $uploadImageRoute = new Zend_Controller_Router_Route(
+ 'rest/show/:id/upload-image',
+ array(
+ 'controller' => 'show',
+ 'action' => 'upload-image',
+ 'module' => 'rest'
+ ),
+ array(
+ 'id' => '\d+'
+ )
+ );
+ $router->addRoute('upload-image', $uploadImageRoute);
+
+ $deleteImageRoute = new Zend_Controller_Router_Route(
+ 'rest/show/:id/delete-image',
+ array(
+ 'controller' => 'show',
+ 'action' => 'delete-image',
+ 'module' => 'rest'
+ ),
+ array(
+ 'id' => '\d+'
+ )
+ );
+ $router->addRoute('delete-image', $deleteImageRoute);
}
}
diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php
index 10ff5723a..e9a77ba5d 100644
--- a/airtime_mvc/application/modules/rest/controllers/MediaController.php
+++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php
@@ -24,6 +24,10 @@ class Rest_MediaController extends Zend_Rest_Controller
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('delete-success', 'json');
+
+ // Remove reliance on .phtml files to render requests
+ $this->_helper->viewRenderer->setNoRender(true);
+
}
public function indexAction()
@@ -96,16 +100,9 @@ class Rest_MediaController extends Zend_Rest_Controller
exec("rm -rf $path");
//update disk_usage value in cc_pref
- $musicDir = CcMusicDirsQuery::create()
- ->filterByType('stor')
- ->filterByExists(true)
- ->findOne();
- $storPath = $musicDir->getDirectory();
-
- $freeSpace = disk_free_space($storPath);
- $totalSpace = disk_total_space($storPath);
-
- Application_Model_Preference::setDiskUsage($totalSpace - $freeSpace);
+ $storDir = isset($_SERVER['AIRTIME_BASE']) ? $_SERVER['AIRTIME_BASE']."srv/airtime/stor" : "/srv/airtime/stor";
+ $diskUsage = shell_exec("du -sb $storDir | awk '{print $1}'");
+ Application_Model_Preference::setDiskUsage($diskUsage);
$this->getResponse()
->setHttpResponseCode(200)
@@ -137,6 +134,15 @@ class Rest_MediaController extends Zend_Rest_Controller
public function postAction()
{
+ /* If the user presents a valid API key, we don't check CSRF tokens.
+ CSRF tokens are only used for session based authentication.
+ */
+ if(!$this->verifyAPIKey()){
+ if(!$this->verifyCSRFToken($this->_getParam('csrf_token'))){
+ return;
+ }
+ }
+
if (!$this->verifyAuth(true, true))
{
return;
@@ -316,6 +322,18 @@ class Rest_MediaController extends Zend_Rest_Controller
return $id;
}
+ private function verifyCSRFToken($token){
+ $current_namespace = new Zend_Session_Namespace('csrf_namespace');
+ $observed_csrf_token = $token;
+ $expected_csrf_token = $current_namespace->authtoken;
+
+ if($observed_csrf_token == $expected_csrf_token){
+ return true;
+ }else{
+ return false;
+ }
+ }
+
private function verifyAuth($checkApiKey, $checkSession)
{
// Session takes precedence over API key for now:
@@ -342,18 +360,6 @@ class Rest_MediaController extends Zend_Rest_Controller
return false;
}
- private function verifyCSRFToken($token){
- $current_namespace = new Zend_Session_Namespace('csrf_namespace');
- $observed_csrf_token = $token;
- $expected_csrf_token = $current_namespace->authtoken;
-
- if($observed_csrf_token == $expected_csrf_token){
- return true;
- }else{
- return false;
- }
- }
-
private function verifyAPIKey()
{
//The API key is passed in via HTTP "basic authentication":
@@ -461,7 +467,7 @@ class Rest_MediaController extends Zend_Rest_Controller
$tempFilePath = $_FILES['file']['tmp_name'];
$tempFileName = basename($tempFilePath);
-
+
//Only accept files with a file extension that we support.
$fileExtension = pathinfo($originalFilename, PATHINFO_EXTENSION);
if (!in_array(strtolower($fileExtension), explode(",", "ogg,mp3,oga,flac,wav,m4a,mp4,opus")))
@@ -469,7 +475,7 @@ class Rest_MediaController extends Zend_Rest_Controller
@unlink($tempFilePath);
throw new Exception("Bad file extension.");
}
-
+
//TODO: Remove uploadFileAction from ApiController.php **IMPORTANT** - It's used by the recorder daemon...
$storDir = Application_Model_MusicDir::getStorDir();
@@ -491,7 +497,7 @@ class Rest_MediaController extends Zend_Rest_Controller
$importedStorageDirectory, basename($originalFilename),
$callbackUrl, $apiKey);
}
-
+
private function getOwnerId()
{
try {
diff --git a/airtime_mvc/application/modules/rest/controllers/ShowController.php b/airtime_mvc/application/modules/rest/controllers/ShowController.php
new file mode 100644
index 000000000..5293b07cb
--- /dev/null
+++ b/airtime_mvc/application/modules/rest/controllers/ShowController.php
@@ -0,0 +1,294 @@
+view->layout()->disableLayout();
+ // Remove reliance on .phtml files to render requests
+ $this->_helper->viewRenderer->setNoRender(true);
+ }
+
+ /*
+ * TODO shift functionality from add-show.js and ScheduleController to here,
+ * and have a referenceable Show object
+ */
+
+ public function indexAction() {
+ Logging::info("INDEX action received");
+ }
+
+ public function getAction() {
+ Logging::info("GET action received");
+ }
+
+ public function putAction() {
+ Logging::info("PUT action received");
+ }
+
+ public function postAction() {
+ Logging::info("POST action received");
+ }
+
+ public function deleteAction() {
+ Logging::info("DELETE action received");
+ }
+
+ public function uploadImageAction()
+ {
+ if (!RestAuth::verifyAuth(true, true))
+ {
+ $this->getResponse()
+ ->setHttpResponseCode(401)
+ ->appendBody("Authentication failed");
+ return;
+ }
+
+ $showId = $this->getShowId();
+
+ if (!$showId) {
+ $this->getResponse()
+ ->setHttpResponseCode(400)
+ ->appendBody("No show ID provided");
+ return;
+ }
+
+ try {
+ $path = $this->processUploadedImage($showId, $_FILES["file"]["tmp_name"], $_FILES["file"]["name"]);
+ } catch (Exception $e) {
+ $this->getResponse()
+ ->setHttpResponseCode(500)
+ ->appendBody("Error processing image: " . $e->getMessage());
+ }
+
+ $show = CcShowQuery::create()->findPk($showId);
+
+ try {
+ $con = Propel::getConnection();
+ $con->beginTransaction();
+
+ $show->setDbImagePath($path);
+ $show->save();
+
+ $con->commit();
+ } catch (Exception $e) {
+ $con->rollBack();
+ $this->getResponse()
+ ->setHttpResponseCode(500)
+ ->appendBody("Couldn't add show image: " . $e->getMessage());
+ }
+
+ $this->getResponse()
+ ->setHttpResponseCode(201);
+ }
+
+ public function deleteImageAction()
+ {
+ if (!RestAuth::verifyAuth(true, true))
+ {
+ $this->getResponse()
+ ->setHttpResponseCode(401)
+ ->appendBody("Authentication failed");
+ return;
+ }
+
+ $showId = $this->getShowId();
+
+ if (!$showId) {
+ $this->getResponse()
+ ->setHttpResponseCode(400)
+ ->appendBody("No show ID provided");
+ return;
+ }
+
+ try {
+ Rest_ShowController::deleteShowImagesFromStor($showId);
+ } catch (Exception $e) {
+ $this->getResponse()
+ ->setHttpResponseCode(500)
+ ->appendBody("Error processing image: " . $e->getMessage());
+ }
+
+ $show = CcShowQuery::create()->findPk($showId);
+
+ try {
+ $con = Propel::getConnection();
+ $con->beginTransaction();
+
+ $show->setDbImagePath(null);
+ $show->save();
+
+ $con->commit();
+ } catch (Exception $e) {
+ $con->rollBack();
+ $this->getResponse()
+ ->setHttpResponseCode(500)
+ ->appendBody("Couldn't remove show image: " . $e->getMessage());
+ }
+
+ $this->getResponse()
+ ->setHttpResponseCode(201);
+ }
+
+ /**
+ * Verify and process an uploaded image file, copying it into
+ * .../stor/imported/:owner-id/show-images/:show-id/ to differentiate between
+ * individual users and shows
+ *
+ * @param unknown $tempFilePath
+ * - temporary filepath assigned to the upload generally of the form /tmp/:tmp_name
+ * @param unknown
+ * - $originalFilename the file name at time of upload
+ * @throws Exception
+ * - when a file with an unsupported file extension is uploaded or an
+ * error occurs in copyFileToStor
+ */
+ private function processUploadedImage($showId, $tempFilePath, $originalFilename)
+ {
+ $ownerId = RestAuth::getOwnerId();
+
+ $CC_CONFIG = Config::getConfig();
+ $apiKey = $CC_CONFIG["apiKey"][0];
+
+ $tempFileName = basename($tempFilePath);
+
+ //Only accept files with a file extension that we support.
+ $fileExtension = $this->getFileExtension($originalFilename, $tempFilePath);
+
+ if (!in_array(strtolower($fileExtension), explode(",", "jpg,png,gif,jpeg")))
+ {
+ @unlink($tempFilePath);
+ throw new Exception("Bad file extension.");
+ }
+
+ $storDir = Application_Model_MusicDir::getStorDir();
+ $importedStorageDirectory = $storDir->getDirectory() . "imported/" . $ownerId . "/show-images/" . $showId;
+
+ try {
+ $importedStorageDirectory = $this->copyFileToStor($tempFilePath, $importedStorageDirectory, $fileExtension);
+ } catch (Exception $e) {
+ @unlink($tempFilePath);
+ throw new Exception("Failed to copy file: " . $e->getMessage());
+ }
+
+ return $importedStorageDirectory;
+ }
+
+ private function getFileExtension($originalFileName, $tempFilePath)
+ {
+ // Don't trust the extension - get the MIME-type instead
+ $fileInfo = finfo_open();
+ $mime = finfo_file($fileInfo, $tempFilePath, FILEINFO_MIME_TYPE);
+ return $this->getExtensionFromMime($mime);
+ }
+
+ private function getExtensionFromMime($mime)
+ {
+ $extensions = array(
+ 'image/jpeg' => 'jpg',
+ 'image/png' => 'png',
+ 'image/gif' => 'gif'
+ );
+
+ return $extensions[$mime];
+ }
+
+ private function copyFileToStor($tempFilePath, $importedStorageDirectory, $fileExtension)
+ {
+ $image_file = $tempFilePath;
+
+ // check if show image dir exists and if not, create one
+ if (!file_exists($importedStorageDirectory)) {
+ if (!mkdir($importedStorageDirectory, 0777, true)) {
+ throw new Exception("Failed to create storage directory.");
+ }
+ }
+
+ if (chmod($image_file, 0644) === false) {
+ Logging::info("Warning: couldn't change permissions of $image_file to 0644");
+ }
+
+ $newFileName = substr($tempFilePath, strrpos($tempFilePath, "/")).".".$fileExtension;
+
+ // Did all the checks for real, now trying to copy
+ $image_stor = Application_Common_OsPath::join($importedStorageDirectory, $newFileName);
+ Logging::info("Adding image: " . $image_stor);
+ Logging::info("copyFileToStor: moving file $image_file to $image_stor");
+
+ if (@rename($image_file, $image_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($image_file); //remove the file after failed rename
+
+ 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 "
+ ."directory does not have correct write permissions.");
+ }
+
+ return $image_stor;
+ }
+
+ // Should this be an endpoint instead?
+ public static function deleteShowImagesFromStor($showId) {
+ $ownerId = RestAuth::getOwnerId();
+
+ $storDir = Application_Model_MusicDir::getStorDir();
+ $importedStorageDirectory = $storDir->getDirectory() . "imported/" . $ownerId . "/show-images/" . $showId;
+
+ Logging::info("Deleting images from " . $importedStorageDirectory);
+
+ // to be safe in case image uploading functionality is extended later
+ if (!file_exists($importedStorageDirectory)) {
+ Logging::info("No uploaded images for show with id " . $showId);
+ return true;
+ } else {
+ return Rest_ShowController::delTree($importedStorageDirectory);
+ }
+ }
+
+ // from a note @ http://php.net/manual/en/function.rmdir.php
+ private static function delTree($dir) {
+ $files = array_diff(scandir($dir), array('.','..'));
+ foreach ($files as $file) {
+ (is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file");
+ }
+ return rmdir($dir);
+ }
+
+ /**
+ * Fetch the id parameter from the request.
+ *
+ * @return boolean|unknown false if the show id wasn't
+ * provided, otherwise returns the id
+ */
+ private function getShowId()
+ {
+ if (!$id = $this->_getParam('id', false)) {
+ $resp = $this->getResponse();
+ $resp->setHttpResponseCode(400);
+ $resp->appendBody("ERROR: No show ID specified.");
+ return false;
+ }
+ return $id;
+ }
+
+}
\ No newline at end of file
diff --git a/airtime_mvc/application/modules/rest/helpers/RestAuth.php b/airtime_mvc/application/modules/rest/helpers/RestAuth.php
new file mode 100644
index 000000000..6024ad582
--- /dev/null
+++ b/airtime_mvc/application/modules/rest/helpers/RestAuth.php
@@ -0,0 +1,64 @@
+getResponse();
+ $resp->setHttpResponseCode(401);
+ $resp->appendBody("ERROR: Incorrect API key.");
+
+ return false;
+ }
+
+ public static function getOwnerId()
+ {
+ try {
+ if (RestAuth::verifySession()) {
+ $service_user = new Application_Service_UserService();
+ return $service_user->getCurrentUser()->getDbId();
+ } else {
+ $defaultOwner = CcSubjsQuery::create()
+ ->filterByDbType('A')
+ ->orderByDbId()
+ ->findOne();
+ if (!$defaultOwner) {
+ // what to do if there is no admin user?
+ // should we handle this case?
+ return null;
+ }
+ return $defaultOwner->getDbId();
+ }
+ } catch(Exception $e) {
+ Logging::info($e->getMessage());
+ }
+ }
+
+ private static function verifySession()
+ {
+ $auth = Zend_Auth::getInstance();
+ return $auth->hasIdentity();
+ }
+
+ private static function verifyAPIKey()
+ {
+ //The API key is passed in via HTTP "basic authentication":
+ // http://en.wikipedia.org/wiki/Basic_access_authentication
+ $CC_CONFIG = Config::getConfig();
+
+ //Decode the API key that was passed to us in the HTTP request.
+ $authHeader = $this->getRequest()->getHeader("Authorization");
+ $encodedRequestApiKey = substr($authHeader, strlen("Basic "));
+ $encodedStoredApiKey = base64_encode($CC_CONFIG["apiKey"][0] . ":");
+
+ return ($encodedRequestApiKey === $encodedStoredApiKey);
+ }
+
+}
\ No newline at end of file
diff --git a/airtime_mvc/application/modules/rest/views/scripts/media/delete.phtml b/airtime_mvc/application/modules/rest/views/scripts/media/delete.phtml
deleted file mode 100644
index e69de29bb..000000000
diff --git a/airtime_mvc/application/modules/rest/views/scripts/media/download.phtml b/airtime_mvc/application/modules/rest/views/scripts/media/download.phtml
deleted file mode 100644
index e69de29bb..000000000
diff --git a/airtime_mvc/application/modules/rest/views/scripts/media/get.phtml b/airtime_mvc/application/modules/rest/views/scripts/media/get.phtml
deleted file mode 100644
index e69de29bb..000000000
diff --git a/airtime_mvc/application/modules/rest/views/scripts/media/index.phtml b/airtime_mvc/application/modules/rest/views/scripts/media/index.phtml
deleted file mode 100644
index e69de29bb..000000000
diff --git a/airtime_mvc/application/modules/rest/views/scripts/media/post.phtml b/airtime_mvc/application/modules/rest/views/scripts/media/post.phtml
deleted file mode 100644
index e69de29bb..000000000
diff --git a/airtime_mvc/application/modules/rest/views/scripts/media/put.phtml b/airtime_mvc/application/modules/rest/views/scripts/media/put.phtml
deleted file mode 100644
index e69de29bb..000000000
diff --git a/airtime_mvc/application/services/ShowFormService.php b/airtime_mvc/application/services/ShowFormService.php
index 882d22c44..6f8c0a9b7 100644
--- a/airtime_mvc/application/services/ShowFormService.php
+++ b/airtime_mvc/application/services/ShowFormService.php
@@ -9,6 +9,7 @@ class Application_Service_ShowFormService
if (!is_null($showId)) {
$this->ccShow = CcShowQuery::create()->findPk($showId);
}
+
$this->instanceId = $instanceId;
}
@@ -91,6 +92,7 @@ class Application_Service_ShowFormService
* when the user edits a repeating instance
*/
$forms["what"]->makeReadonly();
+ $forms["what"]->enableInstanceDesc();
$forms["repeats"]->disable();
$forms["who"]->disable();
$forms["style"]->disable();
@@ -123,14 +125,17 @@ class Application_Service_ShowFormService
private function populateFormWhat($form)
{
- $form->populate(
+ $ccShowInstance = CcShowInstancesQuery::create()->findPk($this->instanceId);
+
+ $form->populate(
array(
'add_show_instance_id' => $this->instanceId,
'add_show_id' => $this->ccShow->getDbId(),
'add_show_name' => $this->ccShow->getDbName(),
'add_show_url' => $this->ccShow->getDbUrl(),
'add_show_genre' => $this->ccShow->getDbGenre(),
- 'add_show_description' => $this->ccShow->getDbDescription()));
+ 'add_show_description' => $this->ccShow->getDbDescription(),
+ 'add_show_instance_description' => $ccShowInstance->getDbDescription()));
}
private function populateFormWhen($form)
@@ -284,10 +289,33 @@ class Application_Service_ShowFormService
private function populateFormStyle($form)
{
+ $src = $this->ccShow->getDbImagePath() ?
+ $this->imagePathToDataUri($this->ccShow->getDbImagePath()) : '';
+
$form->populate(
array(
'add_show_background_color' => $this->ccShow->getDbBackgroundColor(),
- 'add_show_color' => $this->ccShow->getDbColor()));
+ 'add_show_color' => $this->ccShow->getDbColor(),
+ 'add_show_logo_current' => $src));
+ }
+
+ /**
+ * Convert a static image from disk to a base64 data URI
+ *
+ * @param unknown $path
+ * - the path to the image on the disk
+ * @return string
+ * - the data URI representation of the image
+ */
+ private function imagePathToDataUri($path) {
+ ob_start();
+ header("Content-type: image/*");
+ readfile($path);
+ $imageData = base64_encode(ob_get_contents());
+ ob_end_clean();
+ // return the data URI - data:{mime};base64,{data}
+ return ($imageData === null || $imageData === '') ?
+ '' : 'data: '.mime_content_type($path).';base64,'.$imageData;
}
private function populateFormLive($form)
@@ -440,7 +468,19 @@ class Application_Service_ShowFormService
$live = $forms["live"]->isValid($formData);
$record = $forms["record"]->isValid($formData);
$who = $forms["who"]->isValid($formData);
+
+ /*
+ * hack to prevent validating the file upload field since it
+ * isn't passed into $data
+ */
+ $upload = $forms["style"]->getElement("add_show_logo");
+ $forms["style"]->removeElement("add_show_logo");
+
$style = $forms["style"]->isValid($formData);
+
+ // re-add the upload element
+ $forms["style"]->addElement($upload);
+
$when = $forms["when"]->isWhenFormValid($formData, $validateStartDate,
$originalStartDate, $editShow, $instanceId);
@@ -478,14 +518,10 @@ class Application_Service_ShowFormService
}
}
- if ($what && $live && $record && $who && $style && $when &&
- $repeats && $absRebroadcast && $rebroadcast) {
- return true;
- } else {
- return false;
- }
+ return ($what && $live && $record && $who && $style && $when &&
+ $repeats && $absRebroadcast && $rebroadcast);
}
-
+
public function calculateDuration($start, $end, $timezone)
{
try {
diff --git a/airtime_mvc/application/services/ShowService.php b/airtime_mvc/application/services/ShowService.php
index 5a2f22e63..362f3a327 100644
--- a/airtime_mvc/application/services/ShowService.php
+++ b/airtime_mvc/application/services/ShowService.php
@@ -141,9 +141,15 @@ class Application_Service_ShowService
$ccShowInstance->updateDbTimeFilled($con);
$ccShowInstance->updateScheduleStatus($con);
+ $ccShowInstance
+ ->setDbDescription($showData['add_show_instance_description'])
+ ->save();
//delete the edited instance from the repeating sequence
- $ccShowInstanceOrig->setDbModifiedInstance(true)->save();
+ $ccShowInstanceOrig
+ ->setDbModifiedInstance(true)
+ ->setDbDescription($showData['add_show_instance_description'])
+ ->save();
$con->commit();
Application_Model_RabbitMq::PushSchedule();
@@ -176,7 +182,7 @@ class Application_Service_ShowService
$this->localShowStartHour = $origStartTime[0];
$this->localShowStartMin = $origStartTime[1];
}
-
+
public function addUpdateShow($showData)
{
$service_user = new Application_Service_UserService();
@@ -199,6 +205,15 @@ class Application_Service_ShowService
if ($this->isUpdate) {
+ $showId = $this->ccShow->getDbId();
+
+ // Only delete the previous logo if a new one is being uploaded
+ if (array_key_exists("add_show_logo_name", $showData) && $showData["add_show_logo_name"] !== "") {
+ if (!Rest_ShowController::deleteShowImagesFromStor($showId)) {
+ throw new Exception("Error deleting show images");
+ }
+ }
+
if (!$this->ccShow->getCcShowDayss()->isEmpty()) {
$this->storeOrigLocalShowInfo();
}
@@ -225,7 +240,7 @@ class Application_Service_ShowService
//update ccShowHosts
$this->setCcShowHosts($showData);
-
+
//create new ccShowInstances
$this->delegateInstanceCreation($daysAdded);
@@ -251,6 +266,9 @@ class Application_Service_ShowService
Logging::info("EXCEPTION: Show ".$action." failed.");
Logging::info($e->getMessage());
}
+
+ // Added to pass along to the RESTful ShowController
+ return $this->ccShow->getDbId();
}
/**
@@ -584,17 +602,17 @@ SQL;
$currentShowEndDateTime = $this->getRepeatingEndDate();
if ($endDateTime && $currentShowEndDateTime != $endDateTime) {
- $endDate = clone $endDateTime;
- $endDate->setTimezone(new DateTimeZone("UTC"));
-
+ $endDate = clone $endDateTime;
+ $endDate->setTimezone(new DateTimeZone("UTC"));
+
//show's "No End" option was toggled
//or the end date comes earlier
if (is_null($currentShowEndDateTime) || ($endDateTime < $currentShowEndDateTime)) {
//"No End" option was unchecked so we need to delete the
//repeat instances that are scheduled after the new end date
//OR
- //end date was pushed back so we have to delete any
- //instances of this show scheduled after the new end date
+ //end date was pushed back so we have to delete any
+ //instances of this show scheduled after the new end date
$this->deleteInstancesFromDate($endDate->format("Y-m-d"), $showId);
}
}
@@ -641,10 +659,10 @@ SQL;
$date = null;
if ($query !== false && isset($query["last_show"])) {
- $date = new DateTime(
- $query["last_show"],
- new DateTimeZone($query["timezone"])
- );
+ $date = new DateTime(
+ $query["last_show"],
+ new DateTimeZone($query["timezone"])
+ );
}
return $date;
@@ -732,6 +750,7 @@ SQL;
$con = Propel::getConnection();
$con->beginTransaction();
try {
+
if (!$currentUser->isAdminOrPM()) {
throw new Exception("Permission denied");
}
@@ -742,7 +761,12 @@ SQL;
throw new Exception("Could not find show instance");
}
+ // Delete show images
$showId = $ccShowInstance->getDbShowId();
+ if (!Rest_ShowController::deleteShowImagesFromStor($showId)) {
+ throw new Exception("Error deleting show images");
+ }
+
if ($singleInstance) {
$ccShowInstances = array($ccShowInstance);
} else {
@@ -772,7 +796,7 @@ SQL;
return false;
}
}
-
+
public function deleteShowInstances($ccShowInstances, $showId)
{
foreach ($ccShowInstances as $ccShowInstance) {
@@ -931,23 +955,23 @@ SQL;
*/
private function calculateEndDate($showData)
{
- //if no end return null
+ //if no end return null
if ($showData['add_show_no_end']) {
$endDate = null;
}
//if the show is repeating & ends, then return the end date
elseif ($showData['add_show_repeats']) {
$endDate = new DateTime(
- $showData['add_show_end_date'],
- new DateTimeZone($showData["add_show_timezone"])
+ $showData['add_show_end_date'],
+ new DateTimeZone($showData["add_show_timezone"])
);
$endDate->add(new DateInterval("P1D"));
}
//the show doesn't repeat, so add one day to the start date.
else {
$endDate = new DateTime(
- $showData['add_show_start_date'],
- new DateTimeZone($showData["add_show_timezone"])
+ $showData['add_show_start_date'],
+ new DateTimeZone($showData["add_show_timezone"])
);
$endDate->add(new DateInterval("P1D"));
}
@@ -1117,11 +1141,11 @@ SQL;
$repeatInterval, $populateUntil);
if ($last_show) {
- $utcLastShowDateTime = new DateTime($last_show, new DateTimeZone($timezone));
- $utcLastShowDateTime->setTimezone(new DateTimeZone("UTC"));
+ $utcLastShowDateTime = new DateTime($last_show, new DateTimeZone($timezone));
+ $utcLastShowDateTime->setTimezone(new DateTimeZone("UTC"));
}
else {
- $utcLastShowDateTime = null;
+ $utcLastShowDateTime = null;
}
$previousDate = clone $start;
@@ -1217,12 +1241,12 @@ SQL;
$this->repeatType = $showDay->getDbRepeatType();
- if ($last_show) {
- $utcLastShowDateTime = new DateTime($last_show, new DateTimeZone($timezone));
- $utcLastShowDateTime->setTimezone(new DateTimeZone("UTC"));
+ if ($last_show) {
+ $utcLastShowDateTime = new DateTime($last_show, new DateTimeZone($timezone));
+ $utcLastShowDateTime->setTimezone(new DateTimeZone("UTC"));
}
else {
- $utcLastShowDateTime = null;
+ $utcLastShowDateTime = null;
}
while ($start->getTimestamp() < $end->getTimestamp()) {
@@ -1545,8 +1569,8 @@ SQL;
$showId = $this->ccShow->getDbId();
$startDateTime = new DateTime(
- $showData['add_show_start_date']." ".$showData['add_show_start_time'],
- new DateTimeZone($showData['add_show_timezone'])
+ $showData['add_show_start_date']." ".$showData['add_show_start_time'],
+ new DateTimeZone($showData['add_show_timezone'])
);
$endDateTime = $this->calculateEndDate($showData);
@@ -1554,7 +1578,7 @@ SQL;
$endDate = $endDateTime->format("Y-m-d");
}
else {
- $endDate = null;
+ $endDate = null;
}
//Our calculated start DOW must be used for non repeating since a day has not been selected.
@@ -1731,7 +1755,7 @@ SQL;
}
}
}
-
+
/**
*
* Gets the date and time shows (particularly repeating shows)
diff --git a/airtime_mvc/application/upgrade/Upgrades.php b/airtime_mvc/application/upgrade/Upgrades.php
new file mode 100644
index 000000000..428d9e2b0
--- /dev/null
+++ b/airtime_mvc/application/upgrade/Upgrades.php
@@ -0,0 +1,254 @@
+filterByKeystr('system_version')
+ ->findOne();
+ $airtime_version = $pref->getValStr();
+ return $airtime_version;
+ }
+
+ /**
+ * This function checks to see if this class can perform an upgrade of your version of Airtime
+ * @return boolean True if we can upgrade your version of Airtime.
+ */
+ public function checkIfUpgradeSupported()
+ {
+ if (!in_array(AirtimeUpgrader::getCurrentVersion(), $this->getSupportedVersions())) {
+ return false;
+ }
+ return true;
+ }
+
+ protected function toggleMaintenanceScreen($toggle)
+ {
+ if ($toggle)
+ {
+ //Disable Airtime UI
+ //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
+ $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
+ if ($this->maintenanceFile) {
+ unlink($this->maintenanceFile);
+ }
+ }
+ }
+
+ /** Implement this for each new version of Airtime */
+ abstract public function upgrade();
+}
+
+class AirtimeUpgrader253 extends AirtimeUpgrader
+{
+ protected function getSupportedVersions()
+ {
+ return array('2.5.1', '2.5.2');
+ }
+ public function getNewVersion()
+ {
+ return '2.5.3';
+ }
+
+ public function upgrade($dir = __DIR__)
+ {
+ Cache::clear();
+ assert($this->checkIfUpgradeSupported());
+
+ $con = Propel::getConnection();
+ $con->beginTransaction();
+ try {
+
+ $this->toggleMaintenanceScreen(true);
+ Cache::clear();
+
+ //Begin upgrade
+
+ //Update disk_usage value in cc_pref
+ $musicDir = CcMusicDirsQuery::create()
+ ->filterByType('stor')
+ ->filterByExists(true)
+ ->findOne();
+ $storPath = $musicDir->getDirectory();
+
+ //Update disk_usage value in cc_pref
+ $storDir = isset($_SERVER['AIRTIME_BASE']) ? $_SERVER['AIRTIME_BASE']."srv/airtime/stor" : "/srv/airtime/stor";
+ $diskUsage = shell_exec("du -sb $storDir | awk '{print $1}'");
+
+ Application_Model_Preference::setDiskUsage($diskUsage);
+
+ //clear out the cache
+ Cache::clear();
+
+ $con->commit();
+
+ //update system_version in cc_pref and change some columns in cc_files
+ $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 \"will create implicit index\"");
+
+ Application_Model_Preference::SetAirtimeVersion($this->getNewVersion());
+ //clear out the cache
+ Cache::clear();
+
+ $this->toggleMaintenanceScreen(false);
+
+ } catch (Exception $e) {
+ $con->rollback();
+ $this->toggleMaintenanceScreen(false);
+ }
+ }
+}
+
+class AirtimeUpgrader254 extends AirtimeUpgrader
+{
+ protected function getSupportedVersions()
+ {
+ return array('2.5.3');
+ }
+ public function getNewVersion()
+ {
+ return '2.5.4';
+ }
+
+ public function upgrade()
+ {
+ Cache::clear();
+
+ assert($this->checkIfUpgradeSupported());
+
+ $newVersion = $this->getNewVersion();
+
+ $con = Propel::getConnection();
+ //$con->beginTransaction();
+ try {
+ $this->toggleMaintenanceScreen(true);
+ Cache::clear();
+
+ //Begin upgrade
+
+ //First, ensure there are no superadmins already.
+ $numberOfSuperAdmins = CcSubjsQuery::create()
+ ->filterByDbType(UTYPE_SUPERADMIN)
+ ->filterByDbLogin("sourcefabric_admin", Criteria::NOT_EQUAL) //Ignore sourcefabric_admin users
+ ->count();
+
+ //Only create a super admin if there isn't one already.
+ if ($numberOfSuperAdmins == 0)
+ {
+ //Find the "admin" user and promote them to superadmin.
+ $adminUser = CcSubjsQuery::create()
+ ->filterByDbLogin('admin')
+ ->findOne();
+ if (!$adminUser)
+ {
+ //TODO: Otherwise get the user with the lowest ID that is of type administrator:
+ //
+ $adminUser = CcSubjsQuery::create()
+ ->filterByDbType(UTYPE_ADMIN)
+ ->orderByDbId(Criteria::ASC)
+ ->findOne();
+
+ if (!$adminUser) {
+ throw new Exception("Failed to find any users of type 'admin' ('A').");
+ }
+ }
+
+ $adminUser = new Application_Model_User($adminUser->getDbId());
+ $adminUser->setType(UTYPE_SUPERADMIN);
+ $adminUser->save();
+ Logging::info($_SERVER['HTTP_HOST'] . ': ' . $newVersion . " Upgrade: Promoted user " . $adminUser->getLogin() . " to be a Super Admin.");
+
+ //Also try to promote the sourcefabric_admin user
+ $sofabAdminUser = CcSubjsQuery::create()
+ ->filterByDbLogin('sourcefabric_admin')
+ ->findOne();
+ if ($sofabAdminUser) {
+ $sofabAdminUser = new Application_Model_User($sofabAdminUser->getDbId());
+ $sofabAdminUser->setType(UTYPE_SUPERADMIN);
+ $sofabAdminUser->save();
+ Logging::info($_SERVER['HTTP_HOST'] . ': ' . $newVersion . " Upgrade: Promoted user " . $sofabAdminUser->getLogin() . " to be a Super Admin.");
+ }
+ }
+
+ //$con->commit();
+ Application_Model_Preference::SetAirtimeVersion($newVersion);
+ Cache::clear();
+
+ $this->toggleMaintenanceScreen(false);
+
+ return true;
+
+ } catch(Exception $e) {
+ //$con->rollback();
+ $this->toggleMaintenanceScreen(false);
+ throw $e;
+ }
+ }
+}
+
+class AirtimeUpgrader255 extends AirtimeUpgrader {
+ protected function getSupportedVersions() {
+ return array (
+ '2.5.4'
+ );
+ }
+
+ public function getNewVersion() {
+ return '2.5.5';
+ }
+
+ 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 \"will create implicit index\"");
+
+ Application_Model_Preference::SetAirtimeVersion($newVersion);
+ Cache::clear();
+
+ $this->toggleMaintenanceScreen(false);
+
+ return true;
+ } catch(Exception $e) {
+ $this->toggleMaintenanceScreen(false);
+ throw $e;
+ }
+ }
+}
\ No newline at end of file
diff --git a/airtime_mvc/application/views/helpers/IsTrial.php b/airtime_mvc/application/views/helpers/IsTrial.php
index 2890bbc49..743232b33 100644
--- a/airtime_mvc/application/views/helpers/IsTrial.php
+++ b/airtime_mvc/application/views/helpers/IsTrial.php
@@ -3,10 +3,6 @@
class Airtime_View_Helper_IsTrial extends Zend_View_Helper_Abstract{
public function isTrial(){
$plan = Application_Model_Preference::GetPlanLevel();
- if($plan == 'trial'){
- return true;
- }else{
- return false;
- }
+ return $plan == 'trial';
}
-}
\ No newline at end of file
+}
diff --git a/airtime_mvc/application/views/helpers/VersionNotify.php b/airtime_mvc/application/views/helpers/VersionNotify.php
index b356d843c..bc940b31a 100644
--- a/airtime_mvc/application/views/helpers/VersionNotify.php
+++ b/airtime_mvc/application/views/helpers/VersionNotify.php
@@ -12,46 +12,6 @@
class Airtime_View_Helper_VersionNotify extends Zend_View_Helper_Abstract{
public function versionNotify(){
- if(Application_Model_Preference::GetPlanLevel() != 'disabled'){
- return "";
- }
-
- // retrieve and validate current and latest versions,
- $current = Application_Model_Preference::GetAirtimeVersion();
- $latest = Application_Model_Preference::GetLatestVersion();
- $link = Application_Model_Preference::GetLatestLink();
- $currentExploded = explode('.', $current);
- $latestExploded = explode('.', $latest);
- if(count($currentExploded) != 3 || count($latestExploded) != 3) {
- return "";
- }
-
- // Calculate the version difference;
- // Example: if current = 1.9.5 and latest = 3.0.0, diff = 105
- // Note: algorithm assumes the number after 1st dot never goes above 9
- $versionDifference = (intval($latestExploded[0]) * 100 + intval($latestExploded[1]) *10 + intval($latestExploded[2]))
- - (intval($currentExploded[0]) * 100 + intval($currentExploded[1] *10 + intval($currentExploded[2])));
-
- // Pick icon based on distance this version is to the latest version available
- if($versionDifference <= 0) {
- // current version is up to date or newer
- $class = "uptodate";
- } else if($versionDifference < 20) {
- // 2 or less major versions back
- $class = "update";
- } else if($versionDifference < 30) {
- // 3 major versions back
- $class = "update2";
- } else {
- // more than 3 major versions back
- $class = "outdated";
- }
-
- $result = "" . $versionDifference . "
"
- . "" . $current . "
"
- . "" . $latest . "
"
- . "" . $link . "
"
- . "";
- return $result;
+ return "";
}
}
diff --git a/airtime_mvc/application/views/scripts/billing/client.phtml b/airtime_mvc/application/views/scripts/billing/client.phtml
new file mode 100644
index 000000000..44a3c8d72
--- /dev/null
+++ b/airtime_mvc/application/views/scripts/billing/client.phtml
@@ -0,0 +1,15 @@
+form->getElement("submit")->setAttrib("class", "right-align");
+$this->form->getElement("country")->setAttrib("class", "right-align");
+$this->form->getElement("securityqid")->setAttrib("class", "right-align");
+?>
+
+
Billing Account Details
+errorMessage)) {?>
+
errorMessage ?>
+successMessage)) {?>
+
successMessage ?>
+
+
+form ?>
+
\ No newline at end of file
diff --git a/airtime_mvc/application/views/scripts/billing/index.phtml b/airtime_mvc/application/views/scripts/billing/index.phtml
new file mode 100644
index 000000000..30d74d258
--- /dev/null
+++ b/airtime_mvc/application/views/scripts/billing/index.phtml
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/airtime_mvc/application/modules/rest/views/scripts/media/clear.phtml b/airtime_mvc/application/views/scripts/billing/invoice.phtml
similarity index 100%
rename from airtime_mvc/application/modules/rest/views/scripts/media/clear.phtml
rename to airtime_mvc/application/views/scripts/billing/invoice.phtml
diff --git a/airtime_mvc/application/views/scripts/billing/invoices.phtml b/airtime_mvc/application/views/scripts/billing/invoices.phtml
new file mode 100644
index 000000000..9f2f65ee3
--- /dev/null
+++ b/airtime_mvc/application/views/scripts/billing/invoices.phtml
@@ -0,0 +1,34 @@
+
+
Invoices
+Thank you! Your plan has been updated and you will be invoiced during your next billing cycle.");
+ $topTextClass = "status-good";
+}
+else {
+ $topText = _("Tip: To pay an invoice, click \"View Invoice\"
and look for the \"Checkout\" button.");
+}
+
+?>
+
=$topText?>
+
+
diff --git a/airtime_mvc/application/views/scripts/billing/upgrade.phtml b/airtime_mvc/application/views/scripts/billing/upgrade.phtml
new file mode 100644
index 000000000..273e44e51
--- /dev/null
+++ b/airtime_mvc/application/views/scripts/billing/upgrade.phtml
@@ -0,0 +1,370 @@
+form;
+ $form->setAttrib('id', 'upgrade-downgrade');
+
+?>
+
+
+
+
=_("Account Plans")?>
+
=_("Upgrade today to get more listeners and storage space!")?>
+
+
+
+ Hobbyist |
+ Starter |
+ Plus |
+ Premium |
+
+
+ 1 Stream
+ |
+ 2 Streams
+ |
+ 2 Streams
+ |
+ 3 Streams
+ |
+
+
+ 64kbps Stream Quality
+ |
+ 64kbps and 128kbps Stream Quality
+ |
+ 64kbps and 196kbps Stream Quality
+ |
+ 64kbps, 128kbps, and 196kbps Stream Quality
+ |
+
+
+ 5 Listeners
+ |
+ 40 Listeners per stream
+ |
+ 100 Listeners per stream
+ |
+ 500 Listeners per stream
+ |
+
+
+ 2GB Storage
+ |
+ 5GB Storage
+ |
+ 30GB Storage
+ |
+ 150GB Storage
+ |
+
+
+ Ticket, Email, Forum Support
+ |
+ Live Chat, Ticket, Email, Forum Support
+ |
+ Live Chat, Ticket, Email, Forum Support
+ |
+ Live Chat, Ticket, Email, Forum Support
+ |
+
+
+
+ |
+ Save 15% if paid annually
+ |
+ Save 15% if paid annually
+ |
+ Save 15% if paid annually
+ |
+
+
+
+ |
+
+ |
+
+ |
+
+ |
+
+
+
+
+
Current Plan:
+
+
+
+
Choose a plan:
+
+
\ No newline at end of file
diff --git a/airtime_mvc/application/views/scripts/form/edit-user.phtml b/airtime_mvc/application/views/scripts/form/edit-user.phtml
index 4b7d7cf53..a36e1aaf9 100644
--- a/airtime_mvc/application/views/scripts/form/edit-user.phtml
+++ b/airtime_mvc/application/views/scripts/form/edit-user.phtml
@@ -1,5 +1,14 @@
escape($this->currentUser)) ?>
+
+ isSuperAdmin()) : ?>
+
+ =sprintf(_("
Note: You are a special \"Super Admin\" type of user.
Account details for Super Admins can be changed in your
Billing Settings instead."), "/billing/client");?>
+
+
+
+
+
diff --git a/airtime_mvc/application/views/scripts/form/preferences.phtml b/airtime_mvc/application/views/scripts/form/preferences.phtml
index afc324126..f32167ea7 100644
--- a/airtime_mvc/application/views/scripts/form/preferences.phtml
+++ b/airtime_mvc/application/views/scripts/form/preferences.phtml
@@ -1,14 +1,8 @@
diff --git a/airtime_mvc/application/views/scripts/plupload/index.phtml b/airtime_mvc/application/views/scripts/plupload/index.phtml
index 6ecb30328..94d5b3264 100644
--- a/airtime_mvc/application/views/scripts/plupload/index.phtml
+++ b/airtime_mvc/application/views/scripts/plupload/index.phtml
@@ -2,7 +2,6 @@
#plupload_files input[type="file"] {
font-size: 200px !important;
}
-<<<<<<< HEAD
quotaLimitReached) { ?>