Rename airtime_mvc/ to legacy/

This commit is contained in:
jo 2021-10-11 13:43:25 +02:00
parent f0879322c2
commit 3e18d42c8b
1316 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,143 @@
<?php
class Application_Model_Auth
{
const TOKEN_LIFETIME = 'P2D'; // DateInterval syntax
private function generateToken($action, $user_id)
{
$salt = md5("pro");
$token = self::generateRandomString();
$info = new CcSubjsToken();
$info->setDbUserId($user_id);
$info->setDbAction($action);
$info->setDbToken(sha1($token.$salt));
$info->setDbCreated(gmdate(DEFAULT_TIMESTAMP_FORMAT));
$info->save();
Logging::debug("generated token {$token}");
return $token;
}
public function sendPasswordRestoreLink($user, $view)
{
$token = $this->generateToken('password.restore', $user->getDbId());
$e_link_protocol = empty($_SERVER['HTTPS']) ? "http" : "https";
$e_link_base = $_SERVER['SERVER_NAME'];
$e_link_port = $_SERVER['SERVER_PORT'];
$e_link_path = $view->url(array('user_id' => $user->getDbId(), 'token' => $token), 'password-change');
$message = sprintf(_("Hi %s, \n\nPlease click this link to reset your password: "), $user->getDbLogin());
$message .= "{$e_link_protocol}://{$e_link_base}:{$e_link_port}{$e_link_path}";
$message .= sprintf(_("\n\nIf you have any problems, please contact our support team: %s"), SUPPORT_ADDRESS);
$message .= sprintf(_("\n\nThank you,\nThe %s Team"), SAAS_PRODUCT_BRANDING_NAME);
$str = sprintf(_('%s Password Reset'), SAAS_PRODUCT_BRANDING_NAME);
return Application_Model_Email::send($str, $message, $user->getDbEmail());
}
public function invalidateTokens($user, $action)
{
CcSubjsTokenQuery::create()
->filterByDbAction($action)
->filterByDbUserId($user->getDbId())
->delete();
}
public function checkToken($user_id, $token, $action)
{
$salt = md5("pro");
$token_info = CcSubjsTokenQuery::create()
->filterByDbAction($action)
->filterByDbUserId($user_id)
->filterByDbToken(sha1($token.$salt))
->findOne();
if (empty($token_info)) {
return false;
}
$now = new DateTime();
$token_life = new DateInterval(self::TOKEN_LIFETIME);
$token_created = new DateTime($token_info->getDbCreated(), new DateTimeZone("UTC"));
return $now->sub($token_life)->getTimestamp() < $token_created->getTimestamp();
}
/**
* Gets the adapter for authentication against a database table
*
* @return object
*/
public static function getAuthAdapter()
{
$CC_CONFIG = Config::getConfig();
if ($CC_CONFIG['auth'] !== 'local') {
return self::getCustomAuthAdapter($CC_CONFIG['auth']);
}
// Database config
$db = Zend_Db::factory('PDO_' . $CC_CONFIG['dsn']['phptype'], array(
'host' => $CC_CONFIG['dsn']['hostspec'],
'username' => $CC_CONFIG['dsn']['username'],
'password' => $CC_CONFIG['dsn']['password'],
'dbname' => $CC_CONFIG['dsn']['database']
));
Zend_Db_Table_Abstract::setDefaultAdapter($db);
$authAdapter = new Zend_Auth_Adapter_DbTable($db);
$authAdapter->setTableName('cc_subjs')
->setIdentityColumn('login')
->setCredentialColumn('pass')
->setCredentialTreatment('MD5(?)');
return $authAdapter;
}
/**
* Gets an alternative Adapter that does not need to auth agains a databse table
*
* @return object
*/
public static function getCustomAuthAdapter($adaptor) {
return new $adaptor();
}
/**
* Get random string
*
* @param int $length
* @param string $allowed_chars
* @return string
*/
final public function generateRandomString($length = 12, $allowed_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')
{
$string = '';
for ($i = 0; $i < $length; $i++) {
$string .= $allowed_chars[mt_rand(0, strlen($allowed_chars) - 1)];
}
return $string;
}
/** It is essential to do this before interacting with Zend_Auth otherwise sessions could be shared between
* different copies of Airtime on the same webserver. This essentially pins this session to:
* - The server hostname - including subdomain so we segment multiple Airtime installs on different subdomains
* - The remote IP of the browser - to help prevent session hijacking
* - The client ID - same reason as server hostname
* @param Zend_Auth $auth Get this with Zend_Auth::getInstance().
*/
public static function pinSessionToClient($auth)
{
$CC_CONFIG = Config::getConfig();
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : "";
$remoteAddr = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : "";
$sessionIdentifier = 'Airtime' . '-' . $serverName . '-' . $remoteAddr . '-' . Application_Model_Preference::GetClientId() . '-' . $CC_CONFIG["baseDir"];
$auth->setStorage(new Zend_Auth_Storage_Session($sessionIdentifier));
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,146 @@
<?php
class Application_Model_Dashboard
{
public static function GetPreviousItem($p_timeNow)
{
//get previous show and previous item in the schedule table.
//Compare the two and if the last show was recorded and started
//after the last item in the schedule table, then return the show's
//name. Else return the last item from the schedule.
$showInstance = Application_Model_ShowInstance::GetLastShowInstance($p_timeNow);
$row = Application_Model_Schedule::GetLastScheduleItem($p_timeNow);
if (is_null($showInstance)) {
if (count($row) == 0) {
return null;
} else {
return array("name"=>$row[0]["artist_name"]." - ".$row[0]["track_title"],
"starts"=>$row[0]["starts"],
"ends"=>$row[0]["ends"]);
}
} else {
if (count($row) == 0) {
if ($showInstance->isRecorded()) {
//last item is a show instance
return array("name"=>$showInstance->getName(),
"starts"=>$showInstance->getShowInstanceStart(),
"ends"=>$showInstance->getShowInstanceEnd());
} else {
return null;
}
} else {
//return the one that started later.
if ($row[0]["starts"] >= $showInstance->getShowInstanceStart()) {
return array("name"=>$row[0]["artist_name"]." - ".$row[0]["track_title"],
"starts"=>$row[0]["starts"],
"ends"=>$row[0]["ends"]);
} else {
return array("name"=>$showInstance->getName(),
"starts"=>$showInstance->getShowInstanceStart(),
"ends"=>$showInstance->getShowInstanceEnd());
}
}
}
}
public static function GetCurrentItem($p_timeNow)
{
//get previous show and previous item in the schedule table.
//Compare the two and if the last show was recorded and started
//after the last item in the schedule table, then return the show's
//name. Else return the last item from the schedule.
$row = array();
$showInstance = Application_Model_ShowInstance::GetCurrentShowInstance($p_timeNow);
if (!is_null($showInstance)) {
$instanceId = $showInstance->getShowInstanceId();
$row = Application_Model_Schedule::GetCurrentScheduleItem($p_timeNow, $instanceId);
}
if (is_null($showInstance)) {
if (count($row) == 0) {
return null;
} else {
/* Should never reach here, but lets return the track information
* just in case we allow tracks to be scheduled without a show
* in the future.
*/
return array("name"=>$row[0]["artist_name"]." - ".$row[0]["track_title"],
"artwork_data"=>$row[0]["artwork_data"],
"starts"=>$row[0]["starts"],
"ends"=>$row[0]["ends"]);
}
} else {
if (count($row) == 0) {
//last item is a show instance
if ($showInstance->isRecorded()) {
return array("name"=>$showInstance->getName(),
"starts"=>$showInstance->getShowInstanceStart(),
"ends"=>$showInstance->getShowInstanceEnd(),
"media_item_played"=>false,
"record"=>true);
} else {
return null;
}
} else {
return array("name"=>$row[0]["artist_name"]." - ".$row[0]["track_title"],
"artwork_data"=>$row[0]["artwork_data"],
"starts"=>$row[0]["starts"],
"ends"=>$row[0]["ends"],
"media_item_played"=>$row[0]["media_item_played"],
"record"=>0);
}
}
}
public static function GetNextItem($p_timeNow)
{
//get previous show and previous item in the schedule table.
//Compare the two and if the last show was recorded and started
//after the last item in the schedule table, then return the show's
//name. Else return the last item from the schedule.
$showInstance = Application_Model_ShowInstance::GetNextShowInstance($p_timeNow);
$row = Application_Model_Schedule::GetNextScheduleItem($p_timeNow);
if (is_null($showInstance)) {
if (count($row) == 0) {
return null;
} else {
return array("name"=>$row[0]["artist_name"]." - ".$row[0]["track_title"],
"artwork_data"=>$row[0]["artwork_data"],
"starts"=>$row[0]["starts"],
"ends"=>$row[0]["ends"]);
}
} else {
if (count($row) == 0) {
if ($showInstance->isRecorded()) {
//last item is a show instance
return array("name"=>$showInstance->getName(),
"starts"=>$showInstance->getShowInstanceStart(),
"ends"=>$showInstance->getShowInstanceEnd());
} else {
return null;
}
} else {
//return the one that starts sooner.
if ($row[0]["starts"] <= $showInstance->getShowInstanceStart()) {
return array("name"=>$row[0]["artist_name"]." - ".$row[0]["track_title"],
"artwork_data"=>$row[0]["artwork_data"],
"starts"=>$row[0]["starts"],
"ends"=>$row[0]["ends"]);
} else {
return array("name"=>$showInstance->getName(),
"starts"=>$showInstance->getShowInstanceStart(),
"ends"=>$showInstance->getShowInstanceEnd());
}
}
}
}
}

View file

@ -0,0 +1,223 @@
<?php
class Application_Model_Datatables
{
private static function buildWhereClauseForAdvancedSearch($dbname2searchTerm)
{
$where = array();
$where['clause'] = array();
$where['params'] = array();
foreach ($dbname2searchTerm as $dbname=>$term) {
$isRange = false;
if (strstr($term, '~')) {
$info = explode('~', $term);
if ($dbname == 'utime' || $dbname == 'mtime' || $dbname == 'lptime') {
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;
} else {
$input1 = isset($info[0])?$info[0]:null;
$input2 = isset($info[1])?$info[1]:null;
}
$isRange = true;
} else {
$input1 = $term;
}
if ($isRange) {
$sub = array();
if ($input1 != null) {
$sub[] = $dbname." >= :" . $dbname . "1";
}
if ($input2 != null) {
$sub[] = $dbname." <= :" . $dbname . "2";
}
if (!empty($sub)) {
$where['clause'][$dbname] = "(".implode(' AND ', $sub).")";
if ($input1 != null) {
$where['params'][$dbname."1"] = $input1;
}
if ($input2 != null) {
$where['params'][$dbname."2"] = $input2;
}
}
} else {
if (trim($input1) !== "") {
$where['clause'][$dbname] = $dbname." ILIKE :" . $dbname."1";
$where['params'][$dbname."1"] = "%".$input1."%";
}
}
}
return $where;
}
/*
* query used to return data for a paginated/searchable datatable.
*/
public static function findEntries($con, $displayColumns, $fromTable,
$data, $dataProp = "aaData")
{
$where = array();
/* Holds the parameters for binding after the statement has been
prepared */
$params = array();
if (isset($data['advSearch']) && $data['advSearch'] === 'true') {
$librarySetting = Application_Model_Preference::getCurrentLibraryTableColumnMap();
//$displayColumns[] = 'owner';
// map that maps original column position to db name
$current2dbname = array();
// array of search terms
$orig2searchTerm = array();
foreach ($data as $key => $d) {
if (strstr($key, "mDataProp_")) {
list($dump, $index) = explode("_", $key);
$current2dbname[$index] = $d;
} elseif (strstr($key, "sSearch_")) {
list($dump, $index) = explode("_", $key);
$orig2searchTerm[$index] = $d;
}
}
// map that maps dbname to searchTerm
$dbname2searchTerm = array();
foreach ($current2dbname as $currentPos => $dbname) {
$new_index = $librarySetting($currentPos);
// TODO : Fix this retarded hack later. Just a band aid for
// now at least we print some warnings so that we don't
// forget about this -- cc-4462
if ( array_key_exists($new_index, $orig2searchTerm) ) {
$dbname2searchTerm[$dbname] = $orig2searchTerm[$new_index];
} else {
Logging::warn("Trying to reorder to unknown index
printing as much debugging as possible...");
$debug = array(
'$new_index' => $new_index,
'$currentPos' => $currentPos,
'$orig2searchTerm' => $orig2searchTerm);
Logging::warn($debug);
}
}
$advancedWhere = self::buildWhereClauseForAdvancedSearch($dbname2searchTerm);
if (!empty($advancedWhere['clause'])) {
$where[] = join(" AND ", $advancedWhere['clause']);
$params = $advancedWhere['params'];
}
}
if ($data["sSearch"] !== "") {
$searchTerms = explode(" ", $data["sSearch"]);
}
$selectorCount = "SELECT COUNT(*) ";
$selectorRows = "SELECT ".join(",", $displayColumns)." ";
$sql = $selectorCount." FROM ".$fromTable;
$sqlTotalRows = $sql;
if (isset($searchTerms)) {
$searchCols = array();
for ($i = 0; $i < $data["iColumns"]; $i++) {
if ($data["bSearchable_".$i] == "true") {
$searchCols[] = $data["mDataProp_{$i}"];
}
}
$outerCond = array();
$simpleWhere = array();
foreach ($searchTerms as $term) {
foreach ($searchCols as $col) {
$simpleWhere['clause']["simple_".$col] = "{$col}::text ILIKE :simple_".$col;
$simpleWhere['params']["simple_".$col] = "%".$term."%";
}
$outerCond[] = "(".implode(" OR ", $simpleWhere['clause']).")";
}
$where[] = "(" .implode(" AND ", $outerCond). ")";
$params = array_merge($params, $simpleWhere['params']);
}
// End Where clause
// Order By clause
$orderby = array();
for ($i = 0; $i < $data["iSortingCols"]; $i++) {
$num = $data["iSortCol_".$i];
$orderby[] = $data["mDataProp_{$num}"]." ".$data["sSortDir_".$i];
}
$orderby[] = "id";
$orderby = join("," , $orderby);
// End Order By clause
$displayLength = intval($data["iDisplayLength"]);
$needToBind = false;
if (count($where) > 0) {
$needToBind = true;
$where = join(" OR ", $where);
$sql = $selectorCount." FROM ".$fromTable." WHERE ".$where;
$sqlTotalDisplayRows = $sql;
$sql = $selectorRows." FROM ".$fromTable." WHERE ".$where." ORDER BY ".$orderby;
}
else {
$sql = $selectorRows." FROM ".$fromTable." ORDER BY ".$orderby;
}
//limit the results returned.
if ($displayLength !== -1) {
$sql .= " OFFSET ".$data["iDisplayStart"]." LIMIT ".$displayLength;
}
try {
//Logging::info($sqlTotalRows);
$r = $con->query($sqlTotalRows);
$totalRows = $r->fetchColumn(0);
if (isset($sqlTotalDisplayRows)) {
//Logging::info("sql is set");
//Logging::info($sqlTotalDisplayRows);
$totalDisplayRows = Application_Common_Database::prepareAndExecute($sqlTotalDisplayRows, $params, 'column');
}
else {
//Logging::info("sql is not set.");
$totalDisplayRows = $totalRows;
}
//TODO
if ($needToBind) {
$results = Application_Common_Database::prepareAndExecute($sql, $params);
}
else {
$stmt = $con->query($sql);
$stmt->setFetchMode(PDO::FETCH_ASSOC);
$results = $stmt->fetchAll();
}
}
catch (Exception $e) {
Logging::info($e->getMessage());
}
return array(
"sEcho" => intval($data["sEcho"]),
"iTotalDisplayRecords" => intval($totalDisplayRows),
"iTotalRecords" => intval($totalRows),
$dataProp => $results
);
}
}

View file

@ -0,0 +1,21 @@
<?php
class Application_Model_Email
{
/**
* Send email
*
* @param string $subject
* @param string $message
* @param mixed $to
* @return boolean
*/
public static function send($subject, $message, $to) {
$headers = sprintf('From: %s <%s>', SAAS_PRODUCT_BRANDING_NAME, LIBRETIME_EMAIL_FROM);
return mail($to, $subject, $message, $headers);
}
}

View file

@ -0,0 +1,74 @@
<?php
class LibreTime_Model_FreeIpa {
/**
* get userinfo in the format needed by the Auth Adaptor
*
* @return array
*/
public static function GetUserInfo($username)
{
$config = Config::getConfig();
$conn = self::_getLdapConnection();
$ldapResults = $conn->search(sprintf('%s=%s', $config['ldap_filter_field'], $username, $config['ldap_basedn']));
if ($ldapResults->count() !== 1) {
throw new Exception('Could not find logged user in LDAP');
}
$ldapUser = $ldapResults->getFirst();
$groupMap = array(
UTYPE_GUEST => $config['ldap_groupmap_guest'],
UTYPE_HOST => $config['ldap_groupmap_host'],
UTYPE_PROGRAM_MANAGER => $config['ldap_groupmap_program_manager'],
UTYPE_ADMIN => $config['ldap_groupmap_admin'],
UTYPE_SUPERADMIN => $config['ldap_groupmap_superadmin'],
);
$type = UTYPE_GUEST;
foreach ($groupMap as $groupType => $group) {
if (in_array($group, $ldapUser['memberof'])) {
$type = $groupType;
}
}
// grab first value for multivalue field
$firstName = $ldapUser['givenname'][0];
$lastName = $ldapUser['sn'][0];
$mail = $ldapUser['mail'][0];
// return full user info for auth adapter
return array(
'type' => $type,
'first_name' => $firstName,
'last_name' => $lastName,
'email' => $mail,
'cell_phone' => '', # empty since I did not find it in ldap
'skype' => '', # empty until we decide on a field
'jabber' => '' # empty until we decide on a field
);
}
/**
* Bind to ldap so we can fetch additional user info
*
* @return Zend_Ldap
*/
private static function _getLdapConnection()
{
$config = Config::getConfig();
$options = array(
'host' => $config['ldap_hostname'],
'username' => $config['ldap_binddn'],
'password' => $config['ldap_password'],
'bindRequiresDn' => true,
'accountDomainName' => $config['ldap_account_domain'],
'baseDn' => $config['ldap_basedn']
);
$conn = new Zend_Ldap($options);
$conn->connect();
return $conn;
}
}

View file

@ -0,0 +1,75 @@
<?php
class Application_Model_Library
{
public static function getObjInfo($p_type)
{
$info = array();
if (strcmp($p_type, 'playlist')==0) {
$info['className'] = 'Application_Model_Playlist';
} elseif (strcmp($p_type, 'block')==0) {
$info['className'] = 'Application_Model_Block';
} elseif (strcmp($p_type, 'webstream')==0) {
$info['className'] = 'Application_Model_Webstream';
} else {
throw new Exception("Unknown object type: '$p_type'");
}
return $info;
}
public static function changePlaylist($p_id, $p_type)
{
$obj_sess = new Zend_Session_Namespace(UI_PLAYLISTCONTROLLER_OBJ_SESSNAME);
if (is_null($p_id) || is_null($p_type)) {
unset($obj_sess->id);
unset($obj_sess->type);
} else {
$obj_sess->id = intval($p_id);
$obj_sess->type = $p_type;
}
}
public static function getPlaylistNames($alphasort = false)
{
$playlistNames = array(NULL => _("None"));
//if we want to return the playlists sorted alphabetically by name
if ($alphasort) {
$playlists = CcPlaylistQuery::create()
->setFormatter(ModelCriteria::FORMAT_ON_DEMAND)
->orderByname()
->find();
}
else {
$playlists = CcPlaylistQuery::create()
->setFormatter(ModelCriteria::FORMAT_ON_DEMAND)
->find();
}
foreach ($playlists as $playlist) {
$playlistNames[$playlist->getDbId()] = $playlist->getDbName();
}
return $playlistNames;
}
public static function getTracktypes()
{
$track_type_options = array(NULL => _("None"));
$track_types = Application_Model_Tracktype::getTracktypes();
array_multisort(array_map(function($element) {
return $element['type_name'];
}, $track_types), SORT_ASC, $track_types);
foreach ($track_types as $key => $tt) {
$track_type_options[$tt['code']] = $tt['type_name'];
}
return $track_type_options;
}
}

View file

@ -0,0 +1,10 @@
<?php
interface Application_Model_LibraryEditable
{
public function setMetadata($key, $val);
public function setName($name);
public function getLength();
public function getId();
}

View file

@ -0,0 +1,193 @@
<?php
class Application_Model_ListenerStat
{
public function __construct()
{
}
public static function getDataPointsWithinRange($p_start, $p_end) {
$sql = <<<SQL
SELECT mount_name, count(*)
FROM cc_listener_count AS lc
INNER JOIN cc_timestamp AS ts ON (lc.timestamp_id = ts.ID)
INNER JOIN cc_mount_name AS mn ON (lc.mount_name_id = mn.ID)
WHERE (ts.timestamp >=:p1 AND ts.timestamp <=:p2)
group by mount_name
SQL;
$data = Application_Common_Database::prepareAndExecute($sql,
array('p1'=>$p_start, 'p2'=>$p_end));
$out = array();
foreach ($data as $d) {
$jump = intval($d['count']/1000);
$jump = max(1, $jump);
$remainder = $jump == 1?0:1;
$sql = <<<SQL
SELECT *
FROM
(SELECT lc.id, ts.timestamp, lc.listener_count, mn.mount_name,
ROW_NUMBER() OVER (ORDER BY timestamp) as rownum
FROM cc_listener_count AS lc
INNER JOIN cc_timestamp AS ts ON (lc.timestamp_id = ts.ID)
INNER JOIN cc_mount_name AS mn ON (lc.mount_name_id = mn.ID)
WHERE (ts.timestamp >=:p1 AND ts.timestamp <= :p2) AND mount_name=:p3) as temp
WHERE (temp.rownum%:p4) = :p5;
SQL;
$result = Application_Common_Database::prepareAndExecute($sql,
array('p1'=>$p_start, 'p2'=>$p_end, 'p3'=>$d['mount_name'], 'p4'=>$jump, 'p5'=>$remainder));
$utcTimezone = new DateTimeZone("UTC");
$displayTimezone = new DateTimeZone(Application_Model_Preference::GetUserTimezone());
foreach ($result as $r) {
$t = new DateTime($r['timestamp'], $utcTimezone);
$t->setTimezone($displayTimezone);
// tricking javascript so it thinks the server timezone is in UTC
$dt = new DateTime($t->format(DEFAULT_TIMESTAMP_FORMAT), $utcTimezone);
$r['timestamp'] = $dt->format("U");
$out[$r['mount_name']][] = $r;
}
}
return $out;
$enabledStreamIds = Application_Model_StreamSetting::getEnabledStreamIds();
$enabledOut = array();
foreach ($enabledStreamIds as $sId) {
$sql = "SELECT value FROM cc_stream_setting"
." WHERE keyname = :key";
$result = Application_Common_Database::prepareAndExecute($sql, array('key' => $sId."_mount"), "single");
$enabledMountPoint = $result["value"];
if (isset($out[$enabledMountPoint])) {
$enabledOut[$enabledMountPoint] = $out[$enabledMountPoint];
}
else {
//TODO fix this hack (here for CC-5254)
//all shoutcast streams are automatically put under "shoutcast" mount point.
if (isset($out["shoutcast"])) {
$enabledOut["shoutcast"] = $out["shoutcast"];
}
}
}
return $enabledOut;
}
// this will currently log the average number of listeners to a specific show during a certain range
public static function getShowDataPointsWithinRange($p_start, $p_end, $show_id) {
$showData = [];
$ccShow = CcShowQuery::create()->findPk($show_id);
$showName = $ccShow->getDbName();
// this query selects all show instances that aired in this date range that match the show_id
$sql = <<<SQL
SELECT id, starts, ends FROM cc_show_instances WHERE show_id =:p1
AND starts >=:p2 AND ends <=:p3
SQL;
$data = Application_Common_Database::prepareAndExecute($sql,
array('p1'=>$show_id,'p2'=>$p_start, 'p3'=>$p_end));
foreach ($data as $d) {
$sql = <<<SQL
SELECT timestamp, SUM(listener_count) AS listeners
FROM cc_listener_count AS lc
INNER JOIN cc_timestamp AS ts ON (lc.timestamp_id = ts.ID)
INNER JOIN cc_mount_name AS mn ON (lc.mount_name_id = mn.ID)
WHERE (ts.timestamp >=:p1 AND ts.timestamp <=:p2)
GROUP BY timestamp
SQL;
$data = Application_Common_Database::prepareAndExecute($sql,
array('p1'=>$d['starts'], 'p2'=>$d['ends']));
$utcTimezone = new DateTimeZone("UTC");
$displayTimezone = new DateTimeZone(Application_Model_Preference::GetUserTimezone());
if (sizeof($data) > 0) {
$t = new DateTime($data[0]['timestamp'], $utcTimezone);
$t->setTimezone($displayTimezone);
// tricking javascript so it thinks the server timezone is in UTC
$average_listeners = array_sum(array_column($data, 'listeners')) / sizeof($data);
$max_num_listeners = max(array_column($data, 'listeners'));
$entry = array("show" => $showName, "time" => $t->format( 'Y-m-d H:i:s')
, "average_number_of_listeners" => $average_listeners,
"maximum_number_of_listeners" => $max_num_listeners);
array_push($showData, $entry);
}
}
return($showData);
}
public static function getAllShowDataPointsWithinRange($p_start, $p_end) {
// this query selects the id of all show instances that aired in this date range
$all_show_data = [];
$sql = <<<SQL
SELECT show_id FROM cc_show_instances
WHERE starts >=:p1 AND ends <=:p2
GROUP BY show_id
SQL;
$data = Application_Common_Database::prepareAndExecute($sql,
array('p1'=>$p_start, 'p2'=>$p_end));
foreach($data as $show_id) {
$all_show_data = array_merge(self::getShowDataPointsWithinRange($p_start,$p_end,$show_id['show_id']), $all_show_data);
}
/* option to sort by number of listeners currently commented out
usort($all_show_data, function($a, $b) {
return $a['average_number_of_listeners'] - $b['average_number_of_listeners'];
});
*/
return $all_show_data;
}
public static function insertDataPoints($p_dataPoints) {
$timestamp_sql = "INSERT INTO cc_timestamp (timestamp) VALUES
(:ts::TIMESTAMP) RETURNING id;";
$mount_name_check_sql = "SELECT id from cc_mount_name WHERE
mount_name = :mn;";
$mount_name_insert_sql = "INSERT INTO cc_mount_name (mount_name) VALUES
(:mn) RETURNING id;";
$stats_sql = "INSERT INTO cc_listener_count (timestamp_id,
listener_count, mount_name_id) VALUES (:timestamp_id,
:listener_count, :mount_name_id)";
foreach ($p_dataPoints as $dp) {
$timestamp_id = Application_Common_Database::prepareAndExecute(
$timestamp_sql,
array('ts'=> $dp['timestamp']),
"column");
$mount_name_id = Application_Common_Database::prepareAndExecute(
$mount_name_check_sql,
array('mn' => $dp['mount_name']),
"column");
if (strlen($mount_name_id) == 0) {
//there is a race condition here where theoretically the row
//with value "mount_name" could appear, but this is *very*
//unlikely and won't break anything even if it happens.
$mount_name_id = Application_Common_Database::prepareAndExecute(
$mount_name_insert_sql,
array('mn' => $dp['mount_name']),
"column");
}
Application_Common_Database::prepareAndExecute($stats_sql,
array('timestamp_id' => $timestamp_id,
'listener_count' => $dp["num_listeners"],
'mount_name_id' => $mount_name_id,
)
);
}
}
}

View file

@ -0,0 +1,370 @@
<?php
class Application_Model_LiveLog
{
public static function GetLiveShowDuration($p_keepData=false)
{
try {
$sql = "SELECT * FROM CC_LIVE_LOG"
." WHERE state = :state"
." and (start_time >= (now() - INTERVAL '1 day'))"
." ORDER BY id";
$rows = Application_Common_Database::prepareAndExecute($sql, array(':state'=>'L'),
Application_Common_Database::ALL);
/* Check if last log has end time.
* If not, set end time to current time
*/
if ($rows != null) {
$last_row = self::UpdateLastLogEndTime(array_pop($rows));
array_push($rows, $last_row);
$skip = false;
} else {
$sql = "SELECT * FROM CC_LIVE_LOG"
." WHERE state = :state"
." ORDER BY id";
$rows = Application_Common_Database::prepareAndExecute($sql, array(':state'=>'L'),
Application_Common_Database::ALL);
if ($rows != null) {
$last_row = self::UpdateLastLogEndTime(array_pop($rows));
array_push($rows, $last_row);
foreach ($rows as $row) {
$sql_delete = "DELETE FROM CC_LIVE_LOG"
." WHERE id = :id";
Application_Common_Database::prepareAndExecute($sql_delete, array(':id'=>$row['id']),
Application_Common_Database::EXECUTE);
}
}
$skip = true;
}
$hours = 0;
$minutes = 0;
$seconds = 0;
if (!$skip) {
foreach ($rows as $row) {
$end = new DateTime($row['end_time']);
$start = new DateTime($row['start_time']);
$duration = $start->diff($end);
$duration = $duration->format("%H:%i:%s");
$intervals = explode(":", $duration);
for ($i = 0; $i < sizeof($intervals); $i++) {
if (!isset($intervals[$i])) {
$intervals[$i] = 0;
}
}
// Trim milliseconds (DateInterval does not support)
$sec = explode(".", $intervals[2]);
if (isset($sec[0])) {
$intervals[2] = $sec[0];
}
$seconds += $intervals[2];
if ($seconds / 60 >= 1) {
$minutes += 1;
$seconds -= 60;
}
$minutes += $intervals[1];
if ($minutes / 60 >= 1) {
$hours += 1;
$minutes -= 60;
}
$hours += $intervals[0];
if (!$p_keepData) {
// Delete data we just used to start a new log history
$sql_delete = "DELETE FROM CC_LIVE_LOG"
." WHERE id = :id";
Application_Common_Database::prepareAndExecute($sql_delete, array(':id'=>$row['id']),
Application_Common_Database::EXECUTE);
}
}
//Trim milliseconds
$seconds = explode(".", $seconds);
if (isset($seconds[0])) {
$minutes = (double) (($hours*60)+$minutes . "." . $seconds[0]);
} else {
$minutes = (double) (($hours*60)+$minutes);
}
}
return $minutes;
} catch (Exception $e) {
header('HTTP/1.0 503 Service Unavailable');
Logging::info("GetLiveShowDuration - Could not connect to database.");
exit;
}
}
public static function GetScheduledDuration($p_keepData=false)
{
try {
$sql_get_logs = "SELECT * FROM CC_LIVE_LOG"
." WHERE state = :state"
." and (start_time >= (now() - INTERVAL '1 day'))"
." ORDER BY id";
$rows = Application_Common_Database::prepareAndExecute($sql_get_logs, array(':state'=>'S'),
Application_Common_Database::ALL);
/* Check if last log has end time.
* If not, set end time to current time
*/
if ($rows != null) {
$last_row = self::UpdateLastLogEndTime(array_pop($rows));
array_push($rows, $last_row);
$skip = false;
} else {
$sql = "SELECT * FROM CC_LIVE_LOG"
." WHERE state = :state"
." ORDER BY id";
$rows = Application_Common_Database::prepareAndExecute($sql, array(':state'=>'S'),
Application_Common_Database::ALL);
if ($rows != null) {
$last_row = self::UpdateLastLogEndTime(array_pop($rows));
array_push($rows, $last_row);
foreach ($rows as $row) {
$sql_delete = "DELETE FROM CC_LIVE_LOG"
." WHERE id = :id";
Application_Common_Database::prepareAndExecute($sql_delete, array(':id'=>$row['id']),
Application_Common_Database::EXECUTE);
}
}
$skip = true;
}
$hours = 0;
$minutes = 0;
$seconds = 0;
if (!$skip) {
/* Get all shows and tracks from cc_schedule that played
* during a scheduled state
*/
foreach ($rows as $row) {
$sql_get_tracks = "SELECT * FROM cc_schedule"
." WHERE starts >= :starts1"
." AND starts < :starts2"
." AND file_id IS NOT NULL"
." AND media_item_played IS TRUE";
$params = array(
':starts1'=>$row['start_time'],
':starts2'=>$row['end_time']
);
$tracks = Application_Common_Database::prepareAndExecute($sql_get_tracks, $params,
Application_Common_Database::ALL);
foreach ($tracks as $track) {
if ($track['ends'] > $row['end_time']) {
$scheduled_ends = new DateTime($row['end_time']);
$track_ends = new DateTime($track['ends']);
$extra_time = $scheduled_ends->diff($track_ends);
/* Get difference between clip_length
* and the extra time. We need to subtract
* this difference from the track's
* clip length.
*/
$clip_length = $track['clip_length'];
//Convert clip_length into seconds
$clip_length_intervals = explode(":", $clip_length);
for ($i = 0; $i < sizeof($clip_length_intervals); $i++) {
if (!isset($clip_length_intervals[$i])) {
$clip_length_intervals[$i] = 0;
}
}
$clip_length_seconds = $clip_length_intervals[0]*3600 + $clip_length_intervals[1]*60 + $clip_length_intervals[2];
$extra_time = $extra_time->format("%H:%i:%s");
//Convert extra_time into seconds;
$extra_time_intervals = explode(":", $extra_time);
for ($i = 0; $i < sizeof($extra_time_intervals); $i++) {
if (!isset($extra_time_intervals[$i])) {
$extra_time_intervals[$i] = 0;
}
}
$extra_time_seconds = $extra_time_intervals[0]*3600 + $extra_time_intervals[1]*60 + $extra_time_intervals[2];
$clip_length_seconds -= $extra_time_seconds;
//Convert new clip_length into "H-i-s" format
$clip_length_arr = array();
if ($clip_length_seconds / 3600 >= 1) {
array_push($clip_length_arr, str_pad(floor($clip_length_seconds / 3600), 2, "0", STR_PAD_LEFT));
$clip_length_seconds -= floor($clip_length_seconds / 3600);
} else {
array_push($clip_length_arr, "00");
}
if ($clip_length_seconds / 60 >= 1) {
array_push($clip_length_arr, str_pad(floor($clip_length_seconds / 60), 2, "0", STR_PAD_LEFT));
$clip_length_seconds -= floor($clip_length_seconds / 60);
} else {
array_push($clip_length_arr, "00");
}
array_push($clip_length_arr, str_pad($clip_length_seconds, 2, "0", STR_PAD_LEFT));
$clip_length = implode(":", $clip_length_arr);
} else {
$clip_length = $track['clip_length'];
}
$intervals = explode(":", $clip_length);
for ($i = 0; $i < sizeof($intervals); $i++) {
if (!isset($intervals[$i])) {
$intervals[$i] = 0;
}
}
// Trim milliseconds (DateInteral does not support)
$sec = explode(".", $intervals[2]);
if (isset($sec[0])) {
$intervals[2] = $sec[0];
}
$seconds += $intervals[2];
if ($seconds / 60 >= 1) {
$minutes += 1;
$seconds -= 60;
}
$minutes += $intervals[1];
if ($minutes / 60 >= 1) {
$hours += 1;
$minutes -= 60;
}
$hours += $intervals[0];
}
if (!$p_keepData) {
//Delete row because we do not need data anymore
$sql_delete = "DELETE FROM CC_LIVE_LOG"
." WHERE id = :id";
Application_Common_Database::prepareAndExecute($sql_delete, array(':id'=>$row['id']),
Application_Common_Database::EXECUTE);
}
}
$seconds = explode(".", $seconds);
if (isset($seconds[0])) {
$minutes = (double) (($hours*60)+$minutes . "." . $seconds[0]);
} else {
$minutes = (double) (($hours*60)+$minutes);
}
}
return $minutes;
} catch (Exception $e) {
header('HTTP/1.0 503 Service Unavailable');
Logging::info("GetScheduledDuration - Could not connect to database.");
exit;
}
}
public static function UpdateLastLogEndTime($log)
{
if ($log['end_time'] == null) {
$current_time = new DateTime("now", new DateTimeZone('UTC'));
$log['end_time'] = $current_time;
$log['end_time'] = $log['end_time']->format(DEFAULT_TIMESTAMP_FORMAT);
self::SetEndTime($log['state'], $current_time, true);
self::SetNewLogTime($log['state'], $current_time);
}
return $log;
}
public static function SetNewLogTime($state, $dateTime)
{
try {
$scheduled = Application_Model_Preference::GetSourceSwitchStatus('scheduled_play');
if ($state == 'L' && $scheduled == 'on') {
self::SetEndTime('S', $dateTime);
}
/* Only insert new state if last log
* has ended
*/
$sql_select = "SELECT max(id) from CC_LIVE_LOG"
." WHERE (state= :state1 and end_time is NULL) or (state= :state2 and end_time is NULL)";
$params = array(
":state1"=> 'L',
":state2"=> 'S'
);
$id = Application_Common_Database::prepareAndExecute($sql_select, $params,
Application_Common_Database::COLUMN);
if ($id == null) {
$sql_insert = "INSERT INTO CC_LIVE_LOG (state, start_time)"
." VALUES (:state, :start)";
$params = array(
':state'=>$state,
':start'=>$dateTime->format(DEFAULT_TIMESTAMP_FORMAT)
);
Application_Common_Database::prepareAndExecute($sql_insert, $params,
Application_Common_Database::EXECUTE);
if ($state == "S") {
// if scheduled play source is getting broadcasted
Application_Model_Schedule::UpdateBrodcastedStatus($dateTime, 1);
}
}
} catch (Exception $e) {
header('HTTP/1.0 503 Service Unavailable');
Logging::info("SetNewLogTime - Could not connect to database.");
exit;
}
}
public static function SetEndTime($state, $dateTime, $override=false)
{
try {
$dj_live = Application_Model_Preference::GetSourceSwitchStatus('live_dj');
$master_live = Application_Model_Preference::GetSourceSwitchStatus('master_dj');
if (($dj_live=='off' && $master_live=='off') || $state == 'S' || $override) {
$sql = "SELECT id, state from cc_live_log"
." where id in (select max(id) from cc_live_log)";
$row = Application_Common_Database::prepareAndExecute($sql, array(),
Application_Common_Database::SINGLE);
/* Only set end time if state recevied ($state)
* is the last row in cc_live_log
*/
if ($row['state'] == $state) {
$update_sql = "UPDATE CC_LIVE_LOG"
." SET end_time = :end"
." WHERE id = :id";
$params = array(
':end'=>$dateTime->format(DEFAULT_TIMESTAMP_FORMAT),
':id'=>$row['id']
);
Application_Common_Database::prepareAndExecute($update_sql, $params,
Application_Common_Database::EXECUTE);
}
//If live broadcasting is off, turn scheduled play on
$scheduled = Application_Model_Preference::GetSourceSwitchStatus('scheduled_play');
if ($state == 'L' && $scheduled=='on' && !$override) {
self::SetNewLogTime('S', $dateTime);
}
}
} catch (Exception $e) {
header('HTTP/1.0 503 Service Unavailable');
Logging::info("SetEndTime - Could not connect to database.");
exit;
}
}
}

View file

@ -0,0 +1,83 @@
<?php
final class Application_Model_Locale
{
private static $domains = array(
'airtime',
'pro',
);
public static $locales = array(
"en_CA" => "English (Canada)",
"en_GB" => "English (Britain)",
"en_US" => "English (USA)",
"cs_CZ" => "Český",
"de_DE" => "Deutsch",
"de_AT" => "Deutsch (Österreich)",
"el_GR" => "Ελληνικά",
"es_ES" => "Español",
"fr_FR" => "Français",
"hr_HR" => "Hrvatski",
"hu_HU" => "Magyar",
"it_IT" => "Italiano",
"ja_JP" => "日本語",
"ko_KR" => "한국어",
"pl_PL" => "Polski",
"pt_BR" => "Português (Brasil)",
"ru_RU" => "Русский",
"sr_RS" => "Српски (Ћирилица)",
"sr_RS@latin" => "Srpski (Latinica)",
"zh_CN" => "简体中文"
);
public static function getLocales()
{
return self::$locales;
}
public static function configureLocalization($locale = null)
{
$codeset = 'UTF-8';
if (is_null($locale)) {
$lang = Application_Model_Preference::GetLocale().'.'.$codeset;
} else {
$lang = $locale.'.'.$codeset;
}
//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);
}
// We need to run bindtextdomain and bind_textdomain_codeset for each domain we're using.
foreach (self::$domains as $domain) {
bindtextdomain($domain, '../locale');
bind_textdomain_codeset($domain, $codeset);
}
textdomain('airtime');
}
/**
* We need this function for the case where a user has logged out, but
* has an airtime_locale cookie containing their locale setting.
*
* If the user does not have an airtime_locale cookie set, we default
* to the station locale.
*
* When the user logs in, the value set in the login form will be passed
* into the airtime_locale cookie. This cookie is also updated when
* a user updates their user settings.
*/
public static function getUserLocale() {
$request = Zend_Controller_Front::getInstance()->getRequest();
$locale = $request->getCookie('airtime_locale', Application_Model_Preference::GetLocale());
return $locale;
}
}

View file

@ -0,0 +1,38 @@
<?php
class Application_Model_LoginAttempts
{
public function __construct()
{
}
public static function increaseAttempts($ip)
{
$sql = "select count(*) from cc_login_attempts WHERE ip= :ip";
$res = Application_Common_Database::prepareAndExecute($sql, array(':ip'=>$ip), Application_Common_Database::ALL);
if ($res) {
$sql = "UPDATE cc_login_attempts SET attempts=attempts+1 WHERE ip= :ip";
Application_Common_Database::prepareAndExecute($sql, array(':ip'=>$ip), Application_Common_Database::EXECUTE);
} else {
$sql = "INSERT INTO cc_login_attempts (ip, attempts) values (':ip', '1')";
Application_Common_Database::prepareAndExecute($sql, array(':ip'=>$ip), Application_Common_Database::EXECUTE);
}
}
public static function getAttempts($ip)
{
$sql = "select attempts from cc_login_attempts WHERE ip= :ip";
$res = Application_Common_Database::prepareAndExecute($sql, array(':ip'=>$ip), Application_Common_Database::ALL);
return $res ? $res : 0;
}
public static function resetAttempts($ip)
{
$sql = "select count(*) from cc_login_attempts WHERE ip= :ip";
$res = Application_Common_Database::prepareAndExecute($sql, array(':ip'=>$ip), Application_Common_Database::COLUMN);
if ($res > 0) {
$sql = "DELETE FROM cc_login_attempts WHERE ip= :ip";
Application_Common_Database::prepareAndExecute($sql, array(':ip'=>$ip), Application_Common_Database::EXECUTE);
}
}
}

View file

@ -0,0 +1,468 @@
<?php
class NestedDirectoryException extends Exception { }
class Application_Model_MusicDir
{
/**
* @holds propel database object
*/
private $_dir;
public function __construct($dir)
{
$this->_dir = $dir;
}
public function getId()
{
return $this->_dir->getId();
}
public function getType()
{
return $this->_dir->getType();
}
public function setType($type)
{
$this->_dir->setType($type);
}
public function getDirectory()
{
return $this->_dir->getDirectory();
}
public function setDirectory($dir)
{
$this->_dir->setDirectory($dir);
$this->_dir->save();
}
public function setExistsFlag($flag)
{
$this->_dir->setExists($flag);
$this->_dir->save();
}
public function setWatchedFlag($flag)
{
$this->_dir->setWatched($flag);
$this->_dir->save();
}
public function getWatchedFlag()
{
return $this->_dir->getWatched();
}
public function getExistsFlag()
{
return $this->_dir->getExists();
}
/**
* There are 2 cases where this function can be called.
* 1. When watched dir was removed
* 2. When some dir was watched, but it was unmounted
*
* In case of 1, $userAddedWatchedDir should be true
* In case of 2, $userAddedWatchedDir should be false
*
* When $userAddedWatchedDir is true, it will set "Watched" flag to false
* otherwise, it will set "Exists" flag to true
*/
public function remove($userAddedWatchedDir=true)
{
$music_dir_id = $this->getId();
$sql = <<<SQL
SELECT DISTINCT s.instance_id
FROM cc_music_dirs AS md
LEFT JOIN cc_files AS f ON f.directory = md.id
RIGHT JOIN cc_schedule AS s ON s.file_id = f.id
WHERE md.id = :musicDirId;
SQL;
$show_instances = Application_Common_Database::prepareAndExecute($sql,
array( ':musicDirId' => $music_dir_id ), 'all' );
// get all the files on this dir
$sql = <<<SQL
UPDATE cc_files
SET file_exists = 'f'
WHERE id IN
(SELECT f.id
FROM cc_music_dirs AS md
LEFT JOIN cc_files AS f ON f.directory = md.id
WHERE md.id = :musicDirId);
SQL;
$affected = Application_Common_Database::prepareAndExecute($sql,
array( ':musicDirId' => $music_dir_id ), 'all');
// set RemovedFlag to true
if ($userAddedWatchedDir) {
self::setWatchedFlag(false);
} else {
self::setExistsFlag(false);
}
//$res = $this->_dir->delete();
foreach ($show_instances as $show_instance_row) {
$temp_show = new Application_Model_ShowInstance($show_instance_row["instance_id"]);
$temp_show->updateScheduledTime();
}
Application_Model_RabbitMq::PushSchedule();
}
/**
* Checks if p_dir1 is the ancestor of p_dir2. Returns
* true if it is the ancestor, false otherwise. Note that
* /home/user is considered the ancestor of /home/user
*
* @param string $p_dir1
* The potential ancestor directory.
* @param string $p_dir2
* The potential descendent directory.
* @return boolean
* Returns true if it is the ancestor, false otherwise.
*/
private static function isAncestorDir($p_dir1, $p_dir2)
{
if (strlen($p_dir1) > strlen($p_dir2)) {
return false;
}
return substr($p_dir2, 0, strlen($p_dir1)) == $p_dir1;
}
/**
* Checks whether the path provided is a valid path. A valid path
* is defined as not being nested within an existing watched directory,
* or vice-versa. Throws a NestedDirectoryException if invalid.
*
* @param string $p_path
* The path we want to validate
* @return void
*/
public static function isPathValid($p_path)
{
$dirs = self::getWatchedDirs();
$dirs[] = self::getStorDir();
foreach ($dirs as $dirObj) {
$dir = $dirObj->getDirectory();
$diff = strlen($dir) - strlen($p_path);
if ($diff == 0) {
if ($dir == $p_path) {
throw new NestedDirectoryException(sprintf(_("%s is already watched."), $p_path));
}
} elseif ($diff > 0) {
if (self::isAncestorDir($p_path, $dir)) {
throw new NestedDirectoryException(sprintf(_("%s contains nested watched directory: %s"), $p_path, $dir));
}
} else { /* diff < 0*/
if (self::isAncestorDir($dir, $p_path)) {
throw new NestedDirectoryException(sprintf(_("%s is nested within existing watched directory: %s"), $p_path, $dir));
}
}
}
}
/** There are 2 cases where this function can be called.
* 1. When watched dir was added
* 2. When some dir was watched, but it was unmounted somehow, but gets mounted again
*
* In case of 1, $userAddedWatchedDir should be true
* In case of 2, $userAddedWatchedDir should be false
*
* When $userAddedWatchedDir is true, it will set "Removed" flag to false
* otherwise, it will set "Exists" flag to true
*
* @param $nestedWatch - if true, bypass path check, and Watched to false
**/
public static function addDir($p_path, $p_type, $userAddedWatchedDir=true, $nestedWatch=false)
{
if (!is_dir($p_path)) {
return array("code"=>2, "error"=>sprintf(_("%s is not a valid directory."), $p_path));
}
$real_path = Application_Common_OsPath::normpath($p_path)."/";
if ($real_path != "/") {
$p_path = $real_path;
}
$exist_dir = self::getDirByPath($p_path);
if (is_null($exist_dir)) {
$temp_dir = new CcMusicDirs();
$dir = new Application_Model_MusicDir($temp_dir);
} else {
$dir = $exist_dir;
}
$dir->setType($p_type);
$p_path = Application_Common_OsPath::normpath($p_path)."/";
try {
/* isPathValid() checks if path is a substring or a superstring of an
* existing dir and if not, throws NestedDirectoryException */
if (!$nestedWatch) {
self::isPathValid($p_path);
}
if ($userAddedWatchedDir) {
$dir->setWatchedFlag(true);
} else {
if ($nestedWatch) {
$dir->setWatchedFlag(false);
}
$dir->setExistsFlag(true);
}
$dir->setDirectory($p_path);
return array("code"=>0);
} catch (NestedDirectoryException $nde) {
$msg = $nde->getMessage();
return array("code"=>1, "error"=>"$msg");
} catch (Exception $e) {
return array("code"=>1,
"error" => sprintf(
_("%s is already set as the current storage dir or in the".
" watched folders list"),
$p_path
)
);
}
}
/** There are 2 cases where this function can be called.
* 1. When watched dir was added
* 2. When some dir was watched, but it was unmounted somehow, but gets mounted again
*
* In case of 1, $userAddedWatchedDir should be true
* In case of 2, $userAddedWatchedDir should be false
*
* When $userAddedWatchedDir is true, it will set "Watched" flag to true
* otherwise, it will set "Exists" flag to true
**/
public static function addWatchedDir($p_path, $userAddedWatchedDir=true, $nestedWatch=false)
{
$res = self::addDir($p_path, "watched", $userAddedWatchedDir, $nestedWatch);
if ($res['code'] != 0) { return $res; }
//convert "linked" files (Airtime <= 1.8.2) to watched files.
$propel_link_dir = CcMusicDirsQuery::create()
->filterByType('link')
->findOne();
//see if any linked files exist.
if (isset($propel_link_dir)) {
//newly added watched directory object
$propel_new_watch = CcMusicDirsQuery::create()
->filterByDirectory(Application_Common_OsPath::normpath($p_path)."/")
->findOne();
//any files of the deprecated "link" type.
$link_files = CcFilesQuery::create()
->setFormatter(ModelCriteria::FORMAT_ON_DEMAND)
->filterByDbDirectory($propel_link_dir->getId())
->find();
$newly_watched_dir = $propel_new_watch->getDirectory();
foreach ($link_files as $link_file) {
$link_filepath = $link_file->getDbFilepath();
//convert "link" file into a watched file.
if ((strlen($newly_watched_dir) < strlen($link_filepath)) && (substr($link_filepath, 0, strlen($newly_watched_dir)) === $newly_watched_dir)) {
//get the filepath path not including the watched directory.
$sub_link_filepath = substr($link_filepath, strlen($newly_watched_dir));
$link_file->setDbDirectory($propel_new_watch->getId());
$link_file->setDbFilepath($sub_link_filepath);
$link_file->save();
}
}
}
$data = array();
$data["directory"] = $p_path;
Application_Model_RabbitMq::SendMessageToMediaMonitor("new_watch", $data);
return $res;
}
public static function getDirByPK($pk)
{
$dir = CcMusicDirsQuery::create()->findPK($pk);
if (!$dir) {
return null;
}
$mus_dir = new Application_Model_MusicDir($dir);
return $mus_dir;
}
public static function getDirByPath($p_path)
{
$dir = CcMusicDirsQuery::create()
->filterByDirectory($p_path)
->findOne();
if ($dir == NULL) {
return null;
} else {
$mus_dir = new Application_Model_MusicDir($dir);
return $mus_dir;
}
}
/**
* Search and returns watched dirs
*
* @param $exists search condition with exists flag
* @param $watched search condition with watched flag
*/
public static function getWatchedDirs($exists=true, $watched=true)
{
$result = array();
$dirs = CcMusicDirsQuery::create()
->filterByType("watched");
if ($exists !== null) {
$dirs = $dirs->filterByExists($exists);
}
if ($watched !== null) {
$dirs = $dirs->filterByWatched($watched);
}
$dirs = $dirs->find();
foreach ($dirs as $dir) {
$result[] = new Application_Model_MusicDir($dir);
}
return $result;
}
public static function getStorDir()
{
$dir = CcMusicDirsQuery::create()
->filterByType("stor")
->findOne();
$mus_dir = new Application_Model_MusicDir($dir);
return $mus_dir;
}
public static function setStorDir($p_dir)
{
// we want to be consistent when storing dir path.
// path should always ends with trailing '/'
$p_dir = Application_Common_OsPath::normpath($p_dir)."/";
if (!is_dir($p_dir)) {
return array("code"=>2, "error"=>sprintf(_("%s is not a valid directory."), $p_dir));
} elseif (Application_Model_Preference::GetImportTimestamp()+10 > time()) {
return array("code"=>3, "error"=>"Airtime is currently importing files. Please wait until this is complete before changing the storage directory.");
}
$dir = self::getStorDir();
// if $p_dir doesn't exist in DB
$exist = $dir->getDirByPath($p_dir);
if ($exist == NULL) {
$dir->setDirectory($p_dir);
$dirId = $dir->getId();
$data = array();
$data["directory"] = $p_dir;
$data["dir_id"] = $dirId;
Application_Model_RabbitMq::SendMessageToMediaMonitor("change_stor", $data);
return array("code"=>0);
} else {
return array("code"=>1,
"error"=>sprintf(_("%s is already set as the current storage dir or in the watched folders list."), $p_dir));
}
}
public static function getWatchedDirFromFilepath($p_filepath)
{
$dirs = CcMusicDirsQuery::create()
->filterByType(array("watched", "stor"))
->filterByExists(true)
->filterByWatched(true)
->find();
foreach ($dirs as $dir) {
$directory = $dir->getDirectory();
if (substr($p_filepath, 0, strlen($directory)) === $directory) {
$mus_dir = new Application_Model_MusicDir($dir);
return $mus_dir;
}
}
return null;
}
/** There are 2 cases where this function can be called.
* 1. When watched dir was removed
* 2. When some dir was watched, but it was unmounted
*
* In case of 1, $userAddedWatchedDir should be true
* In case of 2, $userAddedWatchedDir should be false
*
* When $userAddedWatchedDir is true, it will set "Watched" flag to false
* otherwise, it will set "Exists" flag to true
**/
public static function removeWatchedDir($p_dir, $userAddedWatchedDir=true)
{
//make sure that $p_dir has a trailing "/"
$real_path = Application_Common_OsPath::normpath($p_dir)."/";
if ($real_path != "/") {
$p_dir = $real_path;
}
$dir = Application_Model_MusicDir::getDirByPath($p_dir);
if (is_null($dir)) {
return array("code"=>1, "error"=>sprintf(_("%s doesn't exist in the watched list."), $p_dir));
} else {
$dir->remove($userAddedWatchedDir);
$data = array();
$data["directory"] = $p_dir;
Application_Model_RabbitMq::SendMessageToMediaMonitor("remove_watch", $data);
return array("code"=>0);
}
}
public static function splitFilePath($p_filepath)
{
$mus_dir = self::getWatchedDirFromFilepath($p_filepath);
if (is_null($mus_dir)) {
return null;
}
$length_dir = strlen($mus_dir->getDirectory());
$fp = substr($p_filepath, $length_dir);
return array($mus_dir->getDirectory(), trim($fp));
}
public function unhideFiles()
{
$files = $this->_dir->getCcFiless();
$hid = 0;
foreach ($files as $file) {
$hid++;
$file->setDbHidden(false);
$file->save();
}
Logging::info("unhide '$hid' files");
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,132 @@
<?php
class Application_Model_RabbitMq
{
public static $doPush = false;
/**
* Sets a flag to push the schedule at the end of the request.
*/
public static function PushSchedule()
{
self::$doPush = true;
}
private static function sendMessage($exchange, $exchangeType, $autoDeleteExchange, $data, $queue="")
{
$CC_CONFIG = Config::getConfig();
$conn = new \PhpAmqpLib\Connection\AMQPConnection($CC_CONFIG["rabbitmq"]["host"],
$CC_CONFIG["rabbitmq"]["port"],
$CC_CONFIG["rabbitmq"]["user"],
$CC_CONFIG["rabbitmq"]["password"],
$CC_CONFIG["rabbitmq"]["vhost"]);
if (!isset($conn)) {
throw new Exception("Cannot connect to RabbitMQ server");
}
$channel = $conn->channel();
$channel->access_request($CC_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 \PhpAmqpLib\Message\AMQPMessage($data, array('content_type' => 'text/plain'));
$channel->basic_publish($msg, $exchange);
$channel->close();
$conn->close();
}
public static function SendMessageToPypo($event_type, $md)
{
$md["event_type"] = $event_type;
$exchange = 'airtime-pypo';
$data = json_encode($md, JSON_FORCE_OBJECT);
self::sendMessage($exchange, 'direct', true, $data);
}
public static function SendMessageToMediaMonitor($event_type, $md)
{
$md["event_type"] = $event_type;
$exchange = 'airtime-analyzer';
$data = json_encode($md);
self::sendMessage($exchange, 'direct', true, $data);
}
public static function SendMessageToShowRecorder($event_type)
{
$exchange = 'airtime-pypo';
$now = new DateTime("@".time()); //in UTC timezone
$end_timestamp = new DateTime("@".(time() + 3600*2)); //in UTC timezone
$temp = array();
$temp['event_type'] = $event_type;
$temp['server_timezone'] = Application_Model_Preference::GetTimezone();
if ($event_type == "update_recorder_schedule") {
$temp['shows'] = Application_Model_Show::getShows($now,
$end_timestamp, $onlyRecord=true);
}
$data = json_encode($temp);
self::sendMessage($exchange, 'direct', true, $data);
}
public static function SendMessageToAnalyzer($tmpFilePath, $importedStorageDirectory, $originalFilename,
$callbackUrl, $apiKey, $storageBackend, $filePrefix)
{
$config = Config::getConfig();
$conn = new \PhpAmqpLib\Connection\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['storage_backend'] = $storageBackend;
$data['import_directory'] = $importedStorageDirectory;
$data['original_filename'] = $originalFilename;
$data['callback_url'] = $callbackUrl;
$data['api_key'] = $apiKey;
// We add a prefix to the resource name so files are not all placed
// under the root folder. We do this in case we need to restore a
// customer's file/s; File restoration is done via the S3 Browser
// client. The client will hang if there are too many files under the
// same folder.
$data['file_prefix'] = $filePrefix;
$jsonData = json_encode($data);
//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 \PhpAmqpLib\Message\AMQPMessage($jsonData, array('content_type' => 'text/plain'));
$channel->basic_publish($msg, $exchange);
$channel->close();
$conn->close();
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,40 @@
<?php
class Application_Model_ServiceRegister
{
public static function GetRemoteIpAddr()
{
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
//check ip from share internet
$ip=$_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
//to check ip is pass from proxy
$ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip=$_SERVER['REMOTE_ADDR'];
}
return $ip;
}
public static function Register($p_componentName, $p_ipAddress)
{
$component = CcServiceRegisterQuery::create()->findOneByDbName($p_componentName);
if (is_null($component)) {
$component = new CcServiceRegister();
$component->setDbName($p_componentName);
}
// Need to convert ipv6 to ipv4 since Monit server does not appear
// to allow access via an ipv6 address.
// http://[::1]:2812 does not respond.
// Bug: http://savannah.nongnu.org/bugs/?27608
if ($p_ipAddress == "::1") {
$p_ipAddress = "127.0.0.1";
}
$component->setDbIp($p_ipAddress);
$component->save();
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,492 @@
<?php
class Application_Model_ShowBuilder
{
private $timezone;
//in UTC timezone
private $startDT;
//in UTC timezone
private $endDT;
private $user;
private $opts;
private $pos;
private $contentDT;
private $epoch_now;
private $currentShow;
private $currentShowId;
private $showInstances = array();
private $defaultRowArray = array(
"header" => false,
"footer" => false,
"empty" => false,
"allowed" => false,
"linked_allowed" => true,
"id" => 0,
"instance" => "",
"starts" => "",
"ends" => "",
"runtime" => "",
"title" => "",
"creator" => "",
"album" => "",
"timestamp" => null,
"cuein" => "",
"cueout" => "",
"fadein" => "",
"fadeout" => "",
"image" => false,
"mime" => null,
"color" => "", //in hex without the '#' sign.
"backgroundColor" => "", //in hex without the '#' sign.
);
/*
* @param DateTime $p_startsDT
* @param DateTime $p_endsDT
*/
public function __construct($p_startDT, $p_endDT, $p_opts)
{
$this->startDT = $p_startDT;
$this->endDT = $p_endDT;
$this->timezone = Application_Model_Preference::GetUserTimezone();
$this->user = Application_Model_User::getCurrentUser();
$this->opts = $p_opts;
$this->epoch_now = floatval(microtime(true));
$this->currentShow = false;
}
private function getUsersShows()
{
$shows = array();
$host_shows = CcShowHostsQuery::create()
->setFormatter(ModelCriteria::FORMAT_ON_DEMAND)
->filterByDbHost($this->user->getId())
->find();
foreach ($host_shows as $host_show) {
$shows[] = $host_show->getDbShow();
}
return $shows;
}
//check to see if this row should be editable by the user.
private function isAllowed($p_item, &$row)
{
//cannot schedule in a recorded show.
if (intval($p_item["si_record"]) === 1) {
return;
}
if ($this->currentShow) {
$this->currentShowId = $p_item["show_id"];
}
/* If any linked show instance is currently playing
* we have to disable editing, or else the times
* will not make sense for shows scheduled in the future
*/
if ($p_item["linked"] && $p_item["show_id"] == $this->currentShowId) {
$row["linked_allowed"] = false;
}
if ($this->user->canSchedule($p_item["show_id"]) == true) {
$row["allowed"] = true;
}
}
private function getItemColor($p_item, &$row)
{
$defaultColor = "ffffff";
$defaultBackground = DEFAULT_SHOW_COLOR;
$color = $p_item["show_color"];
if ($color === '') {
$color = $defaultColor;
}
$backgroundColor = $p_item["show_background_color"];
if ($backgroundColor === '') {
$backgroundColor = $defaultBackground;
}
$row["color"] = $color;
$row["backgroundColor"] = $backgroundColor;
}
//information about whether a track is inside|boundary|outside a show.
private function getItemStatus($p_item, &$row)
{
$row["status"] = intval($p_item["playout_status"]);
}
private function getRowTimestamp($p_item, &$row)
{
if (is_null($p_item["si_last_scheduled"])) {
$ts = 0;
} else {
$dt = new DateTime($p_item["si_last_scheduled"], new DateTimeZone("UTC"));
$ts = intval($dt->format("U"));
}
$row["timestamp"] = $ts;
}
/*
* marks a row's status.
* 0 = past
* 1 = current
* 2 = future
* TODO : change all of the above to real constants -- RG
*/
private function getScheduledStatus($p_epochItemStart, $p_epochItemEnd, &$row)
{
if ($row["footer"] === true && $this->epoch_now > $p_epochItemStart &&
$this->epoch_now > $p_epochItemEnd) {
$row["scheduled"] = 0;
} elseif ($row["footer"] === true && $this->epoch_now < $p_epochItemEnd) {
$row["scheduled"] = 2;
} elseif ($row["header"] === true && $this->epoch_now >= $p_epochItemStart) {
$row["scheduled"] = 0;
} elseif ($row["header"] === true && $this->epoch_now < $p_epochItemEnd) {
$row["scheduled"] = 2;
}
//item is in the past.
else if ($this->epoch_now > $p_epochItemEnd) {
$row["scheduled"] = 0;
}
//item is the currently scheduled item.
else if ($this->epoch_now >= $p_epochItemStart && $this->epoch_now < $p_epochItemEnd) {
$row["scheduled"] = 1;
//how many seconds the view should wait to redraw itself.
$row["refresh"] = $p_epochItemEnd - $this->epoch_now;
}
//item is in the future.
else if ($this->epoch_now < $p_epochItemStart) {
$row["scheduled"] = 2;
} else {
Logging::warn("No-op? is this what should happen...printing
debug just in case");
$d = array(
'$p_epochItemStart' => $p_epochItemStart,
'$p_epochItemEnd' => $p_epochItemEnd,
'$row' => $row);
Logging::warn($d);
}
}
private function makeHeaderRow($p_item)
{
$row = $this->defaultRowArray;
//$this->isAllowed($p_item, $row);
$this->getRowTimestamp($p_item, $row);
$this->getItemColor($p_item, $row);
$showStartDT = new DateTime($p_item["si_starts"], new DateTimeZone("UTC"));
$showStartDT->setTimezone(new DateTimeZone($this->timezone));
$startsEpoch = floatval($showStartDT->format("U.u"));
$showEndDT = new DateTime($p_item["si_ends"], new DateTimeZone("UTC"));
$showEndDT->setTimezone(new DateTimeZone($this->timezone));
$endsEpoch = floatval($showEndDT->format("U.u"));
//is a rebroadcast show
if (intval($p_item["si_rebroadcast"]) === 1) {
$row["rebroadcast"] = true;
$parentInstance = CcShowInstancesQuery::create()->findPk($p_item["parent_show"]);
$name = $parentInstance->getCcShow()->getDbName();
$dt = $parentInstance->getDbStarts(null);
$dt->setTimezone(new DateTimeZone($this->timezone));
$time = $dt->format("Y-m-d H:i");
$row["rebroadcast_title"] = sprintf(_("Rebroadcast of %s from %s"), $name, $time);
} elseif (intval($p_item["si_record"]) === 1) {
$row["record"] = true;
}
if ($startsEpoch < $this->epoch_now && $endsEpoch > $this->epoch_now) {
$row["currentShow"] = true;
$this->currentShow = true;
} else {
$this->currentShow = false;
}
$this->isAllowed($p_item, $row);
$row["header"] = true;
$row["starts"] = $showStartDT->format("Y-m-d H:i");
$row["startDate"] = $showStartDT->format("Y-m-d");
$row["startTime"] = $showStartDT->format("H:i");
$row["refresh"] = floatval($showStartDT->format("U.u")) - $this->epoch_now;
$row["ends"] = $showEndDT->format("Y-m-d H:i");
$row["endDate"] = $showEndDT->format("Y-m-d");
$row["endTime"] = $showEndDT->format("H:i");
$row["duration"] = floatval($showEndDT->format("U.u")) - floatval($showStartDT->format("U.u"));
$row["title"] = htmlspecialchars($p_item["show_name"]);
$row["instance"] = intval($p_item["si_id"]);
$row["image"] = '';
$this->getScheduledStatus($startsEpoch, $endsEpoch, $row);
$this->contentDT = $showStartDT;
return $row;
}
private function makeScheduledItemRow($p_item)
{
$row = $this->defaultRowArray;
if (isset($p_item["sched_starts"])) {
$schedStartDT = new DateTime($p_item["sched_starts"],
new DateTimeZone("UTC"));
$schedStartDT->setTimezone(new DateTimeZone($this->timezone));
$schedEndDT = new DateTime($p_item["sched_ends"],
new DateTimeZone("UTC"));
$schedEndDT->setTimezone(new DateTimeZone($this->timezone));
$showEndDT = new DateTime($p_item["si_ends"], new DateTimeZone("UTC"));
$this->getItemStatus($p_item, $row);
$startsEpoch = floatval($schedStartDT->format("U.u"));
$endsEpoch = floatval($schedEndDT->format("U.u"));
$showEndEpoch = floatval($showEndDT->format("U.u"));
//don't want an overbooked item to stay marked as current.
$this->getScheduledStatus($startsEpoch, min($endsEpoch, $showEndEpoch), $row);
$row["id"] = intval($p_item["sched_id"]);
$row["image"] = $p_item["file_exists"];
$row["instance"] = intval($p_item["si_id"]);
$row["starts"] = $schedStartDT->format("H:i:s");
$row["ends"] = $schedEndDT->format("H:i:s");
$cue_out = Application_Common_DateHelper::playlistTimeToSeconds($p_item['cue_out']);
$cue_in = Application_Common_DateHelper::playlistTimeToSeconds($p_item['cue_in']);
$run_time = $cue_out-$cue_in;
$formatter = new LengthFormatter(Application_Common_DateHelper::secondsToPlaylistTime($run_time));
$row['runtime'] = $formatter->format();
$row["title"] = htmlspecialchars($p_item["file_track_title"]);
$row["creator"] = htmlspecialchars($p_item["file_artist_name"]);
$row["album"] = htmlspecialchars($p_item["file_album_title"]);
$row["cuein"] = $p_item["cue_in"];
$row["cueout"] = $p_item["cue_out"];
$row["fadein"] = round(substr($p_item["fade_in"], 6), 6);
$row["fadeout"] = round(substr($p_item["fade_out"], 6), 6);
$row["mime"] = $p_item["file_mime"];
$row["pos"] = $this->pos++;
$this->contentDT = $schedEndDT;
}
//show is empty or is a special kind of show (recording etc)
else if (intval($p_item["si_record"]) === 1) {
$row["record"] = true;
$row["instance"] = intval($p_item["si_id"]);
$showStartDT = new DateTime($p_item["si_starts"], new DateTimeZone("UTC"));
$showEndDT = new DateTime($p_item["si_ends"], new DateTimeZone("UTC"));
$startsEpoch = floatval($showStartDT->format("U.u"));
$endsEpoch = floatval($showEndDT->format("U.u"));
$this->getScheduledStatus($startsEpoch, $endsEpoch, $row);
} else {
$row["empty"] = true;
$row["id"] = 0 ;
$row["instance"] = intval($p_item["si_id"]);
}
if (intval($p_item["si_rebroadcast"]) === 1) {
$row["rebroadcast"] = true;
}
if ($this->currentShow === true) {
$row["currentShow"] = true;
}
$this->getItemColor($p_item, $row);
$this->getRowTimestamp($p_item, $row);
$this->isAllowed($p_item, $row);
return $row;
}
private function makeFooterRow($p_item)
{
$row = $this->defaultRowArray;
$row["footer"] = true;
$row["instance"] = intval($p_item["si_id"]);
$this->getRowTimestamp($p_item, $row);
$showEndDT = new DateTime($p_item["si_ends"], new DateTimeZone("UTC"));
$contentDT = $this->contentDT;
$runtime = bcsub($contentDT->format("U.u"), $showEndDT->format("U.u"), 6);
$row["runtime"] = $runtime;
$timeFilled = new TimeFilledFormatter($runtime);
$row["fRuntime"] = $timeFilled->format();
$showStartDT = new DateTime($p_item["si_starts"], new DateTimeZone("UTC"));
$showStartDT->setTimezone(new DateTimeZone($this->timezone));
$startsEpoch = floatval($showStartDT->format("U.u"));
$showEndDT = new DateTime($p_item["si_ends"], new DateTimeZone("UTC"));
$showEndDT->setTimezone(new DateTimeZone($this->timezone));
$endsEpoch = floatval($showEndDT->format("U.u"));
$row["refresh"] = floatval($showEndDT->format("U.u")) - $this->epoch_now;
if ($this->currentShow === true) {
$row["currentShow"] = true;
}
$this->getScheduledStatus($startsEpoch, $endsEpoch, $row);
$this->isAllowed($p_item, $row);
if (intval($p_item["si_record"]) === 1) {
$row["record"] = true;
}
return $row;
}
/*
* @param int $timestamp Unix timestamp in seconds.
*
* @return boolean whether the schedule in the show builder's range has
* been updated.
*
*/
public function hasBeenUpdatedSince($timestamp, $instances)
{
$outdated = false;
$shows = Application_Model_Show::getShows($this->startDT, $this->endDT);
$include = array();
if ($this->opts["showFilter"] !== 0) {
$include[] = $this->opts["showFilter"];
} elseif ($this->opts["myShows"] === 1) {
$include = $this->getUsersShows();
}
$currentInstances = array();
foreach ($shows as $show) {
if (empty($include) || in_array($show["show_id"], $include)) {
$currentInstances[] = $show["instance_id"];
if (isset($show["last_scheduled"])) {
$dt = new DateTime($show["last_scheduled"],
new DateTimeZone("UTC"));
} else {
$dt = new DateTime($show["created"],
new DateTimeZone("UTC"));
}
//check if any of the shows have a more recent timestamp.
$showTimeStamp = intval($dt->format("U"));
if ($timestamp < $showTimeStamp) {
$outdated = true;
break;
}
}
}
//see if the displayed show instances have changed. (deleted,
//empty schedule etc)
if ($outdated === false && count($instances)
!== count($currentInstances)) {
Logging::debug("show instances have changed.");
$outdated = true;
}
return $outdated;
}
public function getItems()
{
$current_id = -1;
$display_items = array();
$shows = array();
$showInstance = array();
if ($this->opts["myShows"] === 1) {
$shows = $this->getUsersShows();
} elseif ($this->opts["showFilter"] !== 0) {
$shows[] = $this->opts["showFilter"];
} elseif ($this->opts["showInstanceFilter"] !== 0) {
$showInstance[] = $this->opts["showInstanceFilter"];
}
$scheduled_items = Application_Model_Schedule::GetScheduleDetailItems(
$this->startDT, $this->endDT, $shows, $showInstance);
for ($i = 0, $rows = count($scheduled_items); $i < $rows; $i++) {
$item = $scheduled_items[$i];
//don't send back data for filler rows.
if (isset($item["playout_status"]) &&
$item["playout_status"] < 0) {
continue;
}
//make a header row.
if ($current_id !== $item["si_id"]) {
//make a footer row.
if ($current_id !== -1) {
// pass in the previous row as it's the last row for
// the previous show.
$display_items[] = $this->makeFooterRow(
$scheduled_items[$i-1]);
}
$display_items[] = $this->makeHeaderRow($item);
$current_id = $item["si_id"];
$this->pos = 1;
}
//make a normal data row.
$row = $this->makeScheduledItemRow($item);
//don't display the empty rows.
if (isset($row)) {
$display_items[] = $row;
}
if ($current_id !== -1 &&
!in_array($current_id, $this->showInstances)) {
$this->showInstances[] = $current_id;
}
}
//make the last footer if there were any scheduled items.
if (count($scheduled_items) > 0) {
$display_items[] = $this->makeFooterRow($scheduled_items[
count($scheduled_items)-1]);
}
return array(
"schedule" => $display_items,
"showInstances" => $this->showInstances);
}
}

View file

@ -0,0 +1,828 @@
<?php
class Application_Model_ShowInstance
{
private $_instanceId;
private $_showInstance;
public function __construct($instanceId)
{
$this->_instanceId = $instanceId;
$this->_showInstance = CcShowInstancesQuery::create()->findPK($instanceId);
if (is_null($this->_showInstance)) {
throw new Exception();
}
}
public function getShowId()
{
return $this->_showInstance->getDbShowId();
}
/* TODO: A little inconsistent because other models have a getId() method
to get PK --RG */
public function getShowInstanceId()
{
return $this->_instanceId;
}
public function getShow()
{
return new Application_Model_Show($this->getShowId());
}
public function deleteRebroadcasts()
{
$timestamp = gmdate(DEFAULT_TIMESTAMP_FORMAT);
$instance_id = $this->getShowInstanceId();
$sql = <<<SQL
DELETE FROM cc_show_instances
WHERE starts > :timestamp::TIMESTAMP
AND instance_id = :instanceId
AND rebroadcast = 1;
SQL;
Application_Common_Database::prepareAndExecute( $sql, array(
':instanceId' => $instance_id,
':timestamp' => $timestamp), 'execute');
}
/* This function is weird. It should return a boolean, but instead returns
* an integer if it is a rebroadcast, or returns null if it isn't. You can convert
* it to boolean by using is_null(isRebroadcast), where true means isn't and false
* means that it is. */
public function isRebroadcast()
{
return $this->_showInstance->getDbOriginalShow();
}
public function isRecorded()
{
return $this->_showInstance->getDbRecord();
}
public function getName()
{
$show = CcShowQuery::create()->findPK($this->getShowId());
return $show->getDbName();
}
public function getImagePath()
{
$show = CcShowQuery::create()->findPK($this->getShowId());
return $show->getDbImagePath();
}
public function getGenre()
{
$show = CcShowQuery::create()->findPK($this->getShowId());
return $show->getDbGenre();
}
public function hasAutoPlaylist()
{
$show = CcShowQuery::create()->findPK($this->getShowId());
return $show->getDbHasAutoPlaylist();
}
public function getAutoPlaylistId()
{
$show = CcShowQuery::create()->findPK($this->getShowId());
return $show->getDbAutoPlaylistId();
}
public function getAutoPlaylistRepeat()
{
$show = CcShowQuery::create()->findPK($this->getShowId());
return $show->getDbAutoPlaylistRepeat();
}
/**
* Return the start time of the Show (UTC time)
* @return string in format DEFAULT_TIMESTAMP_FORMAT (PHP time notation)
*/
public function getShowInstanceStart($format=DEFAULT_TIMESTAMP_FORMAT)
{
return $this->_showInstance->getDbStarts($format);
}
/**
* Return the end time of the Show (UTC time)
* @return string in format DEFAULT_TIMESTAMP_FORMAT (PHP time notation)
*/
public function getShowInstanceEnd($format=DEFAULT_TIMESTAMP_FORMAT)
{
return $this->_showInstance->getDbEnds($format);
}
public function getStartDate()
{
$showStart = $this->getShowInstanceStart();
$showStartExplode = explode(" ", $showStart);
return $showStartExplode[0];
}
public function getStartTime()
{
$showStart = $this->getShowInstanceStart();
$showStartExplode = explode(" ", $showStart);
return $showStartExplode[1];
}
public function getRecordedFile()
{
$file_id = $this->_showInstance->getDbRecordedFile();
if (isset($file_id)) {
$file = Application_Model_StoredFile::RecallById($file_id);
if (isset($file)) {
$filePaths = $file->getFilePaths();
if (file_exists($filePaths[0])) {
return $file;
}
}
}
return null;
}
public function setShowStart($start)
{
$this->_showInstance->setDbStarts($start)
->save();
Application_Model_RabbitMq::PushSchedule();
}
public function setShowEnd($end)
{
$this->_showInstance->setDbEnds($end)
->save();
Application_Model_RabbitMq::PushSchedule();
}
public function setAutoPlaylistBuilt($bool)
{
$this->_showInstance->setDbAutoPlaylistBuilt($bool)
->save();
}
public function updateScheduledTime()
{
$con = Propel::getConnection(CcShowInstancesPeer::DATABASE_NAME);
$this->_showInstance->updateDbTimeFilled($con);
}
public function isDeleted()
{
$this->_showInstance->getDbModifiedInstance();
}
/*
* @param $dateTime
* php Datetime object to add deltas to
*
* @param $deltaDay
* php int, delta days show moved
*
* @param $deltaMin
* php int, delta mins show moved
*
* @return $newDateTime
* php DateTime, $dateTime with the added time deltas.
*/
public static function addDeltas($dateTime, $deltaDay, $deltaMin)
{
$newDateTime = clone $dateTime;
$days = abs($deltaDay);
$mins = abs($deltaMin);
$dayInterval = new DateInterval("P{$days}D");
$minInterval = new DateInterval("PT{$mins}M");
if ($deltaDay > 0) {
$newDateTime->add($dayInterval);
} elseif ($deltaDay < 0) {
$newDateTime->sub($dayInterval);
}
if ($deltaMin > 0) {
$newDateTime->add($minInterval);
} elseif ($deltaMin < 0) {
$newDateTime->sub($minInterval);
}
return $newDateTime;
}
/**
* Add a playlist as the last item of the current show.
*
* @param int $plId
* Playlist ID.
*/
public function addPlaylistToShow($pl_id, $checkUserPerm = true)
{
$ts = intval($this->_showInstance->getDbLastScheduled("U")) ? : 0;
$id = $this->_showInstance->getDbId();
$lastid = $this->getLastAudioItemId();
$scheduler = new Application_Model_Scheduler($checkUserPerm);
$scheduler->scheduleAfter(
array(array("id" => $lastid, "instance" => $id, "timestamp" => $ts)),
array(array("id" => $pl_id, "type" => "playlist"))
);
// doing this to update the database schedule so that subsequent adds will work.
$con = Propel::getConnection(CcShowInstancesPeer::DATABASE_NAME);
$this->_showInstance->updateScheduleStatus($con);
}
/**
* Add a playlist as the first item of the current show.
*
* @param int $plId
* Playlist ID.
*/
public function addPlaylistToShowStart($pl_id, $checkUserPerm = true)
{
$ts = intval($this->_showInstance->getDbLastScheduled("U")) ? : 0;
$id = $this->_showInstance->getDbId();
$scheduler = new Application_Model_Scheduler($checkUserPerm);
$scheduler->scheduleAfter(
array(array("id" => 0, "instance" => $id, "timestamp" => $ts)),
array(array("id" => $pl_id, "type" => "playlist"))
);
// doing this to update the database schedule so that subsequent adds will work.
$con = Propel::getConnection(CcShowInstancesPeer::DATABASE_NAME);
$this->_showInstance->updateScheduleStatus($con);
}
/**
* Add a media file as the last item in the show.
*
* @param int $file_id
*/
public function addFileToShow($file_id, $checkUserPerm = true)
{
$ts = intval($this->_showInstance->getDbLastScheduled("U")) ? : 0;
$id = $this->_showInstance->getDbId();
$scheduler = new Application_Model_Scheduler();
$scheduler->setCheckUserPermissions($checkUserPerm);
$scheduler->scheduleAfter(
array(array("id" => 0, "instance" => $id, "timestamp" => $ts)),
array(array("id" => $file_id, "type" => "audioclip"))
);
}
/**
* Add the given playlists to the show.
*
* @param array $plIds
* An array of playlist IDs.
*/
public function scheduleShow($plIds)
{
foreach ($plIds as $plId) {
$this->addPlaylistToShow($plId);
}
}
public function clearShow()
{
CcScheduleQuery::create()
->filterByDbInstanceId($this->_instanceId)
->delete();
Application_Model_RabbitMq::PushSchedule();
$this->updateScheduledTime();
}
private function checkToDeleteShow($showId)
{
//UTC DateTime object
$showsPopUntil = Application_Model_Preference::GetShowsPopulatedUntil();
$showDays = CcShowDaysQuery::create()
->filterByDbShowId($showId)
->findOne();
$showEnd = $showDays->getDbLastShow();
//there will always be more shows populated.
if (is_null($showEnd)) {
return false;
}
$lastShowStartDateTime = new DateTime("{$showEnd} {$showDays->getDbStartTime()}", new DateTimeZone($showDays->getDbTimezone()));
//end dates were non inclusive.
$lastShowStartDateTime = self::addDeltas($lastShowStartDateTime, -1, 0);
//there's still some shows left to be populated.
if ($lastShowStartDateTime->getTimestamp() > $showsPopUntil->getTimestamp()) {
return false;
}
// check if there are any non deleted show instances remaining.
$showInstances = CcShowInstancesQuery::create()
->filterByDbShowId($showId)
->filterByDbModifiedInstance(false)
->filterByDbRebroadcast(0)
->find();
if (is_null($showInstances)) {
return true;
}
//only 1 show instance left of the show, make it non repeating.
else if (count($showInstances) === 1) {
$showInstance = $showInstances[0];
$showDaysOld = CcShowDaysQuery::create()
->filterByDbShowId($showId)
->find();
$tz = $showDaysOld[0]->getDbTimezone();
$startDate = new DateTime($showInstance->getDbStarts(), new DateTimeZone("UTC"));
$startDate->setTimeZone(new DateTimeZone($tz));
$endDate = self::addDeltas($startDate, 1, 0);
//make a new rule for a non repeating show.
$showDayNew = new CcShowDays();
$showDayNew->setDbFirstShow($startDate->format("Y-m-d"));
$showDayNew->setDbLastShow($endDate->format("Y-m-d"));
$showDayNew->setDbStartTime($startDate->format("H:i:s"));
$showDayNew->setDbTimezone($tz);
$showDayNew->setDbDay($startDate->format('w'));
$showDayNew->setDbDuration($showDaysOld[0]->getDbDuration());
$showDayNew->setDbRepeatType(-1);
$showDayNew->setDbShowId($showDaysOld[0]->getDbShowId());
$showDayNew->setDbRecord($showDaysOld[0]->getDbRecord());
$showDayNew->save();
//delete the old rules for repeating shows
$showDaysOld->delete();
//remove the old repeating deleted instances.
$showInstances = CcShowInstancesQuery::create()
->filterByDbShowId($showId)
->filterByDbModifiedInstance(true)
->delete();
}
return false;
}
public function delete($rabbitmqPush = true)
{
// see if it was recording show
$recording = $this->isRecorded();
// get show id
$showId = $this->getShowId();
$show = $this->getShow();
$current_timestamp = gmdate(DEFAULT_TIMESTAMP_FORMAT);
if ($current_timestamp <= $this->getShowInstanceEnd()) {
if ($show->isRepeating()) {
CcShowInstancesQuery::create()
->findPK($this->_instanceId)
->setDbModifiedInstance(true)
->save();
if ($this->isRebroadcast()) {
return;
}
//delete the rebroadcasts of the removed recorded show.
if ($recording) {
CcShowInstancesQuery::create()
->filterByDbOriginalShow($this->_instanceId)
->delete();
}
/* Automatically delete all files scheduled in cc_schedules table. */
CcScheduleQuery::create()
->filterByDbInstanceId($this->_instanceId)
->delete();
if ($this->checkToDeleteShow($showId)) {
CcShowQuery::create()
->filterByDbId($showId)
->delete();
}
} else {
if ($this->isRebroadcast()) {
$this->_showInstance->delete();
} else {
$show->delete();
}
}
}
if ($rabbitmqPush) {
Application_Model_RabbitMq::PushSchedule();
}
}
public function setRecordedFile($file_id)
{
$showInstance = CcShowInstancesQuery::create()
->findPK($this->_instanceId);
$showInstance->setDbRecordedFile($file_id)
->save();
$rebroadcasts = CcShowInstancesQuery::create()
->filterByDbOriginalShow($this->_instanceId)
->find();
foreach ($rebroadcasts as $rebroadcast) {
try {
$rebroad = new Application_Model_ShowInstance($rebroadcast->getDbId());
$rebroad->addFileToShow($file_id, false);
} catch (Exception $e) {
Logging::info($e->getMessage());
}
}
}
public function getTimeScheduled()
{
$time = $this->_showInstance->getDbTimeFilled();
if ($time != "00:00:00" && !empty($time)) {
$time_arr = explode(".", $time);
if (count($time_arr) > 1) {
$time_arr[1] = "." . $time_arr[1];
$milliseconds = number_format(round($time_arr[1], 2), 2);
$time = $time_arr[0] . substr($milliseconds, 1);
} else {
$time = $time_arr[0] . ".00";
}
} else {
$time = "00:00:00.00";
}
return $time;
}
public function getTimeScheduledSecs()
{
$time_filled = $this->getTimeScheduled();
return Application_Common_DateHelper::playlistTimeToSeconds($time_filled);
}
public function getDurationSecs()
{
$ends = $this->getShowInstanceEnd(null);
$starts = $this->getShowInstanceStart(null);
return intval($ends->format('U')) - intval($starts->format('U'));
}
// should return the amount of seconds remaining to be scheduled in a show instance
public function getSecondsRemaining()
{
return ($this->getDurationSecs() - $this->getTimeScheduledSecs());
}
public function getPercentScheduled()
{
$durationSeconds = $this->getDurationSecs();
$timeSeconds = $this->getTimeScheduledSecs();
if ($durationSeconds != 0) { //Prevent division by zero if the show duration is somehow zero.
$percent = ceil(($timeSeconds / $durationSeconds) * 100);
} else {
$percent = 0;
}
return $percent;
}
public function getShowLength()
{
$start = $this->getShowInstanceStart(null);
$end = $this->getShowInstanceEnd(null);
$interval = $start->diff($end);
$days = $interval->format("%d");
$hours = sprintf("%02d" ,$interval->format("%h"));
if ($days > 0) {
$totalHours = $days * 24 + $hours;
//$interval object does not have milliseconds so hard code to .00
$returnStr = $totalHours . ":" . $interval->format("%I:%S") . ".00";
} else {
$returnStr = $hours . ":" . $interval->format("%I:%S") . ".00";
}
return $returnStr;
}
public static function getContentCount($p_start, $p_end)
{
$sql = <<<SQL
SELECT instance_id,
count(*) AS instance_count
FROM cc_schedule
WHERE ends > :p_start::TIMESTAMP
AND starts < :p_end::TIMESTAMP
GROUP BY instance_id
SQL;
$counts = Application_Common_Database::prepareAndExecute($sql, array(
':p_start' => $p_start->format("Y-m-d G:i:s"),
':p_end' => $p_end->format("Y-m-d G:i:s"))
, 'all');
$real_counts = array();
foreach ($counts as $c) {
$real_counts[$c['instance_id']] = $c['instance_count'];
}
return $real_counts;
}
public static function getIsFull($p_start, $p_end)
{
$sql = <<<SQL
SELECT id, ends-starts-'00:00:05' < time_filled as filled
from cc_show_instances
WHERE ends > :p_start::TIMESTAMP
AND starts < :p_end::TIMESTAMP
SQL;
$res = Application_Common_Database::prepareAndExecute($sql, array(
':p_start' => $p_start->format("Y-m-d G:i:s"),
':p_end' => $p_end->format("Y-m-d G:i:s"))
, 'all');
$isFilled = array();
foreach ($res as $r) {
$isFilled[$r['id']] = $r['filled'];
}
return $isFilled;
}
public static function getShowHasAutoplaylist($p_start, $p_end)
{
$con = Propel::getConnection(CcShowInstancesPeer::DATABASE_NAME);
$con->beginTransaction();
try {
// query the show instances to find whether a show instance has an autoplaylist
$showInstances = CcShowInstancesQuery::create()
->filterByDbEnds($p_end->format(DEFAULT_TIMESTAMP_FORMAT), Criteria::LESS_THAN)
->filterByDbStarts($p_start->format(DEFAULT_TIMESTAMP_FORMAT), Criteria::GREATER_THAN)
->leftJoinCcShow()
->where('CcShow.has_autoplaylist = ?', 'true')
->find($con);
$hasAutoplaylist = array();
foreach ($showInstances->toArray() as $ap) {
$hasAutoplaylist[$ap['DbId']] = true;
}
return $hasAutoplaylist;
}
catch (Exception $e) {
$con->rollback();
Logging::info("Couldn't query show instances for calendar to find which had autoplaylists");
Logging::info($e->getMessage());
}
}
public function showEmpty()
{
$sql = <<<SQL
SELECT s.starts
FROM cc_schedule AS s
WHERE s.instance_id = :instance_id
AND s.playout_status >= 0
AND ((s.stream_id IS NOT NULL)
OR (s.file_id IS NOT NULL)) LIMIT 1
SQL;
# TODO : use prepareAndExecute properly
$res = Application_Common_Database::prepareAndExecute($sql,
array( ':instance_id' => $this->_instanceId ), 'all' );
# TODO : A bit retarded. fix this later
foreach ($res as $r) {
return false;
}
return true;
}
public function getShowListContent($timezone = null)
{
$con = Propel::getConnection();
$sql = <<<SQL
SELECT *
FROM (
(SELECT s.starts,
0::INTEGER as type ,
f.id AS item_id,
f.track_title,
f.album_title AS album,
f.genre AS genre,
f.length AS length,
f.artist_name AS creator,
f.file_exists AS EXISTS,
f.filepath AS filepath,
f.mime AS mime
FROM cc_schedule AS s
LEFT JOIN cc_files AS f ON f.id = s.file_id
WHERE s.instance_id = :instance_id1
AND s.playout_status >= 0
AND s.file_id IS NOT NULL
AND f.hidden = 'false')
UNION
(SELECT s.starts,
1::INTEGER as type,
ws.id AS item_id,
(ws.name || ': ' || ws.url) AS title,
null AS album,
null AS genre,
ws.length AS length,
sub.login AS creator,
't'::boolean AS EXISTS,
ws.url AS filepath,
ws.mime as mime
FROM cc_schedule AS s
LEFT JOIN cc_webstream AS ws ON ws.id = s.stream_id
LEFT JOIN cc_subjs AS sub ON ws.creator_id = sub.id
WHERE s.instance_id = :instance_id2
AND s.playout_status >= 0
AND s.stream_id IS NOT NULL)) AS temp
ORDER BY starts;
SQL;
$stmt = $con->prepare($sql);
$stmt->execute(array(
':instance_id1' => $this->_instanceId,
':instance_id2' => $this->_instanceId
));
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (isset($timezone)) {
$displayTimezone = new DateTimeZone($timezone);
} else {
$userTimezone = Application_Model_Preference::GetUserTimezone();
$displayTimezone = new DateTimeZone($userTimezone);
}
$utcTimezone = new DateTimeZone("UTC");
foreach ($results as &$row) {
$dt = new DateTime($row["starts"], $utcTimezone);
$dt->setTimezone($displayTimezone);
$row["starts"] = $dt->format(DEFAULT_TIMESTAMP_FORMAT);
if (isset($row['length'])) {
$formatter = new LengthFormatter($row["length"]);
$row["length"] = $formatter->format();
}
}
return $results;
}
public function getLastAudioItemId()
{
$con = Propel::getConnection();
$sql = "SELECT id FROM cc_schedule "
."WHERE instance_id = :instanceId "
."ORDER BY ends DESC "
."LIMIT 1";
$query = Application_Common_Database::prepareAndExecute( $sql,
array(':instanceId' => $this->_instanceId), 'column');
return ($query !== false) ? $query : null;
}
public function getLastAudioItemEnd()
{
$con = Propel::getConnection();
$sql = "SELECT ends FROM cc_schedule "
."WHERE instance_id = :instanceId "
."ORDER BY ends DESC "
."LIMIT 1";
$query = Application_Common_Database::prepareAndExecute( $sql,
array(':instanceId' => $this->_instanceId), 'column');
return ($query !== false) ? $query : null;
}
public static function GetLastShowInstance($p_timeNow)
{
$sql = <<<SQL
SELECT si.id
FROM cc_show_instances si
WHERE si.ends < :timeNow::TIMESTAMP
AND si.modified_instance = 'f'
ORDER BY si.ends DESC LIMIT 1;
SQL;
$id = Application_Common_Database( $sql, array(
':timeNow' => $p_timeNow ), 'column' );
return ($id ? new Application_Model_ShowInstance($id) : null );
}
public static function GetCurrentShowInstance($p_timeNow)
{
/* Orderby si.starts descending, because in some cases
* we can have multiple shows overlapping each other. In
* this case, the show that started later is the one that
* is actually playing, and so this is the one we want.
*/
$sql = <<<SQL
SELECT si.id
FROM cc_show_instances si
WHERE si.starts <= :timeNow1::TIMESTAMP
AND si.ends > :timeNow2::TIMESTAMP
AND si.modified_instance = 'f'
ORDER BY si.starts DESC LIMIT 1
SQL;
$id = Application_Common_Database( $sql, array(
':timeNow1' => $p_timeNow,
':timeNow2' => $p_timeNow ), 'column');
return ( $id ? new Application_Model_ShowInstance($id) : null );
}
public static function GetNextShowInstance($p_timeNow)
{
$sql = <<<SQL
SELECT si.id
FROM cc_show_instances si
WHERE si.starts > :timeNow::TIMESTAMP
AND si.modified_instance = 'f'
ORDER BY si.starts
LIMIT 1
SQL;
$id = Application_Common_Database::prepareAndExecute( $sql,
array( 'timeNow' => $p_timeNow ), 'column' );
return ( $id ? new Application_Model_ShowInstance($id) : null );
}
// returns number of show instances that ends later than $day
public static function GetShowInstanceCount($day)
{
$sql = <<<SQL
SELECT count(*) AS cnt
FROM cc_show_instances
WHERE ends < :day
SQL;
return Application_Common_Database::prepareAndExecute( $sql,
array( ':day' => $day ), 'column' );
}
// this returns end timestamp of all shows that are in the range and has live DJ set up
public static function GetEndTimeOfNextShowWithLiveDJ($p_startTime, $p_endTime)
{
$sql = <<<SQL
SELECT ends
FROM cc_show_instances AS si
JOIN cc_show AS sh ON si.show_id = sh.id
WHERE si.ends > :startTime::TIMESTAMP
AND si.ends < :endTime::TIMESTAMP
AND (sh.live_stream_using_airtime_auth
OR live_stream_using_custom_auth)
ORDER BY si.ends
SQL;
return Application_Common_Database::prepareAndExecute( $sql, array(
':startTime' => $p_startTime,
':endTime' => $p_endTime), 'all');
}
public function isRepeating()
{
return $this->getShow()->isRepeating();
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,536 @@
<?php
define("MAX_NUM_STREAMS", 4);
class Application_Model_StreamSetting
{
public static function setValue($key, $value, $type)
{
$con = Propel::getConnection();
// Check if key already exists
$sql = "SELECT COUNT(*) FROM cc_stream_setting"
." WHERE keyname = :key";
$stmt = $con->prepare($sql);
$stmt->bindParam(':key', $key);
if ($stmt->execute()) {
$result = $stmt->fetchColumn(0);
} else {
$msg = implode(',', $stmt->errorInfo());
throw new Exception("Error: $msg");
}
if ($result == 1) {
$sql = "UPDATE cc_stream_setting"
." SET value = :value, type = :type"
." WHERE keyname = :key";
} else {
$sql = "INSERT INTO cc_stream_setting (keyname, value, type)"
." VALUES (:key, :value, :type)";
}
$stmt = $con->prepare($sql);
$stmt->bindParam(':key', $key);
$stmt->bindParam(':value', $value);
$stmt->bindParam(':type', $type);
if ($stmt->execute()) {
//do nothing
} else {
$msg = implode(',', $stmt->errorInfo());
throw new Exception("Error: $msg");
}
}
public static function getValue($key, $default="")
{
$con = Propel::getConnection();
//Check if key already exists
$sql = "SELECT value FROM cc_stream_setting"
." WHERE keyname = :key";
$stmt = $con->prepare($sql);
$stmt->bindParam(':key', $key);
if ($stmt->execute()) {
$result = $stmt->fetchColumn(0);
} else {
$msg = implode(',', $stmt->errorInfo());
throw new Exception("Error: $msg");
}
return $result ? $result : $default;
}
public static function getEnabledStreamData()
{
$streams = Array();
$streamIds = self::getEnabledStreamIds();
foreach ($streamIds as $id) {
$streamData = self::getStreamData($id);
$prefix = $id."_";
$host = $streamData[$prefix."host"];
$port = $streamData[$prefix."port"];
$mount = $streamData[$prefix."mount"];
if ($streamData[$prefix."output"] == "shoutcast") {
$url = "http://$host:$port/;"; //The semi-colon is important to make Shoutcast stream URLs play instead turn into a page.
} else { //Icecast
$url = "http://$host:$port/$mount";
}
$streams[$id] = Array(
"url" => $url,
"codec" => $streamData[$prefix."type"],
"bitrate" => $streamData[$prefix."bitrate"],
"mobile" => $streamData[$prefix."mobile"]
);
}
return $streams;
}
/* Returns the id's of all streams that are enabled in an array. An
* example of the array returned in JSON notation is ["s1", "s2", "s3"] */
public static function getEnabledStreamIds()
{
$con = Propel::getConnection();
$sql = "SELECT * "
."FROM cc_stream_setting "
."WHERE keyname LIKE '%_enable' "
."AND value='true'";
$ids = array();
$rows = Application_Common_Database::prepareAndExecute($sql, array(), 'all');
foreach ($rows as $row) {
$ids[] = substr($row["keyname"], 0, strpos($row["keyname"], "_"));
}
return $ids;
}
/* Returns all information related to a specific stream. An example
* of a stream id is 's1' or 's2'. */
public static function getStreamData($p_streamId)
{
$rows = CcStreamSettingQuery::create()
->filterByDbKeyName("${p_streamId}_%")
->find();
//This is way too much code because someone made only stupid decisions about how
//the layout of this table worked. The git history doesn't lie.
$data = array();
foreach ($rows as $row) {
$key = $row->getDbKeyName();
$value = $row->getDbValue();
$type = $row->getDbType();
//Fix stupid defaults so we end up with proper typing in our JSON
if ($row->getDbType() == "boolean") {
if (empty($value)) {
//In Python, there is no way to tell the difference between ints and booleans,
//which we need to differentiate between for when we're generating the Liquidsoap
//config file. Returning booleans as a string is a workaround that lets us do that.
$value = "false";
}
$data[$key] = $value;
}
elseif ($row->getDbType() == "integer") {
if (empty($value)) {
$value = 0;
}
$data[$key] = intval($value);
}
else {
$data[$key] = $value;
}
}
//Add in defaults in case they don't exist in the database.
$keyPrefix = $p_streamId . '_';
self::ensureKeyExists($keyPrefix . 'admin_pass', $data);
self::ensureKeyExists($keyPrefix . 'admin_user', $data);
self::ensureKeyExists($keyPrefix . 'bitrate', $data, 128);
self::ensureKeyExists($keyPrefix . 'channels', $data, "stereo");
self::ensureKeyExists($keyPrefix . 'description', $data);
self::ensureKeyExists($keyPrefix . 'enable', $data, "false");
self::ensureKeyExists($keyPrefix . 'genre', $data);
self::ensureKeyExists($keyPrefix . 'host', $data);
self::ensureKeyExists($keyPrefix . 'liquidsoap_error', $data, "waiting");
self::ensureKeyExists($keyPrefix . 'mount', $data);
self::ensureKeyExists($keyPrefix . 'name', $data);
self::ensureKeyExists($keyPrefix . 'output', $data);
self::ensureKeyExists($keyPrefix . 'pass', $data);
self::ensureKeyExists($keyPrefix . 'port', $data, 8000);
self::ensureKeyExists($keyPrefix . 'type', $data);
self::ensureKeyExists($keyPrefix . 'url', $data);
self::ensureKeyExists($keyPrefix . 'user', $data);
self::ensureKeyExists($keyPrefix . 'mobile', $data);
return $data;
}
/* Similar to getStreamData, but removes all sX prefixes to
* make data easier to iterate over */
public static function getStreamDataNormalized($p_streamId)
{
$settings = self::getStreamData($p_streamId);
foreach ($settings as $key => $value)
{
unset($settings[$key]);
$newKey = substr($key, strlen($p_streamId)+1); //$p_streamId is assumed to be the key prefix.
$settings[$newKey] = $value;
}
return $settings;
}
private static function ensureKeyExists($key, &$array, $default='')
{
if (!array_key_exists($key, $array)) {
$array[$key] = $default;
}
return $array;
}
public static function getStreamSetting()
{
$settings = array();
$numStreams = MAX_NUM_STREAMS;
for ($streamIdx = 1; $streamIdx <= $numStreams; $streamIdx++)
{
$settings = array_merge($settings, self::getStreamData("s" . $streamIdx));
}
$settings["master_live_stream_port"] = self::getMasterLiveStreamPort();
$settings["master_live_stream_mp"] = self::getMasterLiveStreamMountPoint();
$settings["dj_live_stream_port"] = self::getDjLiveStreamPort();
$settings["dj_live_stream_mp"] = self::getDjLiveStreamMountPoint();
$settings["off_air_meta"] = self::getOffAirMeta();
$settings["icecast_vorbis_metadata"] = self::getIcecastVorbisMetadata();
$settings["output_sound_device"] = self::getOutputSoundDevice();
$settings["output_sound_device_type"] = self::getOutputSoundDeviceType();
return $settings;
}
private static function saveStreamSetting($key, $value)
{
$stream_setting = CcStreamSettingQuery::create()->filterByDbKeyName($key)->findOne();
if (is_null($stream_setting)) {
//throw new Exception("Keyname $key does not exist!");
$stream_setting = new CcStreamSetting();
$stream_setting->setDbKeyName($key);
$stream_setting->setDbType("");
}
$stream_setting->setDbValue($value);
$stream_setting->save();
}
/*
* function that take all the information of stream and sets them.
* This is used by stream setting via UI.
*
* @param $data - array that contains all the data. $data is [][] which
* contains multiple stream information
*/
public static function setStreamSetting($data)
{
foreach ($data as $key => $d) {
if ($key == "output_sound_device" || $key == "icecast_vorbis_metadata") {
$v = ($d == 1) ? "true" : "false";
self::saveStreamSetting($key, $v);
} elseif ($key == "output_sound_device_type") {
self::saveStreamSetting($key, $d);
} elseif (is_array($d)) {
$temp = explode('_', $key);
$prefix = $temp[0];
// SAAS-876 - If we're using Airtime Pro streaming, set the stream to use the default settings
if (!Application_Model_Preference::getUsingCustomStreamSettings()) {
$d = array_merge($d, static::getDefaults($prefix));
}
foreach ($d as $k => $v) {
$keyname = $prefix . "_" . $k;
if ($k == 'enable') {
$v = $d['enable'] == 1 ? 'true' : 'false';
}
$v = trim($v);
if ($k != 'admin_pass') {
self::saveStreamSetting($keyname, $v);
/* We use 'xxxxxx' as the admin password placeholder so we
* only want to save it when it is a different string
*/
} elseif ($v != 'xxxxxx') {
self::saveStreamSetting($keyname, $v);
}
}
}
}
}
/**
* SAAS-876 - Get the default stream settings values for Airtime Pro streaming
*
* @param int $prefix
*
* @return array array of default stream setting values
*/
public static function getDefaults($prefix) {
$config = Config::getConfig();
return array(
'host' => $config['baseUrl'],
'port' => DEFAULT_ICECAST_PORT,
'output' => 'icecast',
'user' => $config['stationId'],
'pass' => Application_Model_Preference::getDefaultIcecastPassword(),
// Manually setting default mountpoint
'mount' => 'airtime_128',
);
}
/*
* Sets individual stream setting.
*
* $data - data array. $data is [].
* TODO: Make this SQL a prepared statement!
*
* Do not remove this function. It is called by airtime-system.php
*/
public static function setIndividualStreamSetting($data)
{
foreach ($data as $keyname => $v) {
$sql = "UPDATE cc_stream_setting SET value=:v WHERE keyname=:keyname";
$map = array(":v" => $v, ":keyname"=>$keyname);
$res = Application_Common_Database::prepareAndExecute($sql, $map,
Application_Common_Database::EXECUTE);
}
}
/*
* Stores liquidsoap status if $boot_time > save time.
* save time is the time that user clicked save on stream setting page
*/
public static function setLiquidsoapError($stream_id, $msg, $boot_time=null)
{
$con = Propel::getConnection();
$update_time = Application_Model_Preference::GetStreamUpdateTimestemp();
if ($boot_time == null || $boot_time > $update_time) {
$keyname = "s".$stream_id."_liquidsoap_error";
$sql = "SELECT COUNT(*) FROM cc_stream_setting"
." WHERE keyname = :keyname";
$stmt = $con->prepare($sql);
$stmt->bindParam(':keyname', $keyname);
if ($stmt->execute()) {
$result= $stmt->fetchColumn(0);
} else {
$msg = implode(',', $stmt->errorInfo());
throw new Exception("Error: $msg");
}
if ($result == 1) {
$sql = "UPDATE cc_stream_setting"
." SET value = :msg"
." WHERE keyname = :keyname";
} else {
$sql = "INSERT INTO cc_stream_setting (keyname, value, type)"
." VALUES (:keyname, :msg, 'string')";
}
$stmt = $con->prepare($sql);
$stmt->bindParam(':keyname', $keyname);
$stmt->bindParam(':msg', $msg);
if ($stmt->execute()) {
//do nothing
} else {
$msg = implode(',', $stmt->errorInfo());
throw new Exception("Error: $msg");
}
}
}
public static function getLiquidsoapError($stream_id)
{
$con = Propel::getConnection();
$keyname = "s".$stream_id."_liquidsoap_error";
$sql = "SELECT value FROM cc_stream_setting"
." WHERE keyname = :keyname";
$stmt = $con->prepare($sql);
$stmt->bindParam(':keyname', $keyname);
if ($stmt->execute()) {
$result= $stmt->fetchColumn(0);
} else {
$msg = implode(',', $stmt->errorInfo());
throw new Exception("Error: $msg");
}
return ($result !== false) ? $result : null;
}
public static function getStreamEnabled($stream_id)
{
$con = Propel::getConnection();
$keyname = "s" . $stream_id . "_enable";
$sql = "SELECT value FROM cc_stream_setting"
." WHERE keyname = :keyname";
$stmt = $con->prepare($sql);
$stmt->bindParam(':keyname', $keyname);
if ($stmt->execute()) {
$result= $stmt->fetchColumn(0);
} else {
$msg = implode(',', $stmt->errorInfo());
throw new Exception("Error: $msg");
}
return ($result != 'false');
}
/*
* Only returns info that is needed for data collection
* returns array('s1'=>array(keyname=>value))
*/
public static function getStreamInfoForDataCollection()
{
$con = Propel::getConnection();
$out = array();
$enabled_stream = self::getEnabledStreamIds();
foreach ($enabled_stream as $stream) {
$keys = array("{$stream}_output", "{$stream}_type", "{$stream}_bitrate", "{$stream}_host");
$key_csv = implode(',', $keys);
$sql = "SELECT keyname, value FROM cc_stream_setting"
." WHERE keyname IN (:key_csv)";
$stmt = $con->prepare($sql);
$stmt->bindParam(':key_csv', $key_csv);
if ($stmt->execute()) {
$rows = $stmt->fetchAll();
} else {
$msg = implode(',', $stmt->errorInfo());
throw new Exception("Error: $msg");
}
$info = array();
foreach ($rows as $r) {
$temp = explode("_", $r['keyname']);
$info[$temp[1]] = $r['value'];
$out[$stream] = $info;
}
}
return $out;
}
public static function setMasterLiveStreamPort($value)
{
self::setValue("master_live_stream_port", $value, "integer");
}
public static function getMasterLiveStreamPort()
{
return self::getValue("master_live_stream_port", 8001);
}
public static function setMasterLiveStreamMountPoint($value)
{
self::setValue("master_live_stream_mp", $value, "string");
}
public static function getMasterLiveStreamMountPoint()
{
return self::getValue("master_live_stream_mp", "/master");
}
public static function setDjLiveStreamPort($value)
{
self::setValue("dj_live_stream_port", $value, "integer");
}
public static function getDjLiveStreamPort()
{
return self::getValue("dj_live_stream_port", 8002);
}
public static function setDjLiveStreamMountPoint($value)
{
self::setValue("dj_live_stream_mp", $value, "string");
}
public static function getDjLiveStreamMountPoint()
{
return self::getValue("dj_live_stream_mp", "/show");
}
public static function getAdminUser($stream){
return self::getValue($stream."_admin_user");
}
public static function setAdminUser($stream, $v){
self::setValue($stream."_admin_user", $v, "string");
}
public static function getAdminPass($stream){
return self::getValue($stream."_admin_pass");
}
public static function setAdminPass($stream, $v){
self::setValue($stream."_admin_pass", $v, "string");
}
public static function getOffAirMeta(){
return self::getValue("off_air_meta");
}
public static function setOffAirMeta($offAirMeta){
self::setValue("off_air_meta", $offAirMeta, "string");
}
public static function GetAllListenerStatErrors(){
$sql = "SELECT * FROM cc_stream_setting WHERE keyname like :p1";
$mounts = Application_Common_Database::prepareAndExecute($sql, array(':p1'=>'%_mount'));
$mps = array();
foreach($mounts as $mount) {
$mps[] = "'" .$mount["value"] . "_listener_stat_error'";
}
$in = implode(",", $mps);
$sql = "SELECT * FROM cc_stream_setting WHERE keyname IN ( $in )";
return Application_Common_Database::prepareAndExecute($sql, array());
}
public static function SetListenerStatError($key, $v) {
self::setValue($key, $v, 'string');
}
public static function getIcecastVorbisMetadata() {
return self::getValue("icecast_vorbis_metadata", "");
}
public static function getOutputSoundDevice() {
return self::getValue("output_sound_device", "false");
}
public static function getOutputSoundDeviceType() {
return self::getValue("output_sound_device_type", "");
}
}

View file

@ -0,0 +1,54 @@
<?php
/**
* Subj class
*
* users + groups
* with "linearized recursive membership" ;)
* (allow adding users to groups or groups to groups)
*
* @package Airtime
* @subpackage Alib
* @copyright 2010 Sourcefabric O.P.S.
* @license http://www.gnu.org/licenses/gpl.txt
*/
class Application_Model_Subjects
{
/* ======================================================= public methods */
public static function increaseLoginAttempts($login)
{
$sql = "UPDATE cc_subjs SET login_attempts = login_attempts+1"
." WHERE login=:login";
$map = array(":login" => $login);
$res = Application_Common_Database::prepareAndExecute($sql, $map,
Application_Common_Database::EXECUTE);
return (intval($res) > 0);
}
public static function resetLoginAttempts($login)
{
$sql = "UPDATE cc_subjs SET login_attempts = '0'"
." WHERE login=:login";
$map = array(":login" => $login);
$res = Application_Common_Database::prepareAndExecute($sql, $map,
Application_Common_Database::EXECUTE);
return true;
}
public static function getLoginAttempts($login)
{
$sql = "SELECT login_attempts FROM cc_subjs WHERE login=:login";
$map = array(":login" => $login);
$res = Application_Common_Database::prepareAndExecute($sql, $map,
Application_Common_Database::COLUMN);
return ($res !== false) ? $res : 0;
}
} // class Subjects

View file

@ -0,0 +1,245 @@
<?php
class Application_Model_Systemstatus
{
public static function GetMonitStatus($p_ip)
{
$CC_CONFIG = Config::getConfig();
// $monit_user = $CC_CONFIG['monit_user'];
// $monit_password = $CC_CONFIG['monit_password'];
$url = "http://$p_ip:2812/_status?format=xml";
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $url);
// curl_setopt($ch, CURLOPT_USERPWD, "$monit_user:$monit_password");
//wait a max of 3 seconds before aborting connection attempt
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
$result = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
$docRoot = null;
if ($result !== FALSE && $info["http_code"] === 200) {
if ($result != "") {
$xmlDoc = new DOMDocument();
$xmlDoc->loadXML($result);
$docRoot = $xmlDoc->documentElement;
}
}
return $docRoot;
}
public static function ExtractServiceInformation($p_docRoot, $p_serviceName)
{
$starting = array(
"name"=>"",
"process_id"=>"STARTING...",
"uptime_seconds"=>"-1",
"status"=>0,
"memory_perc"=>"0%",
"memory_kb"=>"0",
"cpu_perc"=>"0%");
$notMonitored = array(
"name"=>$p_serviceName,
"process_id"=>"NOT MONITORED",
"uptime_seconds"=>"1",
"status"=>1,
"memory_perc"=>"0%",
"memory_kb"=>"0",
"cpu_perc"=>"0%"
);
$notRunning = array(
"name"=>$p_serviceName,
"process_id"=>"FAILED",
"uptime_seconds"=>"-1",
"status"=>0,
"memory_perc"=>"0%",
"memory_kb"=>"0",
"cpu_perc"=>"0%"
);
$data = $notRunning;
if (!is_null($p_docRoot)) {
foreach ($p_docRoot->getElementsByTagName("service") AS $item) {
if ($item->getElementsByTagName("name")->item(0)->nodeValue == $p_serviceName) {
$monitor = $item->getElementsByTagName("monitor");
if ($monitor->length > 0) {
$status = $monitor->item(0)->nodeValue;
if ($status == "2") {
$data = $starting;
} elseif ($status == 1) {
//is monitored, but is it running?
$pid = $item->getElementsByTagName("pid");
if ($pid->length == 0) {
$data = $notRunning;
} else {
//running!
}
} elseif ($status == 0) {
$data = $notMonitored;
}
}
$process_id = $item->getElementsByTagName("name");
if ($process_id->length > 0) {
$data["name"] = $process_id->item(0)->nodeValue;
}
$process_id = $item->getElementsByTagName("pid");
if ($process_id->length > 0) {
$data["process_id"] = $process_id->item(0)->nodeValue;
$data["status"] = 0;
}
$uptime = $item->getElementsByTagName("uptime");
if ($uptime->length > 0) {
$data["uptime_seconds"] = $uptime->item(0)->nodeValue;
}
$memory = $item->getElementsByTagName("memory");
if ($memory->length > 0) {
$data["memory_perc"] = $memory->item(0)->getElementsByTagName("percenttotal")->item(0)->nodeValue."%";
$data["memory_kb"] = $memory->item(0)->getElementsByTagName("kilobytetotal")->item(0)->nodeValue;
}
$cpu = $item->getElementsByTagName("cpu");
if ($cpu->length > 0) {
$data["cpu_perc"] = $cpu->item(0)->getElementsByTagName("percent")->item(0)->nodeValue."%";
}
break;
}
}
}
return $data;
}
public static function GetPlatformInfo()
{
$keys = array("release", "machine", "memory", "swap");
$data = array();
foreach ($keys as $key) {
$data[$key] = "UNKNOWN";
}
$docRoot = self::GetMonitStatus("localhost");
if (!is_null($docRoot)) {
foreach ($docRoot->getElementsByTagName("platform") AS $item) {
foreach ($keys as $key) {
$keyElement = $item->getElementsByTagName($key);
if ($keyElement->length > 0) {
$data[$key] = $keyElement->item(0)->nodeValue;
}
}
}
}
return $data;
}
public static function GetPypoStatus()
{
$component = CcServiceRegisterQuery::create()->findOneByDbName("pypo");
if (is_null($component)) {
return null;
} else {
$ip = $component->getDbIp();
$docRoot = self::GetMonitStatus($ip);
$data = self::ExtractServiceInformation($docRoot, "airtime-playout");
return $data;
}
}
public static function GetLiquidsoapStatus()
{
$component = CcServiceRegisterQuery::create()->findOneByDbName("pypo");
if (is_null($component)) {
return null;
} else {
$ip = $component->getDbIp();
$docRoot = self::GetMonitStatus($ip);
$data = self::ExtractServiceInformation($docRoot, "airtime-liquidsoap");
return $data;
}
}
public static function GetMediaMonitorStatus()
{
$component = CcServiceRegisterQuery::create()->findOneByDbName("media-monitor");
if (is_null($component)) {
return null;
} else {
$ip = $component->getDbIp();
$docRoot = self::GetMonitStatus($ip);
$data = self::ExtractServiceInformation($docRoot, "airtime-analyzer");
return $data;
}
}
public static function GetIcecastStatus()
{
$docRoot = self::GetMonitStatus("localhost");
$data = self::ExtractServiceInformation($docRoot, "icecast2");
return $data;
}
public static function GetRabbitMqStatus()
{
if (isset($_SERVER["RABBITMQ_HOST"])) {
$rabbitmq_host = $_SERVER["RABBITMQ_HOST"];
} else {
$rabbitmq_host = "localhost";
}
$docRoot = self::GetMonitStatus($rabbitmq_host);
$data = self::ExtractServiceInformation($docRoot, "rabbitmq-server");
return $data;
}
public static function GetDiskInfo()
{
$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();
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]->usedSpace = $totalSpace - $partitions[$totalSpace]->totalFreeSpace;
}
$partitions[$totalSpace]->dirs[] = $md->getDirectory();
}
return array_values($partitions);
}
public static function isDiskOverQuota()
{
$diskInfo = self::GetDiskInfo();
$diskInfo = $diskInfo[0];
$diskUsage = $diskInfo->totalSpace - $diskInfo->totalFreeSpace;
if ($diskUsage > 0 && $diskUsage >= $diskInfo->totalSpace) {
return true;
}
return false;
}
}

View file

@ -0,0 +1,173 @@
<?php
class Application_Model_Tracktype
{
private $_tracktypeInstance;
public function __construct($tracktypeId)
{
if (empty($tracktypeId)) {
$this->_tracktypeInstance = $this->createTracktype();
} else {
$this->_tracktypeInstance = CcTracktypesQuery::create()->findPK($tracktypeId);
if (is_null($this->_tracktypeInstance)) {
throw new Exception();
}
}
}
public function getId()
{
return $this->_tracktypeInstance->getDbId();
}
public function setCode($code)
{
$tracktype = $this->_tracktypeInstance;
$tracktype->setDbCode($code);
}
public function setTypeName($typeName)
{
$tracktype = $this->_tracktypeInstance;
$tracktype->setDbTypeName($typeName);
}
public function setDescription($description)
{
$tracktype = $this->_tracktypeInstance;
$tracktype->setDbDescription($description);
}
public function setVisibility($visibility)
{
$tracktype = $this->_tracktypeInstance;
$tracktype->setDbVisibility($visibility);
}
public function getCode()
{
$tracktype = $this->_tracktypeInstance;
return $tracktype->getDbCode();
}
public function getTypeName()
{
$tracktype = $this->_tracktypeInstance;
return $tracktype->getDbTypeName();
}
public function getDescription()
{
$tracktype = $this->_tracktypeInstance;
return $tracktype->getDbDescription();
}
public function getVisibility()
{
$tracktype = $this->_tracktypeInstance;
return $tracktype->getDbVisibility();
}
public function save()
{
$this->_tracktypeInstance->save();
}
public function delete()
{
if (!$this->_tracktypeInstance->isDeleted()) {
$this->_tracktypeInstance->delete();
}
}
private function createTracktype()
{
$tracktype = new CcTracktypes();
return $tracktype;
}
public static function getTracktypes($search=null)
{
return Application_Model_Tracktype::getTracktypesData(array(true), $search);
}
public static function getTracktypesData(array $visible, $search=null)
{
$con = Propel::getConnection();
$sql_gen = "SELECT id, code, type_name, description FROM cc_track_types ";
$visibility = array();
$params = array();
for ($i=0; $i<count($visible); $i++) {
$p = ":visibility{$i}";
$visibility[] = "visibility = $p";
$params[$p] = $visible[$i];
}
$sql_type = join(" OR ", $visibility);
$sql = $sql_gen ." WHERE (". $sql_type.") ";
$sql .= " AND code ILIKE :search";
$params[":search"] = "%$search%";
$sql = $sql ." ORDER BY id";
return Application_Common_Database::prepareAndExecute($sql, $params, "all");
}
public static function getTracktypeCount()
{
$sql_gen = "SELECT count(*) AS cnt FROM cc_track_types";
$query = Application_Common_Database::prepareAndExecute($sql_gen, array(),
Application_Common_Database::COLUMN);
return ($query !== false) ? $query : null;
}
public static function getTracktypesDataTablesInfo($datatables)
{
$con = Propel::getConnection(CcTracktypesPeer::DATABASE_NAME);
$displayColumns = array("id", "code", "type_name", "description", "visibility");
$fromTable = "cc_track_types";
$tracktypename = "";
$res = Application_Model_Datatables::findEntries($con, $displayColumns, $fromTable, $datatables);
foreach($res['aaData'] as $key => &$record){
if ($record['code'] == $tracktypename) {
$record['delete'] = "self";
} else {
$record['delete'] = "";
}
$record = array_map('htmlspecialchars', $record);
}
$res['aaData'] = array_values($res['aaData']);
return $res;
}
public static function getTracktypeData($id)
{
$sql = <<<SQL
SELECT code, type_name, description, visibility, id
FROM cc_track_types
WHERE id = :id
SQL;
return Application_Common_Database::prepareAndExecute($sql, array(
":id" => $id), 'single');
}
}

View file

@ -0,0 +1,403 @@
<?php
class Application_Model_User
{
private $_userInstance;
public function __construct($userId)
{
if (empty($userId)) {
$this->_userInstance = $this->createUser();
} else {
$this->_userInstance = CcSubjsQuery::create()->findPK($userId);
if (is_null($this->_userInstance)) {
throw new Exception();
}
}
}
public function getId()
{
return $this->_userInstance->getDbId();
}
public function isGuest()
{
return $this->getType() == UTYPE_GUEST;
}
public function isHostOfShow($showId)
{
$userId = $this->_userInstance->getDbId();
return CcShowHostsQuery::create()
->filterByDbShow($showId)
->filterByDbHost($userId)->count() > 0;
}
public function isHost()
{
return $this->isUserType(UTYPE_HOST);
}
public function isPM()
{
return $this->isUserType(UTYPE_PROGRAM_MANAGER);
}
public function isAdmin()
{
return $this->isUserType(UTYPE_ADMIN);
}
public function isSuperAdmin()
{
return $this->isUserType(UTYPE_SUPERADMIN);
}
public function canSchedule($p_showId)
{
$type = $this->getType();
$result = false;
if ($this->isAdmin() ||
$this->isSuperAdmin() ||
$this->isPM() ||
self::isHostOfShow($p_showId)) {
$result = true;
}
return $result;
}
public function isSourcefabricAdmin()
{
$username = $this->getLogin();
if ($username == "sourcefabric_admin") {
return true;
}
return false;
}
// TODO : refactor code to only accept arrays for isUserType and
// simplify code even further
public function isUserType($type)
{
if (!is_array($type)) {
$type = array($type);
}
$real_type = $this->_userInstance->getDbType();
return in_array($real_type, $type);
}
public function setLogin($login)
{
$user = $this->_userInstance;
$user->setDbLogin($login);
}
public function setPassword($password)
{
$user = $this->_userInstance;
$user->setDbPass(md5($password));
}
public function setFirstName($firstName)
{
$user = $this->_userInstance;
$user->setDbFirstName($firstName);
}
public function setLastName($lastName)
{
$user = $this->_userInstance;
$user->setDbLastName($lastName);
}
public function setType($type)
{
$user = $this->_userInstance;
$user->setDbType($type);
}
public function setEmail($email)
{
$user = $this->_userInstance;
$user->setDbEmail(strtolower($email));
}
public function setCellPhone($cellPhone)
{
$user = $this->_userInstance;
$user->setDbCellPhone($cellPhone);
}
public function setSkype($skype)
{
$user = $this->_userInstance;
$user->setDbSkypeContact($skype);
}
public function setJabber($jabber)
{
$user = $this->_userInstance;
$user->setDbJabberContact($jabber);
}
public function getLogin()
{
$user = $this->_userInstance;
return $user->getDbLogin();
}
public function getPassword()
{
$user = $this->_userInstance;
return $user->getDbPass();
}
public function getFirstName()
{
$user = $this->_userInstance;
return $user->getDbFirstName();
}
public function getLastName()
{
$user = $this->_userInstance;
return $user->getDbLastName();
}
public function getType()
{
$user = $this->_userInstance;
return $user->getDbType();
}
public function getEmail()
{
$user = $this->_userInstance;
return $user->getDbEmail();
}
public function getCellPhone()
{
$user = $this->_userInstance;
return $user->getDbCellPhone();
}
public function getSkype()
{
$user = $this->_userInstance;
return $user->getDbSkypeContact();
}
public function getJabber()
{
$user = $this->_userInstance;
return $user->getDbJabberContact();
}
public function save()
{
$this->_userInstance->save();
}
public function delete()
{
if (!$this->_userInstance->isDeleted()) {
$this->_userInstance->delete();
}
}
public function getOwnedFiles()
{
$user = $this->_userInstance;
// do we need a find call at the end here?
return $user->getCcFilessRelatedByDbOwnerId();
}
public function donateFilesTo($user) // $user is object not user id
{
$my_files = $this->getOwnedFiles();
foreach ($my_files as $file) {
$file->reassignTo($user);
}
}
public function deleteAllFiles()
{
$my_files = $this->getOwnedFiles();
foreach ($my_files as $file) {
$file->delete();
}
}
private function createUser()
{
$user = new CcSubjs();
return $user;
}
public static function getUsersOfType($type)
{
return CcSubjsQuery::create()->filterByDbType($type)->find();
}
/**
* Get the first admin user from the database
*
* This function gets used in UserController in the delete action. The controller
* uses it to figure out who to reassign the deleted users files to.
*
* @param $ignoreUser String optional userid of a user that shall be ignored when
* when looking for the "first" admin.
*
* @return CcSubj|null
*/
public static function getFirstAdmin($ignoreUser = null) {
$superAdmins = Application_Model_User::getUsersOfType('S');
if (count($superAdmins) > 0) { // found superadmin => pick first one
return $superAdmins[0];
} else {
// get all admin users
$query = CcSubjsQuery::create()->filterByDbType('A');
// ignore current user if one was specified
if ($ignoreUser !== null) {
$query->filterByDbId($ignoreUser, Criteria::NOT_EQUAL);
}
$admins = $query->find();
if (count($admins) > 0) { // found admin => pick first one
return $admins[0];
}
Logging::warn("Warning. no admins found in database");
return null;
}
}
public static function getUsers(array $type, $search=null)
{
$con = Propel::getConnection();
$sql_gen = "SELECT login AS value, login AS label, id as index FROM cc_subjs ";
$types = array();
$params = array();
for ($i=0; $i<count($type); $i++) {
$p = ":type{$i}";
$types[] = "type = $p";
$params[$p] = $type[$i];
}
$sql_type = join(" OR ", $types);
$sql = $sql_gen ." WHERE (". $sql_type.") ";
$sql .= " AND login ILIKE :search";
$params[":search"] = "%$search%";
$sql = $sql ." ORDER BY login";
return Application_Common_Database::prepareAndExecute($sql, $params, "all");
}
public static function getUserCount()
{
$sql_gen = "SELECT count(*) AS cnt FROM cc_subjs";
$query = Application_Common_Database::prepareAndExecute($sql_gen, array(),
Application_Common_Database::COLUMN);
return ($query !== false) ? $query : null;
}
public static function getHosts($search=null)
{
return Application_Model_User::getUsers(array('H'), $search);
}
public static function getNonGuestUsers($search=null)
{
return Application_Model_User::getUsers(array('H','A','S','P'), $search);
}
public static function getUsersDataTablesInfo($datatables)
{
$con = Propel::getConnection(CcSubjsPeer::DATABASE_NAME);
$displayColumns = array("id", "login", "first_name", "last_name", "type");
$fromTable = "cc_subjs";
// get current user
$username = "";
$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
$username = $auth->getIdentity()->login;
}
$res = Application_Model_Datatables::findEntries($con, $displayColumns, $fromTable, $datatables);
// mark record which is for the current user
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;
}
public static function getUserData($id)
{
$sql = <<<SQL
SELECT login, first_name, last_name, type, id, email, cell_phone, skype_contact,
jabber_contact
FROM cc_subjs
WHERE id = :id
SQL;
return Application_Common_Database::prepareAndExecute($sql, array(
":id" => $id), 'single');
}
public static function getCurrentUser()
{
$userinfo = Zend_Auth::getInstance()->getStorage()->read();
if (is_null($userinfo)) {
return null;
}
try {
return new self($userinfo->id);
} catch (Exception $e) {
//we get here if $userinfo->id is defined, but doesn't exist
//in the database anymore.
Zend_Auth::getInstance()->clearIdentity();
return null;
}
}
}

View file

@ -0,0 +1,455 @@
<?php
class Application_Model_Webstream implements Application_Model_LibraryEditable
{
private $id;
public function __construct($webstream)
{
//TODO: hacky...
if (is_int($webstream)) {
$this->webstream = CcWebstreamQuery::create()->findPK($webstream);
if (is_null($this->webstream)) {
throw new Exception();
}
} else {
$this->webstream = $webstream;
}
}
public function getOrm()
{
return $this->webstream;
}
public function getName()
{
return $this->webstream->getDbName();
}
public function getId()
{
return $this->webstream->getDbId();
}
public function getCreatorId()
{
return $this->webstream->getDbCreatorId();
}
public function getLastModified($p_type)
{
return $this->webstream->getDbMtime();
}
public function getDefaultLength()
{
$dateString = $this->webstream->getDbLength();
$arr = explode(":", $dateString);
if (count($arr) == 3) {
list($hours, $min, $sec) = $arr;
$di = new DateInterval("PT{$hours}H{$min}M{$sec}S");
return $di->format("%Hh %Im");
}
return "";
}
public function getLength()
{
return $this->getDefaultLength();
}
public function getDescription()
{
return $this->webstream->getDbDescription();
}
public function getUrl()
{
return $this->webstream->getDbUrl();
}
public function getMetadata()
{
$subjs = CcSubjsQuery::create()->findPK($this->webstream->getDbCreatorId());
$username = $subjs->getDbLogin();
return array(
"name" => $this->webstream->getDbName(),
"length" => $this->webstream->getDbLength(),
"description" => $this->webstream->getDbDescription(),
"login" => $username,
"url" => $this->webstream->getDbUrl(),
);
}
public static function deleteStreams($p_ids, $p_userId)
{
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
$isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
if (!$isAdminOrPM) {
//Make sure the user has ownership of ALL the selected webstreams before
$leftOver = self::streamsNotOwnedByUser($p_ids, $p_userId);
if (count($leftOver) == 0) {
CcWebstreamQuery::create()->findPKs($p_ids)->delete();
} else {
throw new WebstreamNoPermissionException;
}
} else {
CcWebstreamQuery::create()->findPKs($p_ids)->delete();
}
}
// This function returns that are not owen by $p_user_id among $p_ids
private static function streamsNotOwnedByUser($p_ids, $p_userId)
{
$ownedByUser = CcWebstreamQuery::create()->filterByDbCreatorId($p_userId)->find()->getData();
$ownedStreams = array();
foreach ($ownedByUser as $pl) {
if (in_array($pl->getDbId(), $p_ids)) {
$ownedStreams[] = $pl->getDbId();
}
}
$leftOvers = array_diff($p_ids, $ownedStreams);
return $leftOvers;
}
public static function analyzeFormData($parameters)
{
$valid = array("length" => array(true, ''),
"url" => array(true, ''),
"name" => array(true, ''));
$di = null;
$length = $parameters["length"];
$result = preg_match("/^(?:([0-9]{1,2})h)?\s*(?:([0-9]{1,2})m)?$/", $length, $matches);
$invalid_date_interval = false;
if ($result == 1 && count($matches) == 2) {
$hours = $matches[1];
$minutes = 0;
} elseif ($result == 1 && count($matches) == 3) {
$hours = $matches[1];
$minutes = $matches[2];
} else {
$invalid_date_interval = true;
}
if (!$invalid_date_interval) {
//Due to the way our Regular Expression is set up, we could have $minutes or $hours
//not set. Do simple test here
if (!is_numeric($hours)) {
$hours = 0;
}
if (!is_numeric($minutes)) {
$minutes = 0;
}
//minutes cannot be over 59. Need to convert anything > 59 minutes into hours.
$hours += intval($minutes/60);
$minutes = $minutes%60;
$di = new DateInterval("PT{$hours}H{$minutes}M");
$totalMinutes = $di->h * 60 + $di->i;
if ($totalMinutes == 0) {
$valid['length'][0] = false;
$valid['length'][1] = _('Length needs to be greater than 0 minutes');
}
} else {
$valid['length'][0] = false;
$valid['length'][1] = _('Length should be of form "00h 00m"');
}
$url = $parameters["url"];
//simple validator that checks to make sure that the url starts with
//http(s),
//and that the domain is at least 1 letter long
$result = preg_match("/^(http|https):\/\/.+/", $url, $matches);
$mime = null;
$mediaUrl = null;
if ($result == 0) {
$valid['url'][0] = false;
$valid['url'][1] = _('URL should be of form "http://domain"');
} elseif (strlen($url) > 512) {
$valid['url'][0] = false;
$valid['url'][1] = _('URL should be 512 characters or less');
} else {
try {
list($mime, $content_length_found) = self::discoverStreamMime($url);
if (is_null($mime)) {
throw new Exception(_("No MIME type found for webstream."));
}
$mediaUrl = self::getMediaUrl($url, $mime, $content_length_found);
if (preg_match("/(x-mpegurl)|(xspf\+xml)|(pls\+xml)|(x-scpls)/", $mime)) {
list($mime, $content_length_found) = self::discoverStreamMime($mediaUrl);
}
} catch (Exception $e) {
$valid['url'][0] = false;
$valid['url'][1] = $e->getMessage();
}
}
$name = $parameters["name"];
if (strlen($name) == 0) {
$valid['name'][0] = false;
$valid['name'][1] = _('Webstream name cannot be empty');
}
$id = $parameters["id"];
return array($valid, $mime, $mediaUrl, $di);
}
public static function isValid($analysis)
{
foreach ($analysis as $k => $v) {
if ($v[0] === false) {
return false;
}
}
return true;
}
// TODO : Fix this interface
//This function should not be defined in the interface.
public function setMetadata($key, $val)
{
throw new Exception("Not implemented.");
}
public function setName($name)
{
$this->webstream->setDbName($name);
}
public function setLastPlayed($timestamp)
{
$this->webstream->setDbLPtime($timestamp);
$this->webstream->save();
}
private static function getUrlData($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// grab URL and pass it to the browser
//TODO: What if invalid url?
$content = curl_exec($ch);
// close cURL resource, and free up system resources
curl_close($ch);
return $content;
}
private static function getXspfUrl($url)
{
$content = self::getUrlData($url);
$dom = new DOMDocument;
//TODO: What if invalid xml?
$dom->loadXML($content);
$tracks = $dom->getElementsByTagName('track');
foreach ($tracks as $track) {
$locations = $track->getElementsByTagName('location');
foreach ($locations as $loc) {
return $loc->nodeValue;
}
}
throw new Exception(_("Could not parse XSPF playlist"));
}
private static function getPlsUrl($url)
{
$content = self::getUrlData($url);
$matches = array();
$numStreams = 0; //Number of streams explicitly listed in the PLS.
if (preg_match("/NumberOfEntries=([0-9]*)/", $content, $matches) !== FALSE) {
$numStreams = $matches[1];
}
//Find all the stream URLs in the playlist
if (preg_match_all("/File[0-9]*=(.*)/", $content, $matches) !== FALSE) {
//This array contains all the streams! If we need fallback stream URLs in the future,
//they're already in this array...
return $matches[1][0];
} else {
throw new Exception(_("Could not parse PLS playlist"));
}
}
private static function getM3uUrl($url)
{
$content = self::getUrlData($url);
//split into lines:
$delim = "\n";
if (strpos($content, "\r\n") !== false) {
$delim = "\r\n";
}
$lines = explode("$delim", $content);
#$lines = preg_split('/$\R?^/m', $content);
if (count($lines) > 0) {
return $lines[0];
}
throw new Exception(_("Could not parse M3U playlist"));
}
private static function getMediaUrl($url, $mime, $content_length_found)
{
if (preg_match("/x-mpegurl/", $mime)) {
$media_url = self::getM3uUrl($url);
} elseif (preg_match("/xspf\+xml/", $mime)) {
$media_url = self::getXspfUrl($url);
} elseif (preg_match("/pls\+xml/", $mime) || preg_match("/x-scpls/", $mime)) {
$media_url = self::getPlsUrl($url);
} elseif (preg_match("/(mpeg|ogg|audio\/aacp|audio\/aac)/", $mime)) {
if ($content_length_found) {
throw new Exception(_("Invalid webstream - This appears to be a file download."));
}
$media_url = $url;
} else {
throw new Exception(sprintf(_("Unrecognized stream type: %s"), $mime));
}
return $media_url;
}
/* PHP get_headers has an annoying property where if the passed in URL is
* a redirect, then it goes to the new URL, and returns headers from both
* requests. We only want the headers from the final request. Here's an
* example:
*
* 0 => "HTTP/1.1 302 Moved Temporarily",
* 1 => "X-Powered-By: Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 3.1.1 Java/Sun Microsystems Inc./1.6)",
* 2 => "Server: GlassFish Server Open Source Edition 3.1.1",
* 3 => "Location: http://3043.live.streamtheworld.com:80/SAM04AAC89_SC",
* 4 => "Content-Type: text/html;charset=ISO-8859-1",
* 5 => "Content-Language: en-US",
* 6 => "Content-Length: 202",
* 7 => "Date: Thu, 27 Dec 2012 21:52:59 GMT",
* 8 => "Connection: close",
* 9 => "HTTP/1.0 200 OK",
* 10 => "Expires: Thu, 01 Dec 2003 16:00:00 GMT",
* 11 => "Cache-Control: no-cache, must-revalidate",
* 12 => "Pragma: no-cache",
* 13 => "Content-Type: audio/aacp",
* 14 => "icy-br: 68",
* 15 => "Server: MediaGateway 3.2.1-04",
* */
private static function cleanHeaders($headers) {
//find the position of HTTP/1 200 OK
//
$position = 0;
foreach ($headers as $i => $v) {
if (preg_match("/^HTTP.*200 OK$/i", $v)) {
$position = $i;
break;
}
}
return array_slice($headers, $position);
}
private static function discoverStreamMime($url)
{
try {
$headers = @get_headers($url);
$mime = null;
$content_length_found = false;
if ($headers !== false) {
$headers = self::cleanHeaders($headers);
foreach ($headers as $h) {
if (preg_match("/^content-type:/i", $h)) {
list(, $value) = explode(":", $h, 2);
$mime = trim($value);
}
if (preg_match("/^content-length:/i", $h)) {
$content_length_found = true;
}
}
}
} catch (Exception $e) {
Logging::info("Invalid stream URL");
Logging::info($e->getMessage());
}
return array($mime, $content_length_found);
}
public static function save($parameters, $mime, $mediaUrl, $di)
{
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$id = $parameters['id'];
if ($id != -1) {
$webstream = CcWebstreamQuery::create()->findPK($id);
} else {
$webstream = new CcWebstream();
}
$webstream->setDbName($parameters["name"]);
$webstream->setDbDescription($parameters["description"]);
$webstream->setDbUrl($mediaUrl);
$dblength = $di->format("%H:%I");
$webstream->setDbLength($dblength);
$webstream->setDbCreatorId($userInfo->id);
$webstream->setDbUtime(new DateTime("now", new DateTimeZone('UTC')));
$webstream->setDbMtime(new DateTime("now", new DateTimeZone('UTC')));
$ws = new Application_Model_Webstream($webstream);
$webstream->setDbMime($mime);
$webstream->save();
return $webstream->getDbId();
}
/*
* method is not used, webstreams aren't currently kept track of for isScheduled.
*/
public static function setIsScheduled($p_webstreamId, $p_status) {
$webstream = CcWebstreamQuery::create()->findPK($p_webstreamId);
$updateIsScheduled = false;
if (isset($webstream) && !in_array($p_webstreamId,
Application_Model_Schedule::getAllFutureScheduledWebstreams())) {
//$webstream->setDbIsScheduled($p_status)->save();
$updateIsScheduled = true;
}
return $updateIsScheduled;
}
}
class WebstreamNoPermissionException extends Exception {}

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_access' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcAccess extends BaseCcAccess {
} // CcAccess

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_access' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcAccessPeer extends BaseCcAccessPeer {
} // CcAccessPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_access' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcAccessQuery extends BaseCcAccessQuery {
} // CcAccessQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_backup' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcBackup extends BaseCcBackup {
} // CcBackup

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_backup' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcBackupPeer extends BaseCcBackupPeer {
} // CcBackupPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_backup' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcBackupQuery extends BaseCcBackupQuery {
} // CcBackupQuery

