Merge branch 'devel' of dev.sourcefabric.org:airtime into devel

This commit is contained in:
Naomi Aro 2012-05-07 14:29:02 +02:00
commit 41e7150462
23 changed files with 461 additions and 185 deletions

View File

@ -12,21 +12,26 @@ require_once "DateHelper.php";
require_once "OsPath.php";
require_once __DIR__.'/controllers/plugins/RabbitMqPlugin.php';
//DateTime in PHP 5.3.0+ need a default timezone set. Set to UTC initially
//in case Application_Model_Preference::GetTimezone fails and creates needs to create
//a log entry. This log entry requires a call to date(), which then complains that
//timezone isn't set. Setting a default timezone allows us to create a a graceful log
//that getting the real timezone failed, without PHP complaining that it cannot log because
//there is no timezone :|.
date_default_timezone_set('UTC');
date_default_timezone_set(Application_Model_Preference::GetTimezone());
global $CC_CONFIG;
$CC_CONFIG['airtime_version'] = Application_Model_Preference::GetAirtimeVersion();
require_once __DIR__."/configs/navigation.php";
//DateTime in PHP 5.3.0+ need a default timezone set.
date_default_timezone_set(Application_Model_Preference::GetTimezone());
Zend_Validate::setDefaultNamespaces("Zend");
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new RabbitMqPlugin());
//Logging::debug($_SERVER['REQUEST_URI']);
/* The bootstrap class should only be used to initialize actions that return a view.
Actions that return JSON will not use the bootstrap class! */
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap

View File

@ -45,7 +45,7 @@ class Application_Common_OsPath{
/* Similar to the os.path.join python method
* http://stackoverflow.com/a/1782990/276949 */
function join() {
public static function join() {
$args = func_get_args();
$paths = array();

View File

@ -0,0 +1,109 @@
<?php
class Airtime_Zend_Log extends Zend_Log
{
/**
*
* @var boolean
*/
protected $_registeredErrorHandler = false;
/**
*
* @var array|boolean
*/
protected $_errorHandlerMap = false;
/**
*
* @var callback
*/
protected $_origErrorHandler = null;
public function __construct(Zend_Log_Writer_Abstract $writer = null)
{
parent::__construct($writer);
}
/**
* Error Handler will convert error into log message, and then call the original error handler
*
* @link http://www.php.net/manual/en/function.set-error-handler.php Custom error handler
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @param array $errcontext
* @return boolean
*/
public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext)
{
$errorLevel = error_reporting();
if ($errorLevel && $errno) {
if (isset($this->_errorHandlerMap[$errno])) {
$priority = $this->_errorHandlerMap[$errno];
} else {
$priority = Zend_Log::INFO;
}
$this->log($errstr, $priority, array('errno'=>$errno, 'file'=>$errfile, 'line'=>$errline, 'context'=>$errcontext));
}
if ($this->_origErrorHandler !== null) {
return call_user_func($this->_origErrorHandler, $errno, $errstr, $errfile, $errline, $errcontext);
}
return false;
}
/**
* Register Logging system as an error handler to log php errors
* Note: it still calls the original error handler if set_error_handler is able to return it.
*
* Errors will be mapped as:
* E_NOTICE, E_USER_NOTICE => NOTICE
* E_WARNING, E_CORE_WARNING, E_USER_WARNING => WARN
* E_ERROR, E_USER_ERROR, E_CORE_ERROR, E_RECOVERABLE_ERROR => ERR
* E_DEPRECATED, E_STRICT, E_USER_DEPRECATED => DEBUG
* (unknown/other) => INFO
*
* @link http://www.php.net/manual/en/function.set-error-handler.php Custom error handler
*
* @return Zend_Log
*/
public function registerErrorHandler()
{
// Only register once. Avoids loop issues if it gets registered twice.
if ($this->_registeredErrorHandler) {
return $this;
}
$this->_origErrorHandler = set_error_handler(array($this, 'errorHandler'));
// Contruct a default map of phpErrors to Zend_Log priorities.
// Some of the errors are uncatchable, but are included for completeness
$this->_errorHandlerMap = array(
E_NOTICE => Zend_Log::NOTICE,
E_USER_NOTICE => Zend_Log::NOTICE,
E_WARNING => Zend_Log::WARN,
E_CORE_WARNING => Zend_Log::WARN,
E_USER_WARNING => Zend_Log::WARN,
E_ERROR => Zend_Log::ERR,
E_USER_ERROR => Zend_Log::ERR,
E_CORE_ERROR => Zend_Log::ERR,
E_RECOVERABLE_ERROR => Zend_Log::ERR,
E_STRICT => Zend_Log::DEBUG,
);
// PHP 5.3.0+
if (defined('E_DEPRECATED')) {
$this->_errorHandlerMap['E_DEPRECATED'] = Zend_Log::DEBUG;
}
if (defined('E_USER_DEPRECATED')) {
$this->_errorHandlerMap['E_USER_DEPRECATED'] = Zend_Log::DEBUG;
}
$this->_registeredErrorHandler = true;
return $this;
}
}

View File

@ -6,9 +6,18 @@ class Logging {
private static $_path;
public static function getLogger(){
if (!isset(self::$logger)) {
if (!isset(self::$_logger)) {
$writer = new Zend_Log_Writer_Stream(self::$_path);
self::$_logger = new Zend_Log($writer);
if (Zend_Version::compareVersion("1.11") > 0){
//Running Zend version 1.10 or lower. Need to instantiate our
//own Zend Log class with backported code from 1.11.
require_once __DIR__."/AirtimeLog.php";
self::$_logger = new Airtime_Zend_Log($writer);
} else {
self::$_logger = new Zend_Log($writer);
}
self::$_logger->registerErrorHandler();
}
return self::$_logger;
}

View File

@ -3,96 +3,109 @@
class Application_Model_Preference
{
public static function SetValue($key, $value, $isUserValue = false){
global $CC_CONFIG;
$con = Propel::getConnection();
public static function SetValue($key, $value, $isUserValue = false){
try {
$con = Propel::getConnection();
//called from a daemon process
if(!class_exists("Zend_Auth", false) || !Zend_Auth::getInstance()->hasIdentity()) {
$id = NULL;
}
else {
$auth = Zend_Auth::getInstance();
$id = $auth->getIdentity()->id;
}
//called from a daemon process
if(!class_exists("Zend_Auth", false) || !Zend_Auth::getInstance()->hasIdentity()) {
$id = NULL;
}
else {
$auth = Zend_Auth::getInstance();
$id = $auth->getIdentity()->id;
}
$key = pg_escape_string($key);
$value = pg_escape_string($value);
$key = pg_escape_string($key);
$value = pg_escape_string($value);
//Check if key already exists
$sql = "SELECT COUNT(*) FROM cc_pref"
." WHERE keystr = '$key'";
//For user specific preference, check if id matches as well
if($isUserValue) {
$sql .= " AND subjid = '$id'";
}
$result = $con->query($sql)->fetchColumn(0);
if($value == "") {
$value = "NULL";
}else {
$value = "'$value'";
}
if($result == 1) {
// result found
if(is_null($id) || !$isUserValue) {
// system pref
$sql = "UPDATE cc_pref"
." SET subjid = NULL, valstr = $value"
." WHERE keystr = '$key'";
} else {
// user pref
$sql = "UPDATE cc_pref"
. " SET valstr = $value"
. " WHERE keystr = '$key' AND subjid = $id";
}
} else {
// result not found
if(is_null($id) || !$isUserValue) {
// system pref
$sql = "INSERT INTO cc_pref (keystr, valstr)"
." VALUES ('$key', $value)";
} else {
// user pref
$sql = "INSERT INTO cc_pref (subjid, keystr, valstr)"
." VALUES ($id, '$key', $value)";
}
}
return $con->exec($sql);
}
public static function GetValue($key, $isUserValue = false){
global $CC_CONFIG;
$con = Propel::getConnection();
//Check if key already exists
$sql = "SELECT COUNT(*) FROM cc_pref"
." WHERE keystr = '$key'";
//For user specific preference, check if id matches as well
if ($isUserValue) {
$auth = Zend_Auth::getInstance();
if($auth->hasIdentity()) {
$id = $auth->getIdentity()->id;
$sql .= " AND subjid = '$id'";
}
}
$result = $con->query($sql)->fetchColumn(0);
if ($result == 0)
return "";
else {
$sql = "SELECT valstr FROM cc_pref"
//Check if key already exists
$sql = "SELECT COUNT(*) FROM cc_pref"
." WHERE keystr = '$key'";
//For user specific preference, check if id matches as well
if($isUserValue && $auth->hasIdentity()) {
$sql .= " AND subjid = '$id'";
}
//For user specific preference, check if id matches as well
if($isUserValue) {
$sql .= " AND subjid = '$id'";
}
$result = $con->query($sql)->fetchColumn(0);
return ($result !== false) ? $result : "";
if($value == "") {
$value = "NULL";
}else {
$value = "'$value'";
}
if($result == 1) {
// result found
if(is_null($id) || !$isUserValue) {
// system pref
$sql = "UPDATE cc_pref"
." SET subjid = NULL, valstr = $value"
." WHERE keystr = '$key'";
} else {
// user pref
$sql = "UPDATE cc_pref"
. " SET valstr = $value"
. " WHERE keystr = '$key' AND subjid = $id";
}
} else {
// result not found
if(is_null($id) || !$isUserValue) {
// system pref
$sql = "INSERT INTO cc_pref (keystr, valstr)"
." VALUES ('$key', $value)";
} else {
// user pref
$sql = "INSERT INTO cc_pref (subjid, keystr, valstr)"
." VALUES ($id, '$key', $value)";
}
}
$con->exec($sql);
} catch (Exception $e){
header('HTTP/1.0 503 Service Unavailable');
Logging::log("Could not connect to database.");
exit;
}
}
public static function GetValue($key, $isUserValue = false){
try {
$con = Propel::getConnection();
//Check if key already exists
$sql = "SELECT COUNT(*) FROM cc_pref"
." WHERE keystr = '$key'";
//For user specific preference, check if id matches as well
if ($isUserValue) {
$auth = Zend_Auth::getInstance();
if($auth->hasIdentity()) {
$id = $auth->getIdentity()->id;
$sql .= " AND subjid = '$id'";
}
}
$result = $con->query($sql)->fetchColumn(0);
if ($result == 0)
return "";
else {
$sql = "SELECT valstr FROM cc_pref"
." WHERE keystr = '$key'";
//For user specific preference, check if id matches as well
if($isUserValue && $auth->hasIdentity()) {
$sql .= " AND subjid = '$id'";
}
$result = $con->query($sql)->fetchColumn(0);
return ($result !== false) ? $result : "";
}
} catch (Exception $e) {
header('HTTP/1.0 503 Service Unavailable');
Logging::log("Could not connect to database.");
exit;
}
}
@ -561,10 +574,12 @@ class Application_Model_Preference
public static function GetAirtimeVersion(){
if (defined('APPLICATION_ENV') && APPLICATION_ENV == "development" && function_exists('exec')){
return self::GetValue("system_version")."+".exec("git rev-parse --short HEAD");
} else {
return self::GetValue("system_version");
$version = exec("git rev-parse --short HEAD 2>/dev/null", $out, $return_code);
if ($return_code == 0){
return self::GetValue("system_version")."+".$version;
}
}
return self::GetValue("system_version");
}
public static function GetLatestVersion(){

View File

@ -25,6 +25,12 @@ class Application_Model_Scheduler {
$this->epochNow = microtime(true);
$this->nowDT = DateTime::createFromFormat("U.u", $this->epochNow, new DateTimeZone("UTC"));
if ($this->nowDT === false){
// DateTime::createFromFormat does not support millisecond string formatting in PHP 5.3.2 (Ubuntu 10.04).
// In PHP 5.3.3 (Ubuntu 10.10), this has been fixed.
$this->nowDT = DateTime::createFromFormat("U", time(), new DateTimeZone("UTC"));
}
$this->user = Application_Model_User::GetCurrentUser();
}
@ -190,6 +196,12 @@ class Application_Model_Scheduler {
$endEpoch = bcadd($startEpoch , (string) $durationSeconds, 6);
$dt = DateTime::createFromFormat("U.u", $endEpoch, new DateTimeZone("UTC"));
if ($dt === false) {
//PHP 5.3.2 problem
$dt = DateTime::createFromFormat("U", intval($endEpoch), new DateTimeZone("UTC"));
}
return $dt;
}

View File

@ -91,6 +91,27 @@ class Application_Model_StoredFile {
}
else {
$dbMd = array();
if (isset($p_md["MDATA_KEY_YEAR"])){
// We need to make sure to clean this value before inserting into database.
// If value is outside of range [-2^31, 2^31-1] then postgresl will throw error
// when trying to retrieve this value. We could make sure number is within these bounds,
// but simplest is to do substring to 4 digits (both values are garbage, but at least our
// new garbage value won't cause errors). If the value is 2012-01-01, then substring to
// 4 digits is an OK result.
// CC-3771
$year = $p_md["MDATA_KEY_YEAR"];
if (strlen($year) > 4){
$year = substr($year, 0, 4);
}
if (!is_numeric($year)){
$year = 0;
}
$p_md["MDATA_KEY_YEAR"] = $year;
}
foreach ($p_md as $mdConst => $mdValue) {
$dbMd[constant($mdConst)] = $mdValue;
}
@ -235,7 +256,9 @@ class Application_Model_StoredFile {
foreach ($c['user'] as $constant => $value) {
if (preg_match('/^MDATA_KEY/', $constant)) {
if (isset($dbmd_copy[$value])) {
$md[$constant] = $this->getDbColMetadataValue($value);
$propelColumn = $dbmd_copy[$value];
$method = "get$propelColumn";
$md[$constant] = $this->_file->$method();
}
}
}

View File

@ -1,8 +1,8 @@
<?php
//error_reporting(E_ALL|E_STRICT);
error_reporting(E_ALL);
ini_set('display_errors', 'on');
//error_reporting(E_ALL);
//ini_set('display_errors', 'on');
// Define path to application directory
defined('APPLICATION_PATH')

View File

@ -160,6 +160,19 @@ if [ "$DO_UPGRADE" -eq "1" ]; then
php --php-ini ${SCRIPTPATH}/airtime-php.ini ${SCRIPTPATH}/include/airtime-upgrade.php $@
fi
set +e
if [ "$DO_UPGRADE" -eq "0" ]; then
php --php-ini ${SCRIPTPATH}/airtime-php.ini ${SCRIPTPATH}/include/airtime-install.php $@
result=$?
if [ "$result" -ne "0" ]; then
#There was an error, exit with error code.
echo "There was an error during install. Exit code $result"
exit 1
fi
fi
set -e
$SCRIPTPATH/include/airtime-copy-files.sh
$SCRIPTPATH/include/airtime-initialize.sh $@

View File

@ -261,7 +261,7 @@ class AirtimeInstall
// Put Propel sql files in Database
//$command = AirtimeInstall::CONF_DIR_WWW."/library/propel/generator/bin/propel-gen ".AirtimeInstall::CONF_DIR_WWW."/build/ insert-sql 2>/dev/null";
$dir = AirtimeInstall::CONF_DIR_WWW."/build/sql/";
$dir = self::GetAirtimeSrcDir()."/build/sql/";
$files = array("schema.sql", "sequences.sql", "views.sql", "triggers.sql", "defaultdata.sql");
foreach ($files as $f){
@ -453,7 +453,7 @@ class AirtimeInstall
}
touch($file);
chmod($file, 0755);
chmod($file, 0644);
chown($file, $CC_CONFIG['webServerUser']);
chgrp($file, $CC_CONFIG['webServerUser']);
}

View File

@ -35,11 +35,18 @@ AIRTIMEROOT=$SCRIPTPATH/../../
echo "* Creating /etc/airtime"
mkdir -p /etc/airtime
#if [ "$DO_UPGRADE" -eq "0" ]; then
if [ ! -e /etc/airtime/airtime.conf ]; then
#config file airtime.conf exists, but Airtime is not installed
cp $AIRTIMEROOT/airtime_mvc/build/airtime.conf /etc/airtime
fi
#if [ -e /etc/airtime/airtime.conf -a "$DO_UPGRADE" -eq "0" ]; then
#config file airtime.conf exists, but Airtime is not installed
# mv /etc/airtime/airtime.conf airtime.conf.bak
# cp $AIRTIMEROOT/airtime_mvc/build/airtime.conf /etc/airtime
#fi
echo "* Creating /etc/monit/conf.d/monit-airtime-generic.cfg"
mkdir -p /etc/monit/conf.d/
if [ ! -e /etc/monit/conf.d/monit-airtime-generic.cfg ]; then
@ -78,6 +85,13 @@ ln -sf /usr/lib/airtime/utils/airtime-log /usr/bin/airtime-log
ln -sf /usr/lib/airtime/utils/airtime-test-soundcard /usr/bin/airtime-test-soundcard
ln -sf /usr/lib/airtime/utils/airtime-test-stream /usr/bin/airtime-test-stream
echo "* Creating /var/log/airtime"
mkdir -p /var/log/airtime
chmod a+x /var/log/airtime
touch /var/log/airtime/zendphp.log
chown www-data:www-data /var/log/airtime/zendphp.log
chmod 644 /var/log/airtime/zendphp.log
if [ "$web" = "t" ]; then
echo "* Creating /usr/share/airtime"
rm -rf "/usr/share/airtime"

View File

@ -14,22 +14,6 @@ SCRIPTPATH=`dirname $SCRIPT`
AIRTIMEROOT=$SCRIPTPATH/../../
#virtualenv_bin="/usr/lib/airtime/airtime_virtualenv/bin/"
#. ${virtualenv_bin}activate
set +e
if [ "$DO_UPGRADE" -eq "0" ]; then
php --php-ini ${SCRIPTPATH}/../airtime-php.ini ${SCRIPTPATH}/airtime-install.php $@
result=$?
if [ "$result" -ne "0" ]; then
#There was an error, exit with error code.
echo "There was an error during install. Exit code $result"
exit 1
fi
fi
set -e
if [ "$mediamonitor" = "t" ]; then
python $AIRTIMEROOT/python_apps/media-monitor/install/media-monitor-initialize.py
fi

View File

@ -3,9 +3,6 @@
* @package Airtime
* @copyright 2011 Sourcefabric O.P.S.
* @license http://www.gnu.org/licenses/gpl.txt
*
* Checks if a previous version of Airtime is currently installed and upgrades Airtime if so.
* Performs a new install (new configs, database install) otherwise.
*/
require_once(__DIR__.'/AirtimeIni.php');
require_once(__DIR__.'/AirtimeInstall.php');
@ -56,7 +53,7 @@ if ($overwrite) {
}
// Update the build.properties file to point to the correct directory.
AirtimeIni::UpdateIniValue(AirtimeInstall::CONF_DIR_WWW.'/build/build.properties', 'project.home', AirtimeInstall::CONF_DIR_WWW);
//AirtimeIni::UpdateIniValue(AirtimeInstall::CONF_DIR_WWW.'/build/build.properties', 'project.home', AirtimeInstall::CONF_DIR_WWW);
require_once(AirtimeInstall::GetAirtimeSrcDir().'/application/configs/conf.php');
@ -74,6 +71,4 @@ if ($db_install) {
}
}
AirtimeInstall::CreateZendPhpLogFile();
/* FINISHED AIRTIME PHP INSTALLER */

View File

@ -5,14 +5,23 @@
*/
class AirtimeDatabaseUpgrade{
public static function start(){
public static function start($p_dbValues){
echo "* Updating Database".PHP_EOL;
self::task0();
self::task0($p_dbValues);
self::task1();
echo " * Complete".PHP_EOL;
}
private static function task0(){
UpgradeCommon::MigrateTablesToVersion(__DIR__, '20120411174904');
private static function task0($p_dbValues){
//UpgradeCommon::MigrateTablesToVersion(__DIR__, '20120411174904');
$username = $p_dbValues['database']['dbuser'];
$password = $p_dbValues['database']['dbpass'];
$host = $p_dbValues['database']['host'];
$database = $p_dbValues['database']['dbname'];
$dir = __DIR__;
passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/data/upgrade.sql $database 2>&1 | grep -v \"will create implicit index\"");
$sql = "INSERT INTO cc_pref(\"keystr\", \"valstr\") VALUES('scheduled_play_switch', 'on')";
UpgradeCommon::queryDb($sql);

View File

@ -49,9 +49,13 @@ require_once 'ConfFileUpgrade.php';
require_once 'DbUpgrade.php';
require_once 'MiscUpgrade.php';
$filename = "/etc/airtime/airtime.conf";
$values = parse_ini_file($filename, true);
UpgradeCommon::connectToDatabase();
UpgradeCommon::SetDefaultTimezone();
AirtimeConfigFileUpgrade::start();
AirtimeDatabaseUpgrade::start();
AirtimeDatabaseUpgrade::start($values);
AirtimeMiscUpgrade::start();

View File

@ -13,18 +13,18 @@ class Version20120411174904 extends AbstractMigration
public function up(Schema $schema)
{
$this->_addSql("ALTER TABLE cc_show_instances ADD created timestamp");
$this->_addSql("ALTER TABLE cc_show_instances ALTER COLUMN created SET NOT NULL");
$this->_addSql("ALTER TABLE cc_show_instances ADD last_scheduled timestamp");
//setting these to a default now for timeline refresh purposes.
$now = gmdate("Y-m-d H:i:s");
$this->_addSql("UPDATE cc_show_instances SET created = '$now'");
$this->_addSql("UPDATE cc_show_instances SET last_scheduled = '$now'");
$this->_addSql("ALTER TABLE cc_show_instances ALTER COLUMN created SET NOT NULL");
}
public function down(Schema $schema)
{
}
}
}

View File

@ -0,0 +1,111 @@
DROP TRIGGER calculate_position ON cc_playlistcontents;
DROP FUNCTION calculate_position();
DROP VIEW cc_playlisttimes;
CREATE FUNCTION airtime_to_int(chartoconvert character varying) RETURNS integer
AS
'SELECT CASE WHEN trim($1) SIMILAR TO ''[0-9]+'' THEN CAST(trim($1) AS integer) ELSE NULL END;'
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT;
ALTER TABLE cc_files
DROP CONSTRAINT cc_music_dirs_folder_fkey;
ALTER TABLE cc_playlist
DROP CONSTRAINT cc_playlist_editedby_fkey;
CREATE SEQUENCE cc_subjs_token_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
CREATE TABLE cc_subjs_token (
id integer DEFAULT nextval('cc_subjs_token_id_seq'::regclass) NOT NULL,
user_id integer NOT NULL,
"action" character varying(255) NOT NULL,
token character varying(40) NOT NULL,
created timestamp without time zone NOT NULL
);
ALTER TABLE cc_files
ADD COLUMN utime timestamp(6) without time zone,
ADD COLUMN lptime timestamp(6) without time zone,
ADD COLUMN file_exists boolean DEFAULT true,
ALTER COLUMN bit_rate TYPE integer USING airtime_to_int(bit_rate) /* TYPE change - table: cc_files original: character varying(32) new: integer */,
ALTER COLUMN sample_rate TYPE integer USING airtime_to_int(bit_rate) /* TYPE change - table: cc_files original: character varying(32) new: integer */,
ALTER COLUMN length TYPE interval /* TYPE change - table: cc_files original: time without time zone new: interval */,
ALTER COLUMN length SET DEFAULT '00:00:00'::interval;
ALTER TABLE cc_music_dirs
ADD COLUMN "exists" boolean DEFAULT true,
ADD COLUMN watched boolean DEFAULT true;
ALTER TABLE cc_playlist
DROP COLUMN "state",
DROP COLUMN currentlyaccessing,
DROP COLUMN editedby,
DROP COLUMN creator,
ADD COLUMN utime timestamp(6) without time zone,
ADD COLUMN creator_id integer,
ADD COLUMN length interval DEFAULT '00:00:00'::interval;
ALTER TABLE cc_playlistcontents
ALTER COLUMN cliplength TYPE interval /* TYPE change - table: cc_playlistcontents original: time without time zone new: interval */,
ALTER COLUMN cliplength SET DEFAULT '00:00:00'::interval,
ALTER COLUMN cuein TYPE interval /* TYPE change - table: cc_playlistcontents original: time without time zone new: interval */,
ALTER COLUMN cuein SET DEFAULT '00:00:00'::interval,
ALTER COLUMN cueout TYPE interval /* TYPE change - table: cc_playlistcontents original: time without time zone new: interval */,
ALTER COLUMN cueout SET DEFAULT '00:00:00'::interval;
ALTER TABLE cc_schedule
DROP COLUMN playlist_id,
DROP COLUMN group_id,
DROP COLUMN schedule_group_played,
ADD COLUMN playout_status smallint DEFAULT 1 NOT NULL,
ALTER COLUMN clip_length TYPE interval /* TYPE change - table: cc_schedule original: time without time zone new: interval */,
ALTER COLUMN clip_length SET DEFAULT '00:00:00'::interval,
ALTER COLUMN cue_in TYPE interval /* TYPE change - table: cc_schedule original: time without time zone new: interval */,
ALTER COLUMN cue_in SET DEFAULT '00:00:00'::interval,
ALTER COLUMN cue_out TYPE interval /* TYPE change - table: cc_schedule original: time without time zone new: interval */,
ALTER COLUMN cue_out SET DEFAULT '00:00:00'::interval;
ALTER TABLE cc_show
ADD COLUMN live_stream_using_airtime_auth boolean DEFAULT false,
ADD COLUMN live_stream_using_custom_auth boolean DEFAULT false,
ADD COLUMN live_stream_user character varying(255),
ADD COLUMN live_stream_pass character varying(255);
ALTER TABLE cc_show_instances
ADD COLUMN created timestamp without time zone,
ADD COLUMN last_scheduled timestamp without time zone,
ALTER COLUMN time_filled TYPE interval /* TYPE change - table: cc_show_instances original: time without time zone new: interval */,
ALTER COLUMN time_filled SET DEFAULT '00:00:00'::interval;
UPDATE cc_show_instances SET created = now();
ALTER TABLE cc_show_instances
ALTER COLUMN created SET NOT NULL;
ALTER TABLE cc_subjs_token
ADD CONSTRAINT cc_subjs_token_pkey PRIMARY KEY (id);
ALTER TABLE cc_files
ADD CONSTRAINT cc_music_dirs_folder_fkey FOREIGN KEY (directory) REFERENCES cc_music_dirs(id);
ALTER TABLE cc_playlist
ADD CONSTRAINT cc_playlist_createdby_fkey FOREIGN KEY (creator_id) REFERENCES cc_subjs(id);
ALTER TABLE cc_subjs_token
ADD CONSTRAINT cc_subjs_token_idx UNIQUE (token);
ALTER TABLE cc_subjs_token
ADD CONSTRAINT cc_subjs_token_userid_fkey FOREIGN KEY (user_id) REFERENCES cc_subjs(id) ON DELETE CASCADE;
CREATE INDEX cc_files_file_exists_idx ON cc_files USING btree (file_exists);
DROP FUNCTION airtime_to_int(chartoconvert character varying);

View File

@ -88,17 +88,16 @@ class AirtimeMetadata:
try:
airtime_file = mutagen.File(m['MDATA_KEY_FILEPATH'], easy=True)
for key in m.keys() :
for key in m:
if key in self.airtime2mutagen:
value = m[key]
if (value is not None):
self.logger.debug("Saving %s to file", key)
self.logger.debug(value)
if isinstance(value, basestring) and (len(value) > 0):
airtime_file[self.airtime2mutagen[key]] = api_client.encode_to(value, 'utf-8')
elif isinstance(value, int):
airtime_file[self.airtime2mutagen[key]] = str(value)
if value is not None:
value = unicode(value)
if len(value) > 0:
self.logger.debug("Saving key '%s' with value '%s' to file", key, value)
airtime_file[self.airtime2mutagen[key]] = value
airtime_file.save()
except Exception, e:

View File

@ -62,7 +62,7 @@ class AirtimeNotifier(Notifier):
message.ack()
self.logger.info("Received md from RabbitMQ: " + body)
m = json.loads(message.body)
m = json.loads(message.body)
if m['event_type'] == "md_update":
self.logger.info("AIRTIME NOTIFIER md update event")
@ -103,9 +103,9 @@ class AirtimeNotifier(Notifier):
self.mmc.ensure_is_dir(self.config.imported_directory)
self.mmc.ensure_is_dir(self.config.organize_directory)
self.mmc.set_needed_file_permissions(self.config.storage_directory, True)
self.mmc.set_needed_file_permissions(self.config.imported_directory, True)
self.mmc.set_needed_file_permissions(self.config.organize_directory, True)
self.mmc.is_readable(self.config.storage_directory, True)
self.mmc.is_readable(self.config.imported_directory, True)
self.mmc.is_readable(self.config.organize_directory, True)
self.watch_directory(new_storage_directory)
elif m['event_type'] == "file_delete":
@ -150,7 +150,6 @@ class AirtimeNotifier(Notifier):
file_md = None
data = None
if (os.path.exists(filepath) and (mode == self.config.MODE_CREATE)):
if file_md is None:
mutagen = self.md_manager.get_md_from_file(filepath)
@ -192,17 +191,13 @@ class AirtimeNotifier(Notifier):
mm = self.proc_fun()
self.mmc.set_needed_file_permissions(directory, True)
self.mmc.is_readable(directory, True)
for (path, dirs, files) in os.walk(directory):
for d in dirs:
self.mmc.set_needed_file_permissions(os.path.join(path, d), True)
for filename in files:
full_filepath = os.path.join(path, filename)
if self.mmc.is_audio_file(full_filepath):
if self.mmc.set_needed_file_permissions(full_filepath, False):
if self.mmc.is_readable(full_filepath, False):
self.logger.info("importing %s", full_filepath)
event = {'filepath': full_filepath, 'mode': self.config.MODE_CREATE, 'is_recorded_show': False}
mm.multi_queue.put(event)

View File

@ -134,7 +134,7 @@ class AirtimeProcessEvent(ProcessEvent):
#file is being overwritten/replaced in GUI.
elif "goutputstream" in pathname:
self.temp_files[pathname] = None
elif self.mmc.is_audio_file(pathname):
elif self.mmc.is_audio_file(pathname) and self.mmc.is_readable(pathname, False):
if self.mmc.is_parent_directory(pathname, self.config.organize_directory):
#file was created in /srv/airtime/stor/organize. Need to process and move
#to /srv/airtime/stor/imported
@ -151,14 +151,14 @@ class AirtimeProcessEvent(ProcessEvent):
self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", traceback.format_exc())
self.mmc.set_needed_file_permissions(pathname, dir)
self.mmc.is_readable(pathname, dir)
is_recorded = self.mmc.is_parent_directory(pathname, self.config.recorded_directory)
self.file_events.append({'mode': self.config.MODE_CREATE, 'filepath': pathname, 'is_recorded_show': is_recorded})
else:
#event is because of a created directory
if self.mmc.is_parent_directory(pathname, self.config.storage_directory):
self.mmc.set_needed_file_permissions(pathname, dir)
self.mmc.is_readable(pathname, dir)
def process_IN_MODIFY(self, event):
# if IN_MODIFY is followed by IN_CREATE, it's not true modify event
@ -236,10 +236,9 @@ class AirtimeProcessEvent(ProcessEvent):
filename = self.mount_file_dir +"/mtab"
if event.pathname in filename:
self.handle_mount_change()
#if stuff dropped in stor via a UI move must change file permissions.
self.mmc.set_needed_file_permissions(event.pathname, event.dir)
if not event.dir:
if self.mmc.is_audio_file(event.name):
if self.mmc.is_audio_file(event.name) and self.mmc.is_readable(event.pathname, False):
if event.cookie in self.temp_files:
self.file_events.append({'filepath': event.pathname, 'mode': self.config.MODE_MODIFY})
del self.temp_files[event.cookie]

View File

@ -49,7 +49,7 @@ class MediaMonitorCommon:
return False
#check if file is readable by "nobody"
def has_correct_permissions(self, filepath, euid='nobody', egid='nogroup'):
def is_user_readable(self, filepath, euid='nobody', egid='nogroup'):
try:
uid = pwd.getpwnam(euid)[2]
@ -76,35 +76,13 @@ class MediaMonitorCommon:
return readable
# the function only changes the permission if its not readable by www-data
def set_needed_file_permissions(self, item, is_dir):
def is_readable(self, item, is_dir):
try:
omask = os.umask(0)
if not self.has_correct_permissions(item, 'www-data', 'www-data') or not self.has_correct_permissions(item, 'pypo', 'pypo'):
# stats.st_mode is the original permission
# stat.S_IROTH - readable by all permission
# stat.S_IXOTH - excutable by all permission
# try to set permission
if self.is_parent_directory(item, self.config.storage_directory) or self.is_parent_directory(item, self.config.imported_directory) or self.is_parent_directory(item, self.config.organize_directory):
if is_dir is True:
os.chmod(item, 02777)
else:
os.chmod(item, 0666)
else :
# add world readable permission
stats = os.stat(item)
if is_dir is True:
bitor = stats.st_mode | stat.S_IROTH | stat.S_IXOTH
else:
bitor = stats.st_mode | stat.S_IROTH
os.chmod(item, bitor)
return self.is_user_readable(item, 'www-data', 'www-data') \
and self.is_user_readable(item, 'pypo', 'pypo')
except Exception, e:
self.logger.error("Failed to change file's owner/group/permissions. %s", e)
self.logger.error("traceback: %s", traceback.format_exc())
self.logger.warn("Failed to check owner/group/permissions for %s", item)
return False
finally:
os.umask(omask)
return True
#checks if path is a directory, and if it doesnt exist, then creates it.
#Otherwise prints error to log file.

View File

@ -51,6 +51,7 @@ def configure_locale():
if current_locale_encoding not in ['utf-8', 'utf8']:
logger.error("Need a UTF-8 locale. Currently '%s'. Exiting..." % current_locale_encoding)
sys.exit(1)
# configure logging
try:

View File

@ -129,7 +129,8 @@ class PypoPush(Thread):
tn.write('exit\n')
tn.read_all()
except Exception, e:
self.logger.error(str(e))
self.logger.error("Error connecting to Liquidsoap: %s", e)
response = []
finally:
self.telnet_lock.release()