diff --git a/configs/AppConfig.inc b/configs/AppConfig.inc index 42f49db4..150e69bc 100644 --- a/configs/AppConfig.inc +++ b/configs/AppConfig.inc @@ -89,6 +89,22 @@ ); + /** + * Allowed mimetypes with sizes + * + * @static + * @var array + */ + public static $mimetypes = array( + 'charactergroupsquests' => array( + array( + 'mimetype' => 'image/jpeg', + 'size' => 1048576, + ) + ) + ); + + /** * Miscellaneous settings * diff --git a/controllers/CharactergroupsquestsController.inc b/controllers/CharactergroupsquestsController.inc index cceaed46..fe47e14e 100644 --- a/controllers/CharactergroupsquestsController.inc +++ b/controllers/CharactergroupsquestsController.inc @@ -25,7 +25,7 @@ * * @var array */ - public $models = array('seminaries', 'charactergroups', 'charactergroupsquests', 'media', 'questgroups'); + public $models = array('seminaries', 'charactergroups', 'charactergroupsquests', 'media', 'questgroups', 'uploads'); /** * Required components * @@ -87,6 +87,12 @@ $questmedia = $this->Media->getSeminaryMediaById($quest['questsmedia_id']); } + // Get uploads + $uploads = $this->Charactergroupsquests->getMediaForQuest($quest['id']); + foreach($uploads as &$upload) { + $upload['upload'] = $this->Uploads->getSeminaryuploadById($upload['seminaryupload_id']); + } + // Pass data to view $this->set('seminary', $seminary); @@ -95,6 +101,7 @@ $this->set('questgroup', $questgroup); $this->set('groups', $groups); $this->set('media', $questmedia); + $this->set('uploads', $uploads); } @@ -127,45 +134,109 @@ // Get Character groups $groups = $this->Charactergroups->getGroupsForGroupsgroup($groupsgroup['id']); - // Set XPs of Character groups for this Character groups Quest - if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('setxps'))) + // Get allowed mimetypes + $mimetypes = \nre\configs\AppConfig::$mimetypes['charactergroupsquests']; + + // Manage + $validation = array(); + if($this->request->getRequestMethod() == 'POST') { - $xps = $this->request->getPostParam('xps'); - foreach($groups as &$group) + // Upload media + if(!is_null($this->request->getPostParam('setmedia'))) { - if(array_key_exists($group['url'], $xps) && $xps[$group['url']] != 'null') - { - $xpsFactor = intval($xps[$group['url']]) / $quest['xps']; - $this->Charactergroupsquests->setXPsOfGroupForQuest($quest['id'], $group['id'], $xpsFactor); + $file = $_FILES['media']; + + // Check error + if($file['error'] !== 0 || empty($file['tmp_name'])) { + $validation = $this->Validation->addValidationResult($validation, 'media', 'error', $file['error']); } - else { - $this->Charactergroupsquests->deleteGroupForQuest($quest['id'], $group['id']); + + // Check mimetype + $mediaMimetype = null; + foreach($mimetypes as &$mimetype) { + if($mimetype['mimetype'] == $file['type']) { + $mediaMimetype = $mimetype; + break; + } + } + if(is_null($mediaMimetype)) { + $validation = $this->Validation->addValidationResult($validation, 'media', 'mimetype', $file['type']); + } + elseif($file['size'] > $mediaMimetype['size']) { + $validation = $this->Validation->addValidationResult($validation, 'media', 'size', $mediaMimetype['size']); + } + + // Upload media + if($validation === true) + { + // Create filename + $filename = sprintf( + '%s-%d-%s.%s', + 'charactergroupsquest', + $quest['id'], + date('Ymd-His'), + mb_substr($file['name'], strrpos($file['name'], '.')+1) + ); + + // Upload file + $this->Charactergroupsquests->uploadMediaForQuest($this->Auth->getUserId(), $seminary['id'], $quest['id'], $file, $filename); + } + } + + // Set XPs of Character groups for this Character groups Quest + if(!is_null($this->request->getPostParam('setxps'))) + { + $xps = $this->request->getPostParam('xps'); + foreach($groups as &$group) + { + if(array_key_exists($group['url'], $xps) && $xps[$group['url']] != 'null') + { + $xpsFactor = intval($xps[$group['url']]) / $quest['xps']; + $this->Charactergroupsquests->setXPsOfGroupForQuest($quest['id'], $group['id'], $xpsFactor); + } + else { + $this->Charactergroupsquests->deleteGroupForQuest($quest['id'], $group['id']); + } } } // Redirect to Quest page - $this->redirect($this->linker->link(array('quest', $seminary['url'], $groupsgroup['url'], $quest['url']), 1)); + if($validation === true || empty($validation)) { + $this->redirect($this->linker->link(array('quest', $seminary['url'], $groupsgroup['url'], $quest['url']), 1)); + } } + // Get icon + $questmedia = null; + if(!is_null($quest['questsmedia_id'])) { + $questmedia = $this->Media->getSeminaryMediaById($quest['questsmedia_id']); + } + + // Get uploads + $uploads = $this->Charactergroupsquests->getMediaForQuest($quest['id']); + foreach($uploads as &$upload) { + $upload['upload'] = $this->Uploads->getSeminaryuploadById($upload['seminaryupload_id']); + } + + // Set XPs for Groups foreach($groups as &$group) { $group['quest_group'] = $this->Charactergroupsquests->getXPsOfGroupForQuest($quest['id'], $group['id']); } - // Media - $questmedia = null; - if(!is_null($quest['questsmedia_id'])) { - $questmedia = $this->Media->getSeminaryMediaById($quest['questsmedia_id']); - } + // Pass data to view $this->set('seminary', $seminary); $this->set('groupsgroup', $groupsgroup); $this->set('quest', $quest); + $this->set('uploads', $uploads); + $this->set('mimetypes', $mimetypes); $this->set('questgroup', $questgroup); $this->set('groups', $groups); $this->set('media', $questmedia); + $this->set('validation', $validation); } diff --git a/controllers/UploadsController.inc b/controllers/UploadsController.inc index fba66335..53cd1981 100644 --- a/controllers/UploadsController.inc +++ b/controllers/UploadsController.inc @@ -75,7 +75,7 @@ * @param string $seminaryUrl URL-title of Seminary * @param string $uploadUrl URL-name of the upload */ - public function seminary($seminaryUrl, $uploadUrl) + public function seminary($seminaryUrl, $uploadUrl, $action=null) { // Get Seminary $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl); @@ -105,7 +105,18 @@ } // Get file - $file = $this->getUploadFile($upload); + switch($action) + { + case null: + $file = $this->getUploadFile($upload); + break; + case 'thumbnail': + $file = $this->createThumbnail($upload); + break; + default: + throw new \nre\exceptions\ParamsNotValidException($action); + break; + } if(is_null($file)) { return; } @@ -184,6 +195,82 @@ } + /** + * Create a thumbnail from an upload. + * + * @param array $upload Upload to create thumbnail for + * @return object Thumbnail for the upload (or null if thumbnail is cached) + */ + private function createThumbnail($upload) + { + // Set filename + $upload['filename'] = ROOT.DS.\nre\configs\AppConfig::$dirs['seminaryuploads'].DS.$upload['url']; + + // Set content-type + $this->response->addHeader("Content-type: image/jpeg"); + + // Cache + if($this->setCacheHeaders($upload['filename'])) { + return null; + } + + // Set geometry + $width = 100; + $height = 100; + + switch($upload['mimetype']) + { + case 'image/jpeg': + case 'image/png': + // Read image from cache + $tempFileName = ROOT.DS.\nre\configs\AppConfig::$dirs['temporary'].DS.$upload['url'].'-'.$width.'x'.$height; + if(file_exists($tempFileName)) + { + // Check age of file + if(date('r', filemtime($tempFileName)+(60*60*24)) > date('r', time())) { + // Too old, delete + unlink($tempFileName); + } + else { + // Valid, read and return + return file_get_contents($tempFileName); + } + } + + // ImageMagick + $im = new \Imagick($upload['filename']); + + // Calculate new size + $geometry = $im->getImageGeometry(); + if($geometry['width'] < $width) { + $width = $geometry['width']; + } + if($geometry['height'] < $height) { + $height = $geometry['width']; + } + + // Process + $im->thumbnailImage($width, $height, true); + $im->contrastImage(1); + $im->setImageFormat('jpeg'); + + // Save temporary file + $im->writeImage($tempFileName); + + + // Return resized image + return $im; + break; + default: + throw new \nre\exceptions\ParamsNotValidException('thumbnail'); + break; + } + + + return $this->getUploadFile($upload); + } + + /** * Determine file information and set the HTTP-header for * caching accordingly. diff --git a/models/CharactergroupsquestsModel.inc b/models/CharactergroupsquestsModel.inc index 5ebe100a..5c9f1602 100644 --- a/models/CharactergroupsquestsModel.inc +++ b/models/CharactergroupsquestsModel.inc @@ -20,6 +20,12 @@ */ class CharactergroupsquestsModel extends \hhu\z\Model { + /** + * Required models + * + * @var array + */ + public $models = array('uploads'); @@ -224,6 +230,57 @@ } + /** + * Upload a media for a Character groups Quest. + * + * @param int $userId ID of user that does the upload + * @param int $seminaryId ID of Seminary + * @param int $questId ID of Quest to upload media for + * @param array $file File-array of file to upload + * @param string $filename Filename for media + * @return boolean Whether upload succeeded or not + */ + public function uploadMediaForQuest($userId, $seminaryId, $questId, $file, $filename) + { + // Save file on harddrive + $uploadId = $this->Uploads->uploadSeminaryFile($userId, $seminaryId, $file['name'], $filename, $file['tmp_name'], $file['type']); + if($uploadId === false) { + return false; + } + + // Create database record + $this->db->query( + 'INSERT INTO charactergroupsquests_seminaryuploads '. + '(seminaryupload_id, charactergroupsquest_id, created_user_id) '. + 'VALUES '. + '(?, ?, ?) ', + 'iii', + $uploadId, $questId, $uploadId + ); + + + return true; + } + + + /** + * Get uploaded Medai for a Character groups Quest. + * + * @param int $questId ID of Quest to get media for + * @return array Seminary uploads + */ + public function getMediaForQuest($questId) + { + return $this->db->query( + 'SELECT seminaryupload_id, created, created_user_id '. + 'FROM charactergroupsquests_seminaryuploads '. + 'WHERE charactergroupsquest_id = ?', + 'i', + $questId + ); + } + + /** * Create a new Character groups Quest. * diff --git a/views/html/charactergroupsquests/create.tpl b/views/html/charactergroupsquests/create.tpl index 58efa071..48e2feb1 100644 --- a/views/html/charactergroupsquests/create.tpl +++ b/views/html/charactergroupsquests/create.tpl @@ -54,9 +54,9 @@