View file

@ -0,0 +1,106 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_block' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcBlock extends BaseCcBlock {
/**
* Get the [optionally formatted] temporal [utime] column value.
*
*
* @param string $format The date/time format string (either date()-style or strftime()-style).
* If format is NULL, then the raw DateTime object will be returned.
* @return mixed Formatted date/time value as string or DateTime object (if format is NULL), NULL if column is NULL
* @throws PropelException - if unable to parse/validate the date/time value.
*/
public function getDbUtime($format = 'Y-m-d H:i:s')
{
if ($this->utime === null) {
return null;
}
try {
$dt = new DateTime($this->utime, new DateTimeZone("UTC"));
} catch (Exception $x) {
throw new PropelException("Internally stored date/time/timestamp value could not be converted to DateTime: " . var_export($this->utime, true), $x);
}
if ($format === null) {
// Because propel.useDateTimeClass is TRUE, we return a DateTime object.
return $dt;
} elseif (strpos($format, '%') !== false) {
return strftime($format, $dt->format('U'));
} else {
return $dt->format($format);
}
}
/**
* Get the [optionally formatted] temporal [mtime] column value.
*
*
* @param string $format The date/time format string (either date()-style or strftime()-style).
* If format is NULL, then the raw DateTime object will be returned.
* @return mixed Formatted date/time value as string or DateTime object (if format is NULL), NULL if column is NULL
* @throws PropelException - if unable to parse/validate the date/time value.
*/
public function getDbMtime($format = 'Y-m-d H:i:s')
{
if ($this->mtime === null) {
return null;
}
try {
$dt = new DateTime($this->mtime, new DateTimeZone("UTC"));
} catch (Exception $x) {
throw new PropelException("Internally stored date/time/timestamp value could not be converted to DateTime: " . var_export($this->mtime, true), $x);
}
if ($format === null) {
// Because propel.useDateTimeClass is TRUE, we return a DateTime object.
return $dt;
} elseif (strpos($format, '%') !== false) {
return strftime($format, $dt->format('U'));
} else {
return $dt->format($format);
}
}
/**
* Computes the value of the aggregate column length
* Overridden to provide a default of 00:00:00 if the block is empty.
*
* @param PropelPDO $con A connection object
*
* @return mixed The scalar result from the aggregate query
*/
public function computeDbLength(PropelPDO $con)
{
$sql = <<<SQL
SELECT SUM(cliplength) FROM cc_blockcontents as bc
JOIN cc_files as f ON bc.file_id = f.id
WHERE BLOCK_ID = :b1
AND f.file_exists = true
SQL;
$stmt = $con->prepare($sql);
$stmt->bindValue(':b1', $this->getDbId());
$stmt->execute();
$length = $stmt->fetchColumn();
if (is_null($length)) {
$length = "00:00:00";
}
return $length;
}
} // CcBlock

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_block' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcBlockPeer extends BaseCcBlockPeer {
} // CcBlockPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_block' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcBlockQuery extends BaseCcBlockQuery {
} // CcBlockQuery

View file

@ -0,0 +1,113 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_blockcontents' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcBlockcontents extends BaseCcBlockcontents {
/**
* Get the [optionally formatted] temporal [fadein] column value.
*
* @return mixed Formatted date/time value as string or DateTime object (if format is NULL), NULL if column is NULL
* @throws PropelException - if unable to parse/validate the date/time value.
*/
public function getDbFadein($format = "s.u")
{
return parent::getDbFadein($format);
}
/**
* Get the [optionally formatted] temporal [fadein] column value.
*
* @return mixed Formatted date/time value as string or DateTime object (if format is NULL), NULL if column is NULL
* @throws PropelException - if unable to parse/validate the date/time value.
*/
public function getDbFadeout($format = "s.u")
{
return parent::getDbFadeout($format);
}
/**
*
* @param String in format SS.uuuuuu, Datetime, or DateTime accepted string.
*
* @return CcBlockcontents The current object (for fluent API support)
*/
public function setDbFadein($v)
{
$microsecond = 0;
if ($v instanceof DateTime) {
$dt = $v;
}
else if (preg_match('/^[0-9]{1,2}(\.\d{1,6})?$/', $v)) {
// in php 5.3.2 createFromFormat() with "u" is not supported(bug)
// Hence we need to do parsing.
$info = explode('.', $v);
$microsecond = $info[1];
$dt = DateTime::createFromFormat("s", $info[0]);
}
else {
try {
$dt = new DateTime($v);
} catch (Exception $x) {
throw new PropelException('Error parsing date/time value: ' . var_export($v, true), $x);
}
}
if ($microsecond == 0) {
$this->fadein = $dt->format('H:i:s.u');
} else {
$this->fadein = $dt->format('H:i:s').".".$microsecond;
}
$this->modifiedColumns[] = CcBlockcontentsPeer::FADEIN;
return $this;
} // setDbFadein()
/**
*
* @param String in format SS.uuuuuu, Datetime, or DateTime accepted string.
*
* @return CcBlockcontents The current object (for fluent API support)
*/
public function setDbFadeout($v)
{
$microsecond = 0;
if ($v instanceof DateTime) {
$dt = $v;
}
else if (preg_match('/^[0-9]{1,2}(\.\d{1,6})?$/', $v)) {
// in php 5.3.2 createFromFormat() with "u" is not supported(bug)
// Hence we need to do parsing.
$info = explode('.', $v);
$microsecond = $info[1];
$dt = DateTime::createFromFormat("s", $info[0]);
}
else {
try {
$dt = new DateTime($v);
} catch (Exception $x) {
throw new PropelException('Error parsing date/time value: ' . var_export($v, true), $x);
}
}
if ($microsecond == 0) {
$this->fadeout = $dt->format('H:i:s.u');
} else {
$this->fadeout = $dt->format('H:i:s').".".$microsecond;
}
$this->modifiedColumns[] = CcBlockcontentsPeer::FADEOUT;
return $this;
} // setDbFadeout()
} // CcBlockcontents

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_blockcontents' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcBlockcontentsPeer extends BaseCcBlockcontentsPeer {
} // CcBlockcontentsPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_blockcontents' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcBlockcontentsQuery extends BaseCcBlockcontentsQuery {
} // CcBlockcontentsQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_blockcriteria' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcBlockcriteria extends BaseCcBlockcriteria {
} // CcBlockcriteria

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_blockcriteria' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcBlockcriteriaPeer extends BaseCcBlockcriteriaPeer {
} // CcBlockcriteriaPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_blockcriteria' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcBlockcriteriaQuery extends BaseCcBlockcriteriaQuery {
} // CcBlockcriteriaQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_country' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcCountry extends BaseCcCountry {
} // CcCountry

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_country' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcCountryPeer extends BaseCcCountryPeer {
} // CcCountryPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_country' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcCountryQuery extends BaseCcCountryQuery {
} // CcCountryQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_file_tag' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcFileTag extends BaseCcFileTag {
} // CcFileTag

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_file_tag' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcFileTagPeer extends BaseCcFileTagPeer {
} // CcFileTagPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_file_tag' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcFileTagQuery extends BaseCcFileTagQuery {
} // CcFileTagQuery

