Merge branch 'saas' into saas-store-file-size-and-hash-in-db
Conflicts: airtime_mvc/application/modules/rest/controllers/MediaController.php
This commit is contained in:
commit
d0bd4bfe81
22 changed files with 272 additions and 9907 deletions
|
@ -22,6 +22,7 @@ require_once "FileDataHelper.php";
|
||||||
require_once "HTTPHelper.php";
|
require_once "HTTPHelper.php";
|
||||||
require_once "OsPath.php";
|
require_once "OsPath.php";
|
||||||
require_once "Database.php";
|
require_once "Database.php";
|
||||||
|
require_once "ProvisioningHelper.php";
|
||||||
require_once "Timezone.php";
|
require_once "Timezone.php";
|
||||||
require_once "Auth.php";
|
require_once "Auth.php";
|
||||||
require_once __DIR__.'/forms/helpers/ValidationTypes.php';
|
require_once __DIR__.'/forms/helpers/ValidationTypes.php';
|
||||||
|
@ -34,6 +35,13 @@ require_once __DIR__.'/modules/rest/controllers/MediaController.php';
|
||||||
require_once (APPLICATION_PATH."/logging/Logging.php");
|
require_once (APPLICATION_PATH."/logging/Logging.php");
|
||||||
Logging::setLogPath('/var/log/airtime/zendphp.log');
|
Logging::setLogPath('/var/log/airtime/zendphp.log');
|
||||||
|
|
||||||
|
// We need to manually route because we can't load Zend without the database being initialized first.
|
||||||
|
if (array_key_exists("REQUEST_URI", $_SERVER) && (strpos($_SERVER["REQUEST_URI"], "/provisioning/create") !== false)) {
|
||||||
|
$provisioningHelper = new ProvisioningHelper($CC_CONFIG["apiKey"][0]);
|
||||||
|
$provisioningHelper->createAction();
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
|
||||||
Config::setAirtimeVersion();
|
Config::setAirtimeVersion();
|
||||||
require_once __DIR__."/configs/navigation.php";
|
require_once __DIR__."/configs/navigation.php";
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Created by PhpStorm.
|
|
||||||
* User: sourcefabric
|
|
||||||
* Date: 17/02/15
|
|
||||||
*/
|
|
||||||
|
|
||||||
class FileDataHelper {
|
class FileDataHelper {
|
||||||
|
|
||||||
|
@ -12,9 +7,16 @@ class FileDataHelper {
|
||||||
* at all costs, so check the data and sanitize it if necessary
|
* at all costs, so check the data and sanitize it if necessary
|
||||||
* @param array $data array containing new file metadata
|
* @param array $data array containing new file metadata
|
||||||
*/
|
*/
|
||||||
public static function sanitizeData(&$data) {
|
public static function sanitizeData(&$data)
|
||||||
|
{
|
||||||
|
if (array_key_exists("track_number", $data)) {
|
||||||
// If the track number isn't numeric, this will return 0
|
// If the track number isn't numeric, this will return 0
|
||||||
$data["track_number"] = intval($data["track_number"]);
|
$data["track_number"] = intval($data["track_number"]);
|
||||||
}
|
}
|
||||||
|
if (array_key_exists("year", $data)) {
|
||||||
|
// If the track number isn't numeric, this will return 0
|
||||||
|
$data["year"] = intval($data["year"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
157
airtime_mvc/application/common/ProvisioningHelper.php
Normal file
157
airtime_mvc/application/common/ProvisioningHelper.php
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/** This class provides the business logic for station provisioning. */
|
||||||
|
class ProvisioningHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
/* @var $dbh PDO */
|
||||||
|
static $dbh;
|
||||||
|
|
||||||
|
// Parameter values
|
||||||
|
private $dbuser, $dbpass, $dbname, $dbhost, $dbowner, $apikey;
|
||||||
|
private $instanceId;
|
||||||
|
|
||||||
|
public function __construct($apikey)
|
||||||
|
{
|
||||||
|
$this->apikey = $apikey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Endpoint for setting up and installing the Airtime database. This all has to be done without Zend
|
||||||
|
* which is why the code looks so old school (eg. http_response_code). (We can't currently bootstrap our
|
||||||
|
* Zend app without the database unfortunately.)
|
||||||
|
*/
|
||||||
|
public function createAction()
|
||||||
|
{
|
||||||
|
$apikey = $_SERVER['PHP_AUTH_USER'];
|
||||||
|
if (!isset($apikey) || $apikey != $this->apikey) {
|
||||||
|
Logging::info("Invalid API Key: $apikey");
|
||||||
|
http_response_code(403);
|
||||||
|
echo "ERROR: Incorrect API key";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$this->parsePostParams();
|
||||||
|
|
||||||
|
//For security, the Airtime Pro provisioning system creates the database for the user.
|
||||||
|
// $this->setNewDatabaseConnection();
|
||||||
|
//if ($this->checkDatabaseExists()) {
|
||||||
|
// throw new Exception("ERROR: Airtime database already exists");
|
||||||
|
//}
|
||||||
|
//$this->createDatabase();
|
||||||
|
|
||||||
|
//All we need to do is create the database tables.
|
||||||
|
$this->createDatabaseTables();
|
||||||
|
$this->initializeMusicDirsTable($this->instanceId);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
http_response_code(400);
|
||||||
|
Logging::error($e->getMessage());
|
||||||
|
echo $e->getMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
http_response_code(201);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the database settings and credentials given are valid
|
||||||
|
* @return boolean true if the database given exists and the user is valid and can access it
|
||||||
|
*/
|
||||||
|
private function checkDatabaseExists()
|
||||||
|
{
|
||||||
|
$statement = self::$dbh->prepare("SELECT datname FROM pg_database WHERE datname = :dbname");
|
||||||
|
$statement->execute(array(":dbname" => $this->dbname));
|
||||||
|
$result = $statement->fetch();
|
||||||
|
return isset($result[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parsePostParams()
|
||||||
|
{
|
||||||
|
$this->dbuser = $_POST['dbuser'];
|
||||||
|
$this->dbpass = $_POST['dbpass'];
|
||||||
|
$this->dbname = $_POST['dbname'];
|
||||||
|
$this->dbhost = $_POST['dbhost'];
|
||||||
|
$this->dbowner = $_POST['dbowner'];
|
||||||
|
$this->instanceId = $_POST['instanceid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up a new database connection based on the parameters in the request
|
||||||
|
* @throws PDOException upon failure to connect
|
||||||
|
*/
|
||||||
|
private function setNewDatabaseConnection()
|
||||||
|
{
|
||||||
|
self::$dbh = new PDO("pgsql:host=" . $this->dbhost
|
||||||
|
. ";dbname=postgres"
|
||||||
|
. ";port=5432" . ";user=" . $this->dbuser
|
||||||
|
. ";password=" . $this->dbpass);
|
||||||
|
$err = self::$dbh->errorInfo();
|
||||||
|
if ($err[1] != null) {
|
||||||
|
throw new PDOException("ERROR: Could not connect to database");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the Airtime database using the given credentials
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function createDatabase()
|
||||||
|
{
|
||||||
|
Logging::info("Creating database...");
|
||||||
|
$statement = self::$dbh->prepare("CREATE DATABASE " . pg_escape_string($this->dbname)
|
||||||
|
. " WITH ENCODING 'UTF8' TEMPLATE template0"
|
||||||
|
. " OWNER " . pg_escape_string($this->dbowner));
|
||||||
|
if (!$statement->execute()) {
|
||||||
|
throw new Exception("ERROR: Failed to create Airtime database");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install the Airtime database
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function createDatabaseTables()
|
||||||
|
{
|
||||||
|
Logging::info("Creating database tables...");
|
||||||
|
$sqlDir = dirname(APPLICATION_PATH) . "/build/sql/";
|
||||||
|
$files = array("schema.sql", "sequences.sql", "views.sql", "triggers.sql", "defaultdata.sql");
|
||||||
|
foreach ($files as $f) {
|
||||||
|
/*
|
||||||
|
* Unfortunately, we need to use exec here due to PDO's lack of support for importing
|
||||||
|
* multi-line .sql files. PDO->exec() almost works, but any SQL errors stop the import,
|
||||||
|
* so the necessary DROPs on non-existent tables make it unusable. Prepared statements
|
||||||
|
* have multiple issues; they similarly die on any SQL errors, fail to read in multi-line
|
||||||
|
* commands, and fail on any unescaped ? or $ characters.
|
||||||
|
*/
|
||||||
|
exec("PGPASSWORD=$this->dbpass psql -U $this->dbuser --dbname $this->dbname -h $this->dbhost -f $sqlDir$f", $out, $status);
|
||||||
|
if ($status != 0) {
|
||||||
|
throw new Exception("ERROR: Failed to create database tables");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function initializeMusicDirsTable($instanceId)
|
||||||
|
{
|
||||||
|
if (!is_string($instanceId) || empty($instanceId) || !is_numeric($instanceId))
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid instance id: " . $instanceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
$instanceIdPrefix = $instanceId[0];
|
||||||
|
|
||||||
|
//Reinitialize Propel, just in case...
|
||||||
|
Propel::init(__DIR__."/../configs/airtime-conf-production.php");
|
||||||
|
|
||||||
|
//Create the cc_music_dir entry
|
||||||
|
$musicDir = new CcMusicDirs();
|
||||||
|
$musicDir->setType("stor");
|
||||||
|
$musicDir->setExists(true);
|
||||||
|
$musicDir->setWatched(true);
|
||||||
|
$musicDir->setDirectory("/mnt/airtimepro/instances/$instanceIdPrefix/$instanceId/srv/airtime/stor/");
|
||||||
|
$musicDir->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -54,7 +54,8 @@ $ccAcl->allow('G', 'index')
|
||||||
->allow('G', 'upgrade')
|
->allow('G', 'upgrade')
|
||||||
->allow('G', 'provisioning')
|
->allow('G', 'provisioning')
|
||||||
->allow('G', 'downgrade')
|
->allow('G', 'downgrade')
|
||||||
->allow('G', 'rest:show-image')
|
->allow('G', 'rest:show-image', 'get')
|
||||||
|
->allow('H', 'rest:show-image')
|
||||||
->allow('G', 'rest:media', 'get')
|
->allow('G', 'rest:media', 'get')
|
||||||
->allow('H', 'rest:media')
|
->allow('H', 'rest:media')
|
||||||
->allow('H', 'preference', 'is-import-in-progress')
|
->allow('H', 'preference', 'is-import-in-progress')
|
||||||
|
|
|
@ -421,9 +421,6 @@ class LibraryController extends Zend_Controller_Action
|
||||||
|
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$file_id = $this->_getParam('id', null);
|
$file_id = $this->_getParam('id', null);
|
||||||
$file = Application_Model_StoredFile::RecallById($file_id);
|
$file = Application_Model_StoredFile::RecallById($file_id);
|
||||||
|
|
||||||
|
@ -444,25 +441,11 @@ class LibraryController extends Zend_Controller_Action
|
||||||
$serialized[$j["name"]] = $j["value"];
|
$serialized[$j["name"]] = $j["value"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sanitize any wildly incorrect metadata before it goes to be validated.
|
||||||
|
FileDataHelper::sanitizeData($serialized);
|
||||||
|
|
||||||
if ($form->isValid($serialized)) {
|
if ($form->isValid($serialized)) {
|
||||||
// Sanitize any incorrect metadata that slipped past validation
|
$file->setDbColMetadata($serialized);
|
||||||
FileDataHelper::sanitizeData($serialized["track_number"]);
|
|
||||||
|
|
||||||
$formValues = $this->_getParam('data', null);
|
|
||||||
$formdata = array();
|
|
||||||
foreach ($formValues as $val) {
|
|
||||||
$formdata[$val["name"]] = $val["value"];
|
|
||||||
}
|
|
||||||
$file->setDbColMetadata($formdata);
|
|
||||||
|
|
||||||
$data = $file->getMetadata();
|
|
||||||
|
|
||||||
// set MDATA_KEY_FILEPATH
|
|
||||||
$data['MDATA_KEY_FILEPATH'] = $file->getFilePath();
|
|
||||||
Logging::info($data['MDATA_KEY_FILEPATH']);
|
|
||||||
Application_Model_RabbitMq::SendMessageToMediaMonitor("md_update", $data);
|
|
||||||
|
|
||||||
$this->_redirect('Library');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,18 @@ use Aws\S3\S3Client;
|
||||||
|
|
||||||
class ProvisioningController extends Zend_Controller_Action
|
class ProvisioningController extends Zend_Controller_Action
|
||||||
{
|
{
|
||||||
|
|
||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* The "create action" is in ProvisioningHelper because it needs to have no dependency on Zend,
|
||||||
|
* since when we bootstrap Zend, we already need the database set up and working (Bootstrap.php is a mess).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the Airtime Pro station's files from Amazon S3
|
* Delete the Airtime Pro station's files from Amazon S3
|
||||||
*/
|
*/
|
||||||
|
@ -17,7 +26,7 @@ class ProvisioningController extends Zend_Controller_Action
|
||||||
$this->view->layout()->disableLayout();
|
$this->view->layout()->disableLayout();
|
||||||
$this->_helper->viewRenderer->setNoRender(true);
|
$this->_helper->viewRenderer->setNoRender(true);
|
||||||
|
|
||||||
if (!$this->verifyAPIKey()) {
|
if (!RestAuth::verifyAuth(true, true, $this)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,27 +42,4 @@ class ProvisioningController extends Zend_Controller_Action
|
||||||
->appendBody("OK");
|
->appendBody("OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
private function verifyAPIKey()
|
|
||||||
{
|
|
||||||
// The API key is passed in via HTTP "basic authentication":
|
|
||||||
// http://en.wikipedia.org/wiki/Basic_access_authentication
|
|
||||||
|
|
||||||
$CC_CONFIG = Config::getConfig();
|
|
||||||
|
|
||||||
// Decode the API key that was passed to us in the HTTP request.
|
|
||||||
$authHeader = $this->getRequest()->getHeader("Authorization");
|
|
||||||
$encodedRequestApiKey = substr($authHeader, strlen("Basic "));
|
|
||||||
$encodedStoredApiKey = base64_encode($CC_CONFIG["apiKey"][0] . ":");
|
|
||||||
|
|
||||||
if ($encodedRequestApiKey === $encodedStoredApiKey)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->getResponse()
|
|
||||||
->setHttpResponseCode(401)
|
|
||||||
->appendBody("ERROR: Incorrect API key.");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,9 +119,6 @@ class Rest_MediaController extends Zend_Rest_Controller
|
||||||
$file->save();
|
$file->save();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Sanitize any incorrect metadata that slipped past validation
|
|
||||||
FileDataHelper::sanitizeData($whiteList);
|
|
||||||
|
|
||||||
/* If full_path is set, the post request came from ftp.
|
/* If full_path is set, the post request came from ftp.
|
||||||
* Users are allowed to upload folders via ftp. If this is the case
|
* 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
|
* we need to include the folder name with the file name, otherwise
|
||||||
|
@ -175,8 +172,6 @@ class Rest_MediaController extends Zend_Rest_Controller
|
||||||
$file->save();
|
$file->save();
|
||||||
return;
|
return;
|
||||||
} else if ($file && isset($requestData["resource_id"])) {
|
} else if ($file && isset($requestData["resource_id"])) {
|
||||||
// Sanitize any incorrect metadata that slipped past validation
|
|
||||||
FileDataHelper::sanitizeData($whiteList);
|
|
||||||
|
|
||||||
$file->fromArray($whiteList, BasePeer::TYPE_FIELDNAME);
|
$file->fromArray($whiteList, BasePeer::TYPE_FIELDNAME);
|
||||||
|
|
||||||
|
@ -206,8 +201,6 @@ class Rest_MediaController extends Zend_Rest_Controller
|
||||||
->setHttpResponseCode(200)
|
->setHttpResponseCode(200)
|
||||||
->appendBody(json_encode(CcFiles::sanitizeResponse($file)));
|
->appendBody(json_encode(CcFiles::sanitizeResponse($file)));
|
||||||
} else if ($file) {
|
} else if ($file) {
|
||||||
// Sanitize any incorrect metadata that slipped past validation
|
|
||||||
FileDataHelper::sanitizeData($whiteList);
|
|
||||||
|
|
||||||
//local file storage
|
//local file storage
|
||||||
$file->setDbDirectory(self::MUSIC_DIRS_STOR_PK);
|
$file->setDbDirectory(self::MUSIC_DIRS_STOR_PK);
|
||||||
|
@ -304,6 +297,9 @@ class Rest_MediaController extends Zend_Rest_Controller
|
||||||
|
|
||||||
private function validateRequestData($file, &$whiteList)
|
private function validateRequestData($file, &$whiteList)
|
||||||
{
|
{
|
||||||
|
// Sanitize any wildly incorrect metadata before it goes to be validated
|
||||||
|
FileDataHelper::sanitizeData($whiteList);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// EditAudioMD form is used here for validation
|
// EditAudioMD form is used here for validation
|
||||||
$fileForm = new Application_Form_EditAudioMD();
|
$fileForm = new Application_Form_EditAudioMD();
|
||||||
|
|
|
@ -40,12 +40,6 @@ class Rest_ShowImageController extends Zend_Rest_Controller {
|
||||||
* RESTful POST endpoint; used when uploading show images
|
* RESTful POST endpoint; used when uploading show images
|
||||||
*/
|
*/
|
||||||
public function postAction() {
|
public function postAction() {
|
||||||
if (!RestAuth::verifyAuth(true, true)) {
|
|
||||||
$this->getResponse()
|
|
||||||
->setHttpResponseCode(401)
|
|
||||||
->appendBody("Authentication failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$showId = $this->getShowId();
|
$showId = $this->getShowId();
|
||||||
|
|
||||||
|
@ -89,12 +83,6 @@ class Rest_ShowImageController extends Zend_Rest_Controller {
|
||||||
* RESTful DELETE endpoint; used when deleting show images
|
* RESTful DELETE endpoint; used when deleting show images
|
||||||
*/
|
*/
|
||||||
public function deleteAction() {
|
public function deleteAction() {
|
||||||
if (!RestAuth::verifyAuth(true, true)) {
|
|
||||||
$this->getResponse()
|
|
||||||
->setHttpResponseCode(401)
|
|
||||||
->appendBody("Authentication failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$showId = $this->getShowId();
|
$showId = $this->getShowId();
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,30 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
class RestAuth
|
class RestAuth {
|
||||||
{
|
|
||||||
public static function verifyAuth($checkApiKey, $checkSession)
|
public static function verifyAuth($checkApiKey, $checkSession, $action) {
|
||||||
{
|
|
||||||
//Session takes precedence over API key for now:
|
//Session takes precedence over API key for now:
|
||||||
if ($checkSession && RestAuth::verifySession()
|
if ($checkSession && self::verifySession()
|
||||||
|| $checkApiKey && RestAuth::verifyAPIKey())
|
|| $checkApiKey && self::verifyAPIKey($action)
|
||||||
{
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$resp = $this->getResponse();
|
$action->getResponse()
|
||||||
$resp->setHttpResponseCode(401);
|
->setHttpResponseCode(401)
|
||||||
$resp->appendBody("ERROR: Incorrect API key.");
|
->appendBody(json_encode(array("message" => "ERROR: Incorrect API key.")));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getOwnerId()
|
public static function getOwnerId() {
|
||||||
{
|
|
||||||
try {
|
try {
|
||||||
if (RestAuth::verifySession()) {
|
if (self::verifySession()) {
|
||||||
$service_user = new Application_Service_UserService();
|
$service_user = new Application_Service_UserService();
|
||||||
return $service_user->getCurrentUser()->getDbId();
|
return $service_user->getCurrentUser()->getDbId();
|
||||||
} else {
|
} else {
|
||||||
$defaultOwner = CcSubjsQuery::create()
|
$defaultOwner = CcSubjsQuery::create()
|
||||||
->filterByDbType('A')
|
->filterByDbType(array('A', 'S'), Criteria::IN)
|
||||||
->orderByDbId()
|
->orderByDbId()
|
||||||
->findOne();
|
->findOne();
|
||||||
if (!$defaultOwner) {
|
if (!$defaultOwner) {
|
||||||
|
@ -41,20 +39,18 @@ class RestAuth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function verifySession()
|
private static function verifySession() {
|
||||||
{
|
|
||||||
$auth = Zend_Auth::getInstance();
|
$auth = Zend_Auth::getInstance();
|
||||||
return $auth->hasIdentity();
|
return $auth->hasIdentity();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function verifyAPIKey()
|
private static function verifyAPIKey($action) {
|
||||||
{
|
|
||||||
//The API key is passed in via HTTP "basic authentication":
|
//The API key is passed in via HTTP "basic authentication":
|
||||||
// http://en.wikipedia.org/wiki/Basic_access_authentication
|
// http://en.wikipedia.org/wiki/Basic_access_authentication
|
||||||
$CC_CONFIG = Config::getConfig();
|
$CC_CONFIG = Config::getConfig();
|
||||||
|
|
||||||
//Decode the API key that was passed to us in the HTTP request.
|
//Decode the API key that was passed to us in the HTTP request.
|
||||||
$authHeader = $this->getRequest()->getHeader("Authorization");
|
$authHeader = $action->getRequest()->getHeader("Authorization");
|
||||||
$encodedRequestApiKey = substr($authHeader, strlen("Basic "));
|
$encodedRequestApiKey = substr($authHeader, strlen("Basic "));
|
||||||
$encodedStoredApiKey = base64_encode($CC_CONFIG["apiKey"][0] . ":");
|
$encodedStoredApiKey = base64_encode($CC_CONFIG["apiKey"][0] . ":");
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
-- Schema version
|
||||||
|
INSERT INTO cc_pref("keystr", "valstr") VALUES('system_version', '2.5.9');
|
||||||
|
|
||||||
INSERT INTO cc_subjs ("login", "type", "pass") VALUES ('admin', 'A', md5('admin'));
|
INSERT INTO cc_subjs ("login", "type", "pass") VALUES ('admin', 'A', md5('admin'));
|
||||||
-- added in 2.3
|
-- added in 2.3
|
||||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('off_air_meta', 'Airtime - offline', 'string');
|
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('off_air_meta', 'Airtime - offline', 'string');
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
Binary file not shown.
|
@ -317,14 +317,23 @@ var AIRTIME = (function(AIRTIME) {
|
||||||
|
|
||||||
mod.fnDeleteItems = function(aMedia) {
|
mod.fnDeleteItems = function(aMedia) {
|
||||||
|
|
||||||
|
//Prevent the user from spamming the delete button while the AJAX request is in progress
|
||||||
|
AIRTIME.button.disableButton("btn-group #sb-trash", false);
|
||||||
|
//Hack to immediately show the "Processing" div in DataTables to give the user some sort of feedback.
|
||||||
|
$(".dataTables_processing").css('visibility','visible');
|
||||||
|
|
||||||
$.post(baseUrl+"library/delete",
|
$.post(baseUrl+"library/delete",
|
||||||
{"format": "json", "media": aMedia},
|
{"format": "json", "media": aMedia},
|
||||||
function(json){
|
function(json){
|
||||||
if (json.message !== undefined) {
|
if (json.message !== undefined) {
|
||||||
alert(json.message);
|
alert(json.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
chosenItems = {};
|
chosenItems = {};
|
||||||
oTable.fnStandingRedraw();
|
oTable.fnStandingRedraw();
|
||||||
|
|
||||||
|
//Re-enable the delete button
|
||||||
|
AIRTIME.button.enableButton("btn-group #sb-trash", false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
import uuid
|
import uuid
|
||||||
|
import socket
|
||||||
from boto.s3.connection import S3Connection
|
from boto.s3.connection import S3Connection
|
||||||
from boto.s3.key import Key
|
from boto.s3.key import Key
|
||||||
|
|
||||||
STORAGE_BACKEND_FILE = "file"
|
STORAGE_BACKEND_FILE = "file"
|
||||||
|
SOCKET_TIMEOUT = 240
|
||||||
|
|
||||||
class CloudStorageUploader:
|
class CloudStorageUploader:
|
||||||
""" A class that uses Python-Boto SDK to upload objects into Amazon S3.
|
""" A class that uses Python-Boto SDK to upload objects into Amazon S3.
|
||||||
|
@ -87,6 +89,10 @@ class CloudStorageUploader:
|
||||||
|
|
||||||
resource_id = "%s/%s/%s_%s%s" % (metadata['file_prefix'], unique_id_prefix, file_name, unique_id, extension)
|
resource_id = "%s/%s/%s_%s%s" % (metadata['file_prefix'], unique_id_prefix, file_name, unique_id, extension)
|
||||||
|
|
||||||
|
# Boto uses the "global default timeout" by default, which is infinite! To prevent network problems from
|
||||||
|
# turning into deadlocks, we explicitly set the global default timeout period here:
|
||||||
|
socket.setdefaulttimeout(SOCKET_TIMEOUT)
|
||||||
|
|
||||||
conn = S3Connection(self._api_key, self._api_key_secret, host=self._host)
|
conn = S3Connection(self._api_key, self._api_key_secret, host=self._host)
|
||||||
bucket = conn.get_bucket(self._bucket)
|
bucket = conn.get_bucket(self._bucket)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue