diff --git a/airtime_mvc/application/modules/rest/Bootstrap.php b/airtime_mvc/application/modules/rest/Bootstrap.php index 999798ee5..180d61010 100644 --- a/airtime_mvc/application/modules/rest/Bootstrap.php +++ b/airtime_mvc/application/modules/rest/Bootstrap.php @@ -8,9 +8,10 @@ class Rest_Bootstrap extends Zend_Application_Module_Bootstrap $router = $front->getRouter(); $restRoute = new Zend_Rest_Route($front, array(), array( - 'rest'=> array('media'))); + 'rest'=> array('media', 'show'))); assert($router->addRoute('rest', $restRoute)); + /** MediaController Routes **/ $downloadRoute = new Zend_Controller_Router_Route( 'rest/media/:id/download', array( @@ -33,5 +34,19 @@ class Rest_Bootstrap extends Zend_Application_Module_Bootstrap ) ); $router->addRoute('clear', $clearLibraryRoute); + + /** ShowController Routes **/ + $uploadImageRoute = new Zend_Controller_Router_Route( + 'rest/show/:id/upload-image', + array( + 'controller' => 'show', + 'action' => 'upload-image', + 'module' => 'rest' + ), + array( + 'id' => '\d+' + ) + ); + $router->addRoute('upload-image', $uploadImageRoute); } } diff --git a/airtime_mvc/application/modules/rest/controllers/ShowController.php b/airtime_mvc/application/modules/rest/controllers/ShowController.php new file mode 100644 index 000000000..a8b06fbbf --- /dev/null +++ b/airtime_mvc/application/modules/rest/controllers/ShowController.php @@ -0,0 +1,222 @@ +restAuth = new RestAuth(); + // Remove layout dependencies + $this->view->layout()->disableLayout(); + // Remove reliance on .phtml files to render requests + $this->_helper->viewRenderer->setNoRender(true); + } + + /* + * TODO shift functionality from add-show.js and ScheduleController to here, + * and have a referenceable Show object + */ + + public function indexAction() { + Logging::info("INDEX action received"); + } + + public function getAction() { + Logging::info("GET action received"); + } + + public function putAction() { + Logging::info("PUT action received"); + } + + public function postAction() { + Logging::info("POST action received"); + } + + public function deleteAction() { + Logging::info("DELETE action received"); + } + + public function uploadImageAction() + { + Logging::info("Uploading image: " . $_FILES["file"]); + + if (!$this->restAuth->verifyAuth(true, true)) + { + Logging::info("Authentication failed"); + return; + } + + $showId = $this->getShowId(); + Logging::info("Show Id " . $showId); + + if (!$showId) { + Logging::info("No show id provided"); + return; + } + + if (Application_Model_Systemstatus::isDiskOverQuota()) { + $this->getResponse() + ->setHttpResponseCode(400) + ->appendBody("ERROR: Disk Quota reached."); + return; + } + + $path = $this->processUploadedImage($showId, $_FILES["file"]["tmp_name"], $_FILES["file"]["name"]); + + $show = CcShowQuery::create()->findPk($showId); + + try { + $con = Propel::getConnection(); + $con->beginTransaction(); + + $show->setDbImagePath($path); + // TODO set linked show image paths + $show->save(); + + $con->commit(); + } catch (Exception $e) { + $con->rollBack(); + Logging::error("Couldn't add show image: " . $e->getMessage()); + } + + $this->getResponse() + ->setHttpResponseCode(201); + } + + /** + * Verify and process an uploaded image file, copying it first into .../stor/organize/ + * and then to RabbitMq to process. Processed image files end up in + * .../stor/imported/:owner-id/show-images/:show-id/ to differentiate between + * individual users and shows + * + * @param unknown $tempFilePath temporary filepath assigned to the upload + * generally of the form /tmp/:tmp_name + * @param unknown $originalFilename the file name at time of upload + * @throws Exception when a file with an unsupported file extension is uploaded + */ + private function processUploadedImage($showId, $tempFilePath, $originalFilename) + { + $ownerId = $this->restAuth->getOwnerId(); + + $CC_CONFIG = Config::getConfig(); + $apiKey = $CC_CONFIG["apiKey"][0]; + + $tempFileName = basename($tempFilePath); + + //Only accept files with a file extension that we support. + $fileExtension = pathinfo($originalFilename, PATHINFO_EXTENSION); + if (!in_array(strtolower($fileExtension), explode(",", "jpg,png,gif,jpeg"))) + { + @unlink($tempFilePath); + // Should this be an HTTPResponse? + throw new Exception("Bad file extension."); + } + + $storDir = Application_Model_MusicDir::getStorDir(); + $importedStorageDirectory = $storDir->getDirectory() . "imported/" . $ownerId . "/show-images/" . $showId; + + try { + $importedStorageDirectory = $this->copyFileToStor($tempFilePath, $importedStorageDirectory, $fileExtension); + } catch (Exception $e) { + @unlink($tempFilePath); + Logging::error($e->getMessage()); + return; + } + + return $importedStorageDirectory; + } + + private function copyFileToStor($tempFilePath, $importedStorageDirectory, $fileExtension) + { + $image_file = $tempFilePath; + + // check if "organize" dir exists and if not create one + if (!file_exists($importedStorageDirectory)) { + if (!mkdir($importedStorageDirectory, 0777)) { + throw new Exception("Failed to create storage directory."); + } + } + + if (chmod($image_file, 0644) === false) { + Logging::info("Warning: couldn't change permissions of $image_file to 0644"); + } + + $newFileName = substr($tempFilePath, strrpos($tempFilePath, "/")).".".$fileExtension; + + // Did all the checks for real, now trying to copy + $image_stor = Application_Common_OsPath::join($importedStorageDirectory, $newFileName); + Logging::info($newFileName); + Logging::info($image_stor); + Logging::info("copyFileToStor: moving file $image_file to $image_stor"); + + if (@rename($image_file, $image_stor) === false) { + //something went wrong likely there wasn't enough space in . + //the audio_stor to move the file too warn the user that . + //the file wasn't uploaded and they should check if there . + //is enough disk space . + unlink($image_file); //remove the file after failed rename + + throw new Exception("The file was not uploaded, this error can occur if the computer " + ."hard drive does not have enough disk space or the stor " + ."directory does not have correct write permissions."); + } + + return $image_stor; + } + + public static function deleteFileFromStor($showId) { + $auth = new RestAuth(); + $ownerId = $auth->getOwnerId(); + + $storDir = Application_Model_MusicDir::getStorDir(); + $importedStorageDirectory = $storDir->getDirectory() . "imported/" . $ownerId . "/show-images/" . $showId; + + Logging::info($importedStorageDirectory); + + // to be safe in case image uploading functionality is extended later + return Rest_ShowController::delTree($importedStorageDirectory); + } + + private static function delTree($dir) { + $files = array_diff(scandir($dir), array('.','..')); + foreach ($files as $file) { + (is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file"); + } + return rmdir($dir); + } + + /** + * Fetch the id parameter from the request. + * + * @return boolean|unknown false if the show id wasn't + * provided, otherwise returns the id + */ + private function getShowId() + { + if (!$id = $this->_getParam('id', false)) { + $resp = $this->getResponse(); + $resp->setHttpResponseCode(400); + $resp->appendBody("ERROR: No show ID specified."); + return false; + } + return $id; + } + +} \ No newline at end of file