View file

@ -0,0 +1,556 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_files' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.campcaster
*/
class InvalidMetadataException extends Exception
{
}
class LibreTimeFileNotFoundException extends Exception
{
}
class OverDiskQuotaException extends Exception
{
}
class CcFiles extends BaseCcFiles {
const MUSIC_DIRS_STOR_PK = 1;
const IMPORT_STATUS_SUCCESS = 0;
const IMPORT_STATUS_PENDING = 1;
const IMPORT_STATUS_FAILED = 2;
//fields that are not modifiable via our RESTful API
private static $blackList = array(
'id',
'directory',
'filepath',
'file_exists',
'mtime',
'utime',
'lptime',
'silan_check',
'is_scheduled',
'is_playlist'
);
//fields we should never expose through our RESTful API
private static $privateFields = array(
'file_exists',
'silan_check',
'is_scheduled',
'is_playlist'
);
/**
* Retrieve a sanitized version of the file metadata, suitable for public access.
* @param $fileId
*/
public static function getSanitizedFileById($fileId)
{
$file = CcFilesQuery::create()->findPk($fileId);
if ($file) {
return CcFiles::sanitizeResponse($file);
} else {
throw new LibreTimeFileNotFoundException();
}
}
/** Used to create a CcFiles object from an array containing metadata and a file uploaded by POST.
* This is used by our Media REST API!
* @param $fileArray An array containing metadata for a CcFiles object.
*
* @return object the sanitized response
* @throws Exception
*/
public static function createFromUpload($fileArray)
{
if (Application_Model_Systemstatus::isDiskOverQuota()) {
throw new OverDiskQuotaException();
}
/* If full_path is set, the post request came from ftp.
* Users are allowed to upload folders via ftp. If this is the case
* we need to include the folder name with the file name, otherwise
* files won't get removed from the organize folder.
*/
//Extract the original filename, which we set as the temporary title for the track
//until it's finished being processed by the analyzer.
$originalFilename = $fileArray['file']['name'];
$tempFilePath = $fileArray['file']['tmp_name'];
try {
return self::createAndImport($fileArray, $tempFilePath, $originalFilename);
} catch (Exception $e) {
if (file_exists($tempFilePath)) {
unlink($tempFilePath);
}
throw $e;
}
}
/** Import a music file to the library from a local file on disk (something pre-existing).
* This function allows you to copy a file rather than move it, which is useful for importing
* static music files (like sample tracks).
* @param string $filePath The full path to the audio file to import.
* @param bool $copyFile True if you want to just copy the false, false if you want to move it (default false)
* @throws Exception
*/
public static function createFromLocalFile($fileArray, $filePath, $copyFile=false)
{
$info = pathinfo($filePath);
$fileName = basename($filePath).'.'.$info['extension'];
self::createAndImport($fileArray, $filePath, $fileName, $copyFile);
}
/** Create a new CcFiles object/row and import a file for it.
* You shouldn't call this directly. Either use createFromUpload() or createFromLocalFile().
* @param array $fileArray Any metadata to pre-fill for the audio file
* @param string $filePath The full path to the audio file to import
* @param string $originalFilename
* @param bool $copyFile
* @return mixed
* @throws Exception
* @throws PropelException
*/
private static function createAndImport($fileArray, $filePath, $originalFilename, $copyFile=false)
{
$file = new CcFiles();
try
{
//Only accept files with a file extension that we support.
// Let the analyzer do the heavy lifting in terms of mime verification and playability
$fileExtension = pathinfo($originalFilename, PATHINFO_EXTENSION);
if (!in_array(strtolower($fileExtension), array_values(FileDataHelper::getAudioMimeTypeArray()))) {
throw new Exception("Bad file extension.");
}
$fileArray = self::removeBlacklistedFields($fileArray);
self::validateFileArray($fileArray);
$storDir = Application_Model_MusicDir::getStorDir();
$importedStorageDir = $storDir->getDirectory() . "imported/" . self::getOwnerId() . "/";
$importedDbPath = "imported/" . self::getOwnerId() . "/";
$artwork = FileDataHelper::saveArtworkData($filePath, $originalFilename, $importedStorageDir, $importedDbPath);
$trackType = FileDataHelper::saveTrackType();
$file->fromArray($fileArray);
$file->setDbOwnerId(self::getOwnerId());
$now = new DateTime("now", new DateTimeZone("UTC"));
$file->setDbTrackTitle($originalFilename);
$file->setDbArtwork($artwork);
$file->setDbTrackType($trackType);
$file->setDbUtime($now);
$file->setDbHidden(true);
$file->save();
$callbackUrl = Application_Common_HTTPHelper::getStationUrl() . "/rest/media/" . $file->getPrimaryKey();
Application_Service_MediaService::importFileToLibrary($callbackUrl, $filePath,
$originalFilename, self::getOwnerId(), $copyFile);
return CcFiles::sanitizeResponse($file);
} catch (Exception $e) {
$file->setDbImportStatus(self::IMPORT_STATUS_FAILED);
$file->setDbHidden(true);
$file->save();
throw $e;
}
}
/** Update a file with metadata specified in an array.
* @param $fileId string The ID of the file to update in the DB.
* @param $fileArray array An associative array containing metadata. Replaces those fields if they exist.
* @return array A sanitized version of the file metadata array.
* @throws Exception
* @throws LibreTimeFileNotFoundException
* @throws PropelException
*/
public static function updateFromArray($fileId, $fileArray)
{
$file = CcFilesQuery::create()->findPk($fileId);
$fileArray = self::removeBlacklistedFields($fileArray);
$fileArray = self::stripTimeStampFromYearTag($fileArray);
try {
self::validateFileArray($fileArray);
if ($file && isset($fileArray["resource_id"])) {
$file->fromArray($fileArray, BasePeer::TYPE_FIELDNAME);
//store the original filename
$file->setDbFilepath($fileArray["filename"]);
$fileSizeBytes = $fileArray["filesize"];
if (!isset($fileSizeBytes) || $fileSizeBytes === false) {
throw new LibreTimeFileNotFoundException("Invalid filesize for $fileId");
}
$cloudFile = new CloudFile();
$cloudFile->setStorageBackend($fileArray["storage_backend"]);
$cloudFile->setResourceId($fileArray["resource_id"]);
$cloudFile->setCcFiles($file);
$cloudFile->save();
Application_Model_Preference::updateDiskUsage($fileSizeBytes);
} else if ($file) {
// Since we check for this value when deleting files, set it first
$file->setDbDirectory(self::MUSIC_DIRS_STOR_PK);
$file->fromArray($fileArray, BasePeer::TYPE_FIELDNAME);
//Our RESTful API takes "full_path" as a field, which we then split and translate to match
//our internal schema. Internally, file path is stored relative to a directory, with the directory
//as a foreign key to cc_music_dirs.
if (isset($fileArray["full_path"])) {
$fileSizeBytes = filesize($fileArray["full_path"]);
if (!isset($fileSizeBytes) || $fileSizeBytes === false) {
throw new LibreTimeFileNotFoundException("Invalid filesize for $fileId");
}
Application_Model_Preference::updateDiskUsage($fileSizeBytes);
$fullPath = $fileArray["full_path"];
$storDir = Application_Model_MusicDir::getStorDir()->getDirectory();
$pos = strpos($fullPath, $storDir);
if ($pos !== FALSE) {
assert($pos == 0); //Path must start with the stor directory path
$filePathRelativeToStor = substr($fullPath, strlen($storDir));
$file->setDbFilepath($filePathRelativeToStor);
}
}
} else {
throw new LibreTimeFileNotFoundException();
}
$now = new DateTime("now", new DateTimeZone("UTC"));
$file->setDbMtime($now);
$file->save();
}
catch (LibreTimeFileNotFoundException $e)
{
$file->setDbImportStatus(self::IMPORT_STATUS_FAILED);
$file->setDbHidden(true);
$file->save();
throw $e;
}
return CcFiles::sanitizeResponse($file);
}
/** Delete a file from the database and disk (or cloud).
* @param $id The file ID
* @throws DeleteScheduledFileException
* @throws Exception
* @throws FileNoPermissionException
* @throws LibreTimeFileNotFoundException
* @throws PropelException
*/
public static function deleteById($id)
{
$file = CcFilesQuery::create()->findPk($id);
if ($file) {
$con = Propel::getConnection();
$storedFile = Application_Model_StoredFile::RecallById($id, $con);
$storedFile->delete();
} else {
throw new LibreTimeFileNotFoundException();
}
}
private static function validateFileArray(&$fileArray)
{
// Sanitize any wildly incorrect metadata before it goes to be validated
FileDataHelper::sanitizeData($fileArray);
// EditAudioMD form is used here for validation
$fileForm = new Application_Form_EditAudioMD();
$fileForm->startForm(0); //The file ID doesn't matter here
$fileForm->populate($fileArray);
/*
* Here we are truncating metadata of any characters greater than the
* max string length set in the database. In the rare case a track's
* genre is more than 64 chars, for example, we don't want to reject
* tracks for that reason
*/
foreach($fileArray as $tag => &$value) {
if ($fileForm->getElement($tag)) {
$stringLengthValidator = $fileForm->getElement($tag)->getValidator('StringLength');
//$stringLengthValidator will be false if the StringLength validator doesn't exist on the current element
//in which case we don't have to truncate the extra characters
if ($stringLengthValidator) {
$value = substr($value, 0, $stringLengthValidator->getMax());
}
$value = self::stripInvalidUtf8Characters($value);
}
}
if (!$fileForm->isValidPartial($fileArray)) {
$errors = $fileForm->getErrors();
$messages = $fileForm->getMessages();
Logging::error($messages);
throw new Exception("Data validation failed: $errors - $messages");
}
return true;
}
public function getCueLength()
{
$cuein = $this->getDbCuein();
$cueout = $this->getDbCueout();
$cueinSec = Application_Common_DateHelper::calculateLengthInSeconds($cuein);
$cueoutSec = Application_Common_DateHelper::calculateLengthInSeconds($cueout);
$lengthSec = bcsub($cueoutSec, $cueinSec, 6);
$length = Application_Common_DateHelper::secondsToPlaylistTime($lengthSec);
return $length;
}
public function setDbTrackNumber($v)
{
$max = pow(2, 31)-1;
$v = ($v > $max) ? $max : $v;
return parent::setDbTrackNumber($v);
}
// returns true if the file exists and is not hidden
public function visible() {
return $this->getDbFileExists() && !$this->getDbHidden();
}
public function reassignTo($user)
{
$this->setDbOwnerId( $user->getDbId() );
$this->save();
}
/**
*
* Strips out the private fields we do not want to send back in API responses
*
* @param CcFiles $file a CcFiles object
*
* @return array
*/
//TODO: rename this function?
public static function sanitizeResponse($file) {
$response = $file->toArray(BasePeer::TYPE_FIELDNAME);
foreach (self::$privateFields as $key) {
unset($response[$key]);
}
return $response;
}
/**
* Returns the file size in bytes.
*/
public function getFileSize()
{
return $this->getDbFilesize();
}
public function getFilename()
{
$info = pathinfo($this->getAbsoluteFilePath());
//filename doesn't contain the extension because PHP is awful
$mime = $this->getDbMime();
$extension = FileDataHelper::getFileExtensionFromMime($mime);
return $info['filename'] . $extension;
}
/**
* Returns the file's absolute file path stored on disk.
*/
public function getURLsForTrackPreviewOrDownload()
{
return array($this->getAbsoluteFilePath());
}
/**
* Returns the file's absolute file path stored on disk.
*/
public function getAbsoluteFilePath()
{
$music_dir = Application_Model_MusicDir::getDirByPK($this->getDbDirectory());
if (!$music_dir) {
throw new Exception("Invalid music_dir for file " . $this->getDbId() . " in database.");
}
$directory = $music_dir->getDirectory();
$filepath = $this->getDbFilepath();
return Application_Common_OsPath::join($directory, $filepath);
}
/**
* Returns the artwork's absolute file path stored on disk.
*/
public function getAbsoluteArtworkPath()
{
$music_dir = Application_Model_MusicDir::getDirByPK($this->getDbDirectory());
if (!$music_dir) {
throw new Exception("Invalid music_dir for file " . $this->getDbId() . " in database.");
}
$directory = $music_dir->getDirectory();
$filepath = $this->getDbArtwork();
return Application_Common_OsPath::join($directory, $filepath);
}
/**
*
* Strips out fields from incoming request data that should never be modified
* from outside of Airtime
* @param array $data
*/
private static function removeBlacklistedFields($data)
{
foreach (self::$blackList as $key) {
unset($data[$key]);
}
return $data;
}
private static function getOwnerId()
{
try {
if (Zend_Auth::getInstance()->hasIdentity()) {
$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());
}
}
/*
* It's possible that the year tag will be a timestamp but Airtime doesn't support this.
* The year field in cc_files can only be 16 chars max.
*
* This functions strips the year field of it's timestamp, if one, and leaves just the year
*/
private static function stripTimeStampFromYearTag($metadata)
{
if (isset($metadata["year"])) {
if (preg_match("/^(\d{4})-(\d{2})-(\d{2})(?:\s+(\d{2}):(\d{2}):(\d{2}))?$/", $metadata["year"])) {
$metadata["year"] = substr($metadata["year"], 0, 4);
}
}
return $metadata;
}
private static function stripInvalidUtf8Characters($string)
{
//Remove invalid UTF-8 characters
//reject overly long 2 byte sequences, as well as characters above U+10000 and replace with ?
$string = preg_replace('/[\x00-\x08\x10\x0B\x0C\x0E-\x19\x7F]'.
'|[\x00-\x7F][\x80-\xBF]+'.
'|([\xC0\xC1]|[\xF0-\xFF])[\x80-\xBF]*'.
'|[\xC2-\xDF]((?![\x80-\xBF])|[\x80-\xBF]{2,})'.
'|[\xE0-\xEF](([\x80-\xBF](?![\x80-\xBF]))|(?![\x80-\xBF]{2})|[\x80-\xBF]{3,})/S',
'?', $string );
//reject overly long 3 byte sequences and UTF-16 surrogates and replace with ?
$string = preg_replace('/\xE0[\x80-\x9F][\x80-\xBF]'.
'|\xED[\xA0-\xBF][\x80-\xBF]/S','?', $string );
//Do a final encoding conversion to
$string = mb_convert_encoding($string, 'UTF-8', 'UTF-8');
return $string;
}
private function removeEmptySubFolders($path)
{
exec("find $path -empty -type d -delete");
}
/**
* Checks if the file is a regular file that can be previewed and downloaded.
*/
public function isValidPhysicalFile()
{
return is_file($this->getAbsoluteFilePath());
}
/**
*
* Deletes the file from the stor directory on disk.
*/
public function deletePhysicalFile()
{
$filepath = $this->getAbsoluteFilePath();
$artworkpath = $this->getAbsoluteArtworkPath();
if (file_exists($filepath)) {
unlink($filepath);
// also delete related images (dataURI and jpeg files)
foreach (glob("$artworkpath*", GLOB_NOSORT) as $filename) {
unlink($filename);
}
unlink($artworkpath);
} else {
throw new Exception("Could not locate file ".$filepath);
}
}
/**
*
* This function refers to the file's Amazon S3 resource id.
* Returns null because cc_files are stored on local disk.
*/
public function getResourceId()
{
return null;
}
public function getCcFileId()
{
return $this->id;
}
} // CcFiles

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_files' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcFilesPeer extends BaseCcFilesPeer {
} // CcFilesPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_files' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcFilesQuery extends BaseCcFilesQuery {
} // CcFilesQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_listener_count' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcListenerCount extends BaseCcListenerCount {
} // CcListenerCount

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_listener_count' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcListenerCountPeer extends BaseCcListenerCountPeer {
} // CcListenerCountPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_listener_count' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcListenerCountQuery extends BaseCcListenerCountQuery {
} // CcListenerCountQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_live_log' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcLiveLog extends BaseCcLiveLog {
} // CcLiveLog

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_live_log' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcLiveLogPeer extends BaseCcLiveLogPeer {
} // CcLiveLogPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_live_log' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcLiveLogQuery extends BaseCcLiveLogQuery {
} // CcLiveLogQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_locale' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcLocale extends BaseCcLocale {
} // CcLocale

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_locale' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcLocalePeer extends BaseCcLocalePeer {
} // CcLocalePeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_locale' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcLocaleQuery extends BaseCcLocaleQuery {
} // CcLocaleQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_login_attempts' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcLoginAttempts extends BaseCcLoginAttempts {
} // CcLoginAttempts

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_login_attempts' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcLoginAttemptsPeer extends BaseCcLoginAttemptsPeer {
} // CcLoginAttemptsPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_login_attempts' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcLoginAttemptsQuery extends BaseCcLoginAttemptsQuery {
} // CcLoginAttemptsQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_mount_name' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcMountName extends BaseCcMountName {
} // CcMountName

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_mount_name' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcMountNamePeer extends BaseCcMountNamePeer {
} // CcMountNamePeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_mount_name' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcMountNameQuery extends BaseCcMountNameQuery {
} // CcMountNameQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_music_dirs' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcMusicDirs extends BaseCcMusicDirs {
} // CcMusicDirs

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_music_dirs' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcMusicDirsPeer extends BaseCcMusicDirsPeer {
} // CcMusicDirsPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_music_dirs' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcMusicDirsQuery extends BaseCcMusicDirsQuery {
} // CcMusicDirsQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_perms' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPerms extends BaseCcPerms {
} // CcPerms

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_perms' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPermsPeer extends BaseCcPermsPeer {
} // CcPermsPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_perms' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPermsQuery extends BaseCcPermsQuery {
} // CcPermsQuery

