diff --git a/3.0/modules/remote/controllers/gallery_remote.php b/3.0/modules/remote/controllers/gallery_remote.php index 0ef99d4f..cc65a53e 100644 --- a/3.0/modules/remote/controllers/gallery_remote.php +++ b/3.0/modules/remote/controllers/gallery_remote.php @@ -18,28 +18,507 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class Gallery_Remote_Controller extends Controller { + private static $thumb_size = 0; + private static $resize_size = 0; + + //XXX access::required("view", $item); + public function index() { - gallery_remote::check_protocol_version(); $input = Input::instance(); - // TODO: Validate protocol version here - switch($input->post("cmd")) { - case "login": - print "#__GR2PROTO__\n"; - $uname = $input->post("uname"); - if (empty($uname)) { - print "status=202\n"; - } else { - $user = user::lookup_by_name($uname); - $password = $input->post("password"); - if ($user && user::is_correct_password($user, $password)) { - print "status=0\n"; - user::login($user); - } else { - print "status=201\n"; - } - } - print "server_version=2.15\n"; + $reply = GalleryRemoteReply::factory(gallery_remote::GR_STAT_SUCCESS); + + if($this->_check_protocol($input, $reply)) { + $reply->set('debug_gallery_version', '3.0+'); //XXX + $reply->set('debug_user', identity::active_user()->name); + $reply->set('debug_user_type', 'Gallery_User'); + $reply->set('debug_user_already_logged_in', identity::active_user()->id != identity::guest()->id ? '1':''); + $reply->set('server_version', '2.15'); + + $cmd = trim($input->post('cmd')); + if($cmd == 'login') { + $this->_login($input, $reply); + } + else if( self::isloggedin() ) { + switch($cmd) { + case 'no-op': + $reply->set('status_text', 'Noop command successful.'); + $reply->send(); + break; + case 'fetch-albums': + case 'fetch-albums-prune': + $this->_fetch_albums_prune($input, $reply); + break; + case 'new-album': + $this->_new_album($input, $reply); + break; + case 'album-properties': + $this->_album_properties($input, $reply); + break; + case 'add-item': + $this->_add_item($input, $reply); + break; + case 'move-album': + $this->_move_album($input, $reply); + break; + case 'increment-view-count': + $this->_increment_view_count($input, $reply); + break; + case 'image-properties': + $this->_image_properties($input, $reply); + break; + case 'fetch-album-images': + $this->_fetch_album_images($input, $reply); + break; + default: + $reply->send(gallery_remote::UNKNOWN_CMD); + } + } + else { + $reply->send(gallery_remote::LOGIN_MISSING); + } + } + } + + private function _check_protocol(&$input, &$reply) { + $version = trim($input->post('protocol_version')); + if($version=='') { + $reply->send(gallery_remote::PROTO_VER_MISSING); + return false; + } + else if(!is_numeric($version)) { + $reply->send(gallery_remote::PROTO_MAJ_FMT_INVAL); + return false; + } + else if($version<'2') { + $reply->send(gallery_remote::PROTO_MAJ_VER_INVAL); + return false; + } + else if($version<'2.3') { + $reply->send(gallery_remote::PROTO_MIN_VER_INVAL); + return false; + } + + return true; + } + + private static function isloggedin() + { + return identity::active_user()->id != identity::guest()->id; + } + + private static function get_mime_type($filename, $mimePath = '/etc') { + $fileext = substr(strrchr($filename, '.'), 1); + if (empty($fileext)) return (false); + $regex = "/^([\w\+\-\.\/]+)\s+(\w+\s)*($fileext\s)/i"; + $lines = file("$mimePath/mime.types"); + foreach($lines as $line) { + if (substr($line, 0, 1) == '#') continue; // skip comments + $line = rtrim($line) . ' '; + if (!preg_match($regex, $line, $matches)) continue; // no match to the extension + return ($matches[1]); } + return (false); // no match at all } + + private function _login(&$input, &$reply) { + $uname = trim($input->post('uname')); + if (empty($uname)) { + $reply->send(gallery_remote::LOGIN_MISSING); + } else { + $user = user::lookup_by_name($uname); + $password = trim($input->post('password')); + if ($user && user::is_correct_password($user, $password)) { + auth::login($user); + Session::instance()->regenerate(); + + $reply->set('debug_user', $user->name); + $reply->set('status_text', 'Login successful.'); + $reply->send(); + + } else { + $reply->send(gallery_remote::PASSWD_WRONG); + } + } + } + + private function _fetch_albums_prune(&$input, &$reply) { + $root = item::root(); + $thumb_size = module::get_var('gallery', 'thumb_size'); + $resize_size = module::get_var('gallery', 'resize_size'); + $count = 0; + foreach( $root->descendants(null, null, array(array("type", "=", "album"))) as $item ) + { + $count++; + + $reply->set('album.name.'.$count, $item->slug); + $reply->set('album.title.'.$count, $item->title); + $reply->set('album.summary.'.$count, $item->description); + $reply->set('album.parent.'.$count, $item->parent()->id == $root->id ? '0' : $item->parent()->name); + $reply->set('album.resize_size.'.$count, $resize_size); + $reply->set('album.max_size.'.$count, '0'); + $reply->set('album.thumb_size.'.$count, $thumb_size); + $reply->set('album.perms.add.'.$count, 'true'); //XXX + $reply->set('album.perms.write.'.$count, 'true'); //XXX + $reply->set('album.perms.del_item.'.$count, 'true'); //XXX + $reply->set('album.perms.del_alb.'.$count, 'true'); //XXX + $reply->set('album.perms.create_sub.'.$count, 'true'); //XXX + $reply->set('album.info.extrafields.'.$count, ''); + } + $reply->set('album_count', $count); + $reply->set('can_create_root', 'yes'); //XXX + $reply->set('status_text', 'Fetch albums successful.'); + $reply->send(); + } + + private function _new_album(&$input, &$reply) { + $album = trim($input->post('set_albumName')); + $name = trim($input->post('newAlbumName')); + $title = trim($input->post('newAlbumTitle')); + $desc = trim($input->post('newAlbumDesc')); + + if($album=='0') $parent = item::root(); + else $parent = ORM::factory("item")->where("slug", "=", $album)->find(); + + if(isset($parent) && $parent->loaded() && $parent->id!='') { + $album = ORM::factory('item'); + $album->type = 'album'; + $album->parent_id = $parent->id; + + $album->name = $name; + $album->slug = $name; // <= verification fails if this property has not been set!!! + $album->title = $title; + $album->title or $album->title = $album->name; + $album->description = $desc; + //$album->owner_id = + $album->view_count = 0; + //$album->created = $fields['clicks_date']; + $album->sort_column = 'weight'; + $album->sort_order = 'ASC'; + + try { + $album->validate(); + + try { + $album->save(); + + $reply->set('album_name', $album->name); + $reply->set('status_text', 'New album created successfuly.'); + $reply->send(); + + } catch (Exception $e) { + $reply->set('status_text', t('Failed to save album with name %name.', array('name' => $name))); + $reply->send(gallery_remote::CREATE_ALBUM_FAILED); + } + + } catch (ORM_Validation_Exception $e) { + $reply->set('status_text', t('Failed to validate album with name %name.', array('name' => $name))); + $reply->send(gallery_remote::CREATE_ALBUM_FAILED); + } + } + else { + $reply->set('status_text', t('Failed to load album with name %name.', array('name' => $album))); + $reply->send(gallery_remote::CREATE_ALBUM_FAILED); + } + } + + private function _album_properties(&$input, &$reply) { + $album = trim($input->post('set_albumName')); + $resize_size = module::get_var('gallery', 'resize_size'); + + if($album=='0') $parent = item::root(); + else $parent = ORM::factory("item")->where("slug", "=", $album)->find(); + + if(isset($parent) && $parent->loaded() && $parent->id!='') { + $reply->set('auto_resize', $resize_size); //XXX + $reply->set('max_size', '0'); //XXX + $reply->set('add_to_beginning', 'no'); //XXX + $reply->set('extrafields', ''); + $reply->set('title', $parent->title); + $reply->set('status_text', 'Album properties queried successfuly.'); + $reply->send(); + } + else { + $reply->set('status_text', t('Failed to load album with name %name.', array('name' => $album))); + $reply->send(gallery_remote::NO_VIEW_PERMISSION); + } + } + + private function _add_item(&$input, &$reply) { + $album = trim($input->post('set_albumName')); + $userfilename = trim($input->post('userfile_name')); + $title = trim($input->post('caption')); + $forcefilename = trim($input->post('force_filename')); + $autorotate = trim($input->post('auto_rotate')); + //print_r($_FILES['userfile']); exit; + + if($album=='0') $parent = item::root(); + else $parent = ORM::factory("item")->where("slug", "=", $album)->find(); + + if(isset($parent) && $parent->loaded() && $parent->id!='') { + + //* + if(function_exists('mime_content_type')) + $type = mime_content_type($_FILES['userfile']['tmp_name']); + else + $type = self::get_mime_type($_FILES['userfile']['name']); + + if ($type!='' && !in_array($type, array('image/jpeg', 'image/gif', 'image/png'))) { + $reply->set('status_text', t("'%path' is an unsupported image type '%type'", array('path' => $_FILES['userfile']['tmp_name'], 'type' => $type))); + $reply->send(gallery_remote::UPLOAD_PHOTO_FAIL); + return; + } + + if($forcefilename!='') $filename = $forcefilename; + else if($userfilename!='') $filename = $userfilename; + else $filename = $_FILES['userfile']['name']; + + $slug = $filename; + $pos = strpos($slug, '.'); + if($pos!==false) + $slug = substr($slug, 0, $pos); + + try { + $item = ORM::factory('item'); + $item->type = 'photo'; + $item->parent_id = $parent->id; + $item->set_data_file($_FILES['userfile']['tmp_name']); + $item->name = $filename; + $item->slug = $slug; + $item->mime_type = $type; + $item->title = $title; + $item->title or $item->title = ' '; //don't use $item->name as this clutters up the UI + //$item->description = + //$item->owner_id = + $item->view_count = 0; + + try { + $item->validate(); + + try { + $item->save(); + + $reply->set('item_name', $item->name); + $reply->set('status_text', 'New item created successfuly.'); + $reply->send(); + + } catch (Exception $e) { + $reply->set('status_text', t('Failed to add item %item.', array('item' => $filename))); + $reply->send(gallery_remote::UPLOAD_PHOTO_FAIL); //XXX gallery remote doesn't accept this :( + } + + } catch (ORM_Validation_Exception $e) { + $validation = $e->validation; + //print_r($validation->errors()); exit; + $reply->set('status_text', t('Failed to validate item %item: %errors', array('item' => $filename, 'errors' => print_r($validation->errors(),true)) )); + $reply->send(gallery_remote::UPLOAD_PHOTO_FAIL); //XXX gallery remote doesn't accept this :( + } + + } catch (Exception $e) { + $reply->set('status_text', t("Corrupt image '%path'", array('path' => $_FILES['userfile']['tmp_name']))); + $reply->send(gallery_remote::UPLOAD_PHOTO_FAIL); //XXX gallery remote doesn't accept this :( + } + + } + else { + $reply->set('status_text', t('Failed to load album with name %name.', array('name' => $album))); + $reply->send(gallery_remote::UPLOAD_PHOTO_FAIL); //XXX gallery remote doesn't accept this :( + } + } + + private function _move_album(&$input, &$reply) { + $name = trim($input->post('set_albumName')); + $destination = trim($input->post('set_destalbumName')); + + $album = ORM::factory("item")->where("slug", "=", $name)->find(); + + if($destination=='0') $parent = item::root(); + else $parent = ORM::factory("item")->where("slug", "=", $destination)->find(); + + if(isset($parent) && $parent->loaded() && $parent->id!='' && isset($album) && $album->loaded() && $album->id!='') { + + $album->parent_id = $parent->id; + try { + $album->validate(); + + try { + $album->save(); + + $reply->set('status_text', 'Album moved successfuly.'); + $reply->send(); + + } catch (Exception $e) { + $reply->set('status_text', t('Failed to save album with name %name.', array('name' => $name))); + $reply->send(gallery_remote::MOVE_ALBUM_FAILED); + } + + } catch (ORM_Validation_Exception $e) { + $reply->set('status_text', t('Failed to validate album with name %name.', array('name' => $name))); + $reply->send(gallery_remote::MOVE_ALBUM_FAILED); + } + } + else { + $reply->set('status_text', t('Failed to load album with name %album or destination with name %dest.', array('name' => $name, 'dest' => $destination))); + $reply->send(gallery_remote::MOVE_ALBUM_FAILED); + } + } + + private function _increment_view_count(&$input, &$reply) { + $name = trim($input->post('itemId')); + + if($name=='0') $item = item::root(); + else $item = ORM::factory("item")->where("slug", "=", $name)->find(); + + if(isset($item) && $item->loaded() && $item->id!='') { + + $item->view_count = $item->view_count + 1; + + try { + $item->validate(); + + try { + $item->save(); + + $reply->set('item_name', $item->name); + $reply->set('status_text', 'Item view count incremented successfuly.'); + $reply->send(); + + } catch (Exception $e) { + $reply->set('status_text', t('Failed to save item %item.', array('item' => $name))); + $reply->send(gallery_remote::NO_WRITE_PERMISSION); + } + + } catch (ORM_Validation_Exception $e) { + $validation = $e->validation; + //print_r($validation->errors()); exit; + $reply->set('status_text', t('Failed to validate item %item.', array('item' => $name)).print_r($validation->errors(),true)); + $reply->send(gallery_remote::NO_WRITE_PERMISSION); + } + + } + else { + $reply->set('status_text', t('Failed to load album with name %name.', array('name' => $name))); + $reply->send(gallery_remote::NO_WRITE_PERMISSION); + } + } + + private function _image_properties(&$input, &$reply) { + $name = trim($input->post('itemId')); + + if($name=='0') $item = item::root(); + else $item = ORM::factory("item")->where("slug", "=", $name)->find(); + + if(isset($item) && $item->loaded() && $item->id!='') { + $reply->set('status_text', 'Item properties queried successfuly.'); + + $reply->set('image.name', $item->slug); + $reply->set('image.raw_width', $item->width); + $reply->set('image.raw_height', $item->height); + $reply->set('image.raw_filesize', filesize($item->file_path())); + $reply->set('image.resizedName', $item->name); //g3 stores resizes and thumbs different than g1 + $reply->set('image.resized_width', $item->resize_width); + $reply->set('image.resized_height', $item->resize_height); + $reply->set('image.thumbName', $item->name); //g3 stores resizes and thumbs different than g1 + $reply->set('image.thumb_width', $item->thumb_width); + $reply->set('image.thumb_height', $item->thumb_height); + $reply->set('image.caption', $item->title); + $reply->set('image.title', $item->title); + //XXX $reply->set('image.forceExtension', ''); + $reply->set('image.hidden', 'no'); //XXX + $reply->send(); + } + else { + $reply->set('status_text', t('Failed to load album with name %name.', array('name' => $name))); + $reply->send(gallery_remote::NO_VIEW_PERMISSION); + } + } + + private function _fetch_album_images(&$input, &$reply) { + $name = trim($input->post('set_albumName')); + $albums = trim($input->post('albums_too')); //yes/no [optional, since 2.13] + $random = trim($input->post('random')); //yes/no [optional, G2 since ***] + $limit = trim($input->post('limit')); //number-of-images [optional, G2 since ***] + $fields = trim($input->post('extrafields')); //yes/no [optional, G2 since 2.12] + $sizes = trim($input->post('all_sizes')); //yes/no [optional, G2 since 2.14] + + if($name=='0') $album = item::root(); + $album = ORM::factory("item")->where("slug", "=", $name)->find(); + + if(isset($album) && $album->loaded() && $album->id!='') { + + if($albums!='no') $iterator = ORM::factory("item")->where("parent_id", "=", $album->id)->find_all(); + else $iterator = ORM::factory("item")->where("parent_id", "=", $album->id)->where("type", "<>", "album")->find_all(); + + $reply->set('status_text', 'Album images query successful.'); + $reply->set('album.caption', $album->title); + $reply->set('album.extrafields', ''); + + /* + $reply->set('image_count', '0'); + $reply->send(); + return; + //*/ + + $count = 0; + foreach($iterator as $item) { + + $count++; + if($item->type != "album") { + $reply->set('image.name.'.$count, $item->name); + //$reply->set('image', print_r($item, true)); + $reply->set('image.raw_width.'.$count, $item->width); + $reply->set('image.raw_height.'.$count, $item->height); + $reply->set('image.raw_filesize.'.$count, filesize($item->file_path())); + $reply->set('image.resizedName.'.$count, $item->name); //g3 stores resizes and thumbs different than g1 + $reply->set('image.resized_width.'.$count, $item->resize_width); + $reply->set('image.resized_height.'.$count, $item->resize_height); + //$reply->set('image.resizedNum.'.$count, 'the number of resized versions for this image [since 2.14]'); + //$reply->set('image.resized.resized-num.name.'.$count, 'filename of the resized-numth resize [G2 since 2.14]'); + //$reply->set('image.resized.resized-num.width.'.$count, 'the width of the resized-numth resize [G2 since 2.14]'); + //$reply->set('image.resized.resized-num.height.'.$count, 'the height of the resized-numth resize [G2 since 2.14]'); + $reply->set('image.thumbName.'.$count, $item->name); //g3 stores resizes and thumbs different than g1 + $reply->set('image.thumb_width.'.$count, $item->thumb_width); + $reply->set('image.thumb_height.'.$count, $item->thumb_height); + + $reply->set('image.caption.'.$count, $item->title); + $reply->set('image.title.'.$count, $item->title); + //$reply->set('image.extrafield.fieldname.'.$count, 'value of the extra field of key fieldname'); + $reply->set('image.clicks.'.$count, $item->view_count); + //* + $reply->set('image.capturedate.year.'.$count, date("Y", $item->captured)); + $reply->set('image.capturedate.mon.'.$count, date("m", $item->captured)); + $reply->set('image.capturedate.mday.'.$count, date("d", $item->captured)); + $reply->set('image.capturedate.hours.'.$count, date("H", $item->captured)); + $reply->set('image.capturedate.minutes.'.$count, date("i", $item->captured)); + $reply->set('image.capturedate.seconds.'.$count, date("s", $item->captured)); + //*/ + //XXX $reply->set('image.forceExtension.'.$count, ''); + $reply->set('image.hidden.'.$count, 'no'); //XXX + } + else { + $reply->set('album.name.'.$count, $item->name); + } + } + + $reply->set('image_count', $count); + //* The baseurl contains a fully-qualified URL. A URL to each image + // can be obtained by appending the filename of the image to this. + if(isset($item) && $item->loaded()) { + $url = $item->file_url(true); + $pos = strrpos($url, '/'); + $reply->set('baseurl', ($pos!==false ? substr($url, 0, $pos+1) : $url) ); + } + else { + $reply->set('baseurl', $album->abs_url()); + } + //*/ + $reply->send(); + + } + else { + $reply->set('status_text', t('Failed to load album with name %name.', array('name' => $name))); + $reply->send(gallery_remote::NO_VIEW_PERMISSION); + } + } + } diff --git a/3.0/modules/remote/libraries/GalleryRemoteReply.php b/3.0/modules/remote/libraries/GalleryRemoteReply.php index 3896ed09..7ad5781f 100644 --- a/3.0/modules/remote/libraries/GalleryRemoteReply.php +++ b/3.0/modules/remote/libraries/GalleryRemoteReply.php @@ -19,22 +19,39 @@ */ class GalleryRemoteReply_Core { + private $values = array(); + private $nl = "\n"; /** * Constructor. * @param int $status a Gallery Remote status code */ - public static function factory($status) { + public static function factory($status='') { $reply = new GalleryRemoteReply(); - $reply->status = $status; + $reply->set('status', $status); + $reply->set('status_text', ''); return $reply; } + public function clear() { + $this->values = array(); + } + /** * Set a property on this reply * @chainable */ - public static function set($key, $value) { - $this->$key = $value; + public function set($key, $value) { + $this->values[$key] = $value; return $this; } + + public function send($status='') { + if($status!='') $reply->set('status', $status); + //ksort($this->values); + + echo '#__GR2PROTO__'.$this->nl; + foreach($this->values as $key => $value) { + echo $key.'='.$value.$this->nl; + } + } }