View file

@ -0,0 +1,107 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_playlist' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.campcaster
*/
class CcPlaylist extends BaseCcPlaylist {
/**
* Get the [optionally formatted] temporal [utime] column value.
*
*
* @param string $format The date/time format string (either date()-style or strftime()-style).
* If format is NULL, then the raw DateTime object will be returned.
* @return mixed Formatted date/time value as string or DateTime object (if format is NULL), NULL if column is NULL
* @throws PropelException - if unable to parse/validate the date/time value.
*/
public function getDbUtime($format = 'Y-m-d H:i:s')
{
if ($this->utime === null) {
return null;
}
try {
$dt = new DateTime($this->utime, new DateTimeZone("UTC"));
} catch (Exception $x) {
throw new PropelException("Internally stored date/time/timestamp value could not be converted to DateTime: " . var_export($this->utime, true), $x);
}
if ($format === null) {
// Because propel.useDateTimeClass is TRUE, we return a DateTime object.
return $dt;
} elseif (strpos($format, '%') !== false) {
return strftime($format, $dt->format('U'));
} else {
return $dt->format($format);
}
}
/**
* Get the [optionally formatted] temporal [mtime] column value.
*
*
* @param string $format The date/time format string (either date()-style or strftime()-style).
* If format is NULL, then the raw DateTime object will be returned.
* @return mixed Formatted date/time value as string or DateTime object (if format is NULL), NULL if column is NULL
* @throws PropelException - if unable to parse/validate the date/time value.
*/
public function getDbMtime($format = 'Y-m-d H:i:s')
{
if ($this->mtime === null) {
return null;
}
try {
$dt = new DateTime($this->mtime, new DateTimeZone("UTC"));
} catch (Exception $x) {
throw new PropelException("Internally stored date/time/timestamp value could not be converted to DateTime: " . var_export($this->mtime, true), $x);
}
if ($format === null) {
// Because propel.useDateTimeClass is TRUE, we return a DateTime object.
return $dt;
} elseif (strpos($format, '%') !== false) {
return strftime($format, $dt->format('U'));
} else {
return $dt->format($format);
}
}
/**
* Computes the value of the aggregate column length
* Overridden to provide a default of 00:00:00 if the playlist is empty.
*
* @param PropelPDO $con A connection object
*
* @return mixed The scalar result from the aggregate query
*/
public function computeDbLength(PropelPDO $con)
{
$sql = <<<SQL
SELECT SUM(cliplength) FROM cc_playlistcontents as pc
LEFT JOIN cc_files as f ON pc.file_id = f.id
WHERE PLAYLIST_ID = :p1
AND (f.file_exists is NUll or f.file_exists = true)
SQL;
$stmt = $con->prepare($sql);
$stmt->bindValue(':p1', $this->getDbId());
$stmt->execute();
$length = $stmt->fetchColumn();
if (is_null($length)) {
$length = "00:00:00";
}
return $length;
}
} // CcPlaylist

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_playlist' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlaylistPeer extends BaseCcPlaylistPeer {
} // CcPlaylistPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_playlist' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlaylistQuery extends BaseCcPlaylistQuery {
} // CcPlaylistQuery

View file

@ -0,0 +1,118 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_playlistcontents' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.campcaster
*/
class CcPlaylistcontents extends BaseCcPlaylistcontents {
/**
* Get the [optionally formatted] temporal [fadein] column value.
*
* @return mixed Formatted date/time value as string or DateTime object (if format is NULL), NULL if column is NULL
* @throws PropelException - if unable to parse/validate the date/time value.
*/
public function getDbFadein($format = "s.u")
{
return parent::getDbFadein($format);
}
/**
* Get the [optionally formatted] temporal [fadein] column value.
*
* @return mixed Formatted date/time value as string or DateTime object (if format is NULL), NULL if column is NULL
* @throws PropelException - if unable to parse/validate the date/time value.
*/
public function getDbFadeout($format = "s.u")
{
return parent::getDbFadeout($format);
}
/**
*
* @param String in format SS.uuuuuu, Datetime, or DateTime accepted string.
*
* @return CcPlaylistcontents The current object (for fluent API support)
*/
public function setDbFadein($v)
{
$microsecond = 0;
if ($v instanceof DateTime) {
$dt = $v;
}
else if (preg_match('/^[0-9]{1,2}(\.\d{1,6})?$/', $v)) {
// in php 5.3.2 createFromFormat() with "u" is not supported(bug)
// Hence we need to do parsing.
$info = explode('.', $v);
$microsecond = $info[1];
$dt = DateTime::createFromFormat("s", $info[0]);
}
else {
try {
$dt = new DateTime($v);
} catch (Exception $x) {
throw new PropelException('Error parsing date/time value: ' . var_export($v, true), $x);
}
}
if ($microsecond == 0) {
$this->fadein = $dt->format('H:i:s.u');
} else {
$this->fadein = $dt->format('H:i:s').".".$microsecond;
}
$this->modifiedColumns[] = CcPlaylistcontentsPeer::FADEIN;
$this->save();
//FIXME(XXX): Propel silently drops the milliseconds from our fadein time. :(
return $this;
} // setDbFadein()
/**
*
* @param String in format SS.uuuuuu, Datetime, or DateTime accepted string.
*
* @return CcPlaylistcontents The current object (for fluent API support)
*/
public function setDbFadeout($v)
{
$microsecond = 0;
if ($v instanceof DateTime) {
$dt = $v;
}
else if (preg_match('/^[0-9]{1,2}(\.\d{1,6})?$/', $v)) {
// in php 5.3.2 createFromFormat() with "u" is not supported(bug)
// Hence we need to do parsing.
$info = explode('.', $v);
$microsecond = $info[1];
$dt = DateTime::createFromFormat("s", $info[0]);
}
else {
try {
$dt = new DateTime($v);
} catch (Exception $x) {
throw new PropelException('Error parsing date/time value: ' . var_export($v, true), $x);
}
}
if ($microsecond == 0) {
$this->fadeout = $dt->format('H:i:s.u');
} else {
$this->fadeout = $dt->format('H:i:s').".".$microsecond;
}
$this->modifiedColumns[] = CcPlaylistcontentsPeer::FADEOUT;
$this->save();
//FIXME(XXX): Propel silently drops the milliseconds from our fadeout time. :(
return $this;
} // setDbFadeout()
} // CcPlaylistcontents

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_playlistcontents' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlaylistcontentsPeer extends BaseCcPlaylistcontentsPeer {
} // CcPlaylistcontentsPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_playlistcontents' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlaylistcontentsQuery extends BaseCcPlaylistcontentsQuery {
} // CcPlaylistcontentsQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_playlistcriteria' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlaylistcriteria extends BaseCcPlaylistcriteria {
} // CcPlaylistcriteria

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_playlistcriteria' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlaylistcriteriaPeer extends BaseCcPlaylistcriteriaPeer {
} // CcPlaylistcriteriaPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_playlistcriteria' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlaylistcriteriaQuery extends BaseCcPlaylistcriteriaQuery {
} // CcPlaylistcriteriaQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_playout_history' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlayoutHistory extends BaseCcPlayoutHistory {
} // CcPlayoutHistory

View file

@ -0,0 +1,34 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_playout_history_metadata' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlayoutHistoryMetaData extends BaseCcPlayoutHistoryMetaData {
/**
* Set the value of [value] column.
*
* @param string $v new value
* @return CcPlayoutHistoryMetaData The current object (for fluent API support)
*/
public function setDbValue($v)
{
//make sure the metadata isn't longer than the DB field.
$v = substr($v, 0, 128);
parent::setDbValue($v);
return $this;
} // setDbValue()
} // CcPlayoutHistoryMetaData

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_playout_history_metadata' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlayoutHistoryMetaDataPeer extends BaseCcPlayoutHistoryMetaDataPeer {
} // CcPlayoutHistoryMetaDataPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_playout_history_metadata' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlayoutHistoryMetaDataQuery extends BaseCcPlayoutHistoryMetaDataQuery {
} // CcPlayoutHistoryMetaDataQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_playout_history' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlayoutHistoryPeer extends BaseCcPlayoutHistoryPeer {
} // CcPlayoutHistoryPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_playout_history' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlayoutHistoryQuery extends BaseCcPlayoutHistoryQuery {
} // CcPlayoutHistoryQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_playout_history_template' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlayoutHistoryTemplate extends BaseCcPlayoutHistoryTemplate {
} // CcPlayoutHistoryTemplate

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_playout_history_template_field' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlayoutHistoryTemplateField extends BaseCcPlayoutHistoryTemplateField {
} // CcPlayoutHistoryTemplateField

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_playout_history_template_field' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlayoutHistoryTemplateFieldPeer extends BaseCcPlayoutHistoryTemplateFieldPeer {
} // CcPlayoutHistoryTemplateFieldPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_playout_history_template_field' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlayoutHistoryTemplateFieldQuery extends BaseCcPlayoutHistoryTemplateFieldQuery {
} // CcPlayoutHistoryTemplateFieldQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_playout_history_template' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlayoutHistoryTemplatePeer extends BaseCcPlayoutHistoryTemplatePeer {
} // CcPlayoutHistoryTemplatePeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_playout_history_template' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPlayoutHistoryTemplateQuery extends BaseCcPlayoutHistoryTemplateQuery {
} // CcPlayoutHistoryTemplateQuery

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_pref' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPref extends BaseCcPref {
} // CcPref

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_pref' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPrefPeer extends BaseCcPrefPeer {
} // CcPrefPeer

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_pref' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcPrefQuery extends BaseCcPrefQuery {
} // CcPrefQuery

View file

@ -0,0 +1,262 @@
<?php
/**
* Skeleton subclass for representing a row from the 'cc_schedule' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcSchedule extends BaseCcSchedule {
/**
* Get the [optionally formatted] temporal [starts] column value.
*
*
* @param string $format The date/time format string (either date()-style or strftime()-style).
* If format is NULL, then the raw DateTime object will be returned.
* @return mixed Formatted date/time value as string or DateTime object (if format is NULL), NULL if column is NULL
* @throws PropelException - if unable to parse/validate the date/time value.
*/
public function getDbStarts($format = 'Y-m-d H:i:s.u')
{
if ($this->starts === null) {
return null;
}
try {
$dt = new DateTime($this->starts, new DateTimeZone("UTC"));
} catch (Exception $x) {
throw new PropelException("Internally stored date/time/timestamp value could not be converted to DateTime: " . var_export($this->starts, true), $x);
}
if ($format === null) {
// Because propel.useDateTimeClass is TRUE, we return a DateTime object.
return $dt;
} elseif (strpos($format, '%') !== false) {
return strftime($format, $dt->format('U'));
} else {
return $dt->format($format);
}
}
/**
* Get the [optionally formatted] temporal [ends] column value.
*
*
* @param string $format The date/time format string (either date()-style or strftime()-style).
* If format is NULL, then the raw DateTime object will be returned.
* @return mixed Formatted date/time value as string or DateTime object (if format is NULL), NULL if column is NULL
* @throws PropelException - if unable to parse/validate the date/time value.
*/
public function getDbEnds($format = 'Y-m-d H:i:s.u')
{
if ($this->ends === null) {
return null;
}
try {
$dt = new DateTime($this->ends, new DateTimeZone("UTC"));
} catch (Exception $x) {
throw new PropelException("Internally stored date/time/timestamp value could not be converted to DateTime: " . var_export($this->ends, true), $x);
}
if ($format === null) {
// Because propel.useDateTimeClass is TRUE, we return a DateTime object.
return $dt;
} elseif (strpos($format, '%') !== false) {
return strftime($format, $dt->format('U'));
} else {
return $dt->format($format);
}
}
/**
* Get the [optionally formatted] temporal [fadein] column value.
*
* @return mixed Formatted date/time value as string or DateTime object (if format is NULL), NULL if column is NULL
* @throws PropelException - if unable to parse/validate the date/time value.
*/
public function getDbFadeIn($format = "s.u")
{
return parent::getDbFadein($format);
}
/**
* Get the [optionally formatted] temporal [fadein] column value.
*
* @return mixed Formatted date/time value as string or DateTime object (if format is NULL), NULL if column is NULL
* @throws PropelException - if unable to parse/validate the date/time value.
*/
public function getDbFadeOut($format = "s.u")
{
return parent::getDbFadeout($format);
}
/**
*
* @param String in format SS.uuuuuu, Datetime, or DateTime accepted string.
*
* @return CcPlaylistcontents The current object (for fluent API support)
*/
public function setDbFadeIn($v)
{
$microsecond = 0;
if ($v instanceof DateTime) {
$dt = $v;
}
else if (preg_match('/^[0-9]{1,2}(\.\d{1,6})?$/', $v)) {
// in php 5.3.2 createFromFormat() with "u" is not supported(bug)
// Hence we need to do parsing.
$info = explode('.', $v);
$microsecond = $info[1];
$dt = DateTime::createFromFormat("s", $info[0]);
}
else {
try {
$dt = new DateTime($v);
} catch (Exception $x) {
throw new PropelException('Error parsing date/time value: ' . var_export($v, true), $x);
}
}
if ($microsecond == 0) {
$this->fade_in = $dt->format('H:i:s.u');
} else {
$this->fade_in = $dt->format('H:i:s').".".$microsecond;
}
$this->modifiedColumns[] = CcSchedulePeer::FADE_IN;
return $this;
} // setDbFadein()
/**
*
* @param String in format SS.uuuuuu, Datetime, or DateTime accepted string.
*
* @return CcPlaylistcontents The current object (for fluent API support)
*/
public function setDbFadeOut($v)
{
$microsecond = 0;
if ($v instanceof DateTime) {
$dt = $v;
}
else if (preg_match('/^[0-9]{1,2}(\.\d{1,6})?$/', $v)) {
// in php 5.3.2 createFromFormat() with "u" is not supported(bug)
// Hence we need to do parsing.
$info = explode('.', $v);
$microsecond = $info[1];
$dt = DateTime::createFromFormat("s", $info[0]);
}
else {
try {
$dt = new DateTime($v);
} catch (Exception $x) {
throw new PropelException('Error parsing date/time value: ' . var_export($v, true), $x);
}
}
if ($microsecond == 0) {
$this->fade_out = $dt->format('H:i:s.u');
} else {
$this->fade_out = $dt->format('H:i:s').".".$microsecond;
}
$this->modifiedColumns[] = CcSchedulePeer::FADE_OUT;
return $this;
} // setDbFadeout()
/**
* Sets the value of [starts] column to a normalized version of the date/time value specified.
*
* @param mixed $v string, integer (timestamp), or DateTime value. Empty string will
* be treated as NULL for temporal objects.
* @return CcSchedule The current object (for fluent API support)
*/
public function setDbStarts($v)
{
$utcTimeZone = new DateTimeZone('UTC');
if ($v instanceof DateTime) {
$dt = $v;
$dt->setTimezone($utcTimeZone);
} else {
// some string/numeric value passed; we normalize that so that we can
// validate it.
try {
if (is_numeric($v)) { // if it's a unix timestamp
$dt = new DateTime('@'.$v, $utcTimeZone);
} else {
$dt = new DateTime($v, $utcTimeZone);
}
} catch (Exception $x) {
throw new PropelException('Error parsing date/time value: ' . var_export($v, true), $x);
}
}
$this->starts = ($dt ? $dt->format('Y-m-d H:i:s.u') : null);
$this->modifiedColumns[] = CcSchedulePeer::STARTS;
return $this;
} // setDbStarts()
/**
* Sets the value of [ends] column to a normalized version of the date/time value specified.
*
* @param mixed $v string, integer (timestamp), or DateTime value. Empty string will
* be treated as NULL for temporal objects.
* @return CcSchedule The current object (for fluent API support)
*/
public function setDbEnds($v)
{
$utcTimeZone = new DateTimeZone('UTC');
if ($v instanceof DateTime) {
$dt = $v;
$dt->setTimezone($utcTimeZone);
} else {
// some string/numeric value passed; we normalize that so that we can
// validate it.
try {
if (is_numeric($v)) { // if it's a unix timestamp
$dt = new DateTime('@'.$v, $utcTimeZone);
} else {
$dt = new DateTime($v, $utcTimeZone);
}
} catch (Exception $x) {
throw new PropelException('Error parsing date/time value: ' . var_export($v, true), $x);
}
}
$this->ends = ($dt ? $dt->format('Y-m-d H:i:s.u') : null);
$this->modifiedColumns[] = CcSchedulePeer::ENDS;
return $this;
} // setDbEnds()
public function isCurrentItem($epochNow = null) {
if (is_null($epochNow)) {
$epochNow = microtime(true);
}
$epochStart = floatval($this->getDbStarts('U.u'));
$epochEnd = floatval($this->getDbEnds('U.u'));
if ($epochStart < $epochNow && $epochEnd > $epochNow) {
return true;
}
return false;
}
} // CcSchedule

View file

@ -0,0 +1,18 @@
<?php
/**
* Skeleton subclass for performing query and update operations on the 'cc_schedule' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.airtime
*/
class CcSchedulePeer extends BaseCcSchedulePeer {
} // CcSchedulePeer

Some files were not shown because too many files have changed in this diff